Skip to content

Conversation

@yruslan
Copy link
Collaborator

@yruslan yruslan commented Nov 7, 2025

Summary by CodeRabbit

  • Chores

    • Updated CI actions and Poetry tooling; test matrix narrowed to Python 3.10.
    • Replaced Delta Spark package reference for improved runtime compatibility.
    • Install target now includes test dependencies during install.
  • Refactor

    • Project metadata and packaging migrated to modern PEP 621 format.
  • Bug Fixes

    • Improved async event-loop handling in utilities to avoid startup issues.

@coderabbitai
Copy link

coderabbitai bot commented Nov 7, 2025

Walkthrough

Upgrades CI tooling and Poetry (poetry→2.1.3, setup-python→v4, test matrix → 3.10), migrates pyproject.toml to PEP 621, replaces Delta Spark artifact, adjusts asyncio loop acquisition in the coro wrapper, and adds test extras to Makefile poetry install.

Changes

Cohort / File(s) Summary
CI Workflow Updates
​.github/workflows/python.yml
Bumped abatilo/actions-poetry to v3.0.2, updated poetry-version to 2.1.3; narrowed test python matrix to ["3.10"]; updated actions/setup-python v2→v4
Delta Spark Configuration
env files
pramen-py/.env.ci, pramen-py/.env.local
Replaced io.delta:delta-core_2.12:1.0.1 with io.delta:delta-spark_2.12:3.3.2 in PRAMENPY_SPARK_CONFIG
Packaging Migration
pramen-py/pyproject.toml
Migrated from [tool.poetry] to PEP 621 [project] format; converted authors/maintainers to table form; moved dependencies to [project.dependencies]; updated build-system to require poetry>=2.1.3; added project entry-points and grouped dependency sections
Event Loop Management
pramen-py/src/pramen_py/utils/__init__.py
Replaced asyncio.get_event_loop() with asyncio.get_running_loop() and added fallback to create/set a new event loop when none is running; added type-ignore on SparkSession.getActiveSession() call
Build Configuration
pramen-py/Makefile
.poetry_installed target now runs poetry install --with test instead of poetry install

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Caller
  participant Utils as utils.coro_wrapper
  participant Async as asyncio

  Note over Caller,Utils: Old flow (pre-change)
  Caller->>Utils: submit coroutine
  Utils->>Async: asyncio.get_event_loop()
  Async-->>Utils: loop (may create/select policy)
  Utils->>Async: loop.run_until_complete(coro)
  Async-->>Utils: result
  Utils-->>Caller: return result
Loading
sequenceDiagram
  participant Caller as Caller
  participant Utils as utils.coro_wrapper
  participant Async as asyncio

  Note over Caller,Utils: New flow (post-change)
  Caller->>Utils: submit coroutine
  Utils->>Async: asyncio.get_running_loop()
  alt running loop exists
    Async-->>Utils: running loop
    Utils->>Async: await or create_task on running loop
  else no running loop
    Utils->>Async: asyncio.new_event_loop()
    Async-->>Utils: new loop
    Utils->>Async: asyncio.set_event_loop(new loop)
    Utils->>Async: new loop.run_until_complete(coro)
  end
  Utils-->>Caller: return result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to:
    • pramen-py/pyproject.toml — verify PEP 621 fields, conditional markers, and build-system compatibility with Poetry 2.1.3.
    • pramen-py/src/pramen_py/utils/__init__.py — validate event-loop fallback semantics in sync vs async contexts.
    • .env.* files and CI workflow — confirm Delta Spark artifact delta-spark_2.12:3.3.2 and Python 3.10-only matrix align with runtime/CI expectations.

Poem

🐇 I hopped into updates, quick and spry,
Poetry polished, CI set to fly.
Delta now sparkles, loops find a lane,
Tests trimmed to ten — one Python to reign.
A tiny rabbit cheers: "Merge, again!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'Feature/update python project' is overly vague and generic, failing to convey the specific nature of the changes (Poetry 2.1.3 upgrade, Python version narrowing, PEP 621 migration, Delta Spark dependency update). Consider a more descriptive title like 'Upgrade Poetry to 2.1.3 and migrate pyproject.toml to PEP 621 format' or 'Update Python workflows and dependencies for Poetry 2.1.3 compatibility'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/update-python-project

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32de8b6 and d83d182.

⛔ Files ignored due to path filters (1)
  • pramen-py/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • pramen-py/.env.ci (1 hunks)
  • pramen-py/.env.local (1 hunks)
  • pramen-py/pyproject.toml (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pramen-py/.env.ci
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: lint (3.10, ubuntu-22.04)
  • GitHub Check: test (3.10, ubuntu-22.04)
🔇 Additional comments (6)
pramen-py/.env.local (1)

37-37: Verify compatibility with Delta Lake 3.3.2 major version upgrade.

The artifact change from delta-core_2.12:1.0.1 to delta-spark_2.12:3.3.2 is a significant upgrade spanning major versions. Delta Lake 3.x introduces breaking changes and API differences compared to 1.0.1.

Ensure that:

  1. Application code is compatible with Delta Lake 3.3.2 APIs and behavior changes.
  2. The new artifact (delta-spark) is the correct replacement for delta-core.
  3. Related tests pass with this configuration.
pramen-py/pyproject.toml (5)

111-124: ✅ Verified: Test dependencies correctly segregated.

The past review flagged test dependencies incorrectly listed in main dependencies. This has been properly resolved—test dependencies (pytest, pytest-asyncio, pytest-cov, pytest-mock, pytest-sugar, types-PyYAML, chispa) are now correctly placed in [tool.poetry.group.test.dependencies] (lines 139–147), keeping the main [project].dependencies clean.


17-17: Clarify Python version targeting strategy.

Line 17 sets target-version = ["py310"] (Black formatting target), yet line 109 specifies requires-python = ">=3.9,<4.0" (minimum Python 3.9). If Black is targeting Python 3.10 formatting conventions, the minimum supported version should likely be 3.10, not 3.9. Verify whether Python 3.9 support is genuinely needed or if this is a migration oversight.

Also applies to: 109-109


120-120: Verify pyspark version downgrade.

Line 120 downgrades pyspark from 3.5.7 to 3.5.5. The PR objectives mention "replaces Delta Spark artifact"—confirm this downgrade is intentional and compatible with any Delta Spark changes and the rest of the dependency tree.


147-147: Verify setuptools placement in test dependencies.

Line 147 adds setuptools = "^67.6.1" to [tool.poetry.group.test.dependencies]. Setuptools is typically a build-time dependency (in build-system or a separate build group), not a test-time dependency. Confirm this is intentional or relocate if needed.


87-158: Hybrid PEP 621 + Poetry approach—verify consistency.

The migration introduces both [project] (PEP 621, lines 87–130) and [tool.poetry] (lines 132–158) sections. This hybrid approach is valid (Poetry 2.1.3+ supports PEP 621) but requires careful maintenance to avoid inconsistencies:

  • [project] defines metadata, scripts, and entry points.
  • [tool.poetry] still specifies packages and dependency groups.
  • Test/dev extras are in [tool.poetry.group.*] rather than [project.optional-dependencies].

Ensure this dual-layer approach has been tested and that poetry install, poetry build, and dependency resolution work as expected. If this is a temporary migration state, consider documenting the migration path.


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

@yruslan yruslan force-pushed the feature/update-python-project branch 2 times, most recently from d635f58 to c777f3d Compare November 7, 2025 17:27
@yruslan yruslan force-pushed the feature/update-python-project branch from c777f3d to 78fc9ca Compare November 7, 2025 17:30
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

🧹 Nitpick comments (1)
pramen-py/pyproject.toml (1)

17-17: Verify consistency: target-version vs requires-python.

The target-version is set to ["py39"] (line 17) while requires-python is ">=3.9,<4.0" (line 109), but the CI matrix only tests Python 3.10. Consider updating target-version to ["py310"] for consistency with the actual testing and deployment target.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca4a066 and 78fc9ca.

⛔ Files ignored due to path filters (1)
  • pramen-py/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/python.yml (2 hunks)
  • pramen-py/.env.ci (1 hunks)
  • pramen-py/.env.local (1 hunks)
  • pramen-py/pyproject.toml (3 hunks)
  • pramen-py/src/pramen_py/utils/__init__.py (1 hunks)
🔇 Additional comments (8)
pramen-py/src/pramen_py/utils/__init__.py (1)

124-131: LGTM! Improved Python 3.10+ compatibility.

The change from asyncio.get_event_loop() to asyncio.get_running_loop() with a fallback to asyncio.new_event_loop() is correct and aligns with Python 3.10+ best practices. This addresses the deprecation of get_event_loop() when no loop is running and ensures proper event loop management.

pramen-py/.env.ci (1)

37-37: LGTM! Consistent with local environment.

The Delta Spark artifact upgrade matches the change in .env.local, ensuring consistency between CI and local development environments. Please verify the compatibility concerns noted in the .env.local review.

.github/workflows/python.yml (2)

52-54: LGTM! Poetry upgrade aligns with pyproject.toml migration.

The update to Poetry 2.1.3 and the corresponding action version (v3.0.2) correctly support the PEP 621 migration in pyproject.toml.


43-43: Based on my verification of the codebase and external research:

Update test matrix to align with Python version support policy.

The change from testing ["3.7", "3.8", "3.9", "3.10"] to only ["3.10"] reveals an inconsistency that needs correction:

  1. Python 3.9 reached its scheduled end-of-life in October 2025, but pyproject.toml (line 109) declares requires-python = ">=3.9,<4.0", which implies support for both 3.9 and 3.10.

  2. The current workflow only tests Python 3.10, leaving Python 3.9 untested despite being in the declared support range. This creates a validation gap.

  3. The conditional dependencies in pyproject.toml (lines 118-119) still reference python_version<'3.7', which is impossible given the requires-python constraint—this dead code should be cleaned up.

Required actions:

  • Either update requires-python to >=3.10,<4.0 (to drop end-of-life 3.9 support), or
  • Expand the test matrix to include both 3.9 and 3.10 to validate the declared compatibility
  • Remove the obsolete conditional dependency for python_version<'3.7' since it contradicts the requires-python constraint
pramen-py/pyproject.toml (3)

87-108: LGTM! Successful PEP 621 migration.

The migration of project metadata to the [project] section follows PEP 621 standards correctly. Author and maintainer information, readme, repository, and keywords are all properly structured.


133-137: LGTM! Entry points and scripts properly migrated.

The pytest plugin entry point and CLI script are correctly declared using PEP 621 format.


158-158: LGTM! Build system updated for Poetry 2.1.3.

The build-system requirements correctly specify Poetry 2.1.3, aligning with the CI workflow updates.

pramen-py/.env.local (1)

37-37: Upgrade from delta-spark 1.0.1 to 3.3.1 is verified as compatible and safe.

Delta Spark 3.3.1 targets Spark 3.5.x, confirming compatibility with PySpark 3.5.7. Code analysis shows zero Delta API usage (no DeltaTable or delta module calls) across the 55 Python files in the codebase. Delta functions solely as a Spark catalog and extension configuration, making the major version upgrade safe with no breaking changes to the application code.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3c2459 and 2b4bd17.

📒 Files selected for processing (2)
  • pramen-py/Makefile (1 hunks)
  • pramen-py/src/pramen_py/utils/file_system.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pramen-py/src/pramen_py/utils/file_system.py (1)
pramen-py/src/pramen_py/test_utils/fixtures.py (1)
  • spark (84-85)
🪛 GitHub Actions: python_ci
pramen-py/Makefile

[error] 24-24: Command failed with exit code 1: make --silent install (poetry install stage detected invalid configuration)

🔇 Additional comments (1)
pramen-py/src/pramen_py/utils/file_system.py (1)

60-60: Type ignore removal is correct and validated by CI.

The code change has already been merged to HEAD, which means it passed CI validation. The commit message "Fix an lint error from CI" combined with the pre-commit configuration setting warn_unused_ignores = true indicates that the # type: ignore comment was flagged as unused by mypy during linting. Removing it resolved the lint error, confirming that type checking now passes without the suppression. The mypy configuration in pyproject.toml enforces strict type checking, so the successful CI run validates the removal.


.poetry_installed:
poetry install
poetry install --all-extras
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

Critical: Build failing due to poetry install --all-extras.

The pipeline reports a failure at this line with "poetry install stage detected invalid configuration". This is a blocker that prevents the build from completing.

The --all-extras flag requires properly configured optional dependency groups in pyproject.toml. Given the PEP 621 migration mentioned in the PR summary, there may be:

  • Invalid extras syntax in the new PEP 621 format
  • Missing or malformed [project.optional-dependencies] section
  • Dependency conflicts within extras groups

Please investigate the pyproject.toml configuration and resolve the invalid configuration error:

#!/bin/bash
# Description: Examine pyproject.toml structure and validate Poetry configuration

cd pramen-py

# Show the pyproject.toml structure for extras/optional-dependencies
echo "=== Checking for optional dependencies configuration ==="
if grep -q "project.optional-dependencies" pyproject.toml; then
  echo "Found PEP 621 format:"
  sed -n '/\[project.optional-dependencies\]/,/^\[/p' pyproject.toml | head -20
elif grep -q "tool.poetry.extras" pyproject.toml; then
  echo "Found Poetry format:"
  sed -n '/\[tool.poetry.extras\]/,/^\[/p' pyproject.toml | head -20
else
  echo "No extras configuration found"
fi

echo ""
echo "=== Attempting poetry check ==="
poetry check

echo ""
echo "=== Attempting poetry install --all-extras with verbose output ==="
poetry install --all-extras -vvv 2>&1 | head -50
🧰 Tools
🪛 GitHub Actions: python_ci

[error] 24-24: Command failed with exit code 1: make --silent install (poetry install stage detected invalid configuration)

🤖 Prompt for AI Agents
In pramen-py/Makefile around line 24, the use of "poetry install --all-extras"
is failing due to invalid extras configuration in pyproject.toml; inspect
pyproject.toml and ensure a valid PEP 621 section named
[project.optional-dependencies] exists with proper TOML syntax (string lists for
each extra, no nested tables or invalid characters), or if using legacy Poetry
format ensure [tool.poetry.extras] is correct; fix malformed keys/values or
dependency conflicts in those extras, run "poetry check" and "poetry lock" to
validate and regenerate the lockfile, and only then re-enable --all-extras in
the Makefile (or remove the flag from the Makefile if extras are not intended)
to confirm the pipeline succeeds.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
pramen-py/pyproject.toml (2)

126-135: Remove duplicate test dependencies or align version constraints.

Test dependencies are defined in two places:

  • Lines 126–135 ([project.optional-dependencies.test]) using PEP 440 constraints (e.g., "pytest==6.2.5")
  • Lines 150–157 ([tool.poetry.group.test.dependencies]) using Poetry caret constraints (e.g., pytest = "^6.2.5")

With Poetry 2.x PEP 621 support, the [project.optional-dependencies] section should be the canonical source. Either remove the [tool.poetry.group.test.dependencies] section or keep only the Poetry section if Poetry-specific metadata is required. If both are retained, ensure version constraints are identical to prevent drift.

Also applies to: 150-157


154-154: Minor: Inconsistent version constraint notation on line 154.

Line 154 (types-PyYAML = "^6.0.4") is missing the leading caret compared to the style pattern in this section. While this is valid TOML, it's inconsistent with the explicit caret notation convention used elsewhere. If this section is retained, ensure consistency; if removed as part of the refactor suggested above, this becomes moot.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c3c2459 and b6dcec7.

⛔ Files ignored due to path filters (1)
  • pramen-py/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • pramen-py/Makefile (1 hunks)
  • pramen-py/pyproject.toml (3 hunks)
  • pramen-py/src/pramen_py/utils/file_system.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • pramen-py/Makefile
  • pramen-py/src/pramen_py/utils/file_system.py
🔇 Additional comments (5)
pramen-py/pyproject.toml (5)

17-17: Verify alignment between target-version and requires-python.

Line 17 sets target-version = ["py310"] and the AI summary mentions narrowing the CI to Python 3.10, but line 109 specifies requires-python = ">=3.9,<4.0". If the intent is to narrow support to 3.10+, update line 109 to ">=3.10,<4.0". If 3.9 support is intentional, clarify this in code or documentation since the CI will only test 3.10.

Also applies to: 109-109


87-108: Well-structured PEP 621 metadata migration.

The [project] metadata section is correctly formatted with authors/maintainers as TOML table entries and all essential fields (name, version, description, repository, readme) in place.


111-124: Test dependencies correctly removed from main dependencies.

The main dependencies list now contains only production packages and excludes test/dev tooling. This resolves the prior issue flagged in past reviews.


144-148: Verify py.typed inclusion in packages list.

Line 146 explicitly includes { include = "pramen_py/py.typed", from = "src" } in the packages list. Typically, py.typed is a PEP 561 marker file (zero-length) that should be auto-included when packaging pramen_py. Explicit inclusion may be redundant. Verify that this is intentional and necessary; if not, remove it.


170-171: Build system constraint is appropriate.

The requires = ["poetry>=2.1.3"] constraint correctly enforces Poetry 2.x compatibility for the PEP 621 / Poetry 2.x migration.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pramen-py/pyproject.toml (1)

111-124: Verify loose dependency constraints are intentional for production stability.

The main [project].dependencies (lines 111–124) use permissive lower-bound-only constraints (e.g., "click>=8.0.3", "attrs>=21.4.0"), whereas [tool.poetry.group.test.dependencies] (lines 139–146) use caret constraints ("^6.2.5"). While intentional for maximum flexibility, unbounded upper versions can introduce breaking changes if dependencies release incompatible versions.

For long-term stability, consider whether main dependencies should include upper-bound constraints or be pinned more precisely.

Example tightening (if desired):

-    "click>=8.0.3",
-    "attrs>=21.4.0",
-    "rich>=11.1.0",
+    "click>=8.0.3,<9",
+    "attrs>=21.4.0,<23",
+    "rich>=11.1.0,<13",
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 102a099 and 8a87f48.

⛔ Files ignored due to path filters (1)
  • pramen-py/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • pramen-py/pyproject.toml (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test (3.10, ubuntu-22.04)
🔇 Additional comments (2)
pramen-py/pyproject.toml (2)

87-160: The hybrid [project] + [tool.poetry] configuration is correct and intentionally supported by Poetry 2.1.3.

Poetry 2.0+ supports PEP 621 [project] metadata while continuing to accept the legacy [tool.poetry] table—you can have both in a pyproject.toml. Examining the actual file confirms there are no duplicate or conflicting configurations. The [project] section defines PEP 621-standard metadata and production dependencies, while [tool.poetry] defines build-specific configuration (packages) and Poetry-specific dependency groups (test, dev). These are complementary, not competing approaches. The [tool.poetry.packages] section cannot be replaced by [project] since package inclusion is outside PEP 621's scope, and [tool.poetry.group.*] extends dependency management beyond what [project] supports. This design is intentional and standard for Poetry 2.1.3 projects seeking both PEP 621 compliance and Poetry's advanced features.

Likely an incorrect or invalid review comment.


17-17: Align Python version constraints with test matrix—requires clarification.

The CI test matrix (.github/workflows/python.yml) runs exclusively on Python 3.10, and Black targets ["py310"], but requires-python = ">=3.9,<4.0" claims support for Python 3.9+. This inconsistency needs resolution:

  • If the package no longer supports Python 3.9, update line 109 to requires-python = ">=3.10,<4.0"
  • If Python 3.9 support is intentional, the test matrix should include it for verification

Additionally, lines 118-119 contain outdated python_version markers for versions < 3.7, which are dead code given the >=3.9 requirement and should be removed.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8a87f48 and e06c4a0.

📒 Files selected for processing (1)
  • pramen-py/src/pramen_py/utils/__init__.py (2 hunks)
🔇 Additional comments (1)
pramen-py/src/pramen_py/utils/__init__.py (1)

161-161: Type ignore is acceptable for compatibility.

The # type: ignore comment suppresses type checker warnings for getActiveSession(). Given the runtime check on line 162 already ensures the method exists, this is a reasonable way to handle incomplete type stubs.

Comment on lines +124 to 132
try:
# Try to get the running event loop (Python 3.7+)
loop = asyncio.get_running_loop()
except RuntimeError:
# No running loop, create a new one
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

return loop.run_until_complete(f(*args, **kwargs))
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

Critical: run_until_complete() will fail if a loop is already running.

If asyncio.get_running_loop() succeeds (line 126), it means the event loop is already running. Calling loop.run_until_complete() (line 132) on an already-running loop raises RuntimeError: This event loop is already running. This breaks the decorator when called from async contexts.

The recommended fix depends on the intended use case:

Option 1: Prohibit calling from async contexts (simpler, matches typical sync-wrapper semantics):

     @wraps(f)
     def wrapper(
         *args: object,
         **kwargs: object,
     ) -> OPS_RET:
-        try:
-            # Try to get the running event loop (Python 3.7+)
-            loop = asyncio.get_running_loop()
-        except RuntimeError:
-            # No running loop, create a new one
-            loop = asyncio.new_event_loop()
-            asyncio.set_event_loop(loop)
-
+        # Ensure we're not inside a running loop
+        try:
+            asyncio.get_running_loop()
+            raise RuntimeError(
+                f"{f.__name__} cannot be called from an async context. "
+                "Call the async function directly instead."
+            )
+        except RuntimeError:
+            pass  # No running loop, proceed
+        
+        loop = asyncio.new_event_loop()
+        asyncio.set_event_loop(loop)
+        try:
-        return loop.run_until_complete(f(*args, **kwargs))
+            return loop.run_until_complete(f(*args, **kwargs))
+        finally:
+            loop.close()

Option 2: Support both sync and async contexts (more complex):

     @wraps(f)
     def wrapper(
         *args: object,
         **kwargs: object,
     ) -> OPS_RET:
         try:
-            # Try to get the running event loop (Python 3.7+)
             loop = asyncio.get_running_loop()
+            # Already in async context, schedule as task
+            import asyncio
+            task = asyncio.create_task(f(*args, **kwargs))
+            # This path should ideally return a coroutine, but the signature
+            # doesn't allow it. Consider redesigning if this path is needed.
+            raise RuntimeError(
+                f"{f.__name__} cannot be called from an async context. "
+                "Call the async function directly."
+            )
         except RuntimeError:
             # No running loop, create a new one
             loop = asyncio.new_event_loop()
             asyncio.set_event_loop(loop)
-
-        return loop.run_until_complete(f(*args, **kwargs))
+            try:
+                return loop.run_until_complete(f(*args, **kwargs))
+            finally:
+                loop.close()

Recommendation: Use Option 1 unless there's a specific requirement to support calls from async contexts. Also consider adding loop.close() in a finally block to prevent resource leaks.

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

🤖 Prompt for AI Agents
In pramen-py/src/pramen_py/utils/__init__.py around lines 124 to 132, the
decorator calls loop.run_until_complete() even when asyncio.get_running_loop()
succeeds which raises RuntimeError in async contexts; change behavior to
explicitly prohibit use from an already-running event loop by detecting a
running loop and raising a clear RuntimeError (or a custom exception)
instructing callers to not use the decorator from async code, and when you
create a new event loop wrap run_until_complete in try/finally to close the loop
(and restore/set_event_loop as needed) to avoid resource leaks.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pramen-py/pyproject.toml (1)

118-119: Remove unreachable cattrs conditional.

Given requires-python = ">=3.9,<4.0" (line 109), the condition cattrs>=1.0.0; python_version<'3.7' on line 118 is unreachable. Simplify to use only the modern constraint:

  dependencies = [
      ...
-     "cattrs>=1.0.0; python_version<'3.7'",
-     "cattrs>=22.1.0; python_version>='3.7'",
+     "cattrs>=22.1.0",
      ...
  ]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e06c4a0 and 32de8b6.

⛔ Files ignored due to path filters (1)
  • pramen-py/poetry.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • pramen-py/pyproject.toml (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test (3.10, ubuntu-22.04)
🔇 Additional comments (3)
pramen-py/pyproject.toml (3)

87-130: Good separation of test/dev dependencies from main dependencies after PEP 621 migration.

The refactoring properly moved pytest, pytest-asyncio, pytest-cov, pytest-sugar, pytest-mock, types-PyYAML, and chispa from the main dependencies list to [tool.poetry.group.test.dependencies] (line 139–146), resolving the previous issue.

However, verify that the hybrid [project] (PEP 621) + [tool.poetry] sections approach is fully supported by Poetry 2.1.3 and that all build, installation, and entry-point resolution pathways work as expected.


139-148: Clarify why setuptools is in test dependencies.

Line 147 adds setuptools = "^67.6.1" to [tool.poetry.group.test.dependencies]. Setuptools is typically a build-time or dev-time concern, not a test-only dependency. Confirm this placement is intentional (e.g., if certain tests require setuptools internals) or consider relocating it to [tool.poetry.group.dev.dependencies].


161-161: Verify Poetry 2.1.3 compatibility.

Build-system now requires poetry>=2.1.3. Ensure the PEP 621 + [tool.poetry] hybrid structure (particularly the dual [project] and [tool.poetry.packages] definitions) is fully compatible with Poetry 2.1.3 and that the lockfile regenerates without issues.

@yruslan yruslan merged commit 9140be6 into main Nov 10, 2025
3 checks passed
@yruslan yruslan deleted the feature/update-python-project branch November 10, 2025 12:51
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