braintree / braintree_python

Braintree Python library
https://developer.paypal.com/braintree/docs/start/overview
MIT License
242 stars 116 forks source link

AttributeError: 'unicode' object has no attribute 'items' #68

Closed alanhamlett closed 8 years ago

alanhamlett commented 8 years ago

This line misses Python2 unicode strings, eventually causing an AttributeError exception.

Traceback (most recent call last):
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/subscription.py", line 150, in update
    return Configuration.gateway().subscription.update(subscription_id, params)
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/subscription_gateway.py", line 59, in update
    Resource.verify_keys(params, Subscription.update_signature())
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/resource.py", line 9, in verify_keys
    params_keys = Resource.__flattened_params_keys(params)
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/resource.py", line 27, in __flattened_params_keys
    keys += Resource.__flattened_params_keys(val, full_key)
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/resource.py", line 30, in __flattened_params_keys
    keys += Resource.__flattened_params_keys(item, full_key)
  File "/opt/wakatime/current/venv/local/lib/python2.7/site-packages/braintree/resource.py", line 24, in __flattened_params_keys
    for key, val in params.items():
AttributeError: 'unicode' object has no attribute 'items'

Should be basestring instead of str, or even better use six.string_types for Python 3 compatibility.

jdlc commented 8 years ago

@alanhamlett, Thanks for opening this issue. Could you share more details about your use case and integration with Braintree so we can better evaluate this change? Currently the Braintree Python client library as a whole favors str over basestring.

alanhamlett commented 8 years ago

Sometimes I pass strings from SQLAlchemy, which prefers unicode over str, and from WTForms, which also prefers unicode over str. I'm not sure which attribute caused the error, but it was when changing the quantity in the addons array when updating a subscription.

jdlc commented 8 years ago

Thanks for clarifying your use case. We'll discuss this change and let you know if we have any further questions.

jdlc commented 8 years ago

Hi @alanhamlett, We've discussed this internally and we will be retaining str as we want encoded strings instead of unicode. I'm closing this issue, but thanks for reaching out.

alanhamlett commented 8 years ago

Ok, just want to say that str should only be used when writing to disk, network, or other things external to Python. unicode is the preferred way to handle any string in Python.

When you’re dealing with text manipulations (finding the number of characters in a string or cutting a string on word boundaries) you should be dealing with unicode strings as they abstract characters in a manner that’s appropriate for thinking of them as a sequence of letters that you will see on a page. When dealing with I/O, reading to and from the disk, printing to a terminal, sending something over a network link, etc, you should be dealing with byte str as those devices are going to need to deal with concrete implementations of what bytes represent your abstract characters.

For example as soon as you get a string from the user or from the network, convert it to unicode: https://pythonhosted.org/kitchen/unicode-frustrations.html#convert-text-at-the-border I've noticed usage of both unicode and str in this library. You should standardize the usage of unicode vs str throughout the library.

You're going to run into a lot of cases where unicode is needed (emails can contain unicode characters) so it's best to standardize on unicode instead of str. Having to somehow guess which string type this library is expecting is a recipe for exceptions.

alanhamlett commented 8 years ago

Also, the 2 most popular Python web frameworks[1] both default to unicode and both convert user input to unicode. For example a payment processor token from braintree.js is automatically treated as unicode and it goes against conventions to have to convert back to str when passing strings to braintree_python.

  1. Django and Flask are in my experience the 2 most popular Python web frameworks