Skip to content

Conversation

@albertsola
Copy link
Contributor

@albertsola albertsola commented Dec 10, 2025

Summary by CodeRabbit

  • Chores
    • Refactored seed data initialization patterns across accounts module (accounts, API tokens, buyers, licensees, sellers, user groups) for improved consistency.
    • Updated static logo file reference.
    • Enhanced test infrastructure with stricter mock specifications and assertion validation.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 10, 2025

Walkthrough

This PR refactors the seed/accounts module to standardize resource initialization. It replaces previous get-or-create flows with deterministic create-only patterns using init_resource and require_context_id helper functions, removes context-based caching logic, updates test mocking from AsyncMock to autospec, and corrects the LOGO path constant.

Changes

Cohort / File(s) Summary
Account seeding refactor
seed/accounts/accounts.py, tests/seed/accounts/test_accounts.py
Added get_account() to read account ID from environment and return Account object. Updated seed_accounts to use init_resource. Extended seeding workflow with seed_api_token, seed_user_group, seed_licensee. Tests updated to patch init_resource with autospec and assert await calls.
API token seeding refactor
seed/accounts/api_tokens.py, tests/seed/accounts/test_api_token.py, tests/seed/accounts/test_api_tokens.py
Removed get_api_token(). Added create_api_token() replacing init_api_token(). Updated build_api_token_data() to use require_context_id() and return additional fields (description, icon, modules). Deleted old test module and added new comprehensive E2E tests for data building, token creation, and resource initialization.
Buyer seeding refactor
seed/accounts/buyer.py, tests/seed/accounts/test_buyer.py
Removed get_buyer(). Renamed init_buyer() to create_buyer(). Updated build_buyer_data() to use require_context_id() and return additional fields (sellers, contact, address). Tests refactored to mock create_buyer and verify init_resource usage.
Licensee seeding refactor
seed/accounts/licensee.py, tests/seed/accounts/test_licensee.py
Removed get_licensee() and init_licensee(). Added create_licensee(). Updated build_licensee_data() to use require_context_id() for all IDs. Tests refactored to patch init_resource with autospec; removed AsyncLicenseesService usage.
Module seeding refactor
seed/accounts/module.py, tests/seed/accounts/test_module.py
Replaced context-based get_module() and refresh_module() with find_module(). Updated seed_module() to return None and use init_resource(). Removed Context imports; added init_resource import. Tests updated to use new public API and verify init_resource usage.
Seller seeding refactor
seed/accounts/seller.py, tests/seed/accounts/test_seller.py
Removed get_seller() and init_seller(). Added create_seller() for direct creation. Updated seed orchestration to use init_resource(). Tests refactored to mock create_seller and verify init_resource calls.
User group seeding refactor
seed/accounts/user_group.py, tests/seed/accounts/test_user_group.py
Removed get_user_group(). Renamed init_user_group() to create_user_group(). Updated build_user_group_data() to use require_context_id(). Updated seed_user_group() to return None and use init_resource(). Tests updated with new public API and init_resource mocking.
Static assets update
seed/static/static.py
Updated LOGO path constant from FIL-9920-4780-9379.png to logo.png.
Test mocking pattern updates
tests/seed/accounts/test_accounts.py, tests/seed/catalog/test_authorization.py, tests/seed/catalog/test_catalog.py, tests/seed/catalog/test_listing.py, tests/seed/catalog/test_price_list.py, tests/seed/test_seed_api.py
Replaced AsyncMock-based patches with autospec=True for consistency; updated assertions from assert_called_once() to assert_awaited_once() to reflect awaiting behavior of coroutines.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Context dependency changes: Review require_context_id() usage across all modules to ensure correct context key retrieval and error handling for missing keys.
  • Public API changes: Verify that removing get_* and init_* functions doesn't break external dependencies; check that create_* functions are properly exported.
  • init_resource integration: Confirm that all modules correctly call init_resource() with proper key names and function references in the correct sequence.
  • Mock spec validation: Ensure autospec=True patches enforce correct function signatures and that assert_awaited_once_with() assertions capture the intended behavior.
  • Data payload enrichment: Verify that additional fields added to data builders (e.g., description, icon, modules in API tokens; sellers, contact, address in buyers) are handled correctly by downstream APIs.

Possibly related PRs

  • [MPT-15443] Seeded accounts e2e data #144: Directly related—both modify the same seed/accounts modules with identical refactoring patterns (init_resource, require_context_id, replacing get/init flows with create variants).
  • MPT-16255 Seeding for catalog #152: Introduces and uses the same seed.helper utilities (init_resource and require_context_id) with matching refactoring of seed modules to adopt the new initialization pattern.

Suggested reviewers

  • d3rky
  • svazquezco
  • alephsur
  • ruben-sebrango

Poem

🐰 Hops through the garden of seeds to sow,
Init_resource helps the sprouts all grow,
No more get-or-create's tangled dance,
Just direct creation—a modernized stance!
Context flows cleaner through require's embrace, 🌱✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.85% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'MPT-16326 Refactor seeding accounts' accurately describes the main change in the changeset, which involves refactoring the account seeding functionality across multiple files in the seed/accounts module.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch MPT-16326-Refactor-accounts-seeding

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 10, 2025

Warnings
⚠️

This PR changes 897 lines across 21 files (threshold: 600). Please consider splitting it into smaller PRs for easier review.

✅ Found Jira issue key in the title: MPT-16326

Generated by 🚫 dangerJS against 00a2382

@albertsola albertsola changed the title MPT-16326 Refactor accounts seeding accounts MPT-16326 Refactor seeding accounts Dec 10, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (15)
tests/seed/accounts/test_accounts.py (1)

1-1: Remove unused import.

The os module is imported but not used in this file. Environment variable manipulation is handled via monkeypatch.

-import os
-
 import pytest
seed/accounts/accounts.py (2)

16-21: Remove unused noqa directives.

Per static analysis, RUF029 is not enabled, making the directive unnecessary. The async keyword is justified for init_resource compatibility as noted.

-async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
+async def get_account() -> Account:
+    """Get account ID from environment variable.
+
+    Note: This function is async for compatibility with init_resource,
+    which expects an async factory callable.
+    """

Moving the rationale into the docstring improves clarity without relying on a disabled linter rule.


24-24: Remove unused noqa directive.

The static analysis indicates WPS213 and WPS217 are unknown rules (not enabled in this project).

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:
tests/seed/accounts/test_seller.py (1)

47-52: Consider adding assertion on arguments.

The test verifies init_resource is awaited but doesn't verify it's called with the correct arguments. For consistency with test_seed_user_group, consider using assert_awaited_once_with.

 async def test_seed_seller(mocker):
     init_resource = mocker.patch(
         "seed.accounts.seller.init_resource", new_callable=mocker.AsyncMock
     )
     await seed_seller()  # act
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.seller.id", create_seller)
tests/seed/accounts/test_api_tokens.py (2)

16-30: Potentially unnecessary environment variable setup.

Line 17 sets CLIENT_ACCOUNT_ID via monkeypatch, but build_api_token_data reads accounts.account.id from the context (line 19), not from the environment. The monkeypatch.setenv call appears to be unnecessary unless there's another code path that reads it.

 def test_build_api_token_data(context, monkeypatch):
-    monkeypatch.setenv("CLIENT_ACCOUNT_ID", "ACC-1086-6867")
     context["accounts.module.id"] = "MOD-456"
     context["accounts.account.id"] = "ACC-1086-6867"

47-52: Consider adding assertion on arguments for consistency.

Similar to test_seed_user_group, consider verifying init_resource is called with the expected arguments.

 async def test_seed_api_token(mocker):
     init_resource = mocker.patch(
         "seed.accounts.api_tokens.init_resource", new_callable=mocker.AsyncMock
     )
     await seed_api_token()  # act
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.api_token", create_api_token)
tests/seed/accounts/test_user_group.py (1)

17-32: Potentially unnecessary environment variable setup.

Line 18 sets CLIENT_ACCOUNT_ID via monkeypatch, but build_user_group_data reads accounts.account.id from the context (line 20), not from the environment.

 def test_build_user_group_data(context: Context, monkeypatch):
-    monkeypatch.setenv("CLIENT_ACCOUNT_ID", "ACC-1086-6867")
     context["accounts.module.id"] = "MOD-456"
     context["accounts.account.id"] = "ACC-1086-6867"
tests/seed/accounts/test_module.py (2)

8-9: Remove unused noqa directives.

Ruff doesn't recognize WPS110 (a wemake-python-styleguide code). If wemake-python-styleguide is no longer part of the linting stack, these directives are unnecessary noise.

-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)

60-64: Consider asserting the arguments passed to init_resource.

The test verifies init_resource was awaited, but doesn't validate the namespace or factory function arguments. This could miss regressions if the wrong namespace or factory is passed.

 async def test_seed_module(mocker):
     init_resource = mocker.patch(
         "seed.accounts.module.init_resource", new_callable=mocker.AsyncMock
     )
     await seed_module()  # act
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.module.id", mocker.ANY)
seed/accounts/module.py (1)

22-27: Avoid materializing all modules when only the first is needed.

The current code collects all matching modules into a list before returning the first one. This is inefficient if there are many matches.

-    modules = [module async for module in filtered.iterate()]
-
-    if not modules:
-        raise ValueError("Module 'Access Management' not found.")
-    return modules[0]
+    async for module in filtered.iterate():
+        return module
+    raise ValueError("Module 'Access Management' not found.")
tests/seed/accounts/test_buyer.py (1)

51-54: Consider asserting init_resource arguments for better coverage.

Similar to test_seed_module, this test only verifies init_resource was called without checking the namespace or factory.

 async def test_seed_buyer(mocker):
     init_resource = mocker.patch("seed.accounts.buyer.init_resource", new_callable=mocker.AsyncMock)
     await seed_buyer()  # act
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.buyer.id", mocker.ANY)
seed/accounts/licensee.py (1)

15-15: Remove unused noqa directive.

Ruff doesn't recognize WPS238. If wemake-python-styleguide is not part of the linting stack, this directive is unnecessary.

-def build_licensee_data(  # noqa: WPS238
+def build_licensee_data(
tests/seed/accounts/test_licensee.py (2)

31-37: Remove obsolete environment variable setup.

Line 32 sets CLIENT_ACCOUNT_ID environment variable, but the refactored build_licensee_data function now uses require_context_id(context, "accounts.account.id", ...) to fetch the account ID from context (line 37), not from environment variables. This setup is now redundant.

Similarly, line 34 sets the user_group resource object, but the new implementation only requires the ID string in context (line 33).

 def test_build_licensee_data(context: Context, monkeypatch):
-    monkeypatch.setenv("CLIENT_ACCOUNT_ID", "ACC-1086-6867")
     context["accounts.user_group.id"] = "UG-123"
-    context.set_resource("accounts.user_group", Model({"id": "UG-123"}))
     context["accounts.seller.id"] = "SEL-123"
     context["accounts.buyer.id"] = "BUY-123"
     context["accounts.account.id"] = "ACC-1086-6867"

74-79: Consider verifying init_resource arguments for more precise testing.

The test confirms init_resource is called but doesn't verify the correct namespace and factory are passed. A more precise assertion would catch regressions if the namespace string changes.

 async def test_seed_licensee(mocker):
     init_resource = mocker.patch(
         "seed.accounts.licensee.init_resource", new_callable=mocker.AsyncMock
     )
     await seed_licensee()  # act
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.licensee.id", create_licensee)
seed/accounts/user_group.py (1)

41-42: Inconsistent error message phrasing.

The action parameter uses "creating user group" on line 41 but "create user group" on line 42. Use consistent phrasing for better error message clarity.

     account_id = require_context_id(context, "accounts.account.id", "creating user group")
-    module_id = require_context_id(context, "accounts.module.id", "create user group")
+    module_id = require_context_id(context, "accounts.module.id", "creating user group")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee74fde and af002fd.

📒 Files selected for processing (16)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (3 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🧰 Additional context used
🧬 Code graph analysis (11)
tests/seed/accounts/test_api_tokens.py (4)
mpt_api_client/resources/accounts/api_tokens.py (1)
  • ApiToken (12-13)
seed/accounts/api_tokens.py (3)
  • build_api_token_data (15-27)
  • create_api_token (31-36)
  • seed_api_token (40-44)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_licensee.py (2)
seed/accounts/licensee.py (3)
  • build_licensee_data (15-44)
  • create_licensee (47-49)
  • seed_licensee (53-57)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_buyer.py (4)
mpt_api_client/resources/accounts/buyers.py (1)
  • Buyer (26-27)
seed/accounts/buyer.py (3)
  • build_buyer_data (15-35)
  • create_buyer (39-46)
  • seed_buyer (50-54)
seed/context.py (1)
  • Context (12-33)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_seller.py (4)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/seller.py (3)
  • build_seller_data (14-29)
  • create_seller (32-37)
  • seed_seller (40-44)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/accounts.py (2)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/licensee.py (2)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/accounts/seller.py (4)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/container.py (1)
  • Container (7-30)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_user_group.py (4)
mpt_api_client/resources/accounts/user_groups.py (1)
  • UserGroup (11-12)
seed/accounts/user_group.py (3)
  • build_user_group_data (37-50)
  • create_user_group (53-58)
  • seed_user_group (62-66)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/user_group.py (2)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
mpt_api_client/resources/accounts/user_groups.py (1)
  • UserGroup (11-12)
seed/accounts/buyer.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
seed/accounts/module.py (3)
seed/helper.py (1)
  • init_resource (44-84)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/modules.py (1)
  • Module (11-12)
🪛 GitHub Actions: PR build and merge
tests/seed/accounts/test_accounts.py

[error] 1-1: Black formatting check failed: 1 file would be reformatted. Run 'black' to format the code.

🪛 Ruff (0.14.8)
tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_accounts.py

23-23: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

15-15: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (18)
seed/accounts/seller.py (2)

32-37: LGTM!

The create_seller function is clean and follows the new pattern. It correctly uses dependency injection via Provide and delegates to the API client for creation.


40-44: LGTM!

The seed_seller function correctly delegates to init_resource with the appropriate namespace and factory function.

tests/seed/accounts/test_accounts.py (2)

9-20: LGTM!

The tests for get_account properly cover both the failure case (missing env var raises ValueError) and the success case (returns Account with correct id).


23-23: Remove unused noqa directive and fix formatting.

The static analysis indicates WPS210 is unknown. Additionally, the pipeline shows a Black formatting failure for this file.

-async def test_seed_accounts(mocker):  # noqa: WPS210
+async def test_seed_accounts(mocker):

Run black on this file to resolve the formatting issue.

⛔ Skipped due to learnings
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.
seed/accounts/accounts.py (1)

27-34: LGTM!

The seeding order is correct: account is seeded first via init_resource, then downstream resources (seller, buyer, module, etc.) that depend on accounts.account.id being present in context.

tests/seed/accounts/test_seller.py (1)

36-44: LGTM!

The test correctly verifies that create_seller delegates to the API client and returns the expected seller object.

tests/seed/accounts/test_api_tokens.py (1)

33-44: LGTM!

The test properly mocks both the API client and build_api_token_data, verifying the create flow works correctly.

tests/seed/accounts/test_user_group.py (1)

35-53: LGTM!

The tests properly verify create_user_group and seed_user_group behavior. The assert_awaited_once_with pattern in test_seed_user_group is a good practice that should be adopted in other similar tests.

seed/accounts/buyer.py (3)

15-35: LGTM!

The build_buyer_data function correctly uses require_context_id to validate that both accounts.account.id and accounts.seller.id are present in the context before building the buyer data.


49-54: LGTM!

The seed_buyer function correctly uses init_resource with the appropriate namespace and factory function, consistent with the refactoring pattern across other seed modules.


38-46: Verify if the @inject decorator is necessary for create_buyer.

The create_buyer function uses both @inject decorator and Provide[] defaults. However, create_seller and create_licensee successfully use Provide[] defaults without @inject. Since init_resource calls the factory with no arguments and dependency-injector resolves Provide[] defaults during wiring, the decorator may be redundant here. Consider removing it for consistency with other create functions in the same module.

seed/static/static.py (1)

5-5: The logo.png file exists in the seed/static/ directory, so this constant definition is correct.

tests/seed/accounts/test_module.py (1)

35-57: Test coverage for find_module looks good.

The tests correctly validate:

  • Finding the first "Access Management" module when available
  • Raising ValueError when no module is found
seed/accounts/module.py (1)

30-37: LGTM!

The seed_module function correctly uses init_resource with the appropriate namespace and factory function.

seed/accounts/api_tokens.py (1)

14-36: LGTM!

The refactored build_api_token_data and create_api_token functions correctly use require_context_id for dependency validation and follow the new create pattern with proper DI wiring.

tests/seed/accounts/test_licensee.py (1)

63-71: LGTM!

Test correctly verifies that create_licensee invokes the API client's create method. The mock setup is adequate for testing the integration.

seed/accounts/user_group.py (2)

61-66: LGTM!

The seed_user_group function correctly follows the new init_resource pattern for resource initialization. The implementation is clean and consistent with the refactoring approach.


36-50: LGTM!

The build_user_group_data function correctly uses require_context_id to validate required dependencies are present before building the data dictionary. The @inject decorator ensures proper DI resolution.

@albertsola albertsola force-pushed the MPT-16326-Refactor-accounts-seeding branch from af002fd to 161092f Compare December 10, 2025 14:06
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (5)
tests/seed/accounts/test_buyer.py (1)

41-48: Use consistent ID prefix for seller.

Line 42 assigns an account-prefixed ID ("ACC-1086-6867") to accounts.seller.id, while test_build_buyer_data at line 15 correctly uses a seller-prefixed ID ("SEL-9999-9999"). This inconsistency reduces test clarity.

Apply this diff to use a seller prefix:

-    context["accounts.seller.id"] = "ACC-1086-6867"
+    context["accounts.seller.id"] = "SEL-9999-9999"
seed/accounts/api_tokens.py (1)

43-43: Inconsistent namespace: missing .id suffix.

Other seed functions use namespaces ending with .id (e.g., "accounts.buyer.id" at seed/accounts/buyer.py:53, "accounts.seller.id" at seed/accounts/seller.py:43), but this uses "accounts.api_token". This inconsistency could cause retrieval issues elsewhere in the codebase.

Apply this diff:

-    await init_resource("accounts.api_token", create_api_token)
+    await init_resource("accounts.api_token.id", create_api_token)
seed/accounts/user_group.py (1)

53-58: Critical: Missing @inject decorator will cause DI resolution failure.

The create_user_group function uses Provide[Container.mpt_operations] as a default parameter but lacks the @inject decorator. When seed_user_group calls init_resource("accounts.user_group.id", create_user_group), the factory is invoked with no arguments. Without @inject, dependency-injector cannot resolve the Provide marker, causing mpt_operations to remain as an unresolved Provide object rather than the actual client instance.

Based on seed/helper.py lines 43-83, init_resource calls resource_factory() with no arguments, expecting DI to resolve defaults.

Apply this diff:

+@inject
 async def create_user_group(
     mpt_operations: AsyncMPTClient = Provide[Container.mpt_operations],
 ) -> UserGroup:
seed/accounts/licensee.py (2)

19-19: Incorrect action string in error message.

The action string says "creating API token" but this function builds licensee data. This produces a confusing error if accounts.account.id is missing.

-    account_id = require_context_id(context, "accounts.account.id", "creating API token")
+    account_id = require_context_id(context, "accounts.account.id", "create licensee")

47-49: Missing @inject decorator on create_licensee.

The function uses Provide[Container.mpt_client] as a default parameter but lacks the @inject decorator. Without it, dependency injection may not resolve the default value correctly at runtime.

+@inject
 async def create_licensee(mpt_client: AsyncMPTClient = Provide[Container.mpt_client]) -> Licensee:
     """Create licensee."""
     return await mpt_client.accounts.licensees.create(build_licensee_data())
🧹 Nitpick comments (6)
tests/seed/accounts/test_accounts.py (1)

23-23: Remove unused noqa directive.

The noqa: WPS210 directive is flagged as unused by Ruff. Consider removing it to keep the code clean.

Apply this diff:

-async def test_seed_accounts(mocker):  # noqa: WPS210
+async def test_seed_accounts(mocker):
seed/accounts/accounts.py (2)

16-16: Remove unused noqa directive.

The noqa: RUF029 directive is flagged as unused (non-enabled rule) by Ruff. Consider removing it.

Apply this diff:

-async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
+async def get_account() -> Account:  # async for compatibility purposes with init_resource

24-24: Remove unused noqa directive.

The noqa: WPS213, WPS217 directive is flagged as unused (unknown rules) by Ruff. Consider removing it.

Apply this diff:

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:
seed/accounts/user_group.py (1)

16-33: Remove the unused get_user_group function.

This function is not referenced anywhere in the codebase and appears to be legacy code from the old get-or-create pattern. Removing it will reduce maintenance burden.

seed/accounts/licensee.py (1)

15-15: Remove unused noqa directive.

The # noqa: WPS238 directive is no longer needed as flagged by Ruff.

-def build_licensee_data(  # noqa: WPS238
+def build_licensee_data(
tests/seed/accounts/test_module.py (1)

8-9: Remove unused noqa directives.

The # noqa: WPS110 directives are no longer needed as flagged by Ruff.

-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af002fd and 161092f.

📒 Files selected for processing (16)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (3 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/seed/accounts/test_user_group.py
  • tests/seed/accounts/test_api_tokens.py
🧰 Additional context used
🧬 Code graph analysis (9)
seed/accounts/module.py (4)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/modules.py (1)
  • Module (11-12)
tests/seed/accounts/test_accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/accounts.py (2)
  • get_account (16-21)
  • seed_accounts (24-36)
mpt_api_client/models/model.py (1)
  • id (119-121)
seed/accounts/user_group.py (1)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/accounts/seller.py (4)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/container.py (1)
  • Container (7-30)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_licensee.py (4)
mpt_api_client/resources/accounts/licensees.py (1)
  • Licensee (21-22)
seed/accounts/licensee.py (2)
  • build_licensee_data (15-44)
  • create_licensee (47-49)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/api_tokens.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
seed/accounts/buyer.py (1)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/accounts/licensee.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (31-38)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
🪛 GitHub Actions: PR build and merge
tests/seed/accounts/test_accounts.py

[error] 1-1: Would reformat: tests/seed/accounts/test_accounts.py. 1 file would be reformatted.

🪛 Ruff (0.14.8)
seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

tests/seed/accounts/test_accounts.py

23-23: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

15-15: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

🔇 Additional comments (19)
seed/static/static.py (1)

5-5: LGTM!

The logo path update is straightforward and aligns the constant with the actual file name.

seed/accounts/buyer.py (4)

9-9: LGTM!

The addition of init_resource and require_context_id helpers aligns with the PR's refactoring objective to standardize resource initialization across the codebase.


17-18: LGTM!

The use of require_context_id ensures that required IDs are validated before creating the buyer, providing clear error messages if dependencies are missing.


38-46: LGTM!

The refactored create_buyer function correctly uses the @inject decorator and follows the new pattern of direct resource creation through init_resource.


53-53: LGTM!

The seed function now leverages init_resource for idempotent resource initialization, consistent with the refactoring pattern across other account seeders.

tests/seed/accounts/test_accounts.py (1)

8-20: LGTM!

The new tests for get_account correctly verify both the failure case (missing env var) and success case (env var present), ensuring proper validation of the CLIENT_ACCOUNT_ID environment variable.

seed/accounts/accounts.py (2)

16-21: LGTM!

The get_account function correctly retrieves and validates the CLIENT_ACCOUNT_ID environment variable, providing a clear error message when it's missing. The async signature is appropriate for compatibility with init_resource.


27-27: LGTM!

The integration of init_resource to seed the account ID is consistent with the refactoring pattern applied across all account seeders.

tests/seed/accounts/test_seller.py (2)

36-44: LGTM!

The test correctly validates the new create_seller flow by mocking the async create method and verifying the return value.


47-52: LGTM!

The test properly validates that seed_seller delegates to init_resource as expected in the new seeding pattern.

seed/accounts/module.py (3)

14-27: LGTM!

The find_module function correctly uses dependency injection with @inject and properly handles the not-found case by raising a descriptive ValueError.


30-37: LGTM!

The seed_module function follows the new init_resource pattern consistently with other seeders in this refactor.


14-27: Missing @inject decorator on find_module.

The function uses Provide[Container.mpt_operations] as a default parameter but lacks the @inject decorator. Without it, dependency injection may not resolve the default value correctly at runtime. Other functions in this file and related files (e.g., seed_module at line 30) properly include @inject.

Apply this diff:

 @inject
 async def find_module(
     mpt_operations: AsyncMPTClient = Provide[Container.mpt_operations],
 ) -> Module:

Wait—@inject is already present at line 14. My initial read was incorrect. The decorator applies to find_module.

seed/accounts/licensee.py (1)

52-57: LGTM!

The seed_licensee function correctly follows the new init_resource pattern.

tests/seed/accounts/test_module.py (2)

35-57: LGTM!

The tests properly cover both the success case and the not-found error case for find_module, with appropriate assertions and mocking.


60-65: LGTM!

The test correctly validates that seed_module delegates to init_resource.

tests/seed/accounts/test_licensee.py (3)

63-71: LGTM!

The test correctly validates the create_licensee flow by mocking the create method and patching build_licensee_data.


74-79: LGTM!

The test properly validates that seed_licensee delegates to init_resource as expected in the new seeding pattern.


31-60: LGTM!

The test correctly sets up all required context IDs (accounts.account.id, accounts.seller.id, accounts.buyer.id, accounts.user_group.id) and validates the expected licensee data structure.

@albertsola albertsola force-pushed the MPT-16326-Refactor-accounts-seeding branch 3 times, most recently from b562336 to 3fbc11f Compare December 10, 2025 14:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
seed/accounts/licensee.py (2)

20-20: Incorrect action string in error message.

The action string says "creating API token" but this function builds licensee data. This would produce a confusing error message if accounts.account.id is missing.

Apply this diff:

-    account_id = require_context_id(context, "accounts.account.id", "creating API token")
+    account_id = require_context_id(context, "accounts.account.id", "create licensee")

47-51: Critical: Missing @inject decorator on create_licensee.

The function uses Provide[Container.mpt_client] as a default parameter but lacks the @inject decorator. Without it, dependency injection will not resolve the default value correctly at runtime, causing mpt_client to remain as an unresolved Provide object instead of an AsyncMPTClient instance.

Apply this diff:

+@inject
 async def create_licensee(mpt_client: AsyncMPTClient = Provide[Container.mpt_client]) -> Licensee:
     """Create licensee."""
     licensee_data = build_licensee_data()
🧹 Nitpick comments (6)
seed/accounts/licensee.py (1)

16-16: Remove unused noqa directive.

The noqa: WPS238 directive is not recognized by the active linters.

Based on static analysis hints.

tests/seed/accounts/test_accounts.py (1)

22-56: LGTM: Comprehensive seed orchestration test.

The test properly verifies that all seeding functions and init_resource are called once during the seed_accounts flow.

Note: The noqa: WPS210 directive is unused and can be removed. Based on static analysis hints.

seed/accounts/accounts.py (2)

16-21: LGTM: Environment-based account retrieval.

The function correctly reads the account ID from the environment variable and validates its presence. The error message is clear and actionable.

Note: The noqa: RUF029 directive appears to be unused or references a non-enabled rule. Based on static analysis hints.


24-36: LGTM: Consolidated seeding orchestration.

The function correctly sequences the account seeding flow, initializing the account resource first before seeding dependent entities.

Note: The noqa: WPS213 WPS217 directives are unused and can be removed. Based on static analysis hints.

tests/seed/accounts/test_seller.py (1)

47-54: LGTM: Updated to test init_resource pattern.

Correctly verifies that seed_seller delegates to init_resource for resource initialization.

Consider asserting the specific arguments passed to init_resource (namespace and factory) for more complete verification, similar to the pattern in test_user_group.py line 53.

tests/seed/accounts/test_module.py (1)

8-9: Remove unused noqa directives.

The noqa directives for WPS110 are not recognized by Ruff and should be removed to keep the code clean.

Apply this diff:

-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)

As per static analysis hints.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 161092f and 6f21d4f.

📒 Files selected for processing (17)
  • docker-compose.yml (1 hunks)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (2 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • seed/static/static.py
  • tests/seed/accounts/test_api_tokens.py
🧰 Additional context used
🧬 Code graph analysis (10)
seed/accounts/accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/buyer.py (1)
  • seed_buyer (49-53)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/seller.py (4)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (30-34)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/user_group.py (4)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/user_groups.py (1)
  • UserGroup (11-12)
tests/seed/accounts/test_user_group.py (2)
seed/accounts/user_group.py (3)
  • build_user_group_data (16-29)
  • create_user_group (33-38)
  • seed_user_group (41-45)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_licensee.py (4)
mpt_api_client/resources/accounts/licensees.py (1)
  • Licensee (21-22)
seed/accounts/licensee.py (3)
  • build_licensee_data (16-44)
  • create_licensee (47-51)
  • seed_licensee (54-58)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/api_tokens.py (2)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/accounts/licensee.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
mpt_api_client/resources/accounts/licensees.py (1)
  • Licensee (21-22)
seed/accounts/module.py (4)
seed/helper.py (1)
  • init_resource (44-84)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/modules.py (1)
  • Module (11-12)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/seed/accounts/test_accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/accounts.py (2)
  • get_account (16-21)
  • seed_accounts (24-36)
mpt_api_client/models/model.py (1)
  • id (119-121)
🪛 Ruff (0.14.8)
seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

16-16: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

tests/seed/accounts/test_accounts.py

22-22: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (28)
docker-compose.yml (1)

30-30: LGTM: Extended test coverage to include seed tests.

The addition of tests/seed to the pytest command correctly aligns with the new seed-related test files introduced in this PR.

seed/accounts/module.py (2)

15-27: LGTM: Module discovery via API filtering.

The implementation correctly filters modules by name and returns the first match. The error handling appropriately raises ValueError when the module is not found.


30-34: LGTM: Clean resource initialization pattern.

The seeding flow correctly delegates to init_resource, which will cache the module ID in the context for downstream use.

tests/seed/accounts/test_accounts.py (2)

7-11: LGTM: Proper error handling test.

Correctly verifies that get_account raises ValueError when the required environment variable is missing.


14-19: LGTM: Successful path test.

Correctly verifies that get_account returns an Account instance with the expected ID from the environment variable.

tests/seed/accounts/test_user_group.py (3)

17-32: LGTM: Test data updated for new context requirements.

Correctly sets accounts.account.id in the context to align with the refactored build_user_group_data that uses require_context_id.


35-43: LGTM: Tests new create_user_group function.

Properly verifies that create_user_group calls the API create method with the expected data.


46-53: LGTM: Updated to test init_resource pattern.

Correctly verifies that seed_user_group delegates to init_resource with the appropriate namespace and factory function.

tests/seed/accounts/test_seller.py (1)

36-44: LGTM: Tests new create_seller function.

Properly verifies that create_seller calls the API create method and returns the expected seller.

seed/accounts/seller.py (2)

32-38: LGTM: Properly decorated create function.

The @inject decorator is present and correctly enables dependency injection for the mpt_operations parameter. The function cleanly creates and returns a seller.


41-45: LGTM: Clean resource initialization pattern.

The seeding flow correctly delegates to init_resource, which will cache the seller ID in the context for downstream use.

tests/seed/accounts/test_module.py (3)

35-45: LGTM!

The test correctly validates that find_module retrieves the expected module using the operations client.


48-57: LGTM!

The test properly verifies that find_module raises ValueError when no module is found.


60-67: LGTM!

The test correctly mocks init_resource and verifies the seeding flow.

seed/accounts/buyer.py (3)

17-18: LGTM!

The use of require_context_id properly enforces that required dependencies (account and seller) are available before creating the buyer.


39-46: LGTM!

The refactored create_buyer function is clean and follows the new pattern of directly creating resources without context-based retrieval logic.


49-53: LGTM!

The seeding flow correctly delegates to init_resource, which handles caching and idempotency.

tests/seed/accounts/test_buyer.py (2)

41-48: LGTM!

The test correctly validates the create_buyer function, and the seller_id now uses the proper "SEL-" prefix consistently with test_build_buyer_data. The past review concern about inconsistent ID formats has been resolved.


51-56: LGTM!

The test properly mocks init_resource and verifies the seed flow.

seed/accounts/api_tokens.py (3)

19-20: LGTM!

The use of require_context_id properly enforces that required dependencies are available before creating the API token.


30-36: LGTM!

The @inject decorator is present and the create_api_token function is correctly structured. The past review concern about the missing decorator has been resolved.


39-43: LGTM!

The namespace "accounts.api_token.id" is now consistent with other seed functions (includes the .id suffix). The past review concern about inconsistent namespace has been resolved.

tests/seed/accounts/test_licensee.py (3)

31-60: LGTM!

The test correctly sets up all required context IDs (including the newly added accounts.account.id on line 37) and validates that build_licensee_data produces the expected output.


63-71: LGTM!

The test appropriately validates the create_licensee function by mocking the creation call and verifying it's awaited.


74-81: LGTM!

The test correctly mocks init_resource and verifies the seed flow.

seed/accounts/user_group.py (3)

20-21: LGTM!

The use of require_context_id properly enforces that required dependencies are available before creating the user group.


32-38: LGTM!

The @inject decorator is present and the create_user_group function is correctly structured. The past review concern about the missing decorator has been resolved.


41-45: LGTM!

The seeding flow correctly delegates to init_resource, which handles caching and idempotency.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
seed/accounts/accounts.py (1)

2-36: Tidy get_account/seed_accounts: docstring & unnecessary noqa cleanup

A few small polish points:

  1. Docstring accuracy

get_account returns an Account instance, not just an ID. Update the docstring:

-async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
-    """Get account ID from environment variable."""
+async def get_account() -> Account:
+    """Get account from environment variable.
+
+    Async for compatibility with ``init_resource``.
+    """
  1. Remove unnecessary noqa for WPS rules

The # noqa: WPS213 WPS217 on seed_accounts is unnecessary. WPS rules are handled by flake8 (wemake-python-styleguide), not Ruff, so this noqa comment won't suppress Ruff warnings. Remove it:

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:

The RUF029 noqa on get_account is justified since the function is intentionally async for API compatibility, so it can remain if needed; however, since RUF029 is not enabled in the linter config, you may remove it along with the comment for clarity.

🧹 Nitpick comments (5)
tests/seed/accounts/test_buyer.py (1)

51-56: Optionally tighten assertion on init_resource call

test_seed_buyer currently only checks that init_resource was awaited once. If you want slightly stronger protection against regressions, consider also asserting the namespace:

-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.buyer.id", mocker.ANY)

This keeps the test resilient to internal changes while ensuring the expected context key is used.

tests/seed/accounts/test_seller.py (1)

3-54: Seller tests correctly exercise builder, creator, and seed flow

The seller tests are in good shape:

  • test_build_seller_data verifies the exact payload including the provided externalId.
  • test_create_seller wires an AsyncMock on operations_client.accounts.sellers.create and ensures create_seller returns that Seller.
  • test_seed_seller confirms init_resource is awaited once when running seed_seller.

If you want slightly stricter coverage, you could also assert the namespace in test_seed_seller:

-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.seller.id", mocker.ANY)

But as-is, the tests already validate the new flow well.

tests/seed/accounts/test_module.py (1)

7-18: Remove unused noqa directives.

The WPS110 rule is from wemake-python-styleguide which doesn't appear to be active in this project. Ruff correctly flags these as unused.

 class DummyAsyncIterator:
-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)
 
     def __aiter__(self):
         return self
seed/accounts/licensee.py (2)

20-23: Inconsistent action string format.

The action strings use inconsistent verb forms: "creating licensee" on line 20 vs "create licensee" on lines 21-23. Consider normalizing for consistency.

-    account_id = require_context_id(context, "accounts.account.id", "creating licensee")
-    seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
-    buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
-    user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")
+    account_id = require_context_id(context, "accounts.account.id", "create licensee")
+    seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
+    buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
+    user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")

16-16: Remove unused noqa directive.

The WPS238 rule is not active in this project's linter configuration.

-def build_licensee_data(  # noqa: WPS238
+def build_licensee_data(
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f21d4f and 3fbc11f.

📒 Files selected for processing (17)
  • docker-compose.yml (1 hunks)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (2 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/seed/accounts/test_user_group.py
  • seed/accounts/buyer.py
  • tests/seed/accounts/test_api_tokens.py
🧰 Additional context used
🧬 Code graph analysis (10)
seed/accounts/accounts.py (2)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/module.py (3)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/resources/accounts/modules.py (1)
  • Module (11-12)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (30-34)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_seller.py (3)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/seller.py (3)
  • build_seller_data (14-29)
  • create_seller (33-38)
  • seed_seller (41-45)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/seller.py (4)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/user_group.py (1)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/accounts/licensee.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
seed/accounts/api_tokens.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
mpt_api_client/resources/accounts/api_tokens.py (1)
  • ApiToken (12-13)
tests/seed/accounts/test_buyer.py (3)
mpt_api_client/resources/accounts/buyers.py (1)
  • Buyer (26-27)
seed/accounts/buyer.py (3)
  • build_buyer_data (15-35)
  • create_buyer (39-46)
  • seed_buyer (49-53)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/accounts.py (2)
  • get_account (16-21)
  • seed_accounts (24-36)
mpt_api_client/models/model.py (1)
  • id (119-121)
🪛 Ruff (0.14.8)
seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

16-16: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_accounts.py

22-22: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (19)
docker-compose.yml (1)

28-31: Expanded app_test command looks consistent with new seed tests

Including pytest tests/unit tests/seed after the existing lint/type checks fits the prior pattern and ensures the new seeding tests run in CI. No issues spotted.

seed/static/static.py (1)

3-5: LOGO path update is safe and localized

Switching LOGO to logo.png while keeping the same directory and constant name is a straightforward asset rename; no behavioral concerns here.

tests/seed/accounts/test_buyer.py (1)

3-48: Buyer creation tests align with new seeding API

The imports and both tests (test_build_buyer_data and test_create_buyer) correctly exercise the new build_buyer_data/create_buyer flow and the updated context keys for account and seller IDs. The AsyncMock wiring against operations_client.accounts.buyers.create is appropriate, and asserting that create_buyer returns the Buyer fixture keeps the test focused.

seed/accounts/api_tokens.py (1)

9-42: API token builder and seeding are consistent with init_resource pattern

Using require_context_id for "accounts.account.id" and "accounts.module.id" plus seeding via init_resource("accounts.api_token.id", create_api_token) brings this module in line with the other account seeders and centralizes the caching behavior. Structure and types look good.

seed/accounts/user_group.py (1)

10-45: User group seeding correctly migrated to init_resource + require_context_id

The user group builder and create_user_group/seed_user_group flow now follow the same context‑driven pattern as other account seeders, with consistent "accounts.user_group.id" naming and required context IDs for account and module. This looks coherent and maintainable.

tests/seed/accounts/test_accounts.py (2)

1-21: get_account tests cover both error and success paths

test_get_account_fails and test_get_account_success neatly exercise the two main branches of get_account, using monkeypatch to control CLIENT_ACCOUNT_ID. Asserting on the concrete Account.id value is a good sanity check on the model wrapper.


22-56: Seed orchestration test is well-structured; keep the noqa for legitimate complexity suppression

The test_seed_accounts orchestration test correctly patches init_resource and all the individual seed functions, then verifies each is called exactly once after seed_accounts().

One clarification:

  1. Keep the noqa: WPS210 comment

The # noqa: WPS210 on line 22 suppresses a Flake8-WPS violation (not Ruff), which is legitimate for this test function. With 7 mock patches and 8+ assertion statements, the function complexity warrants the suppression. This is consistent with similar test functions throughout the codebase that use the same suppression.

  1. (Optional) Assert expected parameters for init_resource

If you want to guard against accidental parameter changes, you could assert the exact call:

-    for mock in mocks:
-        mock.assert_called_once()
+    for mock in mocks:
+        mock.assert_called_once()
+
+    mock_init_resource.assert_awaited_once_with("accounts.account.id", get_account)

This keeps the generic "called once" checks while adding a more precise assertion for the context key and account resolver.

Likely an incorrect or invalid review comment.

seed/accounts/seller.py (2)

32-38: LGTM!

The @inject decorator is correctly applied, and the function properly delegates to the MPT client for seller creation. The implementation aligns with the refactored seeding pattern.


41-45: LGTM!

The seed_seller function correctly uses init_resource for idempotent seeding, consistent with the PR's refactoring goals.

seed/accounts/module.py (2)

14-27: LGTM!

The find_module function correctly uses RQL filtering and handles the not-found case with an appropriate error. The @inject decorator ensures proper DI resolution.


30-34: LGTM!

The seed_module function correctly uses init_resource for idempotent module seeding.

tests/seed/accounts/test_module.py (3)

35-45: LGTM!

The test correctly verifies find_module returns the expected module when the filter yields results.


48-57: LGTM!

Good coverage for the error case when the "Access Management" module is not found.


60-67: LGTM!

The test correctly verifies that seed_module delegates to init_resource.

seed/accounts/licensee.py (2)

47-52: LGTM!

The @inject decorator is correctly applied, and the ICON file is properly handled with a context manager ensuring the file descriptor is closed.


55-59: LGTM!

The seed_licensee function correctly uses init_resource for idempotent seeding.

tests/seed/accounts/test_licensee.py (3)

31-60: LGTM!

The test comprehensively sets up context with all required IDs and verifies the expected licensee data structure.


74-81: LGTM!

The test correctly verifies that seed_licensee delegates to init_resource.


63-71: The fixture naming is correct and requires no change.

The test appropriately uses the operations_client fixture and passes it as a positional argument to create_licensee, which correctly overrides the dependency injection. While the parameter is named mpt_client in the function signature (referencing Container.mpt_client), the fixture name operations_client is semantically correct—it represents the MPT client for account operations. Renaming it to client or mpt_client would actually reduce code clarity. No action needed.

Likely an incorrect or invalid review comment.

@albertsola albertsola force-pushed the MPT-16326-Refactor-accounts-seeding branch from 3fbc11f to 6e6bbb8 Compare December 11, 2025 15:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (13)
seed/accounts/accounts.py (2)

16-21: Clean up unused noqa directives.

The static analysis indicates RUF029 is not enabled, making the noqa directive unnecessary. Consider removing it for cleaner code.

-async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
+async def get_account() -> Account:

24-36: Clean up unused noqa directive.

Static analysis indicates WPS213 and WPS217 are unknown rules (not enabled in Ruff). The directive can be removed.

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:
tests/seed/accounts/test_accounts.py (2)

22-22: Clean up unused noqa directive.

Static analysis indicates WPS210 is an unknown rule. The directive can be removed.

-async def test_seed_accounts(mocker):  # noqa: WPS210
+async def test_seed_accounts(mocker):

46-56: Consider asserting init_resource was called with correct arguments.

The test asserts mock_init_resource.assert_called_once() but doesn't verify it was called with the expected arguments ("accounts.account.id", get_account). Other tests in this PR (e.g., test_seed_user_group, test_seed_module) verify the exact call arguments.

+from seed.accounts.accounts import get_account, seed_accounts
+
 ...
 
     mocks = [
         mock_seed_seller,
         mock_seed_buyer,
         mock_seed_module,
         mock_seed_api_token,
         mock_seed_user_group,
         mock_seed_licensee,
-        mock_init_resource,
     ]
     for mock in mocks:
         mock.assert_called_once()
+    mock_init_resource.assert_awaited_once_with("accounts.account.id", get_account)
tests/seed/accounts/test_module.py (2)

8-9: Clean up unused noqa directives.

Static analysis indicates WPS110 is an unknown rule (not enabled in Ruff). The directives can be removed.

-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)

60-67: Consider asserting init_resource was called with correct arguments.

For consistency with test_seed_user_group, consider verifying the exact call arguments to ensure the seeding is properly wired.

-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.module.id", find_module)
seed/accounts/module.py (1)

14-27: LGTM! Clean module lookup implementation.

The find_module function properly uses dependency injection and async iteration to find the target module. The error handling for missing modules is appropriate.

Regarding the static analysis hint (TRY003): consider extracting the error message to a custom exception class if this pattern is used elsewhere, but it's acceptable as-is for a single occurrence.

seed/accounts/licensee.py (2)

20-23: Inconsistent action string format.

The action string on line 20 uses "creating licensee" (gerund form) while lines 21-23 use "create licensee" (infinitive form). For consistency and clearer error messages, use the same format throughout.

     account_id = require_context_id(context, "accounts.account.id", "creating licensee")
-    seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
-    buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
-    user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")
+    seller_id = require_context_id(context, "accounts.seller.id", "creating licensee")
+    buyer_id = require_context_id(context, "accounts.buyer.id", "creating licensee")
+    user_group_id = require_context_id(context, "accounts.user_group.id", "creating licensee")

16-16: Remove unused noqa directive.

The static analysis tool indicates that WPS238 is an unknown code for Ruff. This directive is no longer needed and can be removed.

-def build_licensee_data(  # noqa: WPS238
+def build_licensee_data(
     context: Context = Provide[Container.context],
 ) -> dict[str, object]:
tests/seed/accounts/test_buyer.py (1)

51-56: Consider asserting the arguments passed to init_resource.

While the test verifies init_resource was awaited, it doesn't validate the namespace or factory function passed. Consider using assert_awaited_once_with for stronger verification.

 async def test_seed_buyer(mocker):
     init_resource = mocker.patch("seed.accounts.buyer.init_resource", new_callable=mocker.AsyncMock)
 
     await seed_buyer()  # act
 
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.buyer.id", create_buyer)
tests/seed/accounts/test_licensee.py (2)

31-37: Remove dead test setup code.

Line 32 sets the CLIENT_ACCOUNT_ID environment variable, but build_licensee_data no longer reads from environment variables—it uses require_context_id instead. Similarly, line 34 sets the user_group resource, but only the ID (line 33) is used by the function.

 def test_build_licensee_data(context: Context, monkeypatch):
-    monkeypatch.setenv("CLIENT_ACCOUNT_ID", "ACC-1086-6867")
     context["accounts.user_group.id"] = "UG-123"
-    context.set_resource("accounts.user_group", Model({"id": "UG-123"}))
     context["accounts.seller.id"] = "SEL-123"
     context["accounts.buyer.id"] = "BUY-123"
     context["accounts.account.id"] = "ACC-1086-6867"

Also update the function signature to remove the unused monkeypatch parameter:

-def test_build_licensee_data(context: Context, monkeypatch):
+def test_build_licensee_data(context: Context):

74-81: Consider asserting the arguments passed to init_resource.

Same as the buyer test—use assert_awaited_once_with for stronger verification of the namespace and factory function.

 async def test_seed_licensee(mocker):
     init_resource = mocker.patch(
         "seed.accounts.licensee.init_resource", new_callable=mocker.AsyncMock
     )
 
     await seed_licensee()  # act
 
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.licensee.id", create_licensee)
seed/accounts/user_group.py (1)

10-29: Context-based ID resolution for account & module looks solid

Switching build_user_group_data() to use require_context_id for "accounts.account.id" and "accounts.module.id" ties user-group creation strictly to previously-seeded context and fails fast when prerequisites are missing, which is a good, explicit contract. The new init_resource / require_context_id imports are correctly used and keep the function free of environment access.

If these "create user group" action strings start to repeat across modules, you might later want to centralize them, but that’s purely cosmetic and can wait.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbc11f and 6e6bbb8.

📒 Files selected for processing (17)
  • docker-compose.yml (1 hunks)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (2 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/seed/accounts/test_seller.py
  • seed/static/static.py
  • docker-compose.yml
  • tests/seed/accounts/test_api_tokens.py
  • seed/accounts/buyer.py
🧰 Additional context used
🧬 Code graph analysis (8)
seed/accounts/accounts.py (7)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/api_tokens.py (1)
  • seed_api_token (39-43)
seed/accounts/buyer.py (1)
  • seed_buyer (49-53)
seed/accounts/licensee.py (1)
  • seed_licensee (55-59)
seed/accounts/module.py (1)
  • seed_module (30-34)
seed/accounts/seller.py (1)
  • seed_seller (41-45)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/seller.py (4)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/api_tokens.py (5)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
mpt_api_client/resources/accounts/api_tokens.py (1)
  • ApiToken (12-13)
tests/seed/accounts/test_user_group.py (4)
mpt_api_client/resources/accounts/user_groups.py (1)
  • UserGroup (11-12)
seed/accounts/user_group.py (3)
  • build_user_group_data (16-29)
  • create_user_group (33-38)
  • seed_user_group (41-45)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_licensee.py (2)
seed/accounts/licensee.py (3)
  • build_licensee_data (16-44)
  • create_licensee (48-52)
  • seed_licensee (55-59)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_buyer.py (4)
mpt_api_client/resources/accounts/buyers.py (1)
  • Buyer (26-27)
seed/accounts/buyer.py (3)
  • build_buyer_data (15-35)
  • create_buyer (39-46)
  • seed_buyer (49-53)
seed/context.py (1)
  • Context (12-33)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (30-34)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/user_group.py (2)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
🪛 Ruff (0.14.8)
seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

16-16: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_accounts.py

22-22: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (17)
seed/accounts/seller.py (2)

32-38: LGTM! DI pattern correctly implemented.

The @inject decorator is properly applied, and the function correctly uses Provide[Container.mpt_operations] for dependency injection. The implementation follows the new seeding pattern consistently with other seed modules.


41-45: LGTM! Seed function properly refactored.

The seed_seller function correctly uses init_resource to manage resource creation and caching, aligning with the new seeding architecture.

seed/accounts/accounts.py (1)

27-34: LGTM! Seed orchestration properly updated.

The seed_accounts function now correctly initializes the account resource first via init_resource, then seeds dependent resources in the appropriate order.

tests/seed/accounts/test_accounts.py (1)

7-19: LGTM! Good test coverage for get_account.

The tests properly cover both the failure case (missing environment variable) and success case, validating the returned Account object's type and id.

tests/seed/accounts/test_user_group.py (3)

17-32: LGTM! Test correctly updated for new context requirements.

The test properly sets accounts.account.id in the context (line 20), which aligns with the updated build_user_group_data that now uses require_context_id for account lookup.


35-43: LGTM! Good test for create_user_group.

The test properly mocks the dependencies and verifies that the user group creation flow works correctly through the operations client.


46-53: LGTM! Seed test correctly validates init_resource usage.

The test properly asserts that init_resource is called with the correct namespace and factory function, ensuring the seeding flow is wired correctly.

tests/seed/accounts/test_module.py (2)

35-45: LGTM! Test correctly validates find_module flow.

The test properly sets up the mock filter chain and validates that the module is returned correctly when found.


48-57: LGTM! Good error case coverage.

The test properly validates that find_module raises a ValueError with the expected message when the module is not found.

seed/accounts/module.py (1)

30-33: LGTM!

The seeding flow correctly delegates to init_resource with the appropriate namespace.

seed/accounts/licensee.py (1)

47-52: LGTM!

The @inject decorator is correctly applied, and the function properly builds data and creates the licensee with the icon file.

tests/seed/accounts/test_buyer.py (1)

41-48: LGTM!

The test correctly sets up context, mocks the API call, and verifies the buyer creation flow.

seed/accounts/api_tokens.py (2)

14-27: LGTM!

The data building function correctly uses require_context_id for both account and module IDs, and the returned dictionary structure is well-formed.


30-43: LGTM!

The @inject decorator is correctly applied, and the seed flow properly uses init_resource with the .id namespace suffix consistent with other seed modules.

tests/seed/accounts/test_licensee.py (1)

63-71: LGTM!

The test correctly mocks build_licensee_data and verifies the creation flow via the operations client.

seed/accounts/user_group.py (2)

32-38: create_user_group factory matches the init_resource pattern

The async create_user_group() factory with an injected AsyncMPTClient and no required positional arguments is exactly what init_resource(..., create_user_group) expects. Centralizing payload construction through build_user_group_data() keeps the template in one place and is easy to override in tests.

Please just make sure your wiring/tests cover this path so that mpt_operations is indeed injected at runtime.


41-45: Function signature correctly reflects that seed_user_group() returns None

Good call—the change to return None and delegate to init_resource() is safe. All call sites (seed/accounts/accounts.py:33 and the test in tests/seed/accounts/test_user_group.py:51) invoke the function with await seed_user_group() without assigning the result, confirming they depend only on side effects.

create = mocker.AsyncMock(return_value=api_token)
operations_client.accounts.api_tokens.create = create
build_api_token_data = mocker.patch(
"seed.accounts.api_tokens.build_api_token_data", new_callable=mocker.Mock
Copy link
Contributor

Choose a reason for hiding this comment

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

new_callable=mocker.Mock seems obsolete here and spec missing

Comment on lines +34 to +35
create = mocker.AsyncMock(return_value=api_token)
operations_client.accounts.api_tokens.create = create
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be done in one line and also we should use spec here.

async def test_create_buyer(mocker, context: Context, operations_client, buyer):
context["accounts.seller.id"] = "SEL-9999-9999"
context["accounts.account.id"] = "ACC-1086-6867"
operations_client.accounts.buyers.create = mocker.AsyncMock(return_value=buyer)
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to spec it


async def test_seed_accounts(mocker): # noqa: WPS210
mock_init_resource = mocker.patch(
"seed.accounts.accounts.init_resource", new_callable=mocker.AsyncMock
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use spec here? Also new_callable seems obsolete

mock_init_licensee = mocker.patch(
"seed.accounts.licensee.init_licensee", new_callable=mocker.AsyncMock
init_resource = mocker.patch(
"seed.accounts.licensee.init_resource", new_callable=mocker.AsyncMock
Copy link
Contributor

Choose a reason for hiding this comment

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

new_callable=mocker.Mock seems obsolete here and spec missing

mock_refresh_module = mocker.patch(
"seed.accounts.module.refresh_module", new_callable=mocker.AsyncMock
init_resource = mocker.patch(
"seed.accounts.module.init_resource", new_callable=mocker.AsyncMock
Copy link
Contributor

Choose a reason for hiding this comment

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

new_callable=mocker.Mock seems obsolete here and spec missing

async def test_create_seller(mocker, operations_client):
seller = Seller({"id": "SEL-123"})
create_mock = mocker.AsyncMock(return_value=seller)
operations_client.accounts.sellers.create = create_mock
Copy link
Contributor

Choose a reason for hiding this comment

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

can we spec it?

mock_init_seller = mocker.patch(
"seed.accounts.seller.init_seller", new_callable=mocker.AsyncMock
init_resource = mocker.patch(
"seed.accounts.seller.init_resource", new_callable=mocker.AsyncMock
Copy link
Contributor

Choose a reason for hiding this comment

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

new_callable=mocker.Mock seems obsolete here and spec missing

mock_init_user_group = mocker.patch(
"seed.accounts.user_group.init_user_group", new_callable=mocker.AsyncMock
init_resource = mocker.patch(
"seed.accounts.user_group.init_resource", new_callable=mocker.AsyncMock
Copy link
Contributor

Choose a reason for hiding this comment

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

new_callable=mocker.Mock seems obsolete here and spec missing

@albertsola albertsola force-pushed the MPT-16326-Refactor-accounts-seeding branch 2 times, most recently from 0ce0c55 to cc4af75 Compare December 12, 2025 09:29
@albertsola albertsola requested a review from jentyk December 12, 2025 09:29
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
tests/seed/accounts/test_licensee.py (1)

63-71: Missing spec parameter on mocks.

The mocks at lines 64 and 66 lack the spec parameter, which was noted in previous reviews. Adding spec helps catch typos and ensures mocks match the actual interface.

-    create_mock = mocker.AsyncMock(return_value=licensee)
+    create_mock = mocker.AsyncMock(return_value=licensee, spec=True)
     operations_client.accounts.licensees.create = create_mock
-    mocker.patch("seed.accounts.licensee.build_licensee_data")
+    mocker.patch("seed.accounts.licensee.build_licensee_data", autospec=True)
🧹 Nitpick comments (6)
tests/seed/accounts/test_accounts.py (1)

22-22: Remove unused noqa directive.

The noqa: WPS210 directive is flagged as unused by Ruff, indicating the "too many local variables" issue it was suppressing is no longer present.

Apply this diff to remove the unused directive:

-async def test_seed_accounts(mocker):  # noqa: WPS210
+async def test_seed_accounts(mocker):
tests/seed/accounts/test_seller.py (1)

47-52: Consider asserting init_resource call arguments (not just “awaited once”)
This makes the test stricter about wiring.

-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once_with("accounts.seller.id", create_seller)
tests/seed/accounts/test_module.py (1)

60-65: seed_module test wiring via init_resource patch aligns with the refactor
Optional tightening: assert the call args ("accounts.module.id", find_module) if you want stricter wiring checks.

seed/accounts/licensee.py (2)

20-23: Inconsistent action string format.

The action strings are inconsistent: line 20 uses "creating licensee" while lines 21-23 use "create licensee". For consistency, use the same format throughout.

-    account_id = require_context_id(context, "accounts.account.id", "creating licensee")
-    seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
-    buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
-    user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")
+    account_id = require_context_id(context, "accounts.account.id", "create licensee")
+    seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
+    buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
+    user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")

16-16: Remove unused noqa directive.

The # noqa: WPS238 comment is flagged as unused by static analysis. This directive should be removed.

-def build_licensee_data(  # noqa: WPS238
+def build_licensee_data(
seed/accounts/buyer.py (1)

15-35: Missing @inject decorator on build_buyer_data.

The function uses Provide[Container.context] as a default parameter but lacks the @inject decorator. While create_buyer passes context explicitly, if build_buyer_data() is called directly without arguments (e.g., in tests or future code), the Provide marker won't resolve.

This is inconsistent with other files in this PR (e.g., build_licensee_data and build_user_group_data have @inject).

+@inject
 def build_buyer_data(context: Context = Provide[Container.context]) -> dict[str, object]:
     """Build buyer data dictionary for creation."""
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6e6bbb8 and cc4af75.

📒 Files selected for processing (22)
  • docker-compose.yml (1 hunks)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (2 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
  • tests/seed/catalog/test_authorization.py (1 hunks)
  • tests/seed/catalog/test_catalog.py (1 hunks)
  • tests/seed/catalog/test_listing.py (1 hunks)
  • tests/seed/catalog/test_price_list.py (1 hunks)
  • tests/seed/test_seed_api.py (2 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/seed/accounts/test_user_group.py
  • tests/seed/accounts/test_api_tokens.py
  • tests/seed/accounts/test_buyer.py
🧰 Additional context used
🧬 Code graph analysis (10)
seed/accounts/accounts.py (2)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/module.py (3)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/resources/accounts/modules.py (1)
  • Module (11-12)
mpt_api_client/rql/query_builder.py (1)
  • RQLQuery (115-524)
tests/seed/catalog/test_authorization.py (2)
seed/catalog/authorization.py (2)
  • seed_authorization (12-14)
  • create_authorization (18-39)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/seller.py (3)
seed/helper.py (1)
  • init_resource (44-84)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/buyer.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
tests/seed/catalog/test_catalog.py (5)
seed/catalog/catalog.py (1)
  • seed_catalog (11-19)
seed/catalog/product.py (1)
  • seed_product (37-51)
seed/catalog/authorization.py (1)
  • seed_authorization (12-14)
seed/catalog/price_list.py (1)
  • seed_price_list (10-12)
seed/catalog/listing.py (1)
  • seed_listing (10-12)
seed/accounts/user_group.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (30-34)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/api_tokens.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
tests/seed/accounts/test_accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/accounts.py (2)
  • get_account (16-21)
  • seed_accounts (24-36)
mpt_api_client/models/model.py (1)
  • id (119-121)
🪛 Ruff (0.14.8)
seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

16-16: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_accounts.py

22-22: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (33)
docker-compose.yml (1)

30-30: LGTM! Seed tests now included in CI.

The addition of tests/seed to the test path ensures the new seed-related tests are executed as part of the test suite.

seed/accounts/api_tokens.py (4)

9-9: LGTM! Proper use of helper functions.

The imports of init_resource and require_context_id align with the PR-wide refactoring to centralize resource initialization and context validation.


19-20: LGTM! Context IDs properly validated.

Using require_context_id ensures that required context values are present before attempting to create the API token, providing clear error messages if prerequisites are missing.


31-36: LGTM! Clean separation of concerns.

The create_api_token function properly uses the @inject decorator and delegates data construction to build_api_token_data, maintaining a clean separation between data preparation and API interaction.


42-42: LGTM! Consistent with init_resource pattern.

The namespace "accounts.api_token.id" follows the convention established across other seed modules, and the use of init_resource ensures idempotent seeding.

tests/seed/catalog/test_authorization.py (1)

35-40: LGTM! Improved test robustness with autospec.

Using autospec=True ensures the mock enforces the actual signature of init_resource, and assert_awaited_once_with correctly verifies the awaited call. These changes improve test reliability.

tests/seed/test_seed_api.py (2)

23-24: LGTM! Consistent autospec usage.

Adding autospec=True to both patches ensures the mocks validate against the actual function signatures, catching potential signature mismatches at test time.


35-36: LGTM! Correct async assertion method.

Using assert_awaited_once() properly validates that the async functions were awaited, which is the correct assertion for coroutines.

tests/seed/catalog/test_catalog.py (2)

8-11: LGTM! Comprehensive autospec coverage.

All seed function patches now use autospec=True, ensuring the test validates against the actual function signatures and catches interface changes.


15-18: LGTM! Proper async assertions.

All assertions correctly use assert_awaited_once() to verify the async seed functions were properly awaited during execution.

tests/seed/catalog/test_price_list.py (1)

29-29: LGTM! Consistent autospec pattern.

The addition of autospec=True aligns with the test improvements across the PR, ensuring the mock validates against the actual init_resource signature.

tests/seed/accounts/test_accounts.py (4)

7-11: LGTM! Proper error handling test.

The test correctly verifies that get_account raises ValueError when the required environment variable is missing, ensuring defensive behavior.


14-19: LGTM! Successful path well tested.

The test properly validates that get_account returns an Account instance with the correct ID when the environment variable is set.


23-30: LGTM! Comprehensive mocking with autospec.

All seed functions and init_resource are properly mocked with autospec=True, ensuring the tests validate against actual function signatures.


32-42: LGTM! Thorough verification of all seed calls.

The test correctly verifies that all seed functions and init_resource are awaited exactly once, ensuring the complete seed flow executes as expected.

seed/static/static.py (1)

5-5: No action needed — logo.png file exists at the expected location.

The file seed/static/logo.png is present, and the path construction in the LOGO constant is correct. The runtime reference to this constant will work as intended.

seed/accounts/accounts.py (2)

24-36: Seed orchestration via init_resource(..., get_account) looks consistent with the new pattern
Initializing "accounts.account.id" up-front before seeding dependent resources matches seed.helper.init_resource’s caching behavior.


24-28: Remove unused/unknown noqa on seed_accounts (RUF100)
Ruff reports the # noqa: WPS213 WPS217 is unused/unknown; drop it to avoid lint failures.

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:
     """Seed accounts data including account."""
     logger.debug("Seeding accounts ...")
     await init_resource("accounts.account.id", get_account)
⛔ Skipped due to learnings
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.
tests/seed/catalog/test_listing.py (1)

35-38: autospec=True for init_resource patch is a good tightening
Keeps the mock aligned with the real callable’s signature and still supports assert_awaited_once_with(...).

seed/accounts/seller.py (2)

32-38: create_seller factory + @inject is the right shape for init_resource
Keeps the factory zero-arg for init_resource() while still resolving mpt_operations through DI.


41-45: seed_seller using init_resource("accounts.seller.id", create_seller) is consistent and cache-friendly
Avoids re-creating sellers when the context already has the ID.

tests/seed/accounts/test_module.py (2)

35-45: test_find_module async-iteration stub looks solid
The DummyAsyncIterator approach exercises the async for path without needing a real service implementation.


48-58: Good coverage for the “module not found” error path
The ValueError message match makes the failure mode explicit.

seed/accounts/module.py (2)

14-27: LGTM! Well-structured module finder with proper DI.

The @inject decorator is correctly applied, and the function properly filters and returns the first matching module. The error handling for missing module is appropriate.

Regarding the static analysis hint (TRY003): the inline message is acceptable here given the simplicity of the error case.


30-34: LGTM! Clean seed orchestration.

The seed_module function correctly delegates to init_resource with the find_module factory. No @inject decorator is needed here since init_resource itself handles the DI resolution.

seed/accounts/licensee.py (2)

47-52: LGTM! Properly decorated with @inject.

The @inject decorator is now correctly applied, addressing the previous review concern. The function properly builds data and creates the licensee with an icon file.


55-59: LGTM! Clean seed orchestration.

The seed_licensee function correctly uses init_resource to handle the create-or-retrieve flow.

tests/seed/accounts/test_licensee.py (1)

74-79: LGTM! Clean seed test.

The test correctly patches init_resource at the module level and verifies it's awaited once.

seed/accounts/user_group.py (3)

15-29: LGTM! Clean data builder with proper DI.

The function correctly uses require_context_id to fetch dependencies and returns a well-structured dictionary for user group creation.


32-38: LGTM! Critical issue from previous review addressed.

The @inject decorator is now correctly applied, resolving the previous critical issue where DI would fail to resolve the Provide marker at runtime.


41-45: LGTM! Clean seed orchestration.

The seed_user_group function correctly delegates to init_resource with the create_user_group factory.

seed/accounts/buyer.py (2)

38-46: LGTM! Properly decorated with @inject.

The create_buyer function is correctly decorated and handles the buyer creation with icon file upload.


49-53: LGTM! Clean seed orchestration.

The seed_buyer function correctly uses init_resource to handle the create-or-retrieve flow.

Comment on lines +16 to +21
async def get_account() -> Account: # noqa: RUF029 async for compatibility purposes with init_resource
"""Get account ID from environment variable."""
account_id = os.getenv("CLIENT_ACCOUNT_ID")
if not account_id:
raise ValueError("CLIENT_ACCOUNT_ID environment variable is required")
return Account({"id": account_id})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix Ruff findings: remove unused noqa + address TRY003 with a custom exception
Ruff reports # noqa: RUF029 is unused and the ValueError("...") message triggers TRY003; both are straightforward to fix.

+class MissingClientAccountIdError(ValueError):
+    """CLIENT_ACCOUNT_ID environment variable is required."""
+
 async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
     """Get account ID from environment variable."""
     account_id = os.getenv("CLIENT_ACCOUNT_ID")
     if not account_id:
-        raise ValueError("CLIENT_ACCOUNT_ID environment variable is required")
+        raise MissingClientAccountIdError
     return Account({"id": account_id})

…and then remove the now-unneeded # noqa: RUF029.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 Ruff (0.14.8)

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
In seed/accounts/accounts.py around lines 16 to 21, remove the unnecessary "#
noqa: RUF029" and replace the generic ValueError raised when CLIENT_ACCOUNT_ID
is missing with a custom exception (e.g., define a MissingClientAccountError in
this module or import one from a shared errors module) so Ruff's TRY003 is
satisfied; add the custom exception definition near the top of the file (or
import it), then raise MissingClientAccountError("CLIENT_ACCOUNT_ID environment
variable is required") instead of ValueError, and delete the now-unneeded noqa
comment.

Comment on lines +8 to 10
def __init__(self, items): # noqa: WPS110
self._iterator = iter(items) # noqa: WPS110

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove unused/unknown # noqa: WPS110 (RUF100)
These are flagged as unused; they can break lint if Ruff is enforced.

 class DummyAsyncIterator:
-    def __init__(self, items):  # noqa: WPS110
-        self._iterator = iter(items)  # noqa: WPS110
+    def __init__(self, items):
+        self._iterator = iter(items)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def __init__(self, items): # noqa: WPS110
self._iterator = iter(items) # noqa: WPS110
class DummyAsyncIterator:
def __init__(self, items):
self._iterator = iter(items)
🧰 Tools
🪛 Ruff (0.14.8)

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

🤖 Prompt for AI Agents
In tests/seed/accounts/test_module.py around lines 8 to 10, the inline noqa
comments "# noqa: WPS110" are unused/unknown and should be removed; delete the
trailing "# noqa: WPS110" on the __init__ signature and the iterator assignment
so the linter (Ruff) won't flag unknown codes and the file uses standard noqa if
needed.

Comment on lines +36 to 45
async def test_create_seller(mocker, operations_client):
seller = Seller({"id": "SEL-123"})
create_mock = mocker.AsyncMock(return_value=seller)
operations_client.accounts.sellers.create = create_mock

result = await create_seller(operations_client)

async def test_init_seller_create_new(
context: Context, operations_client, sellers_service, seller, mocker
):
sellers_service.create.return_value = seller
operations_client.accounts.sellers = sellers_service
mocker.patch("seed.accounts.seller.get_seller", return_value=None)
mocker.patch(
"seed.accounts.seller.build_seller_data", return_value=build_seller_data("test-external-id")
)
result = await init_seller(context, mpt_operations=operations_client)
assert result == seller
sellers_service.create.assert_called_once()
create_mock.assert_called_once()

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use assert_awaited_once() for AsyncMock instead of assert_called_once()
This ensures the coroutine was actually awaited.

     assert result == seller
-    create_mock.assert_called_once()
+    create_mock.assert_awaited_once()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async def test_create_seller(mocker, operations_client):
seller = Seller({"id": "SEL-123"})
create_mock = mocker.AsyncMock(return_value=seller)
operations_client.accounts.sellers.create = create_mock
result = await create_seller(operations_client)
async def test_init_seller_create_new(
context: Context, operations_client, sellers_service, seller, mocker
):
sellers_service.create.return_value = seller
operations_client.accounts.sellers = sellers_service
mocker.patch("seed.accounts.seller.get_seller", return_value=None)
mocker.patch(
"seed.accounts.seller.build_seller_data", return_value=build_seller_data("test-external-id")
)
result = await init_seller(context, mpt_operations=operations_client)
assert result == seller
sellers_service.create.assert_called_once()
create_mock.assert_called_once()
async def test_create_seller(mocker, operations_client):
seller = Seller({"id": "SEL-123"})
create_mock = mocker.AsyncMock(return_value=seller)
operations_client.accounts.sellers.create = create_mock
result = await create_seller(operations_client)
assert result == seller
create_mock.assert_awaited_once()
🤖 Prompt for AI Agents
In tests/seed/accounts/test_seller.py around lines 36 to 45, the test uses
create_mock.assert_called_once() on an AsyncMock; replace that call with
create_mock.assert_awaited_once() so the test verifies the coroutine was
actually awaited, updating this assertion (and any similar AsyncMock assertions
in the file) to use assert_awaited_once().

@albertsola albertsola force-pushed the MPT-16326-Refactor-accounts-seeding branch from cc4af75 to 00a2382 Compare December 12, 2025 10:22
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (3)
seed/accounts/accounts.py (1)

16-21: Fix Ruff: remove unused noqa and avoid TRY003 by using a custom exception
Ruff flags the # noqa: RUF029 as unused and the inline exception message as TRY003; simplest fix is a small custom exception type and dropping the unused noqa.

+class MissingClientAccountIdError(ValueError):
+    """CLIENT_ACCOUNT_ID environment variable is required."""
+
-async def get_account() -> Account:  # noqa: RUF029 async for compatibility purposes with init_resource
+async def get_account() -> Account:
     """Get account ID from environment variable."""
     account_id = os.getenv("CLIENT_ACCOUNT_ID")
     if not account_id:
-        raise ValueError("CLIENT_ACCOUNT_ID environment variable is required")
+        raise MissingClientAccountIdError
     return Account({"id": account_id})
tests/seed/accounts/test_seller.py (1)

36-44: Use assert_awaited_once() for AsyncMock.

Line 44 should use assert_awaited_once() instead of assert_called_once() to properly verify the coroutine was awaited.

Apply this diff:

     assert result == seller
-    create_mock.assert_called_once()
+    create_mock.assert_awaited_once()
tests/seed/accounts/test_buyer.py (1)

41-47: Prefer patching buyers.create with autospec (vs direct assignment) to keep the mock honest.
Directly assigning operations_client.accounts.buyers.create = AsyncMock(...) skips signature/attribute validation; patching with autospec would better match the intent of this PR’s “autospec” move.

 async def test_create_buyer(mocker, context: Context, operations_client, buyer):
@@
-    operations_client.accounts.buyers.create = mocker.AsyncMock(return_value=buyer)
+    mocker.patch.object(
+        operations_client.accounts.buyers,
+        "create",
+        autospec=True,
+        new_callable=mocker.AsyncMock,
+        return_value=buyer,
+    )
@@
     result = await create_buyer(context, operations_client)
🧹 Nitpick comments (3)
tests/seed/test_seed_api.py (1)

22-37: Minor: set mock_seed_accounts.return_value = None for consistency
Not required, but avoids accidentally propagating an AsyncMock return object if the implementation ever starts using the result.

     mock_seed_catalog.return_value = None
+    mock_seed_accounts.return_value = None
     mock_context_file.return_value = pathlib.Path("test_context.json")
tests/seed/accounts/test_accounts.py (1)

22-22: Consider removing the unused noqa directive.

Ruff flags # noqa: WPS210 as unknown. If the project no longer uses wemake-python-styleguide or this specific check isn't needed, remove the directive.

Apply this diff if the directive is not needed:

-async def test_seed_accounts(mocker):  # noqa: WPS210
+async def test_seed_accounts(mocker):

Based on learnings, WPS directives are valid for wemake-python-styleguide. However, verify whether this specific check is still applicable here.

tests/seed/accounts/test_buyer.py (1)

51-56: Strengthen test_seed_buyer by asserting the awaited call arguments.
assert_awaited_once() can pass even if the namespace/factory are wrong; asserting args would lock down the behavior.

 async def test_seed_buyer(mocker):
     init_resource = mocker.patch("seed.accounts.buyer.init_resource", autospec=True)
@@
-    init_resource.assert_awaited_once()
+    init_resource.assert_awaited_once()
+    # optionally:
+    # init_resource.assert_awaited_once_with("accounts.buyer.id", mocker.ANY)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc4af75 and 00a2382.

📒 Files selected for processing (21)
  • seed/accounts/accounts.py (1 hunks)
  • seed/accounts/api_tokens.py (2 hunks)
  • seed/accounts/buyer.py (2 hunks)
  • seed/accounts/licensee.py (2 hunks)
  • seed/accounts/module.py (1 hunks)
  • seed/accounts/seller.py (2 hunks)
  • seed/accounts/user_group.py (2 hunks)
  • seed/static/static.py (1 hunks)
  • tests/seed/accounts/test_accounts.py (2 hunks)
  • tests/seed/accounts/test_api_token.py (0 hunks)
  • tests/seed/accounts/test_api_tokens.py (1 hunks)
  • tests/seed/accounts/test_buyer.py (2 hunks)
  • tests/seed/accounts/test_licensee.py (3 hunks)
  • tests/seed/accounts/test_module.py (2 hunks)
  • tests/seed/accounts/test_seller.py (2 hunks)
  • tests/seed/accounts/test_user_group.py (3 hunks)
  • tests/seed/catalog/test_authorization.py (1 hunks)
  • tests/seed/catalog/test_catalog.py (1 hunks)
  • tests/seed/catalog/test_listing.py (1 hunks)
  • tests/seed/catalog/test_price_list.py (1 hunks)
  • tests/seed/test_seed_api.py (2 hunks)
💤 Files with no reviewable changes (1)
  • tests/seed/accounts/test_api_token.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • tests/seed/catalog/test_listing.py
  • tests/seed/accounts/test_api_tokens.py
  • seed/static/static.py
  • tests/seed/catalog/test_price_list.py
  • tests/seed/catalog/test_authorization.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-01T10:48:52.586Z
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.

Applied to files:

  • tests/seed/accounts/test_module.py
🧬 Code graph analysis (12)
tests/seed/accounts/test_seller.py (3)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
seed/accounts/seller.py (3)
  • build_seller_data (14-29)
  • create_seller (33-38)
  • seed_seller (41-45)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/module.py (1)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/buyer.py (2)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
tests/seed/accounts/test_module.py (3)
seed/accounts/module.py (2)
  • find_module (15-27)
  • seed_module (30-34)
tests/seed/conftest.py (1)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/accounts.py (2)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/accounts/test_user_group.py (4)
mpt_api_client/resources/accounts/user_groups.py (1)
  • UserGroup (11-12)
seed/accounts/user_group.py (3)
  • build_user_group_data (16-29)
  • create_user_group (33-38)
  • seed_user_group (41-45)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
tests/seed/catalog/test_catalog.py (5)
seed/catalog/catalog.py (1)
  • seed_catalog (11-19)
seed/catalog/product.py (1)
  • seed_product (37-51)
seed/catalog/authorization.py (1)
  • seed_authorization (12-14)
seed/catalog/price_list.py (1)
  • seed_price_list (10-12)
seed/catalog/listing.py (1)
  • seed_listing (10-12)
seed/accounts/licensee.py (4)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/accounts/user_group.py (3)
seed/helper.py (2)
  • init_resource (44-84)
  • require_context_id (23-40)
seed/context.py (1)
  • Context (12-33)
seed/container.py (1)
  • Container (7-30)
tests/seed/accounts/test_licensee.py (4)
mpt_api_client/resources/accounts/licensees.py (1)
  • Licensee (21-22)
seed/accounts/licensee.py (2)
  • build_licensee_data (16-44)
  • create_licensee (48-52)
tests/seed/conftest.py (2)
  • context (14-15)
  • operations_client (24-25)
seed/helper.py (1)
  • init_resource (44-84)
seed/accounts/seller.py (4)
seed/helper.py (1)
  • init_resource (44-84)
mpt_api_client/mpt_client.py (1)
  • AsyncMPTClient (20-71)
seed/container.py (1)
  • Container (7-30)
mpt_api_client/resources/accounts/sellers.py (1)
  • Seller (13-14)
tests/seed/accounts/test_accounts.py (3)
mpt_api_client/resources/accounts/account.py (1)
  • Account (27-28)
seed/accounts/accounts.py (2)
  • get_account (16-21)
  • seed_accounts (24-36)
mpt_api_client/models/model.py (1)
  • id (119-121)
🪛 Ruff (0.14.8)
seed/accounts/module.py

26-26: Avoid specifying long messages outside the exception class

(TRY003)

tests/seed/accounts/test_module.py

8-8: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)


9-9: Unused noqa directive (unknown: WPS110)

Remove unused noqa directive

(RUF100)

seed/accounts/accounts.py

16-16: Unused noqa directive (non-enabled: RUF029)

Remove unused noqa directive

(RUF100)


20-20: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Unused noqa directive (unknown: WPS213, WPS217)

Remove unused noqa directive

(RUF100)

seed/accounts/licensee.py

16-16: Unused noqa directive (unknown: WPS238)

Remove unused noqa directive

(RUF100)

tests/seed/accounts/test_accounts.py

22-22: Unused noqa directive (unknown: WPS210)

Remove unused noqa directive

(RUF100)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (25)
seed/accounts/seller.py (2)

32-38: create_seller factory wiring looks correct (inject + Provide)
Factory is zero-arg callable for init_resource, and @inject ensures Provide[Container.mpt_operations] resolves.


41-45: Seeding via init_resource("accounts.seller.id", create_seller) is consistent with the new pattern

seed/accounts/api_tokens.py (3)

14-27: Good: explicit context prerequisites via require_context_id
This makes missing "accounts.account.id" / "accounts.module.id" fail fast and with better intent than ad-hoc context access.


30-37: Good: create_api_token is compatible with init_resource (zero-arg + injected client)


39-43: Namespace "accounts.api_token.id" matches the .id convention used elsewhere

tests/seed/catalog/test_catalog.py (1)

7-18: Test assertions now match async behavior (assert_awaited_once) and autospec improves safety

seed/accounts/accounts.py (1)

24-28: Remove unused/unknown noqa on seed_accounts
Ruff reports the # noqa: WPS213 WPS217 as unused/unknown; better to delete it and let real complexity warnings surface if/when enabled.

-async def seed_accounts() -> None:  # noqa: WPS213 WPS217
+async def seed_accounts() -> None:
⛔ Skipped due to learnings
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.
tests/seed/accounts/test_accounts.py (2)

7-19: LGTM!

The new tests for get_account provide good coverage of both the failure case (missing env var) and the success case (correct Account returned).


23-42: LGTM!

The test updates are excellent:

  • All mocks now use autospec=True for better type safety
  • assert_awaited_once() correctly verifies async calls
  • init_resource properly included in the assertion list

These changes address all previous feedback about adding spec and using proper async assertions.

tests/seed/accounts/test_seller.py (1)

48-52: LGTM!

The test correctly uses autospec=True for mocking and assert_awaited_once() for async verification.

tests/seed/accounts/test_user_group.py (2)

17-32: LGTM!

The test correctly sets up the required context (including accounts.account.id) and validates the expected data structure.


35-51: LGTM!

Both tests demonstrate excellent patterns:

  • test_create_user_group properly uses AsyncMock with assert_awaited_once()
  • test_seed_user_group uses autospec=True and verifies the exact arguments passed to init_resource
tests/seed/accounts/test_module.py (1)

35-65: LGTM!

The tests are well-structured:

  • test_find_module validates successful module retrieval
  • test_find_module_not_found properly tests the ValueError case
  • test_seed_module uses autospec=True and correct async assertions
seed/accounts/module.py (2)

15-27: LGTM!

The find_module function is well-implemented:

  • Clear RQL filtering by module name
  • Proper error handling when module not found
  • Returns the first matching module

30-34: LGTM!

The updated seed_module function correctly delegates to init_resource with the find_module factory, aligning with the broader seeding refactor.

tests/seed/accounts/test_licensee.py (2)

31-60: LGTM!

The test comprehensively validates build_licensee_data, ensuring all required context IDs are set and the output structure is complete.


63-79: LGTM!

Both tests demonstrate excellent async testing patterns:

  • test_create_licensee properly mocks and verifies the async create flow
  • test_seed_licensee uses autospec=True and correct async assertions
seed/accounts/user_group.py (3)

15-29: LGTM!

The build_user_group_data function correctly uses require_context_id to ensure required IDs are present, improving error handling over environment variable access.


32-38: LGTM!

The create_user_group function is correctly implemented with the @inject decorator, ensuring dependency injection works properly. This addresses the previous feedback about the missing decorator.


41-45: LGTM!

The updated seed_user_group function correctly delegates to init_resource, aligning with the standardized seeding pattern across the module.

seed/accounts/buyer.py (2)

15-35: LGTM!

The build_buyer_data function correctly uses require_context_id to validate required IDs are present, and returns a comprehensive buyer data structure.


38-53: LGTM!

Both functions are well-implemented:

  • create_buyer properly uses the @inject decorator, handles file I/O with a context manager, and creates the buyer
  • seed_buyer correctly delegates to init_resource following the standardized pattern
seed/accounts/licensee.py (3)

47-52: Verify DI wiring + file upload semantics for create_licensee().
Since create_licensee() and build_licensee_data() are invoked with no args and rely on dependency-injector (@inject + Provide[...]), ensure the application wires seed.accounts.licensee into the container at runtime. Also confirm mpt_client.accounts.licensees.create(..., file=icon_fd) fully reads the file during the awaited call (so the with ICON.open(...) scope is safe).


55-59: seed_licensee orchestration via init_resource looks consistent with the new seeding pattern.
Good use of a single id namespace (accounts.licensee.id) and a create-only factory.


16-16: Remove unused # noqa: WPS238 to satisfy Ruff.
Ruff reports the directive is unused on Line 16.

⛔ Skipped due to learnings
Learnt from: jentyk
Repo: softwareone-platform/mpt-api-python-client PR: 136
File: tests/e2e/notifications/subscribers/conftest.py:14-25
Timestamp: 2025-12-01T10:48:52.586Z
Learning: The repository softwareone-platform/mpt-api-python-client uses wemake-python-styleguide linter, so noqa directives for WPS rules should not be flagged as unused.

Comment on lines +20 to +23
account_id = require_context_id(context, "accounts.account.id", "creating licensee")
seller_id = require_context_id(context, "accounts.seller.id", "create licensee")
buyer_id = require_context_id(context, "accounts.buyer.id", "create licensee")
user_group_id = require_context_id(context, "accounts.user_group.id", "create licensee")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unify action strings passed to require_context_id for consistent error messages.
Line 20 uses "creating licensee" while Lines 21-23 use "create licensee". Pick one phrasing (e.g., "create licensee") so missing-context errors read consistently.

🤖 Prompt for AI Agents
In seed/accounts/licensee.py around lines 20 to 23, the action string passed to
require_context_id is inconsistent: line 20 uses "creating licensee" while lines
21–23 use "create licensee"; change the action on line 20 to "create licensee"
so all four calls use the identical phrase and produce consistent
missing-context error messages.

@sonarqubecloud
Copy link

@albertsola albertsola merged commit d4ca602 into main Dec 12, 2025
6 checks passed
@albertsola albertsola deleted the MPT-16326-Refactor-accounts-seeding branch December 12, 2025 10:41
@coderabbitai coderabbitai bot mentioned this pull request Dec 15, 2025
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