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

Type inference #1

Merged
merged 14 commits into from
Apr 27, 2024
Merged

Type inference #1

merged 14 commits into from
Apr 27, 2024

Conversation

dhpitt
Copy link
Collaborator

@dhpitt dhpitt commented Feb 8, 2024

Argparse directly takes custom Callable functions as a type.

This PR:

  • creates a custom type inferencer class
  • supports strict and loose typing (e.g. inferring a numeric value of None)
  • supports passing iterables of any type into the command line

elif var.lower() == 'false':
return False
else:
raise ArgumentTypeError()
Copy link
Owner

Choose a reason for hiding this comment

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

So I think one thing is that we'd want to allow e.g. int : if a user has False or None in the config, they might want to pass in another param.

Perhaps we could express these as just a "priority" list of types?

return float(var)
elif var.isnumeric():
return int(var)
else:
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe we can default to str and support None?

@@ -62,7 +62,13 @@ def read_conf(self, config=None, **additional_config):
parser = argparse.ArgumentParser(description='Read the config from the commandline.')
for key, value in iter_nested_dict_flat(config, return_intermediate_keys=self.overwrite_nested_config):
if self.infer_types and value is not None:
parser.add_argument(f'--{key}', type=type(value), default=value)
# use type inferencing callable if available, otherwise strictly infer type
if type(value) == int or type(value) == float:
Copy link
Owner

Choose a reason for hiding this comment

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

Do you think we should tie the parser to ArgParse Specifically or should we make it generic?

e.g.

class TypeInferencer:
    def __init__(self, original_type, strict=False):
        ...
    
    def infer(self, var):
        if self.strict:
            return original_type(var)
        else:
            # infer type smartly

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this may cause issues, since argparse will infer bool('False') => True

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Where should the inference go if not in between the parser and the config?

Copy link
Owner

Choose a reason for hiding this comment

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

Right that's what I mean -- we need to have an option to use our own type inference rather than relying on argparse which can be too rigid. It can be just in a separate file (e.g. type_inference.py and just used in the argparse config)

@dhpitt dhpitt changed the title Type inference [DRAFT] Type inference Mar 14, 2024
Copy link
Owner

@JeanKossaifi JeanKossaifi left a comment

Choose a reason for hiding this comment

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

It looks great, thanks @dhpitt -- just realized we have a slight inconsistency with the arg name.

src/configmypy/argparse_config.py Outdated Show resolved Hide resolved
@JeanKossaifi
Copy link
Owner

Thanks @dhpitt, merging!

@JeanKossaifi JeanKossaifi merged commit 836382b into JeanKossaifi:main Apr 27, 2024
1 check passed
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