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

added requests session to ApiClient #80

Open
wants to merge 22 commits into
base: develop
Choose a base branch
from

Conversation

seantibor
Copy link
Contributor

@seantibor seantibor commented Apr 19, 2020

Fixes #62 by adding requests session to ApiClient utility instances. This may be a naive approach, so please let me know if we need additional changes to support this.

  • added session instance to ApiClient
  • replaced requests.<method> with self.session.<method> calls
  • updated mock patches to use util.requests.Session object patches in test_util.py

@prschmid
Copy link
Owner

@seantibor Thank you for your work! We just switched over to using the responses library for better and cleaner testing. I'm going to leave this PR open but, my guess is that when you merge develop in to your branch, this will no longer be relevant.

That being said thank you for your effort in trying to improve this library!

@seantibor
Copy link
Contributor Author

I was able to accept all of the incoming changes from develop, particularly in test_util. The util.ApiClient uses a session object from requests now, which should save some resources and time when making large numbers of requests sequentially.

Copy link
Owner

@prschmid prschmid left a comment

Choose a reason for hiding this comment

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

Thanks for taking the time to add this in and it's a great start! I added a suggestion that would make this a bit more flexible and retain backwards compatibility for those who need it.

Could I also trouble you to write some tests for this? Thank you!

zoomus/util.py Outdated
@@ -30,6 +30,7 @@ def __init__(self, base_uri=None, timeout=15, **kwargs):
self.timeout = timeout
for k, v in kwargs.items():
setattr(self, k, v)
self.session = requests.Session()
Copy link
Owner

Choose a reason for hiding this comment

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

This is a great start! For the sake of flexibility can we make this a configurable option and have the ability to start a new session. I.e. Let's make the method signature

def __init__(self, base_uri=None, timeout=15, use_session=True, **kwargs):

Then we can do something like

self.session = requests.Session() ? use_session : requests

This should then either use the Session or requests depending on what was requested.

We'd then also want to add a new method called something like new_session or something like that so that if someone needs a new session for some reason, they could do that without having to reinstantiate the ApiClient.

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps it might even be better if this let the client be used as a context manager, rather than having to explicitly say use_session. So then, reusing an example from the readme, a user could do something like:

with ApiClient() as client:
    users = client.user.list().content
    meetings = {user["id"]: client.meeting.list(user_id=user["id"]).content for user in users}

This could be implemented by adding basically

def __enter__(self):
    self.session = requests.Session()

def __exit__(self):
    self.session = None

And the individual get/post, etc, optionally call the client if it's present.

Copy link
Owner

Choose a reason for hiding this comment

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

Even better! Great idea!

@seantibor
Copy link
Contributor Author

Ok -- this should be working now. I've implemented the context manager methods, added tests for the context manager and methods, but I have not added tests for the v2 client yet.

Do we want to write V2 client context manager tests too? I've added a lot of tests for the context manager code so I'm not sure if the value is there. Or we could move them to v2 client calls?

zoomus/util.py Outdated
@@ -30,6 +30,7 @@ def __init__(self, base_uri=None, timeout=15, **kwargs):
self.timeout = timeout
for k, v in kwargs.items():
setattr(self, k, v)
self.session = requests
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a little bit alarming and confusing to see without proper context. I think this probably warrants an explanatory comment, or maybe self.session could become a property instead? Along the lines of...

@property
def session(self):
    """Provide a session if one is in use; otherwise, provide the requests module directly."""
    if self._session is not None:
        return self._session
    return requests

@session.setter
def session(self, val):
    self._session = val

@session.deleter
def session(self):
    self._session = None

Copy link
Contributor Author

Choose a reason for hiding this comment

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

REALLY fair point. I'll include your suggestions now. This approach seems a lot more sane

@seantibor
Copy link
Contributor Author

Updated session approach to use setter, getter, and deleter property methods.

@seantibor seantibor requested a review from prschmid May 8, 2020 20:51
@mfldavidson
Copy link
Contributor

Tests passed for all supported Python versions. Would like @prschmid to take a look before confirming merge.

Copy link
Owner

@prschmid prschmid left a comment

Choose a reason for hiding this comment

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

Thank you for taking this on and for your patience in getting this approved!!! Just ran the tests locally and it looks like some tests are failing -- based on the error that I'm seeing, if you merge in the latest develop to your branch, those tests should fix themselves.

(~/Development/zoomus:[feature/requests-session]) # nosetests .      
....................................................................................................................................................................EEEEEEEEEEEE.EEE.....................................................................................S.S......
======================================================================
ERROR: test_api_version_defaults_to_2 (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 91, in test_api_version_defaults_to_2
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_api_key (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 95, in test_can_get_api_key
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_api_secret (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 104, in test_can_get_api_secret
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_meeting_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 113, in test_can_get_meeting_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_phone_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 135, in test_can_get_phone_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_recording_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 129, in test_can_get_recording_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_report_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 117, in test_can_get_report_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_user_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 121, in test_can_get_user_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_get_webinar_component (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 125, in test_can_get_webinar_component
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_set_api_key (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 99, in test_can_set_api_key
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_set_api_secret (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 108, in test_can_set_api_secret
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_can_use_client_with_context (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 139, in test_can_use_client_with_context
    with ZoomClient("KEY", "SECRET") as client:
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_init_creates_all_components (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 48, in test_init_creates_all_components
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_init_sets_config (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 20, in test_init_sets_config
    client = ZoomClient("KEY", "SECRET")
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

======================================================================
ERROR: test_init_sets_config_with_timeout (tests.zoomus.test_client.ZoomClientTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/prschmid/Development/zoomus/tests/zoomus/test_client.py", line 37, in test_init_sets_config_with_timeout
    client = ZoomClient("KEY", "SECRET", timeout=500)
  File "/Users/prschmid/Development/zoomus/zoomus/client.py", line 64, in __init__
    "token": util.generate_jwt(api_key, api_secret),
  File "/Users/prschmid/Development/zoomus/zoomus/util.py", line 286, in generate_jwt
    return token.decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

Name                                Stmts   Miss Branch BrPart  Cover
---------------------------------------------------------------------
zoomus/__init__.py                      5      0      0      0   100%
zoomus/client.py                       46      0      2      0   100%
zoomus/components/__init__.py           2      0      0      0   100%
zoomus/components/base.py              13      0      4      0   100%
zoomus/components/meeting.py           48      0     10      0   100%
zoomus/components/metric.py            22      0      0      0   100%
zoomus/components/past_meeting.py      16      0      0      0   100%
zoomus/components/phone.py             15      0      0      0   100%
zoomus/components/recording.py         34      0      8      0   100%
zoomus/components/report.py            39      0      0      0   100%
zoomus/components/user.py              39      0      0      0   100%
zoomus/components/webinar.py           66      0     10      0   100%
zoomus/util.py                        108      1     40      2    98%
---------------------------------------------------------------------
TOTAL                                 453      1     74      2    99%
----------------------------------------------------------------------
Ran 274 tests in 0.751s

FAILED (SKIP=2, errors=15)

Also, looks like the files don't conform to the black formatting guidelines. Can I trouble you to also make sure to run black . when you re-submit your PR? Thanks!

(~/Development/zoomus:[feature/requests-session]) # black . --check
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/phone/test_call_logs.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/phone/test_calling_plans.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/phone/test_numbers_list.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/phone/test_users.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/phone/test_numbers_get.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/past_meeting/test_participants.py
would reformat /Users/prschmid/Development/zoomus/zoomus/components/metric.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/meeting/test_update.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/meeting/test_create.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/components/webinar/test_register.py
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/test_util.py
Oh no! 💥 💔 💥
11 files would be reformatted, 57 files would be left unchanged.

@seantibor
Copy link
Contributor Author

Ok -- I think I got it. I've run black on everything and merged develop. Tests are running against 3.6.13 and passing. Let me know if you need anything else.

@prschmid
Copy link
Owner

prschmid commented May 5, 2021

@seantibor Thanks for fixing up those tests! I just verified and they indeed do pass now. I did notice, however, that there still appears to be one file that is in need of formatting

(~/Development/zoomus:[feature/requests-session]) # black . --check
would reformat /Users/prschmid/Development/zoomus/tests/zoomus/test_util.py
Oh no! 💥 💔 💥
1 file would be reformatted, 95 files would be left unchanged.

Assuming you are running the same version of black as the repo (black==20.8b0) you should be able to just do black . and it will automatically format your files correctly.

Thanks for dealing with these formatting details!

@seantibor
Copy link
Contributor Author

I'm trying to figure out why black keeps formatting this section differently from the command line vs. the pre-commit hook. Possibly a configuration variable I'm missing?

Screen Shot 2021-05-05 at 4 19 15 PM

Any ideas?

@tarkatronic
Copy link
Contributor

I'm trying to figure out why black keeps formatting this section differently from the command line vs. the pre-commit hook. Possibly a configuration variable I'm missing?

Screen Shot 2021-05-05 at 4 19 15 PM

Any ideas?

Usually when that happens it's due to a black version mismatch. I would be sure to check through and make sure that the versions match up between what you have installed, what's listed in requirements, and what's listed in the pre-commit hook.

@seantibor
Copy link
Contributor Author

Sorry for the many extra commits on this trying to get my pre-commit to work. I finally manually ran black 21.4b and skipped the pre-commit hook that was formatting the test_util.py wrong. I'm not entirely sure why my pre-commit got so messed up but this should bring it back in line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants