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

Ignoring an argument for typer command #506

Open
7 tasks done
lvijnck opened this issue Nov 17, 2022 · 5 comments
Open
7 tasks done

Ignoring an argument for typer command #506

lvijnck opened this issue Nov 17, 2022 · 5 comments
Labels
investigate question Question or problem

Comments

@lvijnck
Copy link

lvijnck commented Nov 17, 2022

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the Typer documentation, with the integrated search.
  • I already searched in Google "How to X in Typer" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to Typer but to Click.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

def serialize_dfs(func):
    """Decorator function to automatically (de)-serialize input and output
    dataframes for the function. It leverages the `df_path` and `df_output_path`
    kwargs to serialize input and output dataframes respectively.

    Args:
        func: function to decorate
    Returns:
        List of deduplicated column names
    """
    def wrapper(
        *args,
        dataframe: Optional[pd.DataFrame] = None,
        df_path: Optional[str] = None,
        df_output_path: Optional[str] = None,
        **kwargs
    ):
        # When df path specified, load it and pass it into the function
        if df_path:
            dataframe = pd.read_csv(df_path)

        # Invoke original function
        result: pd.DataFrame = func(*args, dataframe=dataframe, **kwargs)

        # When output path specified, serialize it into output
        if df_output_path:
            result.to_csv(df_output_path, index=False)

        return result

    return wrapper

@app.command()
@serialize_dfs
def expand_columns(
    dataframe: pd.DataFrame = typer.Argument(lazy=True, default=None, formats=[""], hidden=True, expose_value=False),
    keys_col: str = "metadata_name",
    values_col: str = "metadata_value",
    col_format: str = "{column_name}{num}",
) -> pd.DataFrame:
   # ... logic here

Description

I have a few functions that I want to type that handle dataframes (both as input and output). I do have a decorator that allows for specifying the dataframes as paths (as opposed to the objects).

Out of this decorator, I now wish to construct a Typer command. Though I keep getting the following error:

RuntimeError: Type not yet supported.

Is there an option to completely ignore an argument to the Typer CLI? I tried:

  • Hidden=True
  • Default=None
  • Expose_value=False
  • Lazy=True

Operating System

macOS

Operating System Details

No response

Typer Version

typer==0.6.1

Python Version

3.9

Additional Context

No response

@lvijnck lvijnck added the question Question or problem label Nov 17, 2022
@lvijnck lvijnck closed this as not planned Won't fix, can't repro, duplicate, stale Nov 17, 2022
@tiangolo
Copy link
Member

I assume you solved it, thanks for closing the issue 👍

@lvijnck
Copy link
Author

lvijnck commented Nov 20, 2022

Hiya @tiangolo! I assumed I solved it, but re-opening as I am still unable to skip the argument.

@lvijnck
Copy link
Author

lvijnck commented Dec 6, 2022

Any ideas on how to solve this one? For the moment being I omitted my type hints but it's far from ideal.

@dyollb
Copy link

dyollb commented Dec 16, 2022

Have a look at my little package sitk-cli . I do something very similar, just for images. The function make_cli replaces arguments of type image with pathlib.Path and does loading/saving.

I use this concept with typer to create command lines from library code.

import SimpleITK as sitk
import typer

from sitk_cli import make_cli


def fill_holes_slice_by_slice(mask: sitk.Image) -> sitk.Image:
    mask = mask != 0
    output = sitk.Image(mask.GetSize(), mask.GetPixelID())
    output.CopyInformation(mask)
    for k in range(mask.GetSize()[2]):
        output[:, :, k] = sitk.BinaryFillhole(mask[:, :, k], fullyConnected=False)
    return output


if __name__ == "__main__":
    typer.run(make_cli(fill_holes_slice_by_slice))

@mwaddoups
Copy link

Just a quick note for anyone else that I ran into this, and the simplest way I could find to skip an option is the below annotation.

skipped_option = typer.Option(parser=lambda _: _, hidden=True, expose_value=False)

Which you can use as e.g.

def foo(a: int, b: Annotate[str, skipped_option] = 'some default'): ...

This works because

  1. hidden=True - hides it from display in the arg list
  2. expose_value=False - stops any parsed value from being parsed
  3. parser=lambda _: _ - indicates that any value passed to the parser should be maintained.

(The parser argument is the key part missing from the start of this issue).

It would be great to have this as a simpler documented feature - but I'm not sure how easy this would be?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate question Question or problem
Projects
None yet
Development

No branches or pull requests

4 participants