Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support python requests keyword arguments when making remote calls #1

Merged
merged 1 commit into from
Jan 31, 2017

Conversation

banjoh
Copy link

@banjoh banjoh commented Jan 31, 2017

Since this library is heavily dependent on python requests for making remote calls, it is necessary to pass down parameters such as timeout and header to requests methods.

This PR is related to simple-salesforce#148

Copy link

@kryptidikettu kryptidikettu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you have lots of changes here and I partly disagree with your style in RequestMixin, see the comments in the diff for more info :).

@@ -37,8 +38,60 @@ def _warn_request_deprecation():
)


class RequestMixin(object):
def __init__(self, session=None):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MixIn-objects generally do not initialize themselves. See examples here: https://github.com/pallets/werkzeug/blob/master/werkzeug/wrappers.py#L1281-L1628
https://github.com/django/django/blob/master/django/contrib/auth/mixins.py

Also this blog post explains some concepts: https://www.ianlewis.org/en/mixins-and-python

Basic idea behind Mixins (as I understand them), is that you give devs possibilities to add "automatic" features to other classes. In this case, your Mixin would not implement _call_salesforce method, it would implement something like request. The Salesforce-class would then always use self.request()-method but depending on the Mixin inherited, the behaviour would change.

I recommend either renaming this class, or thinking how to implement it in a more "generic" mixin style.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I think this is subject to different interpretations, but I see your point. I'll make some changes to simplify the implementation. Using a mixin may stir the wrong interpretation.

@@ -3,6 +3,7 @@

# has to be defined prior to login import
DEFAULT_API_VERSION = '29.0'
TIMEOUT = 60

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we want to have TIMEOUT as a global property... If the idea is for the user of Salesforce to pass the timeout parameter for requests, timeout should be empty by default.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could also be configurable when you instantiate the Salesforce class...

self.session_id = "sessionId"
self.name = ""

def _call_salesforce(self, method, url, **kwargs):
Copy link

@kryptidikettu kryptidikettu Jan 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You defined timeout as a global property, it could be also implemented here as an argument for this function. This would make more sense, since you can also provide default value for it.

"""Describes all available objects

Keyword Args: Parameters passed down to requests.request method

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case Keyword Args is actually passed down to requests.Sessions.request-method, not requests.request. The documentation for those functions is (almost) the same, but we want to be accurate in our own documentation :).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember the backticks for requests.request. The original documentation also uses * kwargs instead of Keyword Args. Is this change intentional?

@@ -774,22 +807,12 @@ def __init__(self, username, password, security_token, sandbox=False,

def _exception_handler(result, name=""):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function has been defined as "private" (by Python naming standards). Why not remove it instead of marking it deprecated?

_single_leading_underscore : weak "internal use" indicator. E.g. from M import * does not import objects whose name starts with an underscore.
-- https://www.python.org/dev/peps/pep-0008/#public-and-internal-interfaces

Use one leading underscore only for non-public methods and instance variables.
-- https://www.python.org/dev/peps/pep-0008/#method-names-and-instance-variables

Any backwards compatibility guarantees apply only to public interfaces. Accordingly, it is important that users be able to clearly distinguish between public and internal interfaces.

Documented interfaces are considered public, unless the documentation explicitly declares them to be provisional or internal interfaces exempt from the usual backwards compatibility guarantees. All undocumented interfaces should be assumed to be internal.
-- https://www.python.org/dev/peps/pep-0008/#descriptive-naming-styles

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my initial approach but I thought its possible to have someone (mis)use it since its not really private. I would rather go through the deprecation processes.

The project has been forked quite a bit. I would not want to break extensions that exist already.

Copy link

@kryptidikettu kryptidikettu Jan 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But as PEP8 describes, it is never a guarantee for undocumented private-functions to stay backward compatible. My personal opinion is to remove this function, but the upstream author has, of course, the ultimate say :).

Edit: You can keep the current implementation, or do my proposed change. It is up to you.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll probably remove it anyway. Let's see what the maintainer comments. I'll add a comment about this.

@@ -21,7 +21,7 @@
def SalesforceLogin(
username=None, password=None, security_token=None,
organizationId=None, sandbox=False, sf_version=DEFAULT_API_VERSION,
proxies=None, session=None, client_id=None):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did the documented proxies Keyword Argument vanish?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's one of the requests kwargs and hence part of the requests' documentation.

https://github.com/kennethreitz/requests/blob/master/requests/api.py#L16

@@ -575,12 +577,14 @@ def setUp(self):
self.mockresult = Mock()
self.mockresult.url = 'http://www.example.com/'
self.mockresult.json.return_value = 'Example Content'
self.mock_mixin = RequestMixin()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this called mock_mixin when it is, in fact, the real Mixin-class?

self.mockresult.status_code = 404
resource_name = 'SpecialContacts'
with self.assertRaises(SalesforceResourceNotFound) as exception:
_exception_handler(result=self.mockresult, name=resource_name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you remove the (currently) deprecated _exception_handler, you can also remove this test and the import for _exception_handler :).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it there as a regression test. Once it's really deprecated then it can be removed.

@@ -38,7 +37,7 @@ def _warn_request_deprecation():
)


class RequestMixin(object):
class RequestBase(object):
def __init__(self, session=None):
"""
Mixin class to encapsulate all remote operations

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed a docstring here :)

@@ -810,7 +809,7 @@ def _exception_handler(result, name=""):
warnings.warn('This global exception handler is deprecated. It has been moved'
'to the RequestMixin class.', DeprecationWarning)

mixin = RequestMixin()
mixin = RequestBase()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mixin name appears here as well.

@@ -61,7 +60,7 @@ def _call_salesforce(self, method, url, **kwargs):
}
additional_headers = kwargs.pop('headers', dict())
headers.update(additional_headers or dict())
timeout = kwargs.pop('timeout', TIMEOUT)
timeout = kwargs.pop('timeout', 60)
Copy link

@kryptidikettu kryptidikettu Jan 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think you should add timeout as an argument with a default value, make it configurable in the __init__()-function or keep it unchanged in kwargs. This timeout = kwargs.pop looks too verbose and, frankly, ugly here...

@@ -577,8 +576,8 @@ def setUp(self):
self.mockresult = Mock()
self.mockresult.url = 'http://www.example.com/'
self.mockresult.json.return_value = 'Example Content'
self.mock_mixin = RequestMixin()
self.exec_handler = self.mock_mixin._exception_handler
self.mixin = RequestBase()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mixin name here as well.

@banjoh banjoh merged commit 6589602 into F-Secure:master Jan 31, 2017
@banjoh banjoh deleted the requests_args branch January 31, 2017 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants