Skip to content

Add client method to Session class #858

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

Merged
merged 8 commits into from
Feb 28, 2023
Merged

Add client method to Session class #858

merged 8 commits into from
Feb 28, 2023

Conversation

sgillies
Copy link
Contributor

@sgillies sgillies commented Feb 26, 2023

It gets a client by the name of the client module. orders -> planet.clients.orders.OrdersClient.

The intent is to simplify the API for casual users. The API centers the Session class. It feels natural to let Session be a factory for clients. And it goes well with code autocompletion. Type session. in VS Code and we get a prompt for .client().

Screenshot from 2023-02-27 10-28-38

Type session.client( and we get a prompt to call it with a name like data, orders, or subscriptions. Actually, I think the docs could be slightly improved to help even more.

Screenshot from 2023-02-27 10-29-30

The new method is intended to be a convenience for users and documentation writers. The Session and three client classes are not otherwise changed. They don't need to be and much testing implementation hinges on the existing relationship between client classes and Session. The pattern used by OrdersClient(session) is a form of dependency injection; it really does make writing good tests easier.

The CLI commands are left as they are.

Under docs/, all examples of client = SomethingClient(session) have been changed to client = session.client('something').

Resolves #857.

Verified

This commit was signed with the committer’s verified signature.
nobu Nobuyoshi Nakada
It gets a client by name. Resolves #857
@sgillies sgillies marked this pull request as ready for review February 27, 2023 16:26
@@ -24,7 +24,7 @@ The best way of doing this is wrapping any code that invokes a client class in a

```python
async with Session() as session:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is what I mean by "centers the Session class". Creating one is the first thing we do and it's the manager for the context of a block of code.

from .io import collect

__all__ = [
'Auth',
'collect',
'DataClient'
'OrdersClient',
'SubscriptionsClient',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I found that this was missing!

planet/http.py Outdated
# To avoid circular dependency.
from planet.clients.data import DataClient
from planet.clients.orders import OrdersClient
from planet.clients.subscriptions import SubscriptionsClient
Copy link
Contributor Author

@sgillies sgillies Feb 27, 2023

Choose a reason for hiding this comment

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

Session and clients aren't fully decoupled because the client modules import http. We could fix that in the future if it became important to do so. For now, we can tolerate some imports here. They don't have a significant impact on performance. By the time this method is called, those modules will already have been loaded.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to file a ticket for fixing that in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, not now. I'm not sure it's important. I changed the text above to reflect that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note: the client modules import http in order to use http.Session in their type hints.

Copy link
Contributor

Choose a reason for hiding this comment

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

I saw that!

planet/http.py Outdated
return {
'data': DataClient,
'orders': OrdersClient,
'subscriptions': SubscriptionsClient
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now, I'm statically configuring the mapping between names and clients here. Getting too fancy would be a mistake. We have no plans to have multiple clients per API or support user-supplied client plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking at my PR as if I was a reviewer, it occurs to me that this static mapping could be moved to planet/client/__init__.py. That would let us reduce those 3 imports to 1.

"""Get an exception when no such client exists."""
session = Session()
with pytest.raises(ClientError):
_ = session.client('bogus')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Test coverage of the new code is 100%.

"""Get a client by its module name.

Parameters:
name: the name of the client module: data, orders, or
subscriptions.
name: one of 'data', 'orders', or 'subscriptions'.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is pretty nice, I think. A user is told that they should pass 'data', 'orders', or 'subscription' as the argument.

Screenshot from 2023-02-27 10-44-36

Copy link
Contributor

Choose a reason for hiding this comment

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

This typing hint IS nice! This would be great to use this for all of the other arguments that have a set number of 'valid' entries, we already have them defined either at the top of the client module or in the specs module.

@@ -30,6 +30,7 @@
'jsonschema',
'pyjwt>=2.1',
'tqdm>=4.56',
'typing-extensions',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This module provides a backport of Literal for Python 3.7.

Copy link
Contributor

@JuLeeAtPlanet JuLeeAtPlanet left a comment

Choose a reason for hiding this comment

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

One comment for you, but good to go!

@sgillies sgillies self-assigned this Feb 28, 2023

try:
return client_directory[name](self, base_url=base_url)
return _client_directory[name](self, base_url=base_url)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This way the Session class only needs to know that it can get a client with a name, it's not responsible for the directory. Looser coupling.

@sgillies sgillies merged commit 1f74347 into main Feb 28, 2023
@sgillies sgillies deleted the issue857 branch February 28, 2023 19:24
@sgillies sgillies restored the issue857 branch February 28, 2023 23:50
@sgillies
Copy link
Contributor Author

Restoring the branch, we might be reverting this.

@sgillies
Copy link
Contributor Author

Reverted pending more discussion.

@jreiberkyle
Copy link
Contributor

This PR looks great and is ready to go. I really like the use of Literals to allow specifying valid entries. That is nice!

This was referenced Mar 15, 2023
@jreiberkyle jreiberkyle deleted the issue857 branch March 15, 2023 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add a method to get a client from a Session instance
3 participants