From f3820c6291209766021e0442ecc1415df4a8fd66 Mon Sep 17 00:00:00 2001 From: "Skhendle@gmail.com" Date: Fri, 30 Jan 2026 14:59:22 +0200 Subject: [PATCH 1/4] completed user management --- examples/company_user_management_demo.py | 248 ++++++++++++++++++ .../company_user_management_demo_README.md | 91 +++++++ .../clients/company_user_management.py | 82 ++++++ tests/conftest.py | 23 +- tests/test_company_user_management_client.py | 106 ++++++++ uv.lock | 2 +- 6 files changed, 550 insertions(+), 2 deletions(-) create mode 100644 examples/company_user_management_demo.py create mode 100644 examples/company_user_management_demo_README.md create mode 100644 src/userverse_python_client/clients/company_user_management.py create mode 100644 tests/test_company_user_management_client.py diff --git a/examples/company_user_management_demo.py b/examples/company_user_management_demo.py new file mode 100644 index 0000000..61f9235 --- /dev/null +++ b/examples/company_user_management_demo.py @@ -0,0 +1,248 @@ +"""Demo script for managing company users through the userverse Python client.""" + +import argparse +import json +import os +import sys +from pathlib import Path +from typing import Any, Callable, Optional, Tuple + +# Allow running the example without installing the package first. +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) + +from userverse_models.user.user import UserLoginModel, UserQueryParams # noqa: E402 +from userverse_models.company.user import CompanyUserAddModel # noqa: E402 +from userverse_python_client import UverseUserClient # noqa: E402 +from userverse_python_client.clients.company_user_management import ( # noqa: E402 + CompanyUserManagementClient, +) +from userverse_python_client.error_model import ClientErrorModel # noqa: E402 + +BASE_URL = "https://apps.oxillium-api.co.za/userverse" + + +ClientProvider = Callable[[], Any] +ActionFunction = Callable[[Any], Any] + + +def require_env(name: str) -> str: + value = os.getenv(name) + if not value: + raise ValueError(f"Missing required env var: {name}") + return value + + +def require_int_env(name: str) -> int: + raw_value = require_env(name) + try: + return int(raw_value) + except ValueError as exc: + raise ValueError(f"{name} must be an integer, got '{raw_value}'") from exc + + +def optional_int_env(name: str) -> Optional[int]: + raw_value = os.getenv(name) + if raw_value is None or raw_value == "": + return None + try: + return int(raw_value) + except ValueError as exc: + raise ValueError(f"{name} must be an integer, got '{raw_value}'") from exc + + +def build_user_client() -> UverseUserClient: + return UverseUserClient(base_url=BASE_URL) + + +def build_company_user_client(token: str) -> CompanyUserManagementClient: + return CompanyUserManagementClient(base_url=BASE_URL, access_token=token) + + +def log_response(label: str, response: Any) -> None: + print(f"{label} Response:", response) + dump_method = getattr(response, "model_dump", None) + if callable(dump_method): + print(f"{label} Response (dict):") + print(json.dumps(dump_method(), indent=2, default=str)) + + +def login_user(client: UverseUserClient) -> str: + login_model = UserLoginModel( + email=require_env("USER_EMAIL"), + password=require_env("USER_PASSWORD"), + ) + response = client.user_login(login_model) + client.set_access_token(response.data.access_token) + log_response("Login", response) + return response.data.access_token + + +def build_user_query_params() -> UserQueryParams: + params: dict[str, object] = {} + + limit = optional_int_env("COMPANY_USER_QUERY_LIMIT") + if limit is not None: + params["limit"] = limit + + page = optional_int_env("COMPANY_USER_QUERY_PAGE") + if page is not None: + params["page"] = page + + for field, env_name in [ + ("role_name", "COMPANY_USER_QUERY_ROLE_NAME"), + ("email", "COMPANY_USER_QUERY_EMAIL"), + ]: + value = os.getenv(env_name) + if value: + params[field] = value + + return UserQueryParams(**params) + + +def require_company_id() -> int: + return require_int_env("COMPANY_USER_COMPANY_ID") + + +def list_company_users(client: CompanyUserManagementClient) -> None: + company_id = require_company_id() + params = build_user_query_params() + response = client.list_company_users(company_id=company_id, query_params=params) + log_response("List Company Users", response) + + +def add_company_user(client: CompanyUserManagementClient) -> None: + company_id = require_company_id() + user_id = require_int_env("COMPANY_USER_ADD_USER_ID") + role_name = os.getenv("COMPANY_USER_ADD_ROLE_NAME") + add_model = CompanyUserAddModel(user_id=user_id, role_name=role_name) + response = client.add_user_to_company(company_id=company_id, user_data=add_model) + log_response("Add Company User", response) + + +def delete_company_user(client: CompanyUserManagementClient) -> None: + company_id = require_company_id() + user_id = require_int_env("COMPANY_USER_DELETE_USER_ID") + response = client.delete_user_from_company(company_id=company_id, user_id=user_id) + log_response("Delete Company User", response) + + +def run_action( + action_name: str, + fn: ActionFunction, + client_provider: ClientProvider, +) -> Tuple[bool, Any]: + try: + client = client_provider() + result = fn(client) + return True, result + except ClientErrorModel as exc: + detail = exc.payload.detail + print(f"{action_name} failed ({exc.status_code}): {detail.message}") + print(f"Error details: {detail.error}") + except ValueError as exc: + print(f"{action_name} skipped: {exc}") + return False, None + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Company user management demo client" + ) + parser.add_argument("--login", action="store_true", help="Login user to get token") + parser.add_argument( + "--list-users", + action="store_true", + help="List users linked to COMPANY_USER_COMPANY_ID", + ) + parser.add_argument( + "--add-user", + action="store_true", + help="Add a user to COMPANY_USER_COMPANY_ID", + ) + parser.add_argument( + "--delete-user", + action="store_true", + help="Delete a user from COMPANY_USER_COMPANY_ID", + ) + parser.add_argument( + "--all", + action="store_true", + help="Run login + list users flow", + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + user_client = build_user_client() + + if args.all: + args.login = True + args.list_users = True + + access_token: Optional[str] = None + company_user_client: Optional[CompanyUserManagementClient] = None + logged_in = False + + def get_company_user_client() -> CompanyUserManagementClient: + nonlocal company_user_client, access_token, logged_in + if not logged_in or not access_token: + raise ValueError("Login is required before making company user calls.") + if company_user_client is None: + company_user_client = build_company_user_client(access_token) + return company_user_client + + actions = [ + ("Login", args.login, login_user, lambda: user_client, False), + ( + "List Company Users", + args.list_users, + list_company_users, + get_company_user_client, + True, + ), + ( + "Add Company User", + args.add_user, + add_company_user, + get_company_user_client, + True, + ), + ( + "Delete Company User", + args.delete_user, + delete_company_user, + get_company_user_client, + True, + ), + ] + + if not any(flag for _, flag, _, _, _ in actions): + print("No actions selected. Try --help for available options.") + return + + for name, enabled, fn, client_provider, needs_token in actions: + if not enabled: + continue + if needs_token and not logged_in: + if args.login: + success, token = run_action("Login", login_user, lambda: user_client) + if not success: + continue + logged_in = True + access_token = token + company_user_client = None + else: + print(f"{name} skipped: missing --login for JWT-protected call") + continue + + success, result = run_action(name, fn, client_provider) + if name == "Login" and success: + logged_in = True + access_token = result + company_user_client = None + + +if __name__ == "__main__": # pragma: no cover + # run with uv: uv run -m examples.company_user_management_demo --login --list-users + main() diff --git a/examples/company_user_management_demo_README.md b/examples/company_user_management_demo_README.md new file mode 100644 index 0000000..6b9106e --- /dev/null +++ b/examples/company_user_management_demo_README.md @@ -0,0 +1,91 @@ +Company user management demo + +`examples/company_user_management_demo.py` demonstrates how to work with the +company user endpoints exposed by `CompanyUserManagementClient`. The script +authenticates a user first (via `UverseUserClient`) and then uses the returned +token for every company user request. + +Running the demo + +Every action is toggled with a CLI flag and reads its data from environment +variables. Missing required env vars cause that action to be skipped with a +message so you can focus on a single flow at a time. + +From the repo root: + +``` +uv run -m examples.company_user_management_demo --help +``` + +Common usage + +Login and list company users: + +``` +USER_EMAIL="you@example.com" USER_PASSWORD="secret" \ +COMPANY_USER_COMPANY_ID=123 \ +uv run -m examples.company_user_management_demo --login --list-users +``` + +Add a user to a company: + +``` +USER_EMAIL="you@example.com" USER_PASSWORD="secret" \ +COMPANY_USER_COMPANY_ID=123 COMPANY_USER_ADD_USER_ID=456 \ +COMPANY_USER_ADD_ROLE_NAME="admin" \ +uv run -m examples.company_user_management_demo --login --add-user +``` + +Delete a user from a company: + +``` +USER_EMAIL="you@example.com" USER_PASSWORD="secret" \ +COMPANY_USER_COMPANY_ID=123 COMPANY_USER_DELETE_USER_ID=456 \ +uv run -m examples.company_user_management_demo --login --delete-user +``` + +Available flags + +- --login +- --list-users +- --add-user +- --delete-user +- --all (runs `--login --list-users`) + +Client methods covered + +- user_login (fetches the JWT used by the company user client) +- list_company_users +- add_user_to_company +- delete_user_from_company + +Environment variables + +Login: +- USER_EMAIL +- USER_PASSWORD + +Shared: +- COMPANY_USER_COMPANY_ID (required for every company user action) + +List users (optional filters): +- COMPANY_USER_QUERY_LIMIT +- COMPANY_USER_QUERY_PAGE +- COMPANY_USER_QUERY_ROLE_NAME +- COMPANY_USER_QUERY_EMAIL + +Add user: +- COMPANY_USER_ADD_USER_ID +- COMPANY_USER_ADD_ROLE_NAME (optional) + +Delete user: +- COMPANY_USER_DELETE_USER_ID + +Notes + +- All company user actions require a logged-in user. Pass `--login` (or `--all`) + and ensure the login env vars are set. +- The script builds the `CompanyUserManagementClient` only after login + succeeds so the Authorization header always uses the latest access token. +- Company user endpoints expect real domains/emails; avoid `.test`, `.example`, + `.invalid`, or `.localhost` to prevent validation failures. diff --git a/src/userverse_python_client/clients/company_user_management.py b/src/userverse_python_client/clients/company_user_management.py new file mode 100644 index 0000000..9209ec5 --- /dev/null +++ b/src/userverse_python_client/clients/company_user_management.py @@ -0,0 +1,82 @@ + +from sverse_generic_models.generic_response import GenericResponseModel +from sverse_generic_models.generic_pagination import PaginatedResponse +from userverse_models.user.user import UserQueryParams +from userverse_models.company.user import ( + CompanyUserReadModel, + CompanyUserAddModel, +) + +from ..http_client_base import BaseClient + + +class CompanyUserManagementClient(BaseClient): + def __init__(self, base_url, access_token, timeout=30): + super().__init__(base_url, access_token, timeout) + + def add_user_to_company( + self, company_id: int, user_data: CompanyUserAddModel + ) -> GenericResponseModel[CompanyUserReadModel]: + """Create a new company user membership for the provided company.""" + + payload = user_data.model_dump(exclude_none=True) + + response = self._request( + "POST", + f"/company/{company_id}/users", + json=payload, + ) + + if not response or "data" not in response: + raise ValueError("Invalid response from add user to company endpoint") + + data = response.get("data", {}) + if not isinstance(data, dict): + raise ValueError( + f"Expected company user data to be a dict, got {type(data)}" + ) + + return GenericResponseModel[CompanyUserReadModel].model_validate(response) + + def delete_user_from_company( + self, company_id: int, user_id: int + ) -> GenericResponseModel[None]: + """Remove a user from the specified company.""" + + response = self._request( + "DELETE", + f"/company/{company_id}/users/{user_id}", + ) + + if response is None or "data" not in response: + raise ValueError("Invalid response from delete company user endpoint") + + return GenericResponseModel[None].model_validate(response) + + def list_company_users( + self, + company_id: int, + query_params: UserQueryParams = UserQueryParams(), + ) -> GenericResponseModel[PaginatedResponse[CompanyUserReadModel]]: + """Fetch paginated company users for the provided company id.""" + + params = query_params.model_dump(exclude_none=True) + + response = self._request( + "GET", + f"/company/{company_id}/users", + params=params, + ) + + if not response or "data" not in response: + raise ValueError("Invalid response from list company users endpoint") + + data = response.get("data", {}) + if not isinstance(data, dict): + raise ValueError( + f"Expected company user pagination data to be a dict, got {type(data)}" + ) + + return GenericResponseModel[ + PaginatedResponse[CompanyUserReadModel] + ].model_validate(response) diff --git a/tests/conftest.py b/tests/conftest.py index f2bd62e..f735faf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -70,8 +70,11 @@ class _TokenResponseModel: @dataclass -class _UserQueryParams: +class _UserQueryParams(_ModelDumpMixin): limit: int | None = None + page: int | None = None + role_name: str | None = None + email: str | None = None @dataclass @@ -110,6 +113,20 @@ class _CompanyQueryParamsModel(_ModelDumpMixin): email: str | None = None +@dataclass +class _CompanyUserAddModel(_ModelDumpMixin): + user_id: int | None = None + role_name: str | None = None + + +@dataclass +class _CompanyUserReadModel: + id: int | None = None + user_id: int | None = None + email: str | None = None + role_name: str | None = None + + def _ensure_module(name: str) -> ModuleType: module = sys.modules.get(name) if module is None: @@ -147,3 +164,7 @@ def _ensure_module(name: str) -> ModuleType: company_company_module.CompanyReadModel = _CompanyReadModel company_company_module.CompanyQueryParamsModel = _CompanyQueryParamsModel company_module.company = company_company_module +company_user_module = _ensure_module("userverse_models.company.user") +company_user_module.CompanyUserAddModel = _CompanyUserAddModel +company_user_module.CompanyUserReadModel = _CompanyUserReadModel +company_module.user = company_user_module diff --git a/tests/test_company_user_management_client.py b/tests/test_company_user_management_client.py new file mode 100644 index 0000000..4372b94 --- /dev/null +++ b/tests/test_company_user_management_client.py @@ -0,0 +1,106 @@ +import pytest + +from userverse_python_client.clients.company_user_management import ( + CompanyUserManagementClient, +) +from userverse_models.company.user import CompanyUserAddModel +from userverse_models.user.user import UserQueryParams + + +def _client() -> CompanyUserManagementClient: + return CompanyUserManagementClient("https://example.test", access_token="token") + + +def test_add_user_to_company_posts_payload() -> None: + client = _client() + add_model = CompanyUserAddModel(user_id=5, role_name="admin") + called: dict[str, object] = {} + + def fake_request(method, path, json=None, **_kwargs): + called.update(method=method, path=path, json=json) + return {"data": {"id": 1, "user_id": 5}} + + client._request = fake_request # type: ignore[method-assign] + response = client.add_user_to_company(company_id=10, user_data=add_model) + + assert called == { + "method": "POST", + "path": "/company/10/users", + "json": add_model.model_dump(exclude_none=True), + } + assert response["data"]["user_id"] == 5 + + +def test_add_user_to_company_requires_dict_payload() -> None: + client = _client() + add_model = CompanyUserAddModel(user_id=5) + + def fake_request(*_args, **_kwargs): + return {"data": []} + + client._request = fake_request # type: ignore[method-assign] + with pytest.raises(ValueError, match="Expected company user data"): + client.add_user_to_company(1, add_model) + + +def test_delete_user_from_company_calls_endpoint() -> None: + client = _client() + called: dict[str, object] = {} + + def fake_request(method, path, **_kwargs): + called.update(method=method, path=path) + return {"data": None} + + client._request = fake_request # type: ignore[method-assign] + response = client.delete_user_from_company(company_id=7, user_id=3) + + assert called == {"method": "DELETE", "path": "/company/7/users/3"} + assert response["data"] is None + + +def test_delete_user_from_company_requires_response_body() -> None: + client = _client() + + def fake_request(*_args, **_kwargs): + return None + + client._request = fake_request # type: ignore[method-assign] + with pytest.raises(ValueError, match="Invalid response"): + client.delete_user_from_company(1, 2) + + +def test_list_company_users_calls_endpoint() -> None: + client = _client() + params = UserQueryParams(limit=25, page=2) + called: dict[str, object] = {} + + def fake_request(method, path, params=None, **_kwargs): + called.update(method=method, path=path, params=params) + return { + "data": { + "records": [{"user_id": 9}], + "pagination": {"limit": 25, "current_page": 2}, + } + } + + client._request = fake_request # type: ignore[method-assign] + response = client.list_company_users(company_id=11, query_params=params) + + assert called == { + "method": "GET", + "path": "/company/11/users", + "params": params.model_dump(exclude_none=True), + } + assert response["data"]["records"][0]["user_id"] == 9 + + +def test_list_company_users_requires_dict_payload() -> None: + client = _client() + params = UserQueryParams() + + def fake_request(*_args, **_kwargs): + return {"data": []} + + client._request = fake_request # type: ignore[method-assign] + with pytest.raises(ValueError, match="Expected company user pagination data"): + client.list_company_users(1, params) diff --git a/uv.lock b/uv.lock index 3337c3c..b46fe7e 100644 --- a/uv.lock +++ b/uv.lock @@ -453,7 +453,7 @@ wheels = [ [[package]] name = "userverse-python-client" -version = "0.1.5" +version = "0.1.6" source = { editable = "." } dependencies = [ { name = "black" }, From bb38a6d423d063855f840ca9663c9026ce91960c Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 30 Jan 2026 13:01:35 +0000 Subject: [PATCH 2/4] style: auto-format code with Black --- examples/company_user_management_demo.py | 4 +--- .../clients/company_user_management.py | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/company_user_management_demo.py b/examples/company_user_management_demo.py index 61f9235..cc45f65 100644 --- a/examples/company_user_management_demo.py +++ b/examples/company_user_management_demo.py @@ -145,9 +145,7 @@ def run_action( def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Company user management demo client" - ) + parser = argparse.ArgumentParser(description="Company user management demo client") parser.add_argument("--login", action="store_true", help="Login user to get token") parser.add_argument( "--list-users", diff --git a/src/userverse_python_client/clients/company_user_management.py b/src/userverse_python_client/clients/company_user_management.py index 9209ec5..a8af588 100644 --- a/src/userverse_python_client/clients/company_user_management.py +++ b/src/userverse_python_client/clients/company_user_management.py @@ -1,4 +1,3 @@ - from sverse_generic_models.generic_response import GenericResponseModel from sverse_generic_models.generic_pagination import PaginatedResponse from userverse_models.user.user import UserQueryParams From 6167a9b982391cc9b27ac5f0561726dcfd6a26f3 Mon Sep 17 00:00:00 2001 From: "Skhendle@gmail.com" Date: Fri, 30 Jan 2026 15:05:01 +0200 Subject: [PATCH 3/4] import fix --- examples/company_user_management_demo.py | 16 ++++++++-------- examples/company_user_management_demo_README.md | 4 ++-- src/userverse_python_client/__init__.py | 15 +++------------ .../clients/company_user_management.py | 2 +- tests/test_company_user_management_client.py | 6 +++--- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/examples/company_user_management_demo.py b/examples/company_user_management_demo.py index cc45f65..2f309a5 100644 --- a/examples/company_user_management_demo.py +++ b/examples/company_user_management_demo.py @@ -14,7 +14,7 @@ from userverse_models.company.user import CompanyUserAddModel # noqa: E402 from userverse_python_client import UverseUserClient # noqa: E402 from userverse_python_client.clients.company_user_management import ( # noqa: E402 - CompanyUserManagementClient, + UverseCompanyUserManagementClient, ) from userverse_python_client.error_model import ClientErrorModel # noqa: E402 @@ -54,8 +54,8 @@ def build_user_client() -> UverseUserClient: return UverseUserClient(base_url=BASE_URL) -def build_company_user_client(token: str) -> CompanyUserManagementClient: - return CompanyUserManagementClient(base_url=BASE_URL, access_token=token) +def build_company_user_client(token: str) -> UverseCompanyUserManagementClient: + return UverseCompanyUserManagementClient(base_url=BASE_URL, access_token=token) def log_response(label: str, response: Any) -> None: @@ -103,14 +103,14 @@ def require_company_id() -> int: return require_int_env("COMPANY_USER_COMPANY_ID") -def list_company_users(client: CompanyUserManagementClient) -> None: +def list_company_users(client: UverseCompanyUserManagementClient) -> None: company_id = require_company_id() params = build_user_query_params() response = client.list_company_users(company_id=company_id, query_params=params) log_response("List Company Users", response) -def add_company_user(client: CompanyUserManagementClient) -> None: +def add_company_user(client: UverseCompanyUserManagementClient) -> None: company_id = require_company_id() user_id = require_int_env("COMPANY_USER_ADD_USER_ID") role_name = os.getenv("COMPANY_USER_ADD_ROLE_NAME") @@ -119,7 +119,7 @@ def add_company_user(client: CompanyUserManagementClient) -> None: log_response("Add Company User", response) -def delete_company_user(client: CompanyUserManagementClient) -> None: +def delete_company_user(client: UverseCompanyUserManagementClient) -> None: company_id = require_company_id() user_id = require_int_env("COMPANY_USER_DELETE_USER_ID") response = client.delete_user_from_company(company_id=company_id, user_id=user_id) @@ -179,10 +179,10 @@ def main() -> None: args.list_users = True access_token: Optional[str] = None - company_user_client: Optional[CompanyUserManagementClient] = None + company_user_client: Optional[UverseCompanyUserManagementClient] = None logged_in = False - def get_company_user_client() -> CompanyUserManagementClient: + def get_company_user_client() -> UverseCompanyUserManagementClient: nonlocal company_user_client, access_token, logged_in if not logged_in or not access_token: raise ValueError("Login is required before making company user calls.") diff --git a/examples/company_user_management_demo_README.md b/examples/company_user_management_demo_README.md index 6b9106e..872610c 100644 --- a/examples/company_user_management_demo_README.md +++ b/examples/company_user_management_demo_README.md @@ -1,7 +1,7 @@ Company user management demo `examples/company_user_management_demo.py` demonstrates how to work with the -company user endpoints exposed by `CompanyUserManagementClient`. The script +company user endpoints exposed by `UverseCompanyUserManagementClient`. The script authenticates a user first (via `UverseUserClient`) and then uses the returned token for every company user request. @@ -85,7 +85,7 @@ Notes - All company user actions require a logged-in user. Pass `--login` (or `--all`) and ensure the login env vars are set. -- The script builds the `CompanyUserManagementClient` only after login +- The script builds the `UverseCompanyUserManagementClient` only after login succeeds so the Authorization header always uses the latest access token. - Company user endpoints expect real domains/emails; avoid `.test`, `.example`, `.invalid`, or `.localhost` to prevent validation failures. diff --git a/src/userverse_python_client/__init__.py b/src/userverse_python_client/__init__.py index 84fd7b7..ba0ee30 100644 --- a/src/userverse_python_client/__init__.py +++ b/src/userverse_python_client/__init__.py @@ -3,16 +3,7 @@ from typing import TYPE_CHECKING, Any from .clients.user import UverseUserClient +from .clients.company import UverseCompanyClient +from .clients.company_user_management import UverseCompanyUserManagementClient -if TYPE_CHECKING: # pragma: no cover - from .clients.company import UverseCompanyClient - -__all__ = ["UverseUserClient", "UverseCompanyClient"] - - -def __getattr__(name: str) -> Any: - if name == "UverseCompanyClient": - from .clients.company import UverseCompanyClient as _CompanyClient - - return _CompanyClient - raise AttributeError(f"module 'userverse_python_client' has no attribute {name!r}") +__all__ = ["UverseUserClient", "UverseCompanyClient", "UverseCompanyUserManagementClient"] \ No newline at end of file diff --git a/src/userverse_python_client/clients/company_user_management.py b/src/userverse_python_client/clients/company_user_management.py index a8af588..a2b08ec 100644 --- a/src/userverse_python_client/clients/company_user_management.py +++ b/src/userverse_python_client/clients/company_user_management.py @@ -9,7 +9,7 @@ from ..http_client_base import BaseClient -class CompanyUserManagementClient(BaseClient): +class UverseCompanyUserManagementClient(BaseClient): def __init__(self, base_url, access_token, timeout=30): super().__init__(base_url, access_token, timeout) diff --git a/tests/test_company_user_management_client.py b/tests/test_company_user_management_client.py index 4372b94..e3c096c 100644 --- a/tests/test_company_user_management_client.py +++ b/tests/test_company_user_management_client.py @@ -1,14 +1,14 @@ import pytest from userverse_python_client.clients.company_user_management import ( - CompanyUserManagementClient, + UverseCompanyUserManagementClient, ) from userverse_models.company.user import CompanyUserAddModel from userverse_models.user.user import UserQueryParams -def _client() -> CompanyUserManagementClient: - return CompanyUserManagementClient("https://example.test", access_token="token") +def _client() -> UverseCompanyUserManagementClient: + return UverseCompanyUserManagementClient("https://example.test", access_token="token") def test_add_user_to_company_posts_payload() -> None: From 3f8433e49a94f026f2e4c5a3eb560294537b14dd Mon Sep 17 00:00:00 2001 From: github-actions Date: Fri, 30 Jan 2026 13:06:27 +0000 Subject: [PATCH 4/4] style: auto-format code with Black --- src/userverse_python_client/__init__.py | 6 +++++- tests/test_company_user_management_client.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/userverse_python_client/__init__.py b/src/userverse_python_client/__init__.py index ba0ee30..d41d022 100644 --- a/src/userverse_python_client/__init__.py +++ b/src/userverse_python_client/__init__.py @@ -6,4 +6,8 @@ from .clients.company import UverseCompanyClient from .clients.company_user_management import UverseCompanyUserManagementClient -__all__ = ["UverseUserClient", "UverseCompanyClient", "UverseCompanyUserManagementClient"] \ No newline at end of file +__all__ = [ + "UverseUserClient", + "UverseCompanyClient", + "UverseCompanyUserManagementClient", +] diff --git a/tests/test_company_user_management_client.py b/tests/test_company_user_management_client.py index e3c096c..9f0a29e 100644 --- a/tests/test_company_user_management_client.py +++ b/tests/test_company_user_management_client.py @@ -8,7 +8,9 @@ def _client() -> UverseCompanyUserManagementClient: - return UverseCompanyUserManagementClient("https://example.test", access_token="token") + return UverseCompanyUserManagementClient( + "https://example.test", access_token="token" + ) def test_add_user_to_company_posts_payload() -> None: