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

Create argument classes #109

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

Conversation

avkoll
Copy link
Contributor

@avkoll avkoll commented Aug 9, 2024

I created the argument_types.py class file similar to what @K-dash had suggested but didn't want to start integrating it into the cli.py yet since that was a huge task. I was testing it by checking and verifying the output of the following code in run() in cli.py.

Example Usage:

default_arguments = Arguments()
print(json.dumps(default_arguments.model_dump(), indent=4))

arguments = Arguments(**parsed_arguments)
# parse inputs
parsed_input = ArgumentMappings.parse_input({"lat": lat, "long": long})
updated_arguments = default_arguments.model_copy(update=parsed_input)

# update arguments with inputs
arguments_dict = updated_arguments.model_dump()
updated_arguments_dict = ArgumentMappings.set_output_values(args, arguments_dict)
arguments = updated_arguments.model_copy(update=updated_arguments_dict)

print("Updated arguments: ")
print(json.dumps(updated_arguments.model_dump(), indent=4))

for key, value in updated_arguments:
    if value is False:
        print("false")
    else:
        print(key)

I can write a test for this but wanted to open the PR incase anyone had any suggestions, if it looks good I can start writing the tests.

I wanted someone to check this before I started replacing stuff.

Summary by Sourcery

Add new classes Arguments and ArgumentMappings to manage and map command-line arguments with default values and multiple aliases. These classes include methods for parsing input and setting output values based on command-line arguments.

New Features:

  • Introduce Arguments class to define and manage various command-line arguments with default values.
  • Introduce ArgumentMappings class to handle multiple aliases for command-line arguments and provide methods for parsing input and setting output values.

Copy link
Contributor

sourcery-ai bot commented Aug 9, 2024

Reviewer's Guide by Sourcery

This pull request introduces a new file argument_types.py that defines two classes, Arguments and ArgumentMappings, to handle command-line arguments and their mappings. The Arguments class defines various arguments with default values, while the ArgumentMappings class provides methods to parse input data and update argument dictionaries based on command-line arguments. The changes are isolated to the new file and do not yet integrate with the existing cli.py file.

File-Level Changes

Files Changes
src/argument_types.py Introduced new argument handling classes (Arguments and ArgumentMappings) with methods for parsing input and setting output values based on command-line arguments.

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @avkoll - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider simplifying the argument handling structure by merging ArgumentMappings functionality into the Arguments class, utilizing Pydantic's built-in alias feature to reduce duplication and improve maintainability.
  • Add comprehensive docstrings and comments to explain the purpose and functionality of each class and method, particularly for complex operations like set_output_values.
  • Proceed with writing tests for this new argument handling system to ensure its correctness and facilitate future maintenance and refactoring.
Here's what I looked at during the review
  • 🟡 General issues: 5 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

description="Show precipitation probability",
)

alias_map: ClassVar[dict[str, list[str]]] = {
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Consider revising the alias mapping for clarity and consistency

The current alias mapping might lead to confusion, especially with aliases like 'hide_wave' for 'show_wave'. Consider using a more consistent naming scheme or restructuring this to make the relationship between aliases and their corresponding actions more explicit.

    alias_map: ClassVar[dict[str, list[str]]] = {
        "city": ["loc", "location"],
        "show_wave": ["sw"],
        "hide_wave": ["hw"],

return remapped_data

"""
TODO: write method to set location and update the dictionary
Copy link
Contributor

Choose a reason for hiding this comment

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

issue: Remove or implement the TODO comment

TODO comments should not be left in production code. Either implement the method to set location and update the dictionary, or remove this comment if it's no longer relevant.

"""

@classmethod
def set_output_values(cls, args, arguments_dictionary: dict) -> dict:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Refactor to use alias_map and reduce code duplication

The set_output_values method duplicates some of the logic from alias_map. Consider refactoring this method to use alias_map directly, which would reduce duplication and potential inconsistencies in the future.

Suggested change
def set_output_values(cls, args, arguments_dictionary: dict) -> dict:
@classmethod
def set_output_values(cls, args, arguments_dictionary: dict) -> dict:
return {cls.alias_map.get(arg, arg): value for arg, value in arguments_dictionary.items()}

}

@classmethod
def generate_mappings(cls) -> dict[str, str]:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (performance): Consider caching the result of generate_mappings

If generate_mappings is called frequently, it might be more efficient to compute the result once and store it, rather than creating a new dictionary on each call.

    @classmethod
    @functools.lru_cache(maxsize=None)
    def generate_mappings(cls) -> dict[str, str]:

return mappings

@classmethod
def parse_input(cls, data: dict) -> dict:
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Handle potential key conflicts in parse_input

The parse_input method doesn't handle the case where a key might be both a valid field name and an alias. Consider adding a check for this scenario to ensure consistent behavior.

Suggested change
def parse_input(cls, data: dict) -> dict:
@classmethod
def parse_input(cls, data: dict) -> dict:
alias_to_field_map = cls.generate_mappings()
field_to_alias_map = {v: k for k, v in alias_to_field_map.items()}
remapped_data = {}
for key, value in data.items():
if key in alias_to_field_map:
remapped_data[alias_to_field_map[key]] = value
elif key in field_to_alias_map:
remapped_data[key] = value

@ryansurf
Copy link
Owner

ryansurf commented Aug 12, 2024

@avkoll

Nice work! Looks good to me, go ahead and start the integration. I'm able to help if you run into any blocks

I left a brief review, I was confused on a couple lines


alias_map: ClassVar[dict[str, list[str]]] = {
"city": ["loc", "location"],
"show_wave": ["sw", "hide_wave", "hw"],
Copy link
Owner

Choose a reason for hiding this comment

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

Why is show wave mapped to both "sw" (which i assume means "show wave") and "hide_wave"?

"city": ["loc", "location"],
"show_wave": ["sw", "hide_wave", "hw"],
"show_large_wave": ["slw"],
"show_uv": ["suv", "hide_uv", "huv"],
Copy link
Owner

Choose a reason for hiding this comment

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

same as show wave

"show_large_wave": ["slw"],
"show_uv": ["suv", "hide_uv", "huv"],
"show_height": ["sh", "hide_height", "hh"],
"show_direction": ["sd", "hide_direction", "hdir"],
Copy link
Owner

Choose a reason for hiding this comment

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

same as show wave

@K-dash
Copy link
Collaborator

K-dash commented Aug 13, 2024

@avkoll
Thanks for your time!
Will review tonight.

gpt: bool = False


class ArgumentMappings(BaseModel):
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the implementation is as I expected, so it looks good!

If I may add a suggestion.
The fields in the ArgumentMappings class overlap with those in the Arguments class. Ideally, if possible, I think it would be better to consolidate all arguments into the Arguments class and create the final mapping dictionary based on the contents of the Arguments class.(For example, when implementing new arguments in the future, we would likely need to add fields to both classes, resulting in dual management, which could lead to reduced maintainability.)

However, I believe that realizing this would require modifications to the cli.py file as well, which could potentially be a substantial amount of work. Therefore, I'll leave the decision on whether to implement this up to you :)
It's perfectly fine to keep this as a future refactoring phase if you prefer!

@ryansurf How do you think?

Copy link
Owner

Choose a reason for hiding this comment

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

Agreed, it would be ideal to reduce any redundancy.

cli.py would indeed need to be revamped. Let us know what you want to do @avkoll !

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.

3 participants