Skip to content

MPT-20684 introduce shared base models for file-like resources#325

Merged
robcsegal merged 1 commit intomainfrom
MPT-20684-update-models-and-base-models-to-reduce-code-duplication
May 1, 2026
Merged

MPT-20684 introduce shared base models for file-like resources#325
robcsegal merged 1 commit intomainfrom
MPT-20684-update-models-and-base-models-to-reduce-code-duplication

Conversation

@robcsegal
Copy link
Copy Markdown
Contributor

@robcsegal robcsegal commented Apr 29, 2026

🤖 AI-generated PR — Please review carefully.

Summary

Reduces duplicated field declarations across the model layer by extracting a
shared FileResourceModel base for attachments, documents, media, and term
variants, plus four specialized subclasses (AttachmentModel, DocumentModel,
MediaModel, TermVariantModel). Resource classes across billing, catalog,
commerce, helpdesk, integration, and program domains now inherit from the new
base models instead of redeclaring the same fields locally.

What changed

New base models (mpt_api_client/models/)

  • file_resource_model.py — shared fields: name, type, size, description, content_type
  • attachment_model.py — attachment-specific fields on top of the base
  • document_model.py — document-specific fields
  • media_model.py — media-specific fields
  • term_variant_model.py — term-variant-specific fields
  • __init__.py re-exports the new classes

Migrated resource classes

  • billing/: credit_memo_attachments, custom_ledger_attachments, invoice_attachments, journal_attachments, ledger_attachments, statement_attachments
  • catalog/: pricing_policy_attachments, product_term_variants, products_documents, products_media
  • helpdesk/: chat_attachments
  • integration/: extension_documents, extension_media, extension_term_variants
  • program/: enrollments_attachments, programs_documents, programs_media, programs_terms_variant

Resource-specific fields (parent references, audit, language, revision, etc.)
remain on the subclasses.

Tests

  • New tests/unit/conftest.py fixtures for inherited-field coverage
  • New unit test files for each base model under tests/unit/models/
  • Updated existing unit tests to reflect the new convention where missing
    optional fields default to None instead of raising AttributeError

Testing

  • make check (lint + types)
  • make test (unit suite)
  • Smoke-run a few e2e tests touching the migrated resources to confirm
    response parsing still works against the live API

Jira

MPT-20684

Closes MPT-20684

Release Notes

  • Introduced shared base models to reduce code duplication for file-like resources:

    • FileResourceModel: Base class with common fields (name, type, size, description, content_type)
    • AttachmentModel: Specialization of FileResourceModel for attachment resources
    • DocumentModel: Extends FileResourceModel with document-specific fields (status, filename, url)
    • MediaModel: Extends FileResourceModel with media-specific fields (status, filename, display_order, url)
    • TermVariantModel: Extends FileResourceModel with term variant fields (asset_url, language_code, status, filename, file_id)
  • Updated resource classes across multiple modules to inherit from appropriate base models instead of directly from Model:

    • Billing: CreditMemoAttachment, CustomLedgerAttachment, InvoiceAttachment, JournalAttachment, LedgerAttachment, StatementAttachment
    • Catalog: PricingPolicyAttachment, TermVariant, Document, Media
    • Helpdesk: Removed ChatAttachment and updated service to use AttachmentModel directly
    • Integration: ExtensionDocument, ExtensionMedia, ExtensionTermVariant
    • Program: Document, Media, TermVariant, EnrollmentAttachment
  • Eliminated duplicate field declarations by migrating resource classes to inherit shared fields from their respective base models

  • Added comprehensive unit test coverage for new base models including field initialization, camelCase-to-snake_case mapping, serialization round-trips, and repr() formatting

  • Updated existing resource tests to validate inherited field behavior with optional fields defaulting to None instead of being absent

  • Updated E2E tests for chat attachments to validate against AttachmentModel instead of the removed ChatAttachment class

  • Expanded module exports in mpt_api_client/models/__init__.py to include new model classes for public API access

@robcsegal robcsegal requested a review from a team as a code owner April 29, 2026 16:01
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

📝 Walkthrough

Walkthrough

Introduces five new shared model classes (FileResourceModel, AttachmentModel, DocumentModel, MediaModel, TermVariantModel) that define common file and resource metadata fields. Refactors 15+ existing resource classes across billing, catalog, integration, and program modules to inherit from these models instead of duplicating field declarations. Removes the ChatAttachment class and updates references to use AttachmentModel directly.

Changes

Cohort / File(s) Summary
New Model Definitions
mpt_api_client/models/file_resource_model.py, mpt_api_client/models/attachment_model.py, mpt_api_client/models/document_model.py, mpt_api_client/models/media_model.py, mpt_api_client/models/term_variant_model.py
Introduces five new model classes with inheritance hierarchy: FileResourceModel as the base with common fields (name, type, size, description, content_type), followed by AttachmentModel, DocumentModel, MediaModel, and TermVariantModel as specialized subclasses with additional attributes.
Module Exports Update
mpt_api_client/models/__init__.py
Expands __all__ export list to include the five new model classes alongside existing exports.
Billing Resource Refactoring
mpt_api_client/resources/billing/credit_memo_attachments.py, mpt_api_client/resources/billing/custom_ledger_attachments.py, mpt_api_client/resources/billing/invoice_attachments.py, mpt_api_client/resources/billing/journal_attachments.py, mpt_api_client/resources/billing/ledger_attachments.py, mpt_api_client/resources/billing/statement_attachments.py
Updates six attachment resource classes to inherit from AttachmentModel instead of Model, removing duplicate field declarations.
Catalog Resource Refactoring
mpt_api_client/resources/catalog/pricing_policy_attachments.py, mpt_api_client/resources/catalog/products_documents.py, mpt_api_client/resources/catalog/products_media.py, mpt_api_client/resources/catalog/product_term_variants.py
Refactors catalog resources to use AttachmentModel, DocumentModel, MediaModel, and TermVariantModel as base classes; removes duplicate field definitions inherited from new model classes.
Integration Resource Refactoring
mpt_api_client/resources/integration/extension_documents.py, mpt_api_client/resources/integration/extension_media.py, mpt_api_client/resources/integration/extension_term_variants.py
Updates extension resource classes to inherit from DocumentModel, MediaModel, and TermVariantModel respectively; consolidates field declarations by removing duplicates now provided by parent models.
Program Resource Refactoring
mpt_api_client/resources/program/enrollments_attachments.py, mpt_api_client/resources/program/programs_documents.py, mpt_api_client/resources/program/programs_media.py, mpt_api_client/resources/program/programs_terms_variant.py
Refactors program resources (EnrollmentAttachment, Document, Media, TermVariant) to use corresponding model base classes (AttachmentModel, DocumentModel, MediaModel, TermVariantModel).
Helpdesk Resource Refactoring
mpt_api_client/resources/helpdesk/chat_attachments.py
Removes the ChatAttachment class entirely; updates service configuration and generic type parameters to use AttachmentModel directly instead of a local resource class.
Unit Test Fixtures and Model Tests
tests/unit/conftest.py, tests/unit/models/test_attachment_model.py, tests/unit/models/test_document_model.py, tests/unit/models/test_file_resource_model.py, tests/unit/models/test_media_model.py, tests/unit/models/test_term_variant_model.py
Adds four new pytest fixtures providing test data for attachment, document, media, and term-variant resources. Introduces five new model test modules with dummy subclasses and validation tests for field initialization, camelCase-to-snake_case mapping, serialization, and string representation.
Unit Test Resource Updates
tests/unit/resources/billing/test_*.py (6 files), tests/unit/resources/catalog/test_*.py (4 files), tests/unit/resources/integration/test_*.py (3 files), tests/unit/resources/program/test_*.py (4 files)`
Updates 17 existing resource test modules to validate inherited field behavior through new test cases and assertion changes; shifts from checking attribute absence via hasattr to asserting explicit None values for optional fields.
E2E Test Updates
tests/e2e/helpdesk/chats/attachment/test_async_attachment.py, tests/e2e/helpdesk/chats/attachment/test_sync_attachment.py
Updates e2e helpdesk attachment tests to assert returned objects are instances of AttachmentModel instead of ChatAttachment.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • PR #286 & #287: Both modify mpt_api_client/resources/integration/extension_term_variants.py — the retrieved PRs introduce or modify the ExtensionTermVariant class structure, while this PR refactors it to inherit from TermVariantModel and consolidates field declarations.
  • PR #231: Modifies the same catalog resource model classes (products_documents, products_media, product_term_variants, pricing_policy_attachments) by adding typed field annotations; this PR factors those common fields into shared model base classes.
  • PR #255: Updates the same e2e helpdesk chat attachment test modules; the retrieved PR un-skips these tests while this PR changes them to use AttachmentModel instead of ChatAttachment.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Jira Issue Key In Title ✅ Passed The PR title contains exactly one Jira issue key (MPT-20684) in the correct format at the beginning.
Test Coverage Required ✅ Passed PR modifies 24 code files with corresponding test changes across 24 test files, including unit tests for new models and updated tests for modified resources.
Single Commit Required ✅ Passed The PR contains exactly one commit (6ed09ac refactor: MPT-20684 introduce shared base models for file-like resources), satisfying the single commit requirement.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Review rate limit: 4/5 reviews remaining, refill in 12 minutes.

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

Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (1)
tests/unit/resources/program/test_programs_documents.py (1)

92-105: ⚠️ Potential issue | 🟡 Minor

Add language to the nullability assertions.

The updated optional-field test still leaves language unverified even though this fixture and resource surface include it. That leaves one nullable document field without regression coverage.

Suggested fix
     assert result.description is None
+    assert result.language is None
     assert result.status is None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/resources/program/test_programs_documents.py` around lines 92 -
105, The test test_document_optional_fields_absent is missing an assertion for
the optional language field; update the test to include an assertion that the
Document created with only {"id": "PDM-001"} has language == None (i.e., add
assert result.language is None) so the nullability of the language attribute on
the Document resource is covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/unit/resources/program/test_programs_documents.py`:
- Around line 92-105: The test test_document_optional_fields_absent is missing
an assertion for the optional language field; update the test to include an
assertion that the Document created with only {"id": "PDM-001"} has language ==
None (i.e., add assert result.language is None) so the nullability of the
language attribute on the Document resource is covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 8f493f58-d1f0-4590-a9e5-2e698f033ef6

📥 Commits

Reviewing files that changed from the base of the PR and between 8389441 and 3eab7da.

📒 Files selected for processing (47)
  • mpt_api_client/models/__init__.py
  • mpt_api_client/models/attachment_model.py
  • mpt_api_client/models/document_model.py
  • mpt_api_client/models/file_resource_model.py
  • mpt_api_client/models/media_model.py
  • mpt_api_client/models/term_variant_model.py
  • mpt_api_client/resources/billing/credit_memo_attachments.py
  • mpt_api_client/resources/billing/custom_ledger_attachments.py
  • mpt_api_client/resources/billing/invoice_attachments.py
  • mpt_api_client/resources/billing/journal_attachments.py
  • mpt_api_client/resources/billing/ledger_attachments.py
  • mpt_api_client/resources/billing/statement_attachments.py
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py
  • mpt_api_client/resources/catalog/product_term_variants.py
  • mpt_api_client/resources/catalog/products_documents.py
  • mpt_api_client/resources/catalog/products_media.py
  • mpt_api_client/resources/helpdesk/chat_attachments.py
  • mpt_api_client/resources/integration/extension_documents.py
  • mpt_api_client/resources/integration/extension_media.py
  • mpt_api_client/resources/integration/extension_term_variants.py
  • mpt_api_client/resources/program/enrollments_attachments.py
  • mpt_api_client/resources/program/programs_documents.py
  • mpt_api_client/resources/program/programs_media.py
  • mpt_api_client/resources/program/programs_terms_variant.py
  • tests/unit/conftest.py
  • tests/unit/models/test_attachment_model.py
  • tests/unit/models/test_document_model.py
  • tests/unit/models/test_file_resource_model.py
  • tests/unit/models/test_media_model.py
  • tests/unit/models/test_term_variant_model.py
  • tests/unit/resources/billing/test_credit_memo_attachments.py
  • tests/unit/resources/billing/test_custom_ledger_attachments.py
  • tests/unit/resources/billing/test_invoice_attachments.py
  • tests/unit/resources/billing/test_journal_attachments.py
  • tests/unit/resources/billing/test_ledger_attachments.py
  • tests/unit/resources/billing/test_statement_attachments.py
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py
  • tests/unit/resources/catalog/test_product_term_variants.py
  • tests/unit/resources/catalog/test_products_documents.py
  • tests/unit/resources/catalog/test_products_media.py
  • tests/unit/resources/helpdesk/test_chat_attachments.py
  • tests/unit/resources/integration/test_extension_documents.py
  • tests/unit/resources/integration/test_extension_media.py
  • tests/unit/resources/integration/test_extension_term_variants.py
  • tests/unit/resources/program/test_programs_documents.py
  • tests/unit/resources/program/test_programs_media.py
  • tests/unit/resources/program/test_programs_terms_variant.py

Comment thread mpt_api_client/resources/helpdesk/chat_attachments.py Outdated
Copy link
Copy Markdown
Member

@jentyk jentyk left a comment

Choose a reason for hiding this comment

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

Pls read a comment

AI Generated.
Extract FileResourceModel as a shared base for fields common to attachments,
documents, media, and term variants (name, type, size, description,
content_type). Add AttachmentModel, DocumentModel, MediaModel, and
TermVariantModel as specialized subclasses that layer on the fields unique to
each resource family. Migrate the corresponding resource classes across
billing, catalog, commerce, helpdesk, integration, and program domains to
inherit from the new base models, removing duplicated field declarations
while keeping resource-specific fields (parent references, audit, language,
revision, etc.) on the subclasses.

Update unit tests to match the new convention where missing optional fields
default to None instead of raising AttributeError, add inherited-field
fixtures in tests/unit/conftest.py, and add dedicated test files for each new
base model under tests/unit/models/.
@robcsegal robcsegal force-pushed the MPT-20684-update-models-and-base-models-to-reduce-code-duplication branch from 3eab7da to 6ed09ac Compare May 1, 2026 13:03
@robcsegal
Copy link
Copy Markdown
Contributor Author

Pls read a comment

resolved

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 1, 2026

Copy link
Copy Markdown

@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.

Caution

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

⚠️ Outside diff range comments (1)
tests/unit/resources/program/test_programs_terms_variant.py (1)

103-118: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add targeted suppression for assertion-count rule on Line 103.

test_term_variant_optional_fields_absent now has many assertions and should match the repo pattern used in adjacent files to avoid lint instability.

Proposed fix
-def test_term_variant_optional_fields_absent() -> None:
+def test_term_variant_optional_fields_absent() -> None:  # noqa: WPS218
As per coding guidelines: “add targeted noqa (e.g., WPS218) only when assertion count makes it unavoidable.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/resources/program/test_programs_terms_variant.py` around lines 103
- 118, The test function test_term_variant_optional_fields_absent contains many
assertions and should include a targeted noqa to suppress the assertion-count
lint rule; update the test function definition line (the def
test_term_variant_optional_fields_absent(...) declaration) to append a focused
noqa for the assertion-count rule used in this repo (e.g., add "  # noqa:
WPS218") so only that rule is suppressed while leaving other linters active.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/unit/resources/program/test_programs_terms_variant.py`:
- Around line 103-118: The test function
test_term_variant_optional_fields_absent contains many assertions and should
include a targeted noqa to suppress the assertion-count lint rule; update the
test function definition line (the def
test_term_variant_optional_fields_absent(...) declaration) to append a focused
noqa for the assertion-count rule used in this repo (e.g., add "  # noqa:
WPS218") so only that rule is suppressed while leaving other linters active.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: e8dab837-2336-4c4d-bfd9-303d3712c4bd

📥 Commits

Reviewing files that changed from the base of the PR and between 3eab7da and 6ed09ac.

📒 Files selected for processing (48)
  • mpt_api_client/models/__init__.py
  • mpt_api_client/models/attachment_model.py
  • mpt_api_client/models/document_model.py
  • mpt_api_client/models/file_resource_model.py
  • mpt_api_client/models/media_model.py
  • mpt_api_client/models/term_variant_model.py
  • mpt_api_client/resources/billing/credit_memo_attachments.py
  • mpt_api_client/resources/billing/custom_ledger_attachments.py
  • mpt_api_client/resources/billing/invoice_attachments.py
  • mpt_api_client/resources/billing/journal_attachments.py
  • mpt_api_client/resources/billing/ledger_attachments.py
  • mpt_api_client/resources/billing/statement_attachments.py
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py
  • mpt_api_client/resources/catalog/product_term_variants.py
  • mpt_api_client/resources/catalog/products_documents.py
  • mpt_api_client/resources/catalog/products_media.py
  • mpt_api_client/resources/helpdesk/chat_attachments.py
  • mpt_api_client/resources/integration/extension_documents.py
  • mpt_api_client/resources/integration/extension_media.py
  • mpt_api_client/resources/integration/extension_term_variants.py
  • mpt_api_client/resources/program/enrollments_attachments.py
  • mpt_api_client/resources/program/programs_documents.py
  • mpt_api_client/resources/program/programs_media.py
  • mpt_api_client/resources/program/programs_terms_variant.py
  • tests/e2e/helpdesk/chats/attachment/test_async_attachment.py
  • tests/e2e/helpdesk/chats/attachment/test_sync_attachment.py
  • tests/unit/conftest.py
  • tests/unit/models/test_attachment_model.py
  • tests/unit/models/test_document_model.py
  • tests/unit/models/test_file_resource_model.py
  • tests/unit/models/test_media_model.py
  • tests/unit/models/test_term_variant_model.py
  • tests/unit/resources/billing/test_credit_memo_attachments.py
  • tests/unit/resources/billing/test_custom_ledger_attachments.py
  • tests/unit/resources/billing/test_invoice_attachments.py
  • tests/unit/resources/billing/test_journal_attachments.py
  • tests/unit/resources/billing/test_ledger_attachments.py
  • tests/unit/resources/billing/test_statement_attachments.py
  • tests/unit/resources/catalog/test_pricing_policy_attachments.py
  • tests/unit/resources/catalog/test_product_term_variants.py
  • tests/unit/resources/catalog/test_products_documents.py
  • tests/unit/resources/catalog/test_products_media.py
  • tests/unit/resources/integration/test_extension_documents.py
  • tests/unit/resources/integration/test_extension_media.py
  • tests/unit/resources/integration/test_extension_term_variants.py
  • tests/unit/resources/program/test_programs_documents.py
  • tests/unit/resources/program/test_programs_media.py
  • tests/unit/resources/program/test_programs_terms_variant.py
✅ Files skipped from review due to trivial changes (9)
  • mpt_api_client/models/attachment_model.py
  • mpt_api_client/models/media_model.py
  • mpt_api_client/resources/billing/credit_memo_attachments.py
  • mpt_api_client/resources/billing/statement_attachments.py
  • mpt_api_client/resources/billing/journal_attachments.py
  • mpt_api_client/resources/billing/invoice_attachments.py
  • mpt_api_client/resources/billing/custom_ledger_attachments.py
  • tests/unit/conftest.py
  • mpt_api_client/resources/billing/ledger_attachments.py
🚧 Files skipped from review as they are similar to previous changes (16)
  • tests/unit/resources/integration/test_extension_media.py
  • mpt_api_client/models/document_model.py
  • mpt_api_client/models/file_resource_model.py
  • tests/unit/resources/program/test_programs_documents.py
  • tests/unit/resources/program/test_programs_media.py
  • mpt_api_client/resources/program/enrollments_attachments.py
  • mpt_api_client/resources/catalog/pricing_policy_attachments.py
  • mpt_api_client/resources/integration/extension_documents.py
  • mpt_api_client/resources/program/programs_media.py
  • mpt_api_client/resources/helpdesk/chat_attachments.py
  • mpt_api_client/resources/catalog/products_documents.py
  • mpt_api_client/resources/integration/extension_media.py
  • mpt_api_client/resources/program/programs_terms_variant.py
  • tests/unit/resources/integration/test_extension_term_variants.py
  • tests/unit/resources/integration/test_extension_documents.py
  • mpt_api_client/models/term_variant_model.py

@robcsegal robcsegal merged commit 7b07dcd into main May 1, 2026
4 checks passed
@robcsegal robcsegal deleted the MPT-20684-update-models-and-base-models-to-reduce-code-duplication branch May 1, 2026 13:10
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.

2 participants