Skip to content

Enhancement | Issue #21 | OPT-1 | Implement typed argument casting #306

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

exequielrafaela
Copy link
Member

@exequielrafaela exequielrafaela commented Jun 5, 2025

Summary

  • add cast_value utility to detect bool/int/float
  • cast task parameters and .env values to their types
  • update tests for new casting behaviour

Testing

  • pytest -q

https://chatgpt.com/codex/tasks/task_e_6841c005a738832fba0a8e5381fda35d

Summary by CodeRabbit

  • New Features

    • Improved automatic conversion of string inputs to appropriate data types (boolean, integer, float) when parsing arguments and loading configuration values.
  • Bug Fixes

    • Enhanced consistency in how argument and configuration values are interpreted, reducing the chance of incorrect data types.
  • Tests

    • Updated tests to verify correct type casting for arguments and configuration values.

Copy link
Contributor

coderabbitai bot commented Jun 5, 2025

Walkthrough

A new utility function, cast_value, was introduced to convert string inputs into their most suitable Python data types (boolean, integer, float, or string). This function is now used in both argument parsing and configuration loading, ensuring that values are automatically cast to appropriate types. Corresponding tests were updated to validate this casting behavior.

Changes

File(s) Change Summary
leverage/_casting.py Added cast_value function for sequential type inference (bool, int, float, or str).
leverage/_parsing.py, leverage/conf.py Integrated cast_value to cast positional and keyword argument values during parsing and config loading.
tests/test__parsing.py, tests/test_conf.py Updated tests to expect casted values (booleans, ints, floats) instead of raw strings.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Parsing
    participant Casting

    User->>Parsing: Provide argument/config string values
    Parsing->>Casting: Call cast_value(value)
    Casting-->>Parsing: Return casted value (bool/int/float/str)
    Parsing-->>User: Return parsed/casted arguments or config
Loading

Poem

In the warren where code bunnies dwell,
Strings now transform, casting a spell.
"True" turns to True, and "3" to three—
Types align as they’re meant to be!
With tests that hop and configs that sing,
This casting brings joy to everything.
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

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

❤️ Share
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @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.

@coveralls
Copy link
Collaborator

coveralls commented Jun 5, 2025

Pull Request Test Coverage Report for Build 15472119070

Details

  • 19 of 21 (90.48%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall first build on codex/review-issue-#21-and-propose-solution at 61.217%

Changes Missing Coverage Covered Lines Changed/Added Lines %
leverage/_casting.py 14 16 87.5%
Totals Coverage Status
Change from base Build 15417024595: 61.2%
Covered Lines: 2608
Relevant Lines: 4128

💛 - Coveralls

Copy link
Contributor

@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

🧹 Nitpick comments (2)
leverage/_casting.py (1)

8-26: Consider expanding boolean detection and adding input validation.

The current implementation has a few areas for improvement:

  1. Limited boolean detection: Only handles "true"/"false" but common boolean representations like "yes"/"no", "1"/"0", "on"/"off" are not supported.

  2. Missing input validation: The function expects a string but doesn't validate the input type.

  3. Whitespace handling: Consider stripping whitespace before processing.

Consider this enhanced version:

def cast_value(value: str) -> Any:
    """Try to cast a string to bool, int or float.

    Args:
        value (str): Value to cast.

    Returns:
        Any: The value converted to its apparent type or the original string.
    """
+   if not isinstance(value, str):
+       return value
+   
+   value = value.strip()
+   if not value:
+       return value
+       
    lowered = value.lower()
-   if lowered in {"true", "false"}:
+   if lowered in {"true", "false", "yes", "no", "1", "0", "on", "off"}:
+       return lowered in {"true", "yes", "1", "on"}
-       return lowered == "true"
    try:
        return int(value)
    except ValueError:
        try:
            return float(value)
        except ValueError:
            return value
leverage/conf.py (1)

39-39: Consider updating the TODO comment.

The TODO comment mentions leveraging type casting utilities, which is now partially implemented with the cast_value integration. Consider updating this comment to reflect the current state.

-    # TODO: Return an Env object instead of a dictionary, to be able to leverage its type casting utilities
+    # TODO: Consider returning an Env object instead of a dictionary for enhanced type casting capabilities
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a4609c6 and 03508b9.

📒 Files selected for processing (5)
  • leverage/_casting.py (1 hunks)
  • leverage/_parsing.py (2 hunks)
  • leverage/conf.py (2 hunks)
  • tests/test__parsing.py (1 hunks)
  • tests/test_conf.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
leverage/conf.py (1)
leverage/_casting.py (1)
  • cast_value (8-26)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: integration_tests_cli_refarch (3.9.15, 1.3.5-0.2.0)
🔇 Additional comments (7)
leverage/conf.py (2)

9-9: Clean integration of the casting utility.

The import is properly placed and follows the project's import organization.


61-61: Effective integration of value casting in config loading.

The casting is applied appropriately during value storage. Since cast_value safely returns the original value if casting fails, this integration is robust and won't introduce errors.

leverage/_parsing.py (3)

5-5: Consistent import of the casting utility.

The import follows the same pattern used in other modules and is properly placed.


45-45: Proper casting integration for positional arguments.

The casting is applied after stripping whitespace but before adding to the args list, ensuring clean typed values.


52-52: Correct casting integration for keyword argument values.

The casting is appropriately applied only to the value (not the key) of keyword arguments, maintaining the expected behavior while ensuring type consistency.

tests/test_conf.py (1)

33-33: Correct test updates to reflect the new casting behavior.

The test expectations are properly updated to expect boolean True values instead of string "true" values, which aligns with the new cast_value integration in the configuration loading. This correctly validates that environment variables like MFA_ENABLED and DEBUG are now cast to their appropriate boolean types.

Also applies to: 35-35

tests/test__parsing.py (1)

11-11:

✅ Verification successful

Verify casting behavior for positional arguments.

The test now expects numeric strings to be cast to their respective types ("2"2, "3.5"3.5), which is a significant behavior change. This automatic casting could break existing code that expects these values to remain as strings.

Please verify that this casting behavior is intentional and won't break existing integrations:


🏁 Script executed:

#!/bin/bash
# Description: Search for existing usages of parse_task_args to assess backwards compatibility impact
# Expected: Find usages that might be affected by the string-to-number casting change

echo "=== Searching for parse_task_args usage ==="
rg -A 5 -B 5 "parse_task_args" --type py

echo -e "\n=== Searching for potential string comparisons that might break ==="
rg -A 3 -B 3 "args\[.*\].*==.*['\"][\d\.]+['\"]" --type py

Length of output: 4061


Casting behavior is isolated and intentional

  • parse_task_args is only invoked in leverage/modules/run.py (and its own tests), so no other code paths will be affected.
  • A grep for comparisons against numeric strings ('["]\d+(\.\d+)?["]') returned only unrelated test assertions (e.g., in tests/test_modules/test_auth.py), so there’s no evidence of existing code relying on string‐typed numbers from parse_task_args.
  • The updated tests in tests/test__parsing.py correctly reflect the new casting behavior.

Since the change is confined to the CLI argument parser and all existing call sites have been adjusted or are unaffected, this casting change appears safe. Please ensure any user documentation or examples are updated to note that numeric and boolean strings will now be cast automatically.

[],
{"kwarg1": "/val/1", "kwarg2": "val2", "kwarg3": "val3"},
{"kwarg1": True, "kwarg2": "val2", "kwarg3": 3},
),
("arg1, arg2, kwarg1=/val/1,kwarg2 = val2", ["arg1", "arg2"], {"kwarg1": "/val/1", "kwarg2": "val2"}), # Both
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add test coverage for mixed scenarios and edge cases.

The current tests cover basic scenarios well, but consider adding tests for these edge cases:

  1. Ambiguous strings: Version numbers like "1.0", IDs like "123" that shouldn't be cast
  2. Scientific notation: "1e10", "3.14e-2"
  3. Leading zeros: "007", "0123"
  4. Special float values: "inf", "nan"
+        # Edge cases for casting
+        ("1e10, inf, nan", [1e10, float('inf'), float('nan')], {}),
+        ("007, 0123", [7, 123], {}),  # Leading zeros
+        ("kwarg1=1.0,kwarg2=0.0", [], {"kwarg1": 1.0, "kwarg2": 0.0}),  # Ensure float casting
📝 Committable suggestion

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

Suggested change
("arg1, arg2, kwarg1=/val/1,kwarg2 = val2", ["arg1", "arg2"], {"kwarg1": "/val/1", "kwarg2": "val2"}), # Both
("arg1, arg2, kwarg1=/val/1,kwarg2 = val2", ["arg1", "arg2"], {"kwarg1": "/val/1", "kwarg2": "val2"}), # Both
# Edge cases for casting
("1e10, inf, nan", [1e10, float('inf'), float('nan')], {}),
("007, 0123", [7, 123], {}), # Leading zeros
("kwarg1=1.0,kwarg2=0.0", [], {"kwarg1": 1.0, "kwarg2": 0.0}), # Ensure float casting
🤖 Prompt for AI Agents
In tests/test__parsing.py at line 17, the current test cases do not cover edge
cases involving ambiguous strings, scientific notation, leading zeros, and
special float values. Add new test cases that include inputs like "1.0", "123",
"1e10", "3.14e-2", "007", "0123", "inf", and "nan" to verify the parsing logic
correctly handles these scenarios without incorrect casting or errors.

Comment on lines +13 to +15
"kwarg1=true,kwarg2 = val2, kwarg3 = 3 ",
[],
{"kwarg1": "/val/1", "kwarg2": "val2", "kwarg3": "val3"},
{"kwarg1": True, "kwarg2": "val2", "kwarg3": 3},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify boolean casting implementation and edge cases.

The test expects "true" to be cast to True, but consider these edge cases that aren't covered:

  1. Case sensitivity: What about "True", "TRUE", "False", "false"?
  2. Other boolean representations: "yes", "no", "1", "0"?
  3. Invalid boolean strings: "tru", "fals"?

Consider adding test cases for boolean edge cases:

+        # Boolean edge cases
+        ("True, False, yes, no", [True, False, "yes", "no"], {}),
+        ("kwarg1=TRUE,kwarg2=false,kwarg3=1,kwarg4=0", [], {"kwarg1": True, "kwarg2": False, "kwarg3": 1, "kwarg4": 0}),

Let's verify the actual boolean casting implementation:


🏁 Script executed:

#!/bin/bash
# Description: Find the cast_value function implementation to understand boolean casting logic
# Expected: Show how boolean strings are handled

echo "=== Finding cast_value function implementation ==="
ast-grep --pattern 'def cast_value($$$) {
  $$$
}'

echo -e "\n=== Searching for boolean casting logic ==="
rg -A 10 -B 5 "bool|True|False" leverage/_casting.py

Length of output: 678


🏁 Script executed:

#!/bin/bash
# Display full cast_value implementation for comprehensive review
sed -n '1,200p' leverage/_casting.py

Length of output: 581


Add comprehensive boolean casting tests

The cast_value implementation lowercases inputs to handle "true"/"false" case-insensitively and then falls back to numeric casts (int or float), returning any other string as-is. To lock in this behavior and guard against regressions, please add tests covering:

  • Case-insensitive booleans: "True", "TRUE", "False", "false"
  • Numeric strings → ints: "1", "0"
  • Other strings unchanged: "yes", "no", invalid boolean tokens like "tru", "fals"

For example, in tests/test__parsing.py:

--- tests/test__parsing.py
+++ tests/test__parsing.py
@@ (existing tests)
     # Boolean edge cases
-    # (add your tests here)
+    ("True, FALSE, yes, no", [True, False, "yes", "no"], {}),
+    ("kwarg1=TRUE,kwarg2=false,kwarg3=1,kwarg4=0", [], {"kwarg1": True, "kwarg2": False, "kwarg3": 1, "kwarg4": 0}),

This will confirm that:

  • "True"/"FALSE"True/False
  • "1"/"0"1/0
  • "yes"/"no" stay as strings
  • malformed tokens like "tru" remain unchanged
📝 Committable suggestion

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

Suggested change
"kwarg1=true,kwarg2 = val2, kwarg3 = 3 ",
[],
{"kwarg1": "/val/1", "kwarg2": "val2", "kwarg3": "val3"},
{"kwarg1": True, "kwarg2": "val2", "kwarg3": 3},
# Boolean edge cases
("True, FALSE, yes, no", [True, False, "yes", "no"], {}),
("kwarg1=TRUE,kwarg2=false,kwarg3=1,kwarg4=0", [], {"kwarg1": True, "kwarg2": False, "kwarg3": 1, "kwarg4": 0}),
🤖 Prompt for AI Agents
In tests/test__parsing.py around lines 13 to 15, the current test only checks
the boolean string "true" being cast to True but misses other important boolean
edge cases. Add test cases to cover case-insensitive boolean strings like
"True", "TRUE", "False", "false", numeric strings "1" and "0" which should cast
to integers, and other strings like "yes", "no", and malformed tokens like "tru"
and "fals" which should remain unchanged as strings. This will ensure the
cast_value function's boolean casting behavior is fully tested and guarded
against regressions.

@exequielrafaela exequielrafaela changed the title Implement typed argument casting Enhancement | Issue #21 | Implement typed argument casting Jun 5, 2025
Copy link
Contributor

@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)
leverage/_casting.py (1)

20-33: Consider the mixed parsing approach implications.

The implementation uses YAML parsing only for booleans but falls back to direct int/float conversion for numeric types. While functional, this creates an inconsistency where some YAML-style inputs (like "yes"/"no" for booleans) are parsed but others (like "1.5" vs "1.50") may not be handled consistently.

Consider one of these approaches for consistency:

Option 1: Use YAML for all types (if you want full YAML compatibility):

def cast_value(value: str) -> Any:
    """Try to cast a string to bool, int or float using PyYAML."""
    try:
        parsed = yaml.safe_load(value)
-        if isinstance(parsed, bool):
-            return parsed
+        if isinstance(parsed, (bool, int, float)):
+            return parsed
    except yaml.YAMLError:
        pass
-
-    try:
-        return int(value)
-    except ValueError:
-        try:
-            return float(value)
-        except ValueError:
-            return value
+    return value

Option 2: Use direct parsing for consistency (if you want to avoid YAML complexity):

def cast_value(value: str) -> Any:
    """Try to cast a string to bool, int or float."""
-    try:
-        parsed = yaml.safe_load(value)
-        if isinstance(parsed, bool):
-            return parsed
-    except yaml.YAMLError:
-        pass
+    # Handle common boolean representations
+    if value.lower() in ('true', 'false', 'yes', 'no', 'on', 'off'):
+        return value.lower() in ('true', 'yes', 'on')
    
    try:
        return int(value)
    except ValueError:
        try:
            return float(value)
        except ValueError:
            return value

The current implementation works correctly but may surprise users when some YAML-style inputs work for booleans but not for other types.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 03508b9 and d5cbd79.

📒 Files selected for processing (1)
  • leverage/_casting.py (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unit_tests (3.12)
  • GitHub Check: unit_tests (3.11)
  • GitHub Check: unit_tests (3.10)
  • GitHub Check: unit_tests (3.9)
🔇 Additional comments (2)
leverage/_casting.py (2)

1-8: LGTM! Clean module structure.

The module imports and structure are well-organized. Using yaml.safe_load is a secure choice for parsing.


10-19: Well-documented function signature.

The function signature and docstring clearly explain the purpose and behavior. The type hints are appropriate for this use case.

@exequielrafaela
Copy link
Member Author

@exequielrafaela exequielrafaela changed the title Enhancement | Issue #21 | Implement typed argument casting Enhancement | Issue #21 | OPT-1 | Implement typed argument casting Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants