Skip to content

Conversation

@MilkClouds
Copy link
Contributor

@MilkClouds MilkClouds commented Aug 15, 2025

What does this PR do?

Fixes #757

This PR enhances the logic for determining whether function/method parameters should be treated as required CLI arguments by implementing more sophisticated parameter kind-aware handling.

Problem: The current implementation uses a simple rule (is_required = default == inspect_empty) which doesn't properly account for Python's different parameter kinds. This conflates two different concepts:

  1. Python requirement semantics: Whether a parameter needs a value for the function to work
  2. CLI argument style: Whether to use positional args vs --flag style

This causes issues particularly with KEYWORD_ONLY parameters, which should always use the --flag style regardless of whether they have defaults, and should be properly marked as required when they don't have defaults. This design matches with CLI project, https://github.com/BrianPugh/cyclopts.

Solution: Introduced a more sophisticated parameter kind-aware approach:

  1. POSITIONAL_ONLY: Always required, can be positional
  2. POSITIONAL_OR_KEYWORD: Required if no default, can be positional
  3. KEYWORD_ONLY: Required if no default, must use --flag style
  4. VAR_POSITIONAL/VAR_KEYWORD: Skip entirely (unchanged behavior)
  5. None (fallback): Required if no default, can be positional (for programmatically created parameters)

Before/After Comparison

Consider this test function:

from typing_extensions import TypedDict, Unpack

class MyTestUnpackDict(TypedDict, total=False):
    a: int
    b: int

def main(posarg: int, *, kwarg: str, kwarg_default: str = "default", **kwargs: Unpack[MyTestUnpackDict]):
    pass

auto_cli(main, as_positional=True)

Before this PR:

usage: main.py [-h] [--config CONFIG] [--print_config[=flags]]
               [--kwarg_default KWARG_DEFAULT] [--print_shtab {bash,zsh,tcsh}]
               posarg kwarg a b

After this PR:

usage: main.py [-h] [--config CONFIG] [--print_config[=flags]] --kwarg KWARG
               [--kwarg_default KWARG_DEFAULT] --a A --b B
               [--print_shtab {bash,zsh,tcsh}]
               posarg

Key improvements:

  • KEYWORD_ONLY parameters (kwarg, a, b) now correctly use --flag style instead of being treated as positional arguments
  • ✅ Required KEYWORD_ONLY parameters are properly marked with --kwarg KWARG, --a A, --b B in the usage line
  • POSITIONAL_OR_KEYWORD parameters (posarg) can still become positional when appropriate
  • ✅ Works correctly with modern Python typing features like Unpack[TypedDict]
  • ✅ Maintains backward compatibility for all existing functionality

The core issue was that KEYWORD_ONLY parameters were incorrectly being treated as positional arguments when as_positional=True, which violates Python's parameter semantics. Now they correctly always use the --flag style as they should.

Before submitting

  • Did you read the contributing guideline?
  • Did you update the documentation? (readme and public docstrings) - n/a (internal logic improvement, no API changes)
  • Did you write unit tests such that there is 100% coverage on related code? (required for bug fixes and new features) - Existing tests cover the functionality and all pass
  • Did you verify that new and existing tests pass locally?
  • Did you make sure that all changes preserve backward compatibility?
  • Did you update the CHANGELOG with the pull request link? (not for typos, docs, test updates, or minor internal changes/refactors) - Will update after PR number is available

- Add sophisticated parameter kind-aware logic for determining CLI argument requirements
- Introduce is_option variable to separate Python semantics from CLI argument style
- Ensure KEYWORD_ONLY parameters always use --flag style and are properly marked as required
- Fix required attribute logic for parameters that can't be made positional
- Maintain full backward compatibility while improving edge case handling
- Add fallback case for programmatically created parameters without kind attribute
- Preserves backward compatibility for add_subclass_arguments and similar methods
- Fixes test failures in subclasses and link_arguments modules
- Add entry for improved parameter kind handling for argument requirement determination
- KEYWORD_ONLY parameters now correctly use --flag style
- Add test coverage for positional-only parameter handling
Copy link
Member

@mauvilsa mauvilsa left a comment

Choose a reason for hiding this comment

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

Makes sense what you propose here. I had not considered well the keyword-only cases. But sound more like a bug fix to me.

Thank you for contributing!

@mauvilsa mauvilsa added the bug Something isn't working label Aug 15, 2025
@MilkClouds
Copy link
Contributor Author

MilkClouds commented Aug 15, 2025

Thanks for the positive review! I'll have a look at your review and make revision in the near future.

MilkClouds and others added 8 commits August 17, 2025 06:49
Co-authored-by: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com>
Co-authored-by: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com>
Co-authored-by: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com>
Co-authored-by: Mauricio Villegas <5780272+mauvilsa@users.noreply.github.com>
@MilkClouds
Copy link
Contributor Author

@mauvilsa I finished revision, please have a review again.

Copy link
Member

@mauvilsa mauvilsa left a comment

Choose a reason for hiding this comment

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

Looking good, but more testing is needed.

@codecov
Copy link

codecov bot commented Aug 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (785af2c) to head (f2b2dc7).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #756   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           22        22           
  Lines         6884      6895   +11     
=========================================
+ Hits          6884      6895   +11     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member

@mauvilsa mauvilsa left a comment

Choose a reason for hiding this comment

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

I committed some changes to finish it off.

@mauvilsa mauvilsa merged commit 0177681 into omni-us:main Aug 18, 2025
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improving CLI args/option seperation logic to match expected keyword arguments behavior

2 participants