2

Ran into this problem trying to call braintree.ClientToken.generate() from a Google App Engine app, running Flask on dev_appserver.py. dev_appserver.py can't currently make outgoing SSL connections. Making the above braintree call yields

ConnectionError: ('Connection aborted.', error(13, 'Permission denied'))

The call works on in a real GAE environment. It's used in one of my views, so it breaks my whole website flow with the above 500 error when it fails. How can I work around this so that I can continue developing in my local environment?

brandones
  • 1,847
  • 2
  • 18
  • 36

2 Answers2

1

If you have some variable global to your app that corresponds with when you're running in dev_appserver.py, you can create a mock of the failing method conditioned on that variable.

In my case, that variable is called env_conf.FLASK_CONF. I used the following code to mock the braintree generate call.

# Imports
import braintree
import env_conf
from flask import render_template

# Mock Braintree in DEV environment
if env_conf.FLASK_CONF == 'DEV':
    from functools import partial
    def mock_generate(self):
        return 'foobarbaz123'
    braintree.ClientToken.generate = partial(mock_generate, braintree.ClientToken())

# Add payment handler
def add_payment():
    token = braintree.ClientToken.generate()
    return render_template('add-payment.html',
                           braintree_client_token=token)

The idea generically is:

import problem_function
if DEV_ENVIRONMENT:
    def mock_problem_fcn():
        return 'expected response'
    problem_function = mock_problem_function

problem_function()
brandones
  • 1,847
  • 2
  • 18
  • 36
1

I work at Braintree. If you have more questions, you can always contact our support team

For help with the Braintree Python library on GAE, see this example on my GitHub. To answer your question, you can force the dev server to use the real Python socket library, so SSL connections work:

try:
    # This is needed to make local development work with SSL.
    # This must be done *before* you import the Braintree Python library.
    # See http://stackoverflow.com/a/24066819/500584
    # and https://code.google.com/p/googleappengine/issues/detail?id=9246 for more information.
    from google.appengine.tools.devappserver2.python import sandbox
    sandbox._WHITE_LIST_C_MODULES += ['_ssl', '_socket']

    import sys
    # this is socket.py copied from a standard python install
    import stdlib_socket
    sys.modules['socket'] = stdlib_socket
except ImportError as e:
    print(e)
agf
  • 171,228
  • 44
  • 289
  • 238
  • This is an answer to a different question (I think). If I understand correctly, this enables incoming SSL connections to dev_appserver.py, not outgoing ones. The problem I was encountering is that dev_appserver can't make outgoing SSL connections. I was pretty frustrated when all I could find at all related to my problem was this answer, which of course I tried to no avail whatsoever, strewn all over the internet. – brandones Aug 31 '15 at 22:40
  • @brandones You're mistaken. This fix is specifically to enable outgoing SSL connections. – agf Aug 31 '15 at 22:49
  • Didn't work for me. There are a few variants of this fix that I tried as well. I just kept getting the same error -- `ConnectionError: ('Connection aborted.', error(13, 'Permission denied'))` – brandones Aug 31 '15 at 23:12
  • @brandones If you post a minimal example of code with the fix from my answer that still has the problem for you, I'll be glad to take a look tomorrow and see if I can reproduce. – agf Aug 31 '15 at 23:15
  • Turns out I was calling `import braintree` above this code, so it wasn't using the provided socket module. `import braintree` needs to come *after* this code. I think that would be a good thing to specify, since it's certainly not obvious. – brandones Oct 19 '15 at 20:38
  • As an aside, silently swallowing ImportErrors is a classic Bad Idea. This bit me in the ass when I had a path problem with `stdlib_socket`. For my application, I was able to remove the `try/except` entirely and make the code conditional on the environment. Since that's not always an option I hugely recommend replacing `except ImportError: pass` with `except ImportError, e: print e`. – brandones Oct 19 '15 at 20:39
  • Now I'm getting `ConnectionError: ('Connection aborted.', error(22, 'Invalid argument'))` on calls to `braintree.ClientToken.generate()`. Pretty sure that means I'm past this issue though. I'll open a new question, @agf ? – brandones Oct 19 '15 at 20:41
  • @brandones Yep, that would do it. I'll make the fact that this is ordering dependent more clear. When you post your new question, link it here and please include a minimal example so I can try to reproduce. – agf Oct 20 '15 at 03:28
  • I pushed an update to my example with the changes you suggested. – agf Oct 20 '15 at 03:40