Giter Site home page Giter Site logo

Ensure lists of items work about cliche HOT 7 OPEN

kootenpv avatar kootenpv commented on August 24, 2024
Ensure lists of items work

from cliche.

Comments (7)

antimirov avatar antimirov commented on August 24, 2024

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.

kootenpv avatar kootenpv commented on August 24, 2024

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.

pykenny avatar pykenny commented on August 24, 2024

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, through nargs='+'. 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 from argparse's behavior on nargs='+' constraint (stop and show violation of the constraint).

  • Trailing positional arguments (variable number of arguments, or *args in general) is not supported get 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 into rm 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 that items 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:
    my_application command item_01
    will append item_01 to the internal list.
  • Passing multiple arguments:
    my_application command item_01 item_02 item_03
    will append item_01, item_02, and item_03 to the internal list.
  • Passing no argument:
    my_application command
    will ring alert and print help doc again to correct usage.

from cliche.

pykenny avatar pykenny commented on August 24, 2024

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.

kootenpv avatar kootenpv commented on August 24, 2024

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.

pykenny avatar pykenny commented on August 24, 2024

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 the fn example above, the internal ArgumentParser instance accepts empty collection for items, 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 of item [items ...], or even item ...)

from cliche.

pykenny avatar pykenny commented on August 24, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.