Skip to content

Conversation

@stabacco
Copy link
Owner

@stabacco stabacco commented Jul 28, 2025

Summary by Sourcery

Add ratings and statements endpoints to Product model, ensure Pydantic models receive client context, update default datetime handling, extend ratings validator, and include integration tests for product features

New Features:

  • Add async ratings() method on Product
  • Add async statements() method on Product

Bug Fixes:

  • Use timezone-aware datetime.now(UTC) for TransactionRecordRequest defaults

Enhancements:

  • Inject StakeClient into Product via PrivateAttr and model_post_init
  • Switch ProductsClient instantiation to Pydantic model_validate with context
  • Extend ratings field_validator to cover current rating fields

Tests:

  • Add integration test for Product.ratings() and Product.statements()

@sourcery-ai
Copy link

sourcery-ai bot commented Jul 28, 2025

Reviewer's Guide

This PR enriches the Product model with context-aware async methods by capturing the client in a private attribute, updates client methods to use pydantic’s model_validate with context, improves timezone handling in transaction requests, extends rating field validation, and adds an integration test for the new Product functionality.

Class diagram for updated Product model and ProductsClient

classDiagram
    class Product {
        +str symbol
        +str name
        +str description
        +str exchange
        +str currency
        +str isin
        +str type
        +str sector
        +str industry
        +str country
        +str logo_url
        +datetime inception_date
        +List instrument_tags
        +List child_instruments
        -StakeClient _client
        +model_post_init(context)
        +ratings() async
        +statements(start_date=None) async
    }
    class ProductsClient {
        +get(symbol) async Product|None
        +search(request) async List[Instrument]
        +product_from_instrument(instrument) async Product|None
    }
    Product <.. ProductsClient : used by
    ProductsClient o-- Product : returns
    Product o-- "1" StakeClient : _client
    Product o-- "*" Rating : ratings()
    Product o-- "*" Statement : statements()
Loading

Class diagram for updated TransactionRecordRequest

classDiagram
    class TransactionRecordRequest {
        +datetime to
        +datetime from_
        +int limit
        +datetime|None offset
    }
Loading

Class diagram for updated Rating field validation

classDiagram
    class Rating {
        +str|None pt_prior
        +str|None rating_prior
        +str|None pt_current
        +str|None rating_current
        +pt_prior_blank_string(value, *args) classmethod
    }
Loading

File-Level Changes

Change Details Files
Integrate client context into Product model and add async retrieval methods
  • Added TYPE_CHECKING imports and forward references for StakeClient, Rating, Statement
  • Introduced PrivateAttr _client and model_post_init to store client instance from context
  • Implemented async ratings() and statements() methods using the stored client to fetch data
  • Updated ProductsClient.get to use Product.model_validate with context and search to use Instrument.model_validate
stake/product.py
Add integration test for Product ratings() and statements()
  • Parameterized a new async test for fetching a Product by symbol
  • Asserted that ratings() returns a non-empty list
  • Asserted that statements() returns data for the past year by default
tests/test_integration.py
Switch transaction date defaults to timezone-aware now
  • Replaced datetime.utcnow default_factory with datetime.now(UTC) for 'to'
  • Updated 'from' default to use datetime.now(UTC) minus one year
stake/transaction.py
Extend Rating model validators to current fields
  • Added pt_current and rating_current to the field_validator decorator
  • Kept blank-string conversion logic consistent across prior and current fields
stake/ratings.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @stabacco - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `stake/product.py:65` </location>
<code_context>
+    _client: "StakeClient" = PrivateAttr()
     model_config = ConfigDict(alias_generator=camelcase)

+    def model_post_init(self, context: Any) -> None:
+        self._client = context.get("client")
+
+    async def ratings(self) -> "List[Rating]":
</code_context>

<issue_to_address>
No fallback if 'client' is missing from context in model_post_init.

Setting self._client to None may cause runtime errors if 'client' is missing. Raise an explicit error or provide a fallback to handle this case predictably.
</issue_to_address>

### Comment 2
<location> `stake/transaction.py:21` </location>
<code_context>


 class TransactionRecordRequest(BaseModel):
-    to: datetime = Field(default_factory=datetime.utcnow)
+    to: datetime = Field(default_factory=lambda *_: datetime.now(UTC))
     from_: datetime = Field(
-        default_factory=lambda *_: datetime.utcnow() - timedelta(days=365), alias="from"
</code_context>

<issue_to_address>
Switch to timezone-aware datetime is an improvement, but UTC must be defined.

Verify that 'UTC' is properly imported to avoid a NameError at runtime.
</issue_to_address>

### Comment 3
<location> `stake/transaction.py:23` </location>
<code_context>
-    to: datetime = Field(default_factory=datetime.utcnow)
+    to: datetime = Field(default_factory=lambda *_: datetime.now(UTC))
     from_: datetime = Field(
-        default_factory=lambda *_: datetime.utcnow() - timedelta(days=365), alias="from"
+        default_factory=lambda *_: datetime.now(UTC) - timedelta(days=365), alias="from"
     )
     limit: int = 1000
</code_context>

<issue_to_address>
Same UTC concern applies to from_ default_factory.

Ensure that UTC is properly defined and accessible in this context.
</issue_to_address>

### Comment 4
<location> `stake/ratings.py:39` </location>
<code_context>
     url_news: Optional[str] = None
     analyst_name: Optional[str] = None

-    @pydantic.field_validator("pt_prior", "rating_prior", mode="before")
+    @pydantic.field_validator("pt_prior", "rating_prior", "pt_current", "rating_current", mode="before")
     @classmethod
     def pt_prior_blank_string(cls, value, *args) -> Optional[str]:
</code_context>

<issue_to_address>
Validator now applies to more fields, but function name is misleading.

Consider renaming pt_prior_blank_string to better reflect that it now validates multiple fields.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

to: datetime = Field(default_factory=datetime.utcnow)
to: datetime = Field(default_factory=lambda *_: datetime.now(UTC))
from_: datetime = Field(
default_factory=lambda *_: datetime.utcnow() - timedelta(days=365), alias="from"
Copy link

Choose a reason for hiding this comment

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

issue (bug_risk): Same UTC concern applies to from_ default_factory.

Ensure that UTC is properly defined and accessible in this context.

@stabacco stabacco merged commit 941bb93 into master Jul 28, 2025
18 checks passed
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