-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Command-line argument parsing #756
Comments
I'd never thought about this but it sounds like a great idea. A few thoughts in no particular order:
Since this is just a new feature and shouldn't have any backwards compatibility problems, I think we should delay it until after v1? |
I want to use the feature. I think CLI argument parsing match pydantic absolutely. I write my thoughts.
|
see #721 (comment), aliases should use
should use
You mean ansi colours? If so, I built this when developing python-devtools, it's not that hard at least for unix platforms. We could either make devtools an optional dependency or copy some of that logic. However I don't think it's required for the first release, also I'm not convinced coloured error messages or help would ever be that useful - please suggest a CLI that makes helpful use of colours in these scenarios? |
Sorry, I never have read the comment. Yes, ANSI colors. |
beets makes a useful use of colors as well
Le sam. 17 août 2019 à 6:58 PM, Koudai Aono <notifications@github.com> a
écrit :
… Sorry, I never have read the comment.
Yes, ANSI colors.
I agree that it's not required for the first release.
A few commands have sub-command, options, description, default as help
command.
The help command makes a console screen is filled a lot of words.
If CLI draws words with colors, I think it's more readable for us.
But, I don't know another user need my suggestion.
serverless command looks good to me.
[image: ss2019-08-18 2 52 03]
<https://user-images.githubusercontent.com/630670/63215570-775cbc00-c163-11e9-8cee-df0658deecd4.png>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#756>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAINSPUQYFVVRPYVQKFU3MTQFA333ANCNFSM4IMLZCTA>
.
|
Agreed with the above.
After some thought, I'm leaning toward a classmethod for this, rather than config. I think it could be nice to be able to choose to from either the environment or the command line (without needing to change the class definition), and I think a method would make it easier to do that flexibly. Also, I think it would be easier to have cli-parsing-specific settings as arguments to the method (rather than extra config settings), such as a bool
Another option would be a custom type
I think this makes sense.
I'd be fine with either
Agreed this could be nice; I think there is a lot of room for cool APIs here. I think this could be supported by extra custom types later.
Agreed. |
I would love something like this as well! One request is I have is that the API should be able to take in a string or list of strings instead of assuming that this will be done only as a command line parser (sys.argv). My use case is for chat bots where a command handler would be wrapped by a decorator that parses and passes the given object to the handler. Something like this class KickUserArgs(BaseModel):
id: int
silent: FlagArgument()
@cli_parser(KickUserArgs)
def kick_user_command(ctx, args):
assert isinstance(args, KickUserArgs) |
@samuelcolvin I've spent some more time thinking about this and I think I'm less interested in I've actually been using @tiangolo's awesome typer package (which is basically just click with much better static typing, and, in my opinion at least, an improved API) and have found it to ergonomically capture the vast majority of my practical needs working with a CLI. It doesn't offer the full power of pydantic for parsing, but to the extent that that is even necessary (basic types seem to get you pretty far with CLIs), I think we might be better served by adding pydantic integration there rather than adding CLI integration here. I'm going to close this issue but I'm happy to reopen it if there is still interest. |
Agreed. I hadn't seen typer, looks great. Perhaps worth creating an issue there and linking to this to at least discuss pydantic integration? Perhaps using #1179? |
I'm glad you're liking Typer! I came just to note that Typer's API is clearly inspired by Pydantic, as FastAPI was inspired (and powered) by Pydantic. |
First of all thanks for the two great libraries! I have been starting to use both for CLI parsing and configuration management. I think it would be great to have Pydantic integration in Typer given that the former already has all the parsing and validation functionality needed (including JSON parsing). In fact, using
already works with CLI examples I have been testing. However, there is redundancy in the type definitions of course. |
@dmontagu I'm believe I had a similar need for a thin layer that enables Pydantic data models to be loaded from command line args or from JSON files. This resulted in pydantic-cli with several examples here and is perhaps similar in spirit to Typer. Here's a simple example: from pydantic import BaseModel
from pydantic_cli import run_and_exit
class Options(BaseModel):
input_file: str
max_records: int
def example_runner(opts: Options) -> int:
print(f"Mock example running with {opts}")
return 0
if __name__ == "__main__":
run_and_exit(Options, example_runner, description=__doc__, version="0.1.0") |
@mpkocher pydantic-cli is exactly what my group has been looking for! We've been interested in using Pydantic, but have a common pattern of using a combination of JSON files and command line args to define settings for scripts (sometimes with the addition of environment vars). I looked into using Pydantic+Typer, but this still requires duplicating the model specification, has some bugs when using non-basic types, and it gets a bit messy to load settings from both JSON and command line (where each may be partial and only the merged results should be checked). I really like the rich types defined in Pydantic and look forward to seeing pydantic-cli extended to include all types supported by pydantic. I think it would make the most sense for this CLI generation functionality, including JSON settings parsing to be included directly in pydantic. @samuelcolvin is there any plan to add this feature? I was surprised that this feature request was closed since there seemed to be community interest in the feature and there still remains no complete solution... |
I haven't tried pydantic-cli yet. I will. I closed this because of typer, but having used typer I find it annoying - mostly because it's a wrapper of click and limitations caused by that. I'd love a cli implementation based on pydantic but I'm struggling to provide support for pydantic as it is, another massive feature like CLI support doesn't seem sensible within this repo therefore. |
@samuelcolvin Thanks for the update. I empathize with the constraints on your time and really appreciate all of the time and effort that you've been putting into pydantic. I tried out pydantic-cli yesterday and feel that it does a good job of adding CLI support to simple pydantic models. I'll think more about how to extend it further to support more complex pydantic models and use cases, and will work with @mpkocher to improve pydantic-cli to be a complete CLI solution for pydantic models. |
I started a thread over at mpkocher/pydantic-cli#23 but I figured I'd mention it here as well. It's a super rough PoC just to see if the concept - leveraging a bit of metaprogramming and introspection - has any traction. Theoretically, using a custom type hint that accepts the metadata needed to populate CLI options (argparse.Action in this case) works, I just need to massage the data flow a bit more and remove the redundancy which can be inferred from inspection or the Pydantic schema. If people think this is a cool approach, I'll keep hacking on it. I actually don't think it would take much code to get CLI functionality into pydantic. |
Pydantic 1.8.0 introduced the an API to set custom "settings sources" (see #2107). I used this API to create a click-based CLI settings source. It's basically a bridge between click and pydantic. I just noticed this thread and thought that I would mention it as an alternative. Highlights:
Because it's just a "settings source", you can easily compose it with other setting sources (environment variables, secrets, JSON, TOML, etc). Code is here: https://github.com/sbtinstruments/cyto/blob/master/cyto/settings/sources/cli/_cli.py |
@frederikaalund Looks good. I've added https://github.com/mpkocher/pydantic-cli#other-related-tools |
Integration between pydantic and CLI would be very helpful. I've returned to the issue of the lack of coordination between config and CLI in my scientific computing work. I've created a tool to save dependency graphs of expensive nested analyses for my own work in a way that facilitates reproducibility, efficiency, and -- hopefully -- sharing, and want to make it publicly available, but one of the issues I keep having to address is the lack of coordination between a potentially massive and complex configuration space (one that contains all parameters for all dependencies) and CLI. Generally the config has not been my focus, but now need to address it more head on. |
Glad you like it. 👍 It's on my to-do list to make some documentation for this part of cyto. |
Apologies if this isn't totally on topic, but it's been in my liminal space and I figured I would share some of my findings. I've recently done a survey of the current python CLI frameworks out there. The viable libraries I've found are argparse, click, docopt, fire, typer, plumbum, and cleo. I think hydra/omegaconf may also have CLI parsing? Not a comprehensive list. None seem to really be a drop-in fit for a |
thanks @xkortex for the CLI thoughts as I am naive -- I've only used argparse, and only glanced at cleo due to its reliance on docstrings which won't work for my use case. I'll look for the more manual API. |
Btw, I use I chose click over the alternatives because click is popular (10.6K stars on GitHub). That gives an indirect promise of maintenance and stability. Also, because typer uses click under the hood, which is a solid stamp of approval in my book. All that being said, I welcome anyone to have a go at an, e.g., cleo-based pydantic settings source. 👍 Maybe you can even re-use some elements from cyto. :) |
Ah, that's good to know that there's a non-decorator API for
from cleo.helpers import argument, option
flag_all = option("--all", "-a", "Do all the things (implementation dependent)")
volume = option("--volume", "-v", "Map paths based on bind mounts", flag=False, default=None, multiple=True)
...etc...
class BasicIoOptions(pydantic.BaseModel):
input_uri: pydantic.FilePath
output_dir: Optional[str]
output_uri: Optional[str]
config_uri: Optional[str]
verbose: Optional[Union[str, bool]] = False
dryrun: Optional[bool] = False
class Config:
extra = "allow"
allow_mutation = False
from cleo import Command
from mymodule.app import opts
from mymodule.util.helpers import dash_to_underscore
from mymodule.subcommand.core import entrypoint, BasicIoOptions
class RunSubCmd(Command):
name = "subcommand"
description = """Run subcommand"""
options = [
opts.input_uri,
opts.output_dir,
opts.output_uri,
opts.manifest_uri,
opts.flag_dry,
]
def handle(self):
tmp = dash_to_underscore(self.option())
args = BasicIoOptions.parse_obj(tmp)
result = entrypoint(args) I could probably get fancy and figure out how to get the pydantic I'm definitely going to be looking through |
I stumbled upon this thread as I was about to open a similar feature request. Consider this a vote to reopen. My thinking is that just like The syntax I have in mind for Personally I don't feel the need to support positional arguments as that would be more complex to design (I have a few ideas but none is perfect or as syntactically clear as I'd like). Thoughts? ¹ It's still settings we're talking about here: no real need to put the functionality on a separate class, is there? Centralising settings seems to be one of the main goals of |
For those interested, this has been resurrected in pydantic/pydantic-settings#209. |
Feature Request
I would really like a lightweight CLI-argument parsing class, similar to
BaseSettings
.These days I always find myself using
BaseSettings
whenever I need to read something from the environment. Using this class is so convenient that I have started to eschew the use of arguments for lightweight scripts and instead just reading values from the environment (and using pydantic to parse them).Taking a step back, though, it seems like it might be nice to just have a built-in class like
BaseSettings
for parsing command line arguments, maybeBaseCLIArguments
? I always find myself struggling to remember the syntax for argparse; I personally think this is a great use case for pydantic.I know there are lots of other libraries that handle command line argument parsing, but given how little effort I think it would take to integrate this with pydantic, I would much prefer to not need to learn (and remember) yet another tool.
I wouldn't mind if it were highly opinionated in the interest of simplicity; I just want an easy way to get parsed command line arguments using patterns I already use daily (namely,
BaseModel
).(Either way I'll probably implement this for myself, but I will put more care into it if there is any interest in upstreaming it. Hence the issue.)
The text was updated successfully, but these errors were encountered: