Comments (7)
How to know when the list stops then? The comma is more explicit. Or you can make it hackable, like a separator definition in a doctring.
from cliche.
It's already implemented, it's done by spaces actually as is custom in bash:
--some-list 1 2 3 4
and you have to use quotes to separate the args if a space occurs in them.
I think it would be difficult to implement in a different way.
from cliche.
Just saw two issues with list options/arguments:
-
In
argparse
, it is allowed to add constraint requiring passing at least one item to a list option, throughnargs='+'
. From source code seems that it's possible to indicate "1 or more" constraint through giving default value (a non-empty collection) as a hint, but that only matters in descriptions shown on help doc, and the generated parser doesn't prevent users from passing an empty list without getting warned, different fromargparse
's behavior onnargs='+'
constraint (stop and show violation of the constraint). -
Trailing positional arguments (variable number of arguments, or
*args
in general)is not supportedget skipped instead of turning into "0 or more" constraint (Updated: 2022/08/25). One common example for this kind of design is passing multiple targets intorm
command without declaring option name (rm file ...
).
Currently if I write:# my_application.py @cli() def command(item: str, *items: str): pass
and run
my_application command --help
, from help text it's pretty clear thatitems
gets ignored.
My current use case for this type of requirement is appending a set of names to internal reference list for the application. Take the command
function above as example, the generated application should behave like this:
- Passing one argument:
will append
my_application command item_01
item_01
to the internal list. - Passing multiple arguments:
will append
my_application command item_01 item_02 item_03
item_01
,item_02
, anditem_03
to the internal list. - Passing no argument:
will ring alert and print help doc again to correct usage.
my_application command
from cliche.
Also it's kind of awkward to use a list parameter with default value to indicate variable number of arguments with "1 or more" constraint like this...
def command(items: List[str] = ['default_00']):
# ...
... since Python linters (such as PyCharm's builtin linter) often captures mutable default arguments to avoid possible runtime errors.
Of course workaround exists, like using tuple, which is how *args
exactly works in Python:
from typing import Tuple
def command(items: Tuple[str, ...] = ('default_00', ))
# ...
Or even using more generic type in typing annotation:
from collections.abc import Sequence
def command(items: Sequence[str] = ('default_00', ))
# ...
But to me they're not so intuitive as the one proposed earlier:
def command(
item: str, # At least one string
*items: str # and more are accepted as well
):
# ...
Plus in my use case there's no default value when users pass nothing to the list argument. They should be warned instead of accidentally appending extra data (from default values) to the internal list.
from cliche.
Yea I have been using tuple
for this which pleases mypy.
If you want to do verification of how many elements, it's best to use that in the function itself (as also the function could be called not as cli
but from within a program)
@cli
def fn(items: tuple[str, ...] = ()):
if not items:
raise ValueError()
from cliche.
Just realized that cliche
still prints "1 or more" in help document even if passing empty collection as default value for an option/kwarg... The problem is usage generated from help doc will become -i [ITEMS [ITEMS ...]]
, which contradicts with the "1 or more" statement.
Also flag is strictly required for this approach, so you'll need to write fn -i item_01 item_02 item_03
instead of fn item_01 item_02 item_03
, which is kind of inconvenient.
In this case I'll prefer implementing "1 or more" positional argument constraint in this way as workaround:
# my_application.py
@cli
def command(
item: str,
items: Tuple[str, ...],
):
# ...
- At least one positional argument is required so running
my_application command
does not work. - Trailing positional arguments is available by running things like
my_application command item_01 item_02 item_03
- Generated
ArgumentParser
instance has behavior that aligns with help document (for thefn
example above, the internalArgumentParser
instance accepts empty collection foritems
, while help document stating at least 1 element is required) - The only shortcoming I can think of is usage in help doc will look a bit cumbersome (
item [items [items ...]]
, instead ofitem [items ...]
, or evenitem ...
)
from cliche.
Another problem when defining positional arguments in this way below (should be invalid since we don't know how to set the boundary between items
and some_other_items
on trailing positional arguments, or one of the list arguments should be converted to option with "0 or more" constraint):
# my_application.py
@cli
def command(
item: str,
items: Tuple[str, ...],
some_other_items: Tuple[str, ...],
):
"""
:param item: An item
:param items: Additional items
:param some_other_items: Some other items
"""
# ...
Generated usage (from ArgumentParser
?):
my_application command [-h] [--notraceback] [--cli] [--pdb] [--timing] [--raw] [-s]
Positional argument section in help doc:
POSITIONAL ARGUMENTS:
item |str| An item
items |0 or more of: str| Additional items
some-other-items |0 or more of: str| Some other items
from cliche.
Related Issues (12)
- Py 3.10 compatibility
- Pandas 1.4.2 throws a FutureWarning which is triggered by cliche
- Readme claiming deprecated/non-existent functionality in CLI tool HOT 5
- Compare with typer and docopt
- type object 'int' has no attribute 'split' error HOT 1
- If no type annotation, get the type from a default value if available
- Compare with clize HOT 1
- An argument to a function cannot be named "command"
- Enum argument option in alphabetical order HOT 2
- Installing bin exec in a specific dir HOT 3
- Grouping HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cliche.