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

Refactor and streamline organization and set base for SDK typing #284

Merged
merged 45 commits into from
Jul 22, 2024

Conversation

jonatascastro12
Copy link
Contributor

@jonatascastro12 jonatascastro12 commented Jul 12, 2024

  • Create new WorkOsListResource to fix .auto_pagination_iter() for list methods
  • Add pydandic for setting new resource classes for Organization and other entities (come later)
  • Add types-requests as mypy complained for typing requests lib
  • Add mypy (initially scoping to workos/organizations.py)
  • Refactored workos/organizations.py - methods return pydandic models
    • removed .list_organizations_v2() method since they were meant to work with .auto_pagination_iter(), but it wasn't functional
    • create/update methods are consistent with using args
    • typed all methods arguments
  • Removed deprecated fields on organizations

@jonatascastro12 jonatascastro12 requested a review from a team as a code owner July 12, 2024 23:18
@jonatascastro12 jonatascastro12 changed the title Refactor and streamline organization tests and resources Refactor and streamline organization and set base for SDK typing Jul 12, 2024
Removed deprecated organization methods and updated organization tests. Also, migrated organization.py to Pydantic models, and added mypy typing for more strict type checking. Additionally, enhance auto-paging to work with new models and restructured fixtures for organization tests.
order=None,
):
domains: Optional[List[str]] = None,
limit: Optional[int] = None,
Copy link

Choose a reason for hiding this comment

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

If limit has a default value of RESPONSE_LIMIT below, any reason not to make that the default value here?

Suggested change
limit: Optional[int] = None,
limit: Optional[int] = RESPONSE_LIMIT,

Copy link

Choose a reason for hiding this comment

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

... and remove the default_limit = True below. It doesn't seem to do anything.

@tribble tribble requested a review from mattgd July 19, 2024 16:28
@@ -45,7 +47,7 @@ def inner(method, response_dict, status_code, headers=None):
def mock(*args, **kwargs):
return MockResponse(response_dict, status_code, headers=headers)

monkeypatch.setattr(requests, method, mock)
monkeypatch.setattr(requests, "request", mock)
Copy link

Choose a reason for hiding this comment

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

I changed how we call requests, rather than using get_attr to retrieve the function by name, always wall request.request and pass in the method



@pytest.fixture
def mock_pagination_request(monkeypatch):
Copy link

Choose a reason for hiding this comment

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

I don't like how complex this test function is, but we need to roughly emulate the behavior of a pagination endpoint and return different pages of data in successive calls.

@@ -18,110 +22,19 @@ def mock_users(self):
return {
"data": user_list,
"list_metadata": {"before": None, "after": None},
"metadata": {
Copy link

Choose a reason for hiding this comment

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

All of this no longer used/needed

limit: int = RESPONSE_LIMIT,
before: Optional[str] = None,
after: Optional[str] = None,
order: PaginationOrder = "desc",
Copy link

Choose a reason for hiding this comment

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

Optional[PaginationOrder] = "desc" is not what we want here. That allows None as a possible value. This disallows None and does not require order to be specified.

token=workos.api_key,
return WorkOsListResource(
list_method=self.list_users,
# TODO: Should we even bother with this validation?
Copy link

Choose a reason for hiding this comment

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

My current opinion is no. But want to constrain scope of this PR and fix later

Copy link
Contributor

Choose a reason for hiding this comment

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

Loaded up the page before you posted this, but down to omit. Better to be consistent everywhere IMO, and I think on Friday we decided against explicit input validation like this.

Copy link

Choose a reason for hiding this comment

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

👍 Will remove in a follow-on PR

"""Delete one existing Directory.

Args:
directory (str): The ID of the directory to be deleted. (Required)

Returns:
dict: Directories response from WorkOS.
None
Copy link

Choose a reason for hiding this comment

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

Yeah. Our doc here was a lie. We return an empty 202


EnumType = TypeVar("EnumType", bound=Enum)

# Identical to the literal or strings path, except meant for a literal of enum values.
Copy link

Choose a reason for hiding this comment

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

Should I just delete this from the PR? Not being used at the moment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, can delete.


params = {
"domains": domains,
"limit": limit,
"before": before,
"after": after,
"order": order or "desc",
"order": order,
Copy link
Contributor

Choose a reason for hiding this comment

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

With order previously being passed as None, this doesn't change the default ordering at all, right?

Copy link

Choose a reason for hiding this comment

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

Previously if order was not passed in, the value would fall back to "desc". Instead that default moves to the function signature: order: PaginationOrder = "desc"

Comment on lines 49 to 51
# Toying around with the differences in type hinting or deserialization for enums vs literals. In the end pretty equivalent,
# it's a question of whether we want to present strings or DirectoryState.ACTIVE to the user
# leaving both options here for now until we settle on a preference
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this comment be removed now?

class OrganizationDomain(WorkOSModel):
id: str
organization_id: str
object: Literal["organization"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be Literal["organization_domain"]?

Copy link

Choose a reason for hiding this comment

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

It sure should

Comment on lines +142 to +144
# These fields end up exposed in the types. Does we care?
list_method: Callable = Field(exclude=True)
list_args: ListArgs = Field(exclude=True)
Copy link
Contributor

Choose a reason for hiding this comment

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

Where do these fields this show up in types exactly?

Copy link

@tribble tribble Jul 22, 2024

Choose a reason for hiding this comment

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

They would appear a developers IDE, like this
CleanShot 2024-07-22 at 13 29 42

Comment on lines 112 to 113
# add all possible generics of List Resource
T = TypeVar("T", Organization, Directory, DirectoryGroup, DirectoryUser)
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like we could name this something better like "ListableResource".

Comment on lines +71 to +72
# TODO: Should we even bother with this validation?
list_args=ListArgs.model_validate(params),
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel like the call made Friday was that we wouldn't focus on inbound param validation. I'm okay with either, but we should probably be consistent.

Copy link

Choose a reason for hiding this comment

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

Will remove in a follow-up.

@tribble tribble changed the base branch from main to beta-5.0 July 22, 2024 21:43
@tribble tribble merged commit 6810556 into beta-5.0 Jul 22, 2024
4 checks passed
@tribble tribble deleted the refactor-organization branch July 22, 2024 21:44
tribble added a commit that referenced this pull request Jul 30, 2024
* Refactor and streamline organization tests and resources

Removed deprecated organization methods and updated organization tests. Also, migrated organization.py to Pydantic models, and added mypy typing for more strict type checking. Additionally, enhance auto-paging to work with new models and restructured fixtures for organization tests.

* Switch directories over to new list resources and add typing

* Mark version as alpha

* Formatting and some type fixes

* Add defaults for all optional fields

* Type dsync getters

* Possible path forward for unknown literal values

* Move comments

* Export the untyped type and a type guard. Leave a comment about my thoughts on the approach

* Test out literals of strings vs enums and factor out types and helpers to a typing directory

* Settled on an approach for untyped literals

* A little refactoring

* More accurate validation for UntypedLiteral

* Comments reminding us to clean up

* Add typing to the rest of the dsync methods

* Just some formattin'

* A little more cleanup to unify organizations and dsync

* Fix organizations test

* DirectorySync tests passing, but still need some cleanup

* Do not bump version yet

* Formatting

* Clean up by removing the enum paths

* Small fixed for compat

* More formatting and compat

* Start fixing dsync tests

* Fix another dsync test

* Fix more dsync tests

* Fix params, optional allows None, instead can force default

* Directory sync tests are green

* Fix audit logs test

* Fix organizations test

* Fix auto paging iter tests

* Remove debugging print

* Fix user management tests

* Switch override to typing_extensions

* Build fixes. Proper dict override and remove duplicate model key

* Add directory sync resource to mypy.ini

* Pantera can't spell

* Fix type and delete unused fixtures

* Remove unused import

* Update dsync tests to new pagination helper

* Delete unused fixtures

* Remove some unneeded comments

* PR feedback

* Remove trailing comma in mypy.ini

---------

Co-authored-by: Peter Arzhintar <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants