Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update/pydantic v2 #410

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open

Update/pydantic v2 #410

wants to merge 29 commits into from

Conversation

gmorales96
Copy link

@gmorales96 gmorales96 commented Dec 22, 2024

Description:

This PR migrates the project to Pydantic v2 and drops support for Python 3.8

Key Changes:

  1. Updates cuenca-validations to version 2.0.0 which includes Pydantic v2 support
  2. Dropped Support for Python 3.8

Breaking Changes:

  • Code relying on Pydantic v1 API require updates to work with the new version.

Summary by CodeRabbit

Release Notes: Cuenca SDK v2.0.0.dev4

Overview

This release introduces additional updates to the Cuenca SDK, including further enhancements to Python version compatibility, additional dependency upgrades, and refined type handling.

Key Changes

  • Python Version Support

    • Updated Python version support from 3.8 to 3.9-3.13.
    • Minimum Python version requirement changed to 3.9.
  • Dependency Updates

    • Updated core dependencies, including requests and cuenca-validations.
    • Introduced new dependency pydantic-extra-types.
  • Type Handling

    • Enhanced type validation across resources, shifting from List to built-in list types.
    • Improved Pydantic model configurations with Field for better clarity and documentation.
    • Added default values and descriptions for several attributes.
  • Development Dependencies

    • Updated testing and development tool versions, including pytest, black, and others.
  • Bug Fixes

    • Fixed assertions in tests to improve type checking and error messaging.
    • Updated test cases to reflect changes in request and response structures.

Migration Recommendations

  • Upgrade to Python 3.9 or higher.
  • Review and update any custom type handling in your code.
  • Check compatibility with new dependency versions.

Copy link

coderabbitai bot commented Dec 22, 2024

Walkthrough

This pull request introduces a comprehensive update to the Cuenca Python library, focusing on modernizing the codebase and enhancing compatibility with newer Python versions. The changes span multiple areas, including GitHub Actions workflows, project configuration, and resource classes. The primary modifications involve updating Python version support from 3.8 to a range of versions including 3.9 through 3.13, transitioning to Pydantic v2 configuration patterns, and refining type handling across various resource classes. The update includes changes to dependency versions, workflow configurations, and numerous resource class implementations, emphasizing improved type safety, more explicit attribute initialization, and alignment with modern Python development practices.

Finishing Touches

  • 📝 Generate Docstrings

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Dec 22, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (b602497) to head (f81c8bf).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #410   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           49        49           
  Lines         1111      1104    -7     
=========================================
- Hits          1111      1104    -7     
Flag Coverage Δ
unittests 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cuenca/resources/api_keys.py 100.00% <100.00%> (ø)
cuenca/resources/arpc.py 100.00% <100.00%> (ø)
cuenca/resources/balance_entries.py 100.00% <100.00%> (ø)
cuenca/resources/base.py 100.00% <100.00%> (ø)
cuenca/resources/card_activations.py 100.00% <100.00%> (ø)
cuenca/resources/card_transactions.py 100.00% <100.00%> (ø)
cuenca/resources/card_validations.py 100.00% <100.00%> (ø)
cuenca/resources/cards.py 100.00% <100.00%> (ø)
cuenca/resources/curp_validations.py 100.00% <100.00%> (ø)
cuenca/resources/deposits.py 100.00% <100.00%> (ø)
... and 26 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b602497...f81c8bf. Read the comment docs.

@gmorales96 gmorales96 marked this pull request as ready for review January 6, 2025 19:50
@gmorales96 gmorales96 requested a review from alexviquez as a code owner January 6, 2025 19:50
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: 7

🔭 Outside diff range comments (4)
cuenca/resources/limited_wallets.py (1)

Line range hint 41-41: Update to Pydantic v2 model_dump()

Replace request.dict() with request.model_dump() to align with Pydantic v2 API changes.

-        return cast('LimitedWallet', cls._create(**request.dict()))
+        return cast('LimitedWallet', cls._create(**request.model_dump()))
cuenca/resources/kyc_validations.py (1)

Line range hint 41-42: Update dict() to model_dump() for Pydantic v2 compatibility.

The create method still uses the Pydantic v1 dict() method. This should be updated to model_dump() for v2 compatibility.

-            'KYCValidation', cls._create(**req.dict(), session=session)
+            'KYCValidation', cls._create(**req.model_dump(), session=session)
cuenca/resources/savings.py (1)

Line range hint 35-35: Update dict() calls to model_dump() for Pydantic v2 compatibility.

The dict() method is deprecated in Pydantic v2.

Apply these changes:

- return cast('Saving', cls._create(**request.dict()))
+ return cast('Saving', cls._create(**request.model_dump()))

- return cast('Saving', cls._update(id=saving_id, **request.dict()))
+ return cast('Saving', cls._update(id=saving_id, **request.model_dump()))

Also applies to: 49-49

cuenca/resources/files.py (1)

Line range hint 54-54: Migrate to model_dump().

The dict() method is deprecated in Pydantic v2. Update to use model_dump() instead.

Apply this diff:

-            **req.dict(),
+            **req.model_dump(),
🧹 Nitpick comments (8)
cuenca/resources/webhooks.py (1)

12-17: LGTM! Consider using computed default factory for payload.

The migration to Pydantic v2 style field declarations looks good. For better type safety and maintainability, consider using a computed default factory for the payload field to ensure a new dict instance for each model:

-    payload: Dict[str, Any] = Field(
-        ..., description='object sent by the webhook'
-    )
+    payload: Dict[str, Any] = Field(
+        default_factory=dict, description='object sent by the webhook'
+    )
cuenca/resources/deposits.py (1)

16-16: LGTM! Consider using Field for better documentation.

The explicit default of None improves clarity. Consider using Pydantic's Field to move the documentation from a comment to the field's metadata:

-    tracking_key: Optional[str] = None  # clave rastreo if network is SPEI
+    tracking_key: Optional[str] = Field(
+        default=None,
+        description='clave rastreo (tracking key) when network is SPEI'
+    )
cuenca/resources/user_events.py (1)

3-3: LGTM! Consider adding migration notes.

The changes correctly implement Pydantic v2 patterns by:

  • Using ConfigDict instead of inner Config class
  • Using json_schema_extra instead of schema_extra

Consider adding a comment or documentation note about the Pydantic v2 migration to help other developers understand the new patterns.

Also applies to: 14-26

cuenca/resources/file_batches.py (1)

3-7: LGTM! Consider improving type annotations.

The changes correctly implement Pydantic v2 patterns:

  • Using model_dump() instead of dict()
  • Enhanced type safety with explicit casting

Consider updating the method signature to use List[FileRequest] instead of List[Dict] to make the type requirements more explicit:

    @classmethod
    def create(
        cls,
-       files: List[Dict],
+       files: List[FileRequest],
        user_id: str,
        *,
        session: Session = global_session,
    ) -> 'FileBatch':
        req = FileBatchUploadRequest(
-           files=cast(List[FileRequest], files),
+           files=files,
            user_id=user_id
        )

Also applies to: 28-33

cuenca/resources/identities.py (1)

26-39: LGTM: Consistent default values for Optional fields

The addition of default None values for Optional fields aligns with Pydantic v2 best practices and improves code consistency.

Add Pydantic v2 model configuration

Consider adding the new Pydantic v2 model configuration:

class Identity(Retrievable, Queryable):
    _resource: ClassVar = 'identities'
    _query_params: ClassVar = IdentityQuery
+    model_config = ConfigDict(
+        populate_by_name=True,
+        validate_assignment=True
+    )
cuenca/resources/card_transactions.py (1)

30-30: LGTM: Default value for Optional field

Adding default None for error_type aligns with Pydantic v2 best practices.

Add Pydantic v2 model configuration

Consider adding the new Pydantic v2 model configuration:

class CardTransaction(Transaction):
+    model_config = ConfigDict(
+        populate_by_name=True,
+        validate_assignment=True
+    )
cuenca/resources/transfers.py (1)

94-94: Consider using a more robust idempotency key format

The current format using string concatenation with date and amount might not guarantee uniqueness in high-frequency scenarios.

Consider using a more robust format:

-        return f'{dt.datetime.utcnow().date()}: {account_number}: {amount}'
+        return f'{dt.datetime.utcnow().isoformat()}-{account_number}-{amount}'
.github/workflows/test.yml (1)

Line range hint 47-51: Update Codecov token handling.

Consider using GITHUB_TOKEN instead of a separate CODECOV_TOKEN for better security. Recent versions of Codecov support this approach.

          file: ./coverage.xml
          flags: unittests
          name: codecov-umbrella
-         token: ${{ secrets.CODECOV_TOKEN }}
+         token: ${{ secrets.GITHUB_TOKEN }}
          fail_ci_if_error: true
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b602497 and 3c0f14f.

📒 Files selected for processing (41)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/test.yml (3 hunks)
  • Makefile (1 hunks)
  • cuenca/resources/api_keys.py (3 hunks)
  • cuenca/resources/arpc.py (3 hunks)
  • cuenca/resources/balance_entries.py (2 hunks)
  • cuenca/resources/base.py (4 hunks)
  • cuenca/resources/card_activations.py (2 hunks)
  • cuenca/resources/card_transactions.py (2 hunks)
  • cuenca/resources/card_validations.py (3 hunks)
  • cuenca/resources/cards.py (1 hunks)
  • cuenca/resources/curp_validations.py (4 hunks)
  • cuenca/resources/deposits.py (1 hunks)
  • cuenca/resources/endpoints.py (2 hunks)
  • cuenca/resources/file_batches.py (2 hunks)
  • cuenca/resources/files.py (2 hunks)
  • cuenca/resources/identities.py (1 hunks)
  • cuenca/resources/kyc_validations.py (3 hunks)
  • cuenca/resources/kyc_verifications.py (4 hunks)
  • cuenca/resources/limited_wallets.py (1 hunks)
  • cuenca/resources/login_tokens.py (1 hunks)
  • cuenca/resources/otps.py (1 hunks)
  • cuenca/resources/platforms.py (4 hunks)
  • cuenca/resources/questionnaires.py (3 hunks)
  • cuenca/resources/resources.py (1 hunks)
  • cuenca/resources/savings.py (1 hunks)
  • cuenca/resources/sessions.py (3 hunks)
  • cuenca/resources/transfers.py (4 hunks)
  • cuenca/resources/user_events.py (3 hunks)
  • cuenca/resources/user_lists_validation.py (2 hunks)
  • cuenca/resources/user_logins.py (2 hunks)
  • cuenca/resources/users.py (7 hunks)
  • cuenca/resources/verifications.py (4 hunks)
  • cuenca/resources/webhooks.py (1 hunks)
  • cuenca/resources/whatsapp_transfers.py (1 hunks)
  • cuenca/version.py (1 hunks)
  • requirements-test.txt (1 hunks)
  • requirements.txt (1 hunks)
  • setup.py (1 hunks)
  • tests/resources/test_endpoints.py (1 hunks)
  • tests/resources/test_transfers.py (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • cuenca/version.py
🧰 Additional context used
🪛 Ruff (0.8.2)
cuenca/resources/sessions.py

50-50: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


51-51: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (57)
cuenca/resources/questionnaires.py (4)

5-5: LGTM! Correct import for Pydantic v2 configuration

The import of ConfigDict is appropriate for the migration to Pydantic v2.


43-43: LGTM! Correct usage of model_dump() for Pydantic v2

The change from dict() to model_dump() aligns with Pydantic v2's API changes.


18-26: Verify schema example completeness

While the migration to model_config and json_schema_extra is correct for Pydantic v2, the example schema is missing the form_id field that's required in the create method.

Add the missing field to the example:

     model_config = ConfigDict(
         json_schema_extra={
             'example': {
                 'user_id': 'US234i23jh23h4h23',
                 'token': '3223j23ij23ij3',
+                'form_id': 'FMewifjwiejf',
-                'alert_id': 'ALewifjwiejf',  # This seems to be an incorrect field
             }
         }
     )
✅ Verification successful

Schema example needs update as suggested

The review comment is correct. The form_id field is required in the class and create method, while alert_id is not used anywhere in the codebase. The suggested changes to add form_id and remove alert_id from the example schema are appropriate.

🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Find the complete class definition and its fields
ast-grep --pattern 'class $_ {
  $$$
  model_config = ConfigDict(
    $$$
  )
  $$$
}'

# Search for create method and its parameters
ast-grep --pattern 'async def create(
  $$$
)'

# Look for usage patterns of form_id and alert_id
rg "form_id|alert_id" -A 2 -B 2

Length of output: 38822


Line range hint 10-10: Verify parent classes compatibility with Pydantic v2

Since this class inherits from Creatable and Retrievable, we should ensure these base classes are also updated for Pydantic v2 compatibility.

✅ Verification successful

Base classes are compatible with Pydantic v2

The parent classes (Creatable and Retrievable) inherit from Resource, which uses a minimal Pydantic implementation that's compatible with both v1 and v2. No version-specific patterns were found that would require migration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if base classes have been migrated to Pydantic v2 patterns
echo "Checking base classes for Pydantic v2 compatibility..."

# Look for old Config class pattern in base classes
rg -l "class Config:" "cuenca/resources/base.py"

# Look for new model_config pattern in base classes
rg -l "model_config = ConfigDict" "cuenca/resources/base.py"

Length of output: 228


Script:

#!/bin/bash
# First, find where Creatable and Retrievable are defined
echo "Searching for base class definitions..."
ast-grep --pattern 'class Creatable' 
ast-grep --pattern 'class Retrievable'

# Also search for imports to find the correct file
echo -e "\nSearching for import statements..."
rg "from.*import.*(Creatable|Retrievable)" -g '*.py'

Length of output: 2681


Script:

#!/bin/bash
echo "Checking base.py for Pydantic patterns..."

# Check imports
echo "Checking imports..."
rg "from pydantic" cuenca/resources/base.py

# Check class implementations
echo -e "\nChecking class implementations..."
rg "class (Creatable|Retrievable)" -A 10 cuenca/resources/base.py

# Look for any Config classes or model_config
echo -e "\nChecking Pydantic configuration..."
rg "class Config|model_config" cuenca/resources/base.py

Length of output: 1180


Script:

#!/bin/bash
# Check Resource class implementation
echo "Checking Resource class implementation..."
ast-grep --pattern 'class Resource'

# Also check for any Resource class references with grep for context
echo -e "\nChecking Resource class with context..."
rg "class Resource" -A 15 cuenca/resources/base.py

Length of output: 761

cuenca/resources/otps.py (1)

12-19: LGTM! Pydantic v2 model configuration properly implemented.

The migration from Config class to model_config using ConfigDict and the rename of schema_extra to json_schema_extra follows Pydantic v2's best practices.

cuenca/resources/login_tokens.py (2)

11-13: LGTM! Pydantic v2 model configuration properly implemented.

The migration from Config class to model_config using ConfigDict and the rename of schema_extra to json_schema_extra follows Pydantic v2's best practices.


1-1: Verify removal of Python 3.8 specific code.

Let's ensure there are no remaining Python 3.8 specific code patterns or version checks:

✅ Verification successful

No Python 3.8 specific code found in the codebase

All checks for Python 3.8 specific features (version checks, walrus operator, positional-only parameters, and f-string = specifier) came back negative. The f-string usages found in jwt.py are standard string formatting available since Python 3.6.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for Python 3.8 specific code patterns

# Check for Python version checks
echo "Checking for Python version checks..."
rg -l "python_version.*3\.8|python_requires.*3\.8|pyversion.*3\.8" .

# Check for Python 3.8 specific syntax in setup files
echo "Checking setup files for Python 3.8 references..."
rg -l "3\.8" setup.* pyproject.* tox.ini

# Check for Python 3.8 in CI configurations
echo "Checking CI configurations..."
rg -l "3\.8" .github/workflows/*

Length of output: 623


Script:

#!/bin/bash
# Check for Python 3.8 specific syntax patterns

# Check for walrus operator (:=)
echo "Checking for walrus operator usage..."
rg -l ":=" --type py .

# Check for positional-only parameters (function definitions with /)
echo "Checking for positional-only parameters..."
ast-grep --pattern 'def $_($_ / $_)'

# Check for f-string = specifier
echo "Checking for f-string = specifier..."
rg -l "f[\"'].*=.*[\"']" --type py .

Length of output: 383


Script:

#!/bin/bash
# Examine f-string usage in jwt.py
echo "Checking f-string usage context in jwt.py..."
rg "f[\"'].*=.*[\"']" -A 2 -B 2 ./cuenca/jwt.py

Length of output: 418

cuenca/resources/whatsapp_transfers.py (1)

17-17: LGTM! Good improvement in type clarity.

The changes improve code clarity by explicitly initializing optional fields with None. This aligns well with Python type hinting best practices.

Also applies to: 20-22

cuenca/resources/resources.py (1)

19-26: LGTM! Consider monitoring performance impact.

The change from concurrent to sequential processing is well-justified:

  • Fixes VCR test reliability issues
  • Small URI lists minimize performance impact

Consider monitoring the performance impact in production, especially if the URI list sizes grow. You might want to add metrics for:

  • Average URI list size
  • Processing time for retrieve_uris calls
cuenca/resources/limited_wallets.py (1)

24-26: ⚠️ Potential issue

Breaking Change: allowed_curp is now required

The create method signature has changed to make allowed_curp mandatory. This is a breaking change that will affect existing code that doesn't provide this parameter.

Let's verify the impact:

cuenca/resources/balance_entries.py (1)

11-11: LGTM: Improved type safety with Union

The change from TypeVar to Union provides better type safety and is more explicit about the allowed types. This change is compatible with Python 3.9+.

setup.py (2)

31-35: LGTM! Python version updates align with PR objectives.

The classifiers correctly reflect the dropped support for Python 3.8 and addition of support through Python 3.13.


24-24: Verify the use of pre-release dependency.

The dependency on cuenca-validations==2.0.0.dev9 is a pre-release version. This could introduce instability in production. Consider:

  1. Using a stable release if available
  2. Adding a comment explaining why a pre-release version is necessary
  3. Planning for an update when the stable version is released

Also applies to: 26-28

✅ Verification successful

Pre-release dependency update is acceptable

The change from cuenca-validations==2.0.0.dev8 to dev9 is an incremental update within the same pre-release series that's already in use. This maintains the existing development track without introducing additional risk.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if a stable version exists
curl -s https://pypi.org/pypi/cuenca-validations/json | jq -r '.releases | keys[]' | sort -V | tail -n 5

Length of output: 161


Script:

#!/bin/bash
# Check current requirements and any migration notes
echo "Previous version in requirements:"
rg "cuenca-validations" -B1 -A1 --no-filename

echo -e "\nChecking for migration/upgrade notes:"
fd "CHANGELOG|UPGRADING|MIGRATION" --type f
cat $(fd "CHANGELOG|UPGRADING|MIGRATION" --type f) 2>/dev/null || true

Length of output: 786

cuenca/resources/card_activations.py (2)

18-18: LGTM! Explicit None default follows Pydantic v2 best practices.

The addition of = None makes the optional nature of the field more explicit.


46-46: LGTM! Correct migration to Pydantic v2 API.

The change from req.dict() to req.model_dump() correctly follows Pydantic v2 migration guidelines.

cuenca/resources/kyc_validations.py (2)

13-15: LGTM! Explicit None defaults enhance clarity.

The addition of = None to optional fields improves code clarity and follows Pydantic v2 best practices.


Line range hint 16-27: LGTM! Correct migration to Pydantic v2 configuration.

The change from Config class to model_config = ConfigDict(...) follows Pydantic v2 migration guidelines.

cuenca/resources/user_lists_validation.py (2)

42-42: LGTM! Correct migration to Pydantic v2 API.

The change from req.dict() to req.model_dump() correctly follows Pydantic v2 migration guidelines.


38-38: Verify type compatibility between Clabe and Optional[str].

The account_number is defined as Optional[str] but cast to Clabe. Ensure that:

  1. The Clabe type is compatible with the field definition
  2. The cast handles None values correctly
✅ Verification successful

Type casting to Clabe is safe and compatible

The cast is safe because:

  • Clabe is a Pydantic model with underlying str field
  • Optional values are properly handled through Pydantic
  • Similar pattern is used elsewhere in the codebase (users.py)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check Clabe type definition and str compatibility
rg -A 5 "class Clabe" || ast-grep --pattern 'class Clabe { $$$ }'

Length of output: 318


Script:

#!/bin/bash
# Check Clabe initialization and parent classes
ast-grep --pattern 'def __init__($$$) { $$$ }' cuenca/resources/clabes.py

# Check for Optional[Clabe] usage patterns
rg "Optional\[Clabe\]"

# Check parent class definitions
rg -A 3 "class (Creatable|Queryable|Retrievable)"

Length of output: 912


Script:

#!/bin/bash
# Check Resource class definition and type handling
rg -A 10 "class Resource" cuenca/resources/base.py

# Check if there's any type conversion in Resource
ast-grep --pattern 'class Resource {
  $$$
  def __init__($$$) {
    $$$
  }
  $$$
}'

Length of output: 385

cuenca/resources/user_logins.py (1)

5-5: LGTM! Required import for Pydantic v2.

The explicit import of ConfigDict from pydantic is correct for v2 compatibility.

cuenca/resources/savings.py (1)

20-21: LGTM! Improved type safety with explicit defaults.

The addition of default None values for optional fields improves type safety and clarity.

tests/resources/test_endpoints.py (1)

46-46: Verify URL normalization behavior change.

The assertion now expects a trailing slash. This might be related to Pydantic v2's URL handling changes.

Run this script to check URL handling across the codebase:

✅ Verification successful

URL assertion change is isolated and aligned with Pydantic's URL handling

The trailing slash assertion is the only URL assertion in the test suite, and the codebase consistently uses Pydantic's URL validation types (HttpUrl, HttpUrlString, AnyUrlString) which handle URL normalization. This change appears to be correctly adapting to Pydantic's URL handling behavior.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for URL assertions and URL field usage
rg -l 'assert.*url.*=.*["\']https?://' | while read -r file; do
  echo "=== $file ==="
  rg 'assert.*url.*=.*["\']https?://' "$file"
done

# Check URL field definitions
ast-grep --pattern 'url: HttpUrlString'

Length of output: 116


Script:

#!/bin/bash
# Search for URL assertions in test files
echo "=== URL Assertions ==="
rg "assert.*url.*=.*'https?://" || rg 'assert.*url.*="https?://'

# Search for URL-related field definitions
echo -e "\n=== URL Field Definitions ==="
rg "url.*=.*Field|url:.*str|url:.*Url"

# Check for Pydantic models and configs
echo -e "\n=== Pydantic Models ==="
rg "class.*\(.*BaseModel.*\)" -A 5

Length of output: 1323

cuenca/resources/kyc_verifications.py (3)

10-10: LGTM! Updated to Pydantic v2 configuration style.

The model configuration has been correctly updated to use Pydantic v2's ConfigDict.

Also applies to: 26-39


21-22: LGTM! Improved type safety with explicit defaults.

Adding default None values for optional fields improves type safety and clarity.


49-49: ⚠️ Potential issue

Breaking change: curp parameter is now required.

The curp parameter in the update method is no longer optional. This is a breaking change that needs to be documented.

Run this script to check for existing usage:

Also, update the dict() call to use model_dump():

- return cast('KYCVerification', cls._update(id=kyc_id, **req.dict()))
+ return cast('KYCVerification', cls._update(id=kyc_id, **req.model_dump()))

Also applies to: 52-52

✅ Verification successful

Breaking change is safe to proceed, but needs documentation

The only existing usage of KYCVerification.update() already provides the curp parameter, making this a safe change. However:

  • Document this breaking change in the changelog
  • Update the method's docstring to clearly indicate that curp is required
  • Consider implementing the suggested Pydantic v2 migration (dict()model_dump())
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for KYCVerification.update calls
rg -A 3 'KYCVerification\.update.*\(' | grep -v 'def update'

Length of output: 396


Script:

#!/bin/bash
# Check the update method implementation and test file content
echo "=== KYCVerification update method ==="
ast-grep --pattern 'def update($$$) { $$$ }' cuenca/resources/kyc_verifications.py

echo -e "\n=== Test file content ==="
cat tests/resources/test_kyc_verifications.py

echo -e "\n=== Checking for indirect usages ==="
rg -l "KYCVerification" | xargs rg "update"

Length of output: 1495

cuenca/resources/arpc.py (2)

27-28: LGTM! Explicit initialization of optional fields.

The explicit None defaults for optional fields align with Pydantic v2's improved schema clarity.


54-54: Verify type casting and model serialization changes.

The changes align with Pydantic v2 migration:

  1. Using model_dump() instead of dict() follows v2 recommendations
  2. Explicit type casting of track_data_method enhances type safety

Let's verify other usages of the deprecated dict() method:

Also applies to: 56-56

✅ Verification successful

Type casting and serialization changes are consistent with codebase patterns

The changes in arpc.py align with:

  • Ongoing Pydantic v2 migration (both dict() and model_dump() methods are present across the codebase)
  • Established type casting patterns used throughout the repository for type safety
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for remaining dict() calls that might need migration
rg --type python 'req\.dict\(' .

Length of output: 65


Script:

#!/bin/bash
# Search for dict() method calls in Python files
rg '\.dict\(' --glob '*.py'

# Search for model_dump() usage
rg '\.model_dump\(' --glob '*.py'

# Search for similar type casting patterns
rg 'cast\([^,]+,' --glob '*.py'

Length of output: 7825

cuenca/resources/verifications.py (3)

19-21: LGTM! Enhanced field documentation.

Good use of Pydantic's Field with description to improve API documentation.


25-34: LGTM! Updated to Pydantic v2 configuration pattern.

Correctly migrated from Config class to model_config using ConfigDict, following Pydantic v2 patterns.


48-50: LGTM! Updated serialization method.

Properly migrated from dict() to model_dump() following Pydantic v2 recommendations.

Also applies to: 62-62

cuenca/resources/files.py (2)

4-9: LGTM! Improved type imports.

Good organization of imports from cuenca_validations.types.


48-48: LGTM! Enhanced type safety.

Good use of explicit type casting for the extension parameter.

cuenca/resources/card_validations.py (3)

21-25: LGTM! Explicit initialization of optional fields.

Good practice to explicitly set None defaults for optional boolean fields.


55-55: LGTM! Updated serialization method.

Properly migrated from dict() to model_dump() following Pydantic v2 recommendations.


40-40: Verify the type change impact.

The type change from Optional[str] to Optional[bool] for pin_attempts_exceeded is a breaking change.

Let's verify the impact:

cuenca/resources/sessions.py (2)

10-16: Well-documented URL field compatibility solution!

Great job documenting the rationale for using AnyUrlString. The comment clearly explains the compatibility issue with Pydantic v2's URL fields and the solution.


27-29: LGTM: Field type updates

The transition from AnyUrl to AnyUrlString for URL fields is correctly implemented, maintaining string compatibility while ensuring URL validation.

cuenca/resources/api_keys.py (1)

Line range hint 16-29: LGTM: Clean Pydantic v2 migration

Good updates:

  • Added explicit None defaults to optional fields
  • Correctly implemented model_config using ConfigDict
cuenca/resources/platforms.py (2)

15-34: Excellent field documentation!

Great job adding descriptive Field annotations. This significantly improves API documentation and code clarity.


76-78: LGTM: Pydantic v2 method updates

Correct usage of model_dump() instead of dict(), which is the recommended approach in Pydantic v2.

cuenca/resources/transfers.py (2)

29-29: LGTM: Explicit optional field initialization

Good practice adding explicit None default to the optional tracking_key field.


66-66: LGTM: Enhanced type safety

Good use of cast(Clabe, account_number) to ensure type safety when creating the transfer request.

cuenca/resources/cards.py (1)

24-24: LGTM! Clear optional field definitions.

The changes make the optional nature of user_id and pin fields more explicit by adding default values, which aligns well with Pydantic v2's best practices.

Also applies to: 29-29

cuenca/resources/endpoints.py (3)

13-19: Well-documented URL field type compatibility fix.

The introduction of HttpUrlString type alias effectively addresses the compatibility issue with Pydantic v2's URL handling while maintaining type safety. The comments clearly explain the rationale.


25-40: Enhanced field definitions with clear descriptions.

The Field definitions now include comprehensive descriptions, improving the API documentation. This is a good practice that makes the code more maintainable.


Line range hint 41-60: Updated model configuration to Pydantic v2 style.

The transition from Config class to model_config with ConfigDict aligns with Pydantic v2's new configuration pattern.

cuenca/resources/curp_validations.py (3)

21-55: Comprehensive field definitions with clear descriptions.

All fields have been updated with proper descriptions using Pydantic's Field, which significantly improves the API documentation and schema generation.


Line range hint 56-76: Updated model configuration to Pydantic v2 style.

The transition from Config class to model_config with ConfigDict follows Pydantic v2's best practices.


98-104: Updated to use model_dump() instead of dict().

The change from req.dict() to req.model_dump() is essential for Pydantic v2 compatibility as dict() is deprecated.

tests/resources/test_transfers.py (1)

132-132: Updated test assertion for Pydantic v2 error message.

The error message assertion has been correctly updated to match Pydantic v2's new validation error format.

cuenca/resources/base.py (2)

27-27: Type annotation broadened for better flexibility

The change from Dict[str, Union[str, int]] to Dict[str, Any] provides better flexibility for handling various field types. This is a good change as it reduces potential type conflicts while maintaining type safety through Pydantic's validation.


82-82: Good practice: Explicit initialization of optional field

Adding = None default value to deactivated_at makes the optional nature of the field explicit and follows Pydantic's best practices.

cuenca/resources/users.py (3)

33-38: Enhanced field documentation with descriptive metadata

Good addition of field descriptions using Field. This improves API documentation and code maintainability.


Line range hint 77-101: Updated to Pydantic v2's model configuration

The change from Config class to model_config with ConfigDict aligns with Pydantic v2's new configuration pattern. The example schema is well-documented.


133-133: Updated to use model_dump() instead of dict()

Consistent update to use model_dump() instead of dict() in both create and update methods, aligning with Pydantic v2's API.

Also applies to: 174-174

requirements-test.txt (1)

1-12: Test dependencies properly updated

All test dependencies have been updated to stable versions that support Python 3.9+. This is appropriate given the decision to drop Python 3.8 support.

.github/workflows/test.yml (1)

23-23: Verify Pydantic v2 compatibility with all Python versions.

The test matrix has been updated to include Python versions 3.9 through 3.13. Since this PR migrates to Pydantic v2, ensure that all these Python versions are supported by Pydantic v2 and its dependencies.

✅ Verification successful

Python versions in test matrix are compatible with Pydantic v2

The test matrix (Python 3.9-3.13) aligns with both the project's Python requirement (>=3.9) and Pydantic v2's supported versions (3.7+). All specified versions are supported.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Pydantic v2's Python version compatibility
# and verify dependencies in requirements.txt

# Check if requirements.txt exists and contains Pydantic
if [ -f "requirements.txt" ]; then
  echo "Checking Pydantic version in requirements.txt:"
  grep -i "pydantic" requirements.txt
fi

# Check if setup.py exists and contains Pydantic
if [ -f "setup.py" ]; then
  echo "Checking Pydantic version in setup.py:"
  grep -i "pydantic" setup.py
fi

# Check for any Python version constraints in project files
echo "Checking Python version constraints in project files:"
rg "python_requires|python_version" setup.py pyproject.toml

Length of output: 646


Script:

#!/bin/bash
# Search for Pydantic core package in all dependency files
echo "Searching for Pydantic core package:"
fd -e txt -e toml -e cfg -e ini -e yaml -e yml | xargs grep -i "pydantic[^-]" 2>/dev/null || true

# Check for any additional requirements files
echo -e "\nChecking for additional requirements files:"
fd "requirements" -e txt -e in

Length of output: 342


Script:

#!/bin/bash
# Check test requirements file
echo "Checking requirements-test.txt for Pydantic:"
cat requirements-test.txt | grep -i "pydantic"

# Look for any Python version constraints
echo -e "\nChecking for Python version constraints:"
cat requirements-test.txt | grep -i "python"

Length of output: 287

cuenca/resources/card_transactions.py Outdated Show resolved Hide resolved
cuenca/resources/user_logins.py Show resolved Hide resolved
cuenca/resources/sessions.py Outdated Show resolved Hide resolved
cuenca/resources/base.py Show resolved Hide resolved
requirements.txt Outdated
Comment on lines 1 to 3
requests==2.32.3
cuenca-validations==2.0.0.dev8
pydantic-extra-types==2.10.*
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Revert to stable version of cuenca-validations

The current development version (2.0.0.dev8) is a major version ahead of the latest stable release (0.11.33). Using development versions in production dependencies can lead to instability. Consider:

  • Using the latest stable version: cuenca-validations==0.11.33
  • Or waiting for the stable 2.0.0 release if new features are required
🔗 Analysis chain

Verify stability of development dependency

While the dependency updates are good, using cuenca-validations==2.0.0.dev8 in production could be risky. Consider waiting for a stable release.

Let's check the latest stable version:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check latest stable version of cuenca-validations
curl -s https://pypi.org/pypi/cuenca-validations/json | jq -r '.releases | keys[]' | grep -v "dev" | sort -V | tail -n 1

Length of output: 128

.github/workflows/release.yml Outdated Show resolved Hide resolved
Makefile Show resolved Hide resolved
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 (1)
cuenca/resources/sessions.py (1)

42-43: ⚠️ Potential issue

Fix cast() usage in method parameters

Using cast() in method parameter defaults is discouraged as it's executed at function definition time. This could lead to unexpected behavior.

Apply this diff to fix the issue:

    @classmethod
    def create(
        cls,
        user_id: str,
        type: SessionType,
-       success_url=cast(Optional[AnyUrl], success_url),
-       failure_url=cast(Optional[AnyUrl], failure_url),
+       success_url: Optional[AnyUrl] = None,
+       failure_url: Optional[AnyUrl] = None,
        *,
        session: http.Session = http.session,
    ) -> 'Session':
🧰 Tools
🪛 Ruff (0.8.2)

42-42: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


43-43: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🧹 Nitpick comments (5)
tests/resources/test_sessions.py (2)

10-10: Consider using typing.Dict for better type safety with Pydantic.

While Python 3.9+ allows using built-in types as type hints, Pydantic v2 recommends using typing.Dict for better type safety and explicit key/value types. Consider updating to:

- def test_session_create(curp_validation_request: dict, user_request: dict):
+ def test_session_create(curp_validation_request: Dict[str, Any], user_request: Dict[str, Any]):

Line range hint 10-41: Consider adding Pydantic v2 specific test cases.

Since this PR migrates to Pydantic v2, consider adding test cases for new v2 features like:

  • Strict type validation
  • Custom serializers
  • New model config options
tests/conftest.py (2)

33-33: Consider using typing.Dict consistently across fixtures.

For consistency with Pydantic v2 and better type safety, consider using explicit typing.Dict with key/value types:

- def curp_validation_request() -> dict:
+ def curp_validation_request() -> Dict[str, Union[str, dt.date, State, Country, Gender]]:

- def user_request() -> dict:
+ def user_request() -> Dict[str, Union[str, Dict[str, Union[str, State, Country]]]]:

- def user_lists_request() -> dict:
+ def user_lists_request() -> Dict[str, str]:

Also applies to: 47-47, 66-66


Line range hint 33-74: Consider using Pydantic models for test data.

Since the project uses Pydantic, consider defining test data using Pydantic models instead of raw dictionaries. This would:

  • Ensure type safety at the model level
  • Validate test data structure
  • Make test data intentions clearer
  • Leverage Pydantic v2's improved performance

Example:

from pydantic import BaseModel

class CurpValidationRequest(BaseModel):
    names: str
    first_surname: str
    second_surname: str
    date_of_birth: dt.date
    state_of_birth: State
    country_of_birth: Country
    gender: Gender

@pytest.fixture
def curp_validation_request() -> Dict[str, Any]:
    return CurpValidationRequest(
        names='José',
        first_surname='López',
        # ... other fields ...
    ).model_dump()
cuenca/resources/user_credentials.py (1)

29-29: Correct migration to Pydantic v2 with proper type safety!

The changes from dict() to model_dump() are correctly implemented while maintaining type safety through proper casting.

Consider using TypeAlias for the repeated cast type to improve maintainability:

+from typing import TypeAlias
+
+UserCredentialType: TypeAlias = 'UserCredential'
+
 class UserCredential(Creatable, Updateable):
     # ...
     @classmethod
     def create(
         # ...
     ) -> 'UserCredential':
         req = UserCredentialRequest(password=password, user_id=user_id)
-        return cast('UserCredential', cls._create(**req.model_dump(), session=session))
+        return cast(UserCredentialType, cls._create(**req.model_dump(), session=session))

Also applies to: 47-47

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c0f14f and 2c6ce31.

📒 Files selected for processing (31)
  • .github/workflows/release.yml (1 hunks)
  • .github/workflows/test.yml (3 hunks)
  • cuenca/resources/api_keys.py (4 hunks)
  • cuenca/resources/base.py (8 hunks)
  • cuenca/resources/card_activations.py (3 hunks)
  • cuenca/resources/card_transactions.py (2 hunks)
  • cuenca/resources/cards.py (3 hunks)
  • cuenca/resources/endpoints.py (5 hunks)
  • cuenca/resources/file_batches.py (2 hunks)
  • cuenca/resources/files.py (2 hunks)
  • cuenca/resources/kyc_validations.py (4 hunks)
  • cuenca/resources/kyc_verifications.py (4 hunks)
  • cuenca/resources/limited_wallets.py (2 hunks)
  • cuenca/resources/resources.py (2 hunks)
  • cuenca/resources/savings.py (3 hunks)
  • cuenca/resources/service_providers.py (2 hunks)
  • cuenca/resources/sessions.py (4 hunks)
  • cuenca/resources/transfers.py (4 hunks)
  • cuenca/resources/user_credentials.py (2 hunks)
  • cuenca/resources/user_logins.py (3 hunks)
  • cuenca/resources/users.py (9 hunks)
  • cuenca/resources/wallet_transactions.py (1 hunks)
  • cuenca/resources/webhooks.py (1 hunks)
  • requirements-test.txt (1 hunks)
  • requirements.txt (1 hunks)
  • tests/conftest.py (3 hunks)
  • tests/resources/cassettes/test_card_activation.yaml (1 hunks)
  • tests/resources/test_card_activations.py (1 hunks)
  • tests/resources/test_commissions.py (2 hunks)
  • tests/resources/test_otps.py (1 hunks)
  • tests/resources/test_sessions.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (15)
  • cuenca/resources/webhooks.py
  • .github/workflows/release.yml
  • cuenca/resources/files.py
  • cuenca/resources/cards.py
  • requirements.txt
  • cuenca/resources/kyc_validations.py
  • cuenca/resources/card_transactions.py
  • cuenca/resources/api_keys.py
  • cuenca/resources/savings.py
  • cuenca/resources/kyc_verifications.py
  • cuenca/resources/transfers.py
  • cuenca/resources/file_batches.py
  • cuenca/resources/user_logins.py
  • cuenca/resources/users.py
  • cuenca/resources/base.py
🧰 Additional context used
🪛 GitHub Actions: test
requirements-test.txt

[error] 11-12: Dependency conflict detected between packages on lines 11 and 12. Resolution is impossible with the current package versions.

🪛 Ruff (0.8.2)
cuenca/resources/sessions.py

42-42: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


43-43: Do not perform function call cast in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🔇 Additional comments (24)
cuenca/resources/limited_wallets.py (3)

40-40: LGTM! Correct usage of Pydantic v2 API.

The change from dict() to model_dump() correctly implements Pydantic v2's serialization API.


18-18: LGTM! Note the breaking change.

The default value addition aligns with Pydantic v2's best practices for optional fields. However, this is a breaking change that might affect existing code initializing LimitedWallet instances.

Let's verify the impact on existing initializations:

✅ Verification successful

Breaking change verified - no impact on existing code

The addition of None as default value for allowed_rfc is safe. The only usage found in the codebase explicitly sets this parameter during creation, and no instances were found where the parameter is omitted.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for LimitedWallet instantiations that might be affected
rg -A 3 "LimitedWallet\(" --type py

Length of output: 323


Script:

#!/bin/bash
# Search for imports of LimitedWallet
rg "from cuenca.resources.limited_wallets import LimitedWallet|from cuenca.resources import LimitedWallet" --type py

# Search for LimitedWallet in test files
rg "LimitedWallet" tests/ --type py || echo "No tests directory found"

Length of output: 417


24-25: LGTM! Note the breaking change in method signature.

Making allowed_curp mandatory improves type safety and aligns with the business requirement that a limited wallet must be tied to a specific person's CURP. However, this is a breaking change that will require updates to existing code calling this method.

Let's verify the impact on existing method calls:

✅ Verification successful

Breaking change verification completed - minimal impact

The mandatory allowed_curp parameter in LimitedWallet.create() has minimal impact on the codebase:

  • The only direct usage in tests already provides the required parameter
  • No other calls to this method found in the codebase
  • No classes inherit from or compose with LimitedWallet
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for create method calls that might be affected
rg -A 3 "LimitedWallet\.create\(" --type py

Length of output: 378


Script:

#!/bin/bash
# Check for classes inheriting from LimitedWallet
ast-grep --pattern 'class $_ (LimitedWallet)'

# Check for any other references to LimitedWallet
rg "LimitedWallet" --type py -C 2

Length of output: 3655

cuenca/resources/service_providers.py (2)

13-13: LGTM! Type annotation change aligns with modern Python.

The change from List to list type annotation is appropriate for Python 3.9+ and aligns well with Pydantic v2's preferences for built-in types.


Line range hint 1-14: Verify Pydantic v2 compatibility of dependencies

Please ensure that the imported components are compatible with Pydantic v2:

  1. The cuenca_validations.types.ServiceProviderCategory
  2. The base classes Retrievable and Queryable

Let's verify the compatibility:

✅ Verification successful

Dependencies are Pydantic v2 compatible

The codebase shows clear signs of Pydantic v2 adoption:

  • cuenca-validations is at version 2.0.0.dev9
  • Base classes use modern Pydantic patterns with ConfigDict
  • Dependencies include Pydantic v2 compatible packages
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for Pydantic v2 compatibility in related files

# Check ServiceProviderCategory implementation
echo "Checking ServiceProviderCategory implementation:"
rg -A 5 "class ServiceProviderCategory" 

# Check base classes for Pydantic v2 patterns
echo "Checking base classes for Pydantic v2 patterns:"
rg -A 10 "class (Retrievable|Queryable)" 

# Look for Pydantic imports and usage
echo "Checking Pydantic usage:"
rg "from pydantic" 

Length of output: 3076


Script:

#!/bin/bash
# Check Resource class implementation
echo "Checking Resource class implementation:"
ast-grep --pattern 'class Resource($_) { $$$ }'

# Check for ServiceProviderCategory usage
echo "Checking ServiceProviderCategory usage:"
rg -A 5 "ServiceProviderCategory"

# Check package dependencies
echo "Checking package dependencies:"
cat pyproject.toml 2>/dev/null || cat setup.py 2>/dev/null || echo "No dependency file found"

Length of output: 2618

tests/conftest.py (1)

Line range hint 1-41: Verify Pydantic v2 compatibility in test files.

Let's check for any Pydantic v1 specific features that need updates:

✅ Verification successful

No Pydantic v2 migration changes needed in test files

The test files, including conftest.py, only use type imports from cuenca_validations and don't contain any Pydantic v1-specific features that would need updates for v2 compatibility.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for Pydantic v1 specific features that might need updates

# Check for deprecated v1 features
echo "Checking for deprecated Pydantic v1 features..."
rg -l 'validator|root_validator|Config|@validator|@root_validator|parse_obj|parse_raw|parse_file|json|schema|construct|validate_model' tests/

# Check for model configurations
echo "Checking for model configurations that might need updates..."
rg -l 'class Config:|from_orm|orm_mode|allow_mutation|allow_population_by_field_name' tests/

# Check for type annotations that might need updates
echo "Checking type annotations..."
rg -l 'from typing import.*Dict|from typing import.*Optional|from typing import.*List|from typing import.*Union' tests/

Length of output: 7427


Script:

#!/bin/bash
# Check actual Pydantic usage in test files
echo "Checking validator usage..."
rg -C 3 '@validator|@root_validator|validator\(' 'tests/test_cuenca.py' 'tests/resources/test_endpoints.py' 'tests/resources/test_verifications.py' 'tests/resources/test_user_lists_validation.py' 'tests/resources/test_cards.py'

echo -e "\nChecking model configurations..."
rg -C 3 'class Config:|from_orm|orm_mode' 'tests/test_cuenca.py' 'tests/resources/test_endpoints.py' 'tests/resources/test_verifications.py' 'tests/resources/test_user_lists_validation.py' 'tests/resources/test_cards.py'

echo -e "\nChecking parse methods..."
rg -C 3 'parse_obj|parse_raw|parse_file|validate_model' 'tests/test_cuenca.py' 'tests/resources/test_endpoints.py' 'tests/resources/test_verifications.py' 'tests/resources/test_user_lists_validation.py' 'tests/resources/test_cards.py'

Length of output: 872


Script:

#!/bin/bash
# Check for model usage and imports
echo "Checking for model imports and usage..."
rg -C 3 'from.*import.*BaseModel|class.*\(BaseModel\)|model.*validate|model.*dict\(\)' tests/

echo -e "\nChecking for validation related code..."
rg -C 3 'validate|validation' tests/test_cuenca.py tests/resources/test_verifications.py tests/resources/test_user_lists_validation.py

echo -e "\nChecking imports from cuenca_validations..."
rg -C 3 'from cuenca_validations' tests/

Length of output: 8436

tests/resources/test_otps.py (1)

28-28: Good improvement in type checking!

The change from type(x) == str to isinstance(x, str) is a better practice as it:

  • Handles inheritance correctly
  • Is more idiomatic Python
  • Is more maintainable
cuenca/resources/wallet_transactions.py (1)

38-38: Correct migration to Pydantic v2!

The change from dict() to model_dump() aligns with Pydantic v2's API changes.

Let's verify the Pydantic version in use:

✅ Verification successful

Pydantic v2 migration verified successfully!

The codebase consistently uses Pydantic v2 features (ConfigDict, model_dump()) and dependencies (pydantic-extra-types 2.10.*). The change from dict() to model_dump() is correct and aligned with the rest of the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check Pydantic version in requirements files
rg -l "pydantic" | grep -i "requirements" | xargs cat

Length of output: 129


Script:

#!/bin/bash
# Check for direct pydantic imports and version constraints
rg "from pydantic" -A 1
rg "import pydantic"
rg "pydantic[>=<]" --type yaml --type txt --type toml

Length of output: 2253

tests/resources/test_card_activations.py (1)

11-14: Test data updates look good!

The updates to test values (card number, CVV, user_id) maintain the test's integrity while using new test data.

Also applies to: 18-18, 21-21

cuenca/resources/resources.py (2)

7-7: Type hint update aligns with modern Python practices

The change from Dict to dict aligns with PEP 585 which made built-in collections support generics.


18-26: Sequential processing improves test reliability

Good decision to replace ThreadPoolExecutor with a list comprehension. The comment explains the rationale well - the performance impact is negligible for small URI lists, and it resolves VCR test reliability issues.

tests/resources/test_commissions.py (1)

20-20: Better type checking with isinstance()

Good improvement replacing type() with isinstance(). This change makes the tests more robust by properly supporting inheritance in type checking.

Also applies to: 31-31

.github/workflows/test.yml (2)

23-23: Python version updates align with project objectives

The updated Python version matrix correctly removes 3.8 and adds newer versions up to 3.13, aligning with the PR objective to drop Python 3.8 support.


48-48: Verify Codecov token configuration

While updating to codecov-action@v5 is good, ensure the CODECOV_TOKEN secret is properly configured in the repository settings.

cuenca/resources/card_activations.py (2)

5-5: Improved type safety with PaymentCardNumber

Good use of PaymentCardNumber from pydantic_extra_types. This provides better validation and type safety for card numbers.

Also applies to: 25-25


47-47: Pydantic v2 compatibility update

Correct update from dict() to model_dump() for Pydantic v2 compatibility.

Let's check for any remaining dict() calls that need updating:

✅ Verification successful

All Pydantic v2 compatibility updates are complete

The codebase has been thoroughly checked and no remaining Pydantic .dict() calls were found. All other dict() usage in the codebase is for standard Python dictionaries or custom to_dict() methods, which don't require updates.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for remaining dict() calls that might need updating
rg "\.dict\(\)" --type py

Length of output: 27


Script:

#!/bin/bash
# First, verify Python files are recognized
echo "Python files in the repository:"
fd -e py

# Use ast-grep to search for dict() method calls
echo -e "\nSearching for dict() method calls:"
ast-grep --pattern '$_.$_.dict()'

# Use ast-grep to search for model_dump() calls for comparison
echo -e "\nSearching for model_dump() method calls:"
ast-grep --pattern '$_.$_.model_dump()'

# Try a different ripgrep pattern
echo -e "\nAlternative ripgrep search:"
rg "dict\(\)" --type py

Length of output: 4724


Script:

#!/bin/bash
# Search for Pydantic BaseModel usage to find potential model instances
echo "Files containing Pydantic BaseModel:"
rg "BaseModel" --type py -l

# Search for specific Pydantic model patterns
echo -e "\nSearching for potential Pydantic model usage:"
rg "class.*\(.*BaseModel.*\):" --type py -A 5

Length of output: 742

cuenca/resources/sessions.py (3)

19-21: LGTM! Field type updates align with Pydantic v2

The transition from AnyUrl to AnyUrlString for URL fields is a good change that aligns with Pydantic v2 best practices.


Line range hint 22-35: LGTM! Proper migration to Pydantic v2 configuration

The transition from Config class to model_config = ConfigDict() follows the recommended Pydantic v2 pattern.


53-55: LGTM! Proper usage of model_dump()

The transition from dict() to model_dump() aligns with Pydantic v2's API changes.

tests/resources/cassettes/test_card_activation.yaml (1)

3-4: Verify test data sensitivity

The test cassettes contain card numbers and CVV values. While these appear to be test data, please verify that no real card data is being committed.

Also applies to: 64-64

cuenca/resources/endpoints.py (4)

18-33: LGTM! Well-documented field definitions

The addition of detailed field descriptions using Field() improves code documentation and API schema generation. The transition to HttpUrlString is consistent with other URL field changes.


Line range hint 34-53: LGTM! Proper Pydantic v2 configuration

The migration from Config class to model_config = ConfigDict() with comprehensive examples follows Pydantic v2 best practices.


73-75: LGTM! Consistent use of model_dump()

The transition from dict() to model_dump() is consistently applied across methods, aligning with Pydantic v2's API changes.

Also applies to: 99-100


Line range hint 1-100: Verify Python 3.8 compatibility removal

Since this PR drops Python 3.8 support, verify that all Python 3.8-specific code patterns have been removed or updated.

✅ Verification successful

Python 3.8 support properly removed

The codebase has been correctly updated to drop Python 3.8 support:

  • setup.py requires Python >=3.9
  • No Python 3.8-specific compatibility code or patterns found
  • Type hints used in the code are compatible with Python 3.9+
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for Python 3.8-specific patterns or compatibility code
rg -l "python_version.*3\.8" .
rg -l "if sys\.version_info.*3\.8" .

Length of output: 71


Script:

#!/bin/bash
# Check for Python version requirements in setup files
fd "setup.py|pyproject.toml" --exec cat {}

# Check for typing-related imports and usage that might need updates
rg "from typing import .*Union" -A 2
rg "from typing import .*Literal" -A 2
rg "from typing import .*Protocol" -A 2
rg "from typing import .*TypedDict" -A 2
rg "from typing_extensions import" -A 2
rg "get_(args|origin)\(" -A 2

Length of output: 1877

requirements-test.txt Outdated Show resolved Hide resolved
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

🔭 Outside diff range comments (2)
cuenca/resources/kyc_validations.py (2)

Line range hint 16-27: Fix type mismatch in json_schema_extra example.

The 'attemps' field in the example is defined as string '1', but the type hint is Optional[int].

Apply this fix:

             'example': {
                 'id': 'KVNEUInh69SuKXXmK95sROwQ',
                 'platform_id': 'PT8UEv02zBTcymd4Kd3MO6pg',
                 'created_at': '2020-05-24T14:15:22Z',
                 'verification_id': 'string',
                 'files_uri': ['cuenca.com/files/id', 'cuenca.com/files/id2'],
-                'attemps': '1',
+                'attemps': 1,
             }

Line range hint 29-43: Fix mutable default argument in create method.

Using a mutable default argument (empty list) can lead to unexpected behavior if the default value is shared between calls.

Apply this fix:

     @classmethod
     def create(
         cls,
         user_id: str,
         force: bool = False,
-        documents: list[KYCFile] = [],
+        documents: list[KYCFile] | None = None,
         session: Session = global_session,
     ) -> 'KYCValidation':
         req = KYCValidationRequest(
             user_id=user_id,
             force=force,
-            documents=documents,
+            documents=documents or [],
         )
         return cast(
             'KYCValidation', cls._create(**req.model_dump(), session=session)
         )
🧰 Tools
🪛 Ruff (0.8.2)

34-34: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)

🧹 Nitpick comments (1)
cuenca/resources/sessions.py (1)

50-54: Improve type safety in the create method

While the migration to model_dump() is correct, there are a few type-related improvements that could be made:

  1. The # type: ignore comments are masking potential type issues. Consider explicitly typing the URL parameters as Optional[AnyUrlString].
  2. The cast() usage in the return statement could be simplified since we're already working with typed objects.

Consider applying this diff:

    @classmethod
    def create(
        cls,
        user_id: str,
        type: SessionType,
-       success_url: Optional[str] = None,
-       failure_url: Optional[str] = None,
+       success_url: Optional[AnyUrlString] = None,
+       failure_url: Optional[AnyUrlString] = None,
        *,
        session: http.Session = http.session,
    ) -> 'Session':
        req = SessionRequest(
            user_id=user_id,
            type=type,
-           success_url=success_url,  # type: ignore
-           failure_url=failure_url,  # type: ignore
+           success_url=success_url,
+           failure_url=failure_url,
        )
-       return cast(
-           'Session', cls._create(session=session, **req.model_dump())
-       )
+       return cls._create(session=session, **req.model_dump())
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19081ee and f295c73.

📒 Files selected for processing (4)
  • cuenca/resources/endpoints.py (5 hunks)
  • cuenca/resources/kyc_validations.py (4 hunks)
  • cuenca/resources/sessions.py (4 hunks)
  • cuenca/resources/transfers.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • cuenca/resources/endpoints.py
  • cuenca/resources/transfers.py
🧰 Additional context used
🪛 Ruff (0.8.2)
cuenca/resources/kyc_validations.py

34-34: Do not use mutable data structures for argument defaults

Replace with None; initialize within function

(B006)

🔇 Additional comments (5)
cuenca/resources/kyc_validations.py (2)

1-7: LGTM! Import changes align with Pydantic v2 and modern Python type hints.

The changes follow best practices by:

  • Using ConfigDict from Pydantic v2
  • Using built-in collection types for type hints (PEP 585)

13-15: LGTM! Explicit None defaults improve clarity.

The changes follow Pydantic v2 best practices by making Optional fields' defaults explicit.

cuenca/resources/sessions.py (3)

4-5: LGTM! Correct imports for Pydantic v2

The imports have been correctly updated to use the new Pydantic v2 patterns with ConfigDict and AnyUrlString.


19-21: LGTM! Correct field type updates for Pydantic v2

The field types have been properly updated to use AnyUrlString instead of AnyUrl, which is the recommended approach in Pydantic v2.


Line range hint 22-35: LGTM! Correct model configuration for Pydantic v2

The model configuration has been properly updated to use model_config = ConfigDict() instead of the v1 Config class pattern.

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: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f295c73 and f81c8bf.

📒 Files selected for processing (3)
  • cuenca/version.py (1 hunks)
  • requirements.txt (1 hunks)
  • setup.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • cuenca/version.py
  • requirements.txt
🔇 Additional comments (1)
setup.py (1)

24-24: LGTM: Python version requirement aligns with PR objectives

The update to require Python >=3.9 correctly implements the stated objective to drop Python 3.8 support.

'dataclasses>=0.7;python_version<"3.8"',
'cuenca-validations>= 0.11.3,<0.12.0',
'requests>=2.32.3',
'cuenca-validations==2.0.0.dev12',
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Avoid using development version in production

The dependency cuenca-validations==2.0.0.dev12 is a development version, which is not suitable for production use as it may contain unstable features or breaking changes.

Consider:

  1. Waiting for a stable release of cuenca-validations 2.0.0
  2. Or pin to the latest stable version that supports Pydantic v2

Comment on lines +31 to +35
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

Remove Python 3.13 classifier and update dependencies

The Python 3.13 classifier should be removed due to dependency compatibility issues:

  • cuenca-validations only supports Python up to 3.8, which conflicts with your minimum Python requirement of 3.9
  • requests package hasn't officially added Python 3.13 support yet

Additionally:

  • Consider upgrading cuenca-validations to a version that supports Python 3.9+ or replace it with an alternative
  • Wait for Python 3.13 to be officially released and for core dependencies to add support before adding the 3.13 classifier
🔗 Analysis chain

Verify Python 3.13 compatibility

While it's good to be forward-looking, Python 3.13 is still in development. Please ensure that:

  1. All dependencies support Python 3.13
  2. CI tests pass on Python 3.13
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if key dependencies support Python 3.13
curl -s https://pypi.org/pypi/pydantic-extra-types/json | jq '.info.classifiers[] | select(contains("Programming Language :: Python :: 3.13"))'
curl -s https://pypi.org/pypi/requests/json | jq '.info.classifiers[] | select(contains("Programming Language :: Python :: 3.13"))'

Length of output: 320


Script:

#!/bin/bash
# Check CI configuration for Python versions
fd -e yml -e yaml . .github/workflows --exec cat {} \; | grep -A 5 "python-version"

# Check dependencies in setup.py
cat setup.py | grep -A 10 "install_requires"

Length of output: 1530


Script:

#!/bin/bash
# Check Python support for cuenca-validations
curl -s https://pypi.org/pypi/cuenca-validations/json | jq '.info.classifiers[] | select(contains("Programming Language :: Python"))'

Length of output: 293

req = FileBatchUploadRequest(files=files, user_id=user_id)
return cast('FileBatch', cls._create(session=session, **req.dict()))
req = FileBatchUploadRequest(
files=cast(List[FileRequest], files), user_id=user_id
Copy link
Member

Choose a reason for hiding this comment

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

porque es necesario hacer este cast?

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