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

Contributing and tools #812

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ on:
- cron: "0 0 * * 1"

jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- uses: pre-commit/[email protected]

test:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -40,8 +49,6 @@ jobs:
- name: Install Dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: pip install -r requirements-tests.txt
- name: Lint
run: bash scripts/lint.sh
- run: mkdir coverage
- run: bash ./scripts/test-files.sh
- name: Test
Expand Down
11 changes: 10 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.0
rev: v0.3.7
hooks:
- id: ruff
args:
- --fix
- id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.10.0
hooks:
- id: mypy
files: ^typer/
additional_dependencies:
- "click"
- "rich"

ci:
autofix_commit_msg: 🎨 [pre-commit.ci] Auto format from pre-commit.com hooks
autoupdate_commit_msg: ⬆ [pre-commit.ci] pre-commit autoupdate
177 changes: 106 additions & 71 deletions docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,82 @@ First, you might want to see the basic ways to [help Typer and get help](help-ty

If you already cloned the repository and you know that you need to deep dive in the code, here are some guidelines to set up your environment.

### Virtual environment with `venv`
### Pre-commit hooks

We use <a href="https://pre-commit.com/" class="external-link" target="_blank">pre-commit</a> to run checks and formatting before submitting code for review.

#### Install pre-commit

We recommend <a href="https://pipx.pypa.io/" class="external-link" target="_blank">pipx</a> to install pre-commit in an isolated environment.

=== "pipx"

<div class="termy">

```console
$ pipx install pre-commit
```

</div>

=== "pip"

<div class="termy">

```console
$ pip install pre-commit
```

</div>

=== "Homebrew"

<div class="termy">

```console
$ brew install pre-commit
```

</div>

=== "Conda"

<div class="termy">

```console
$ conda install pre-commit
```

</div>

#### Activate hooks on the repository

By activating the hooks we instruct git to run the checks before every commit.

<div class="termy">

```console
$ pre-commit install
```

</div>

!!! note
It's only needed once. From that point on, every time you commit, the pre-commit hooks will run, checking and formating the files you are committing.

#### Run checks manually

You can also manually run the checks on all files with:

<div class="termy">

```console
$ pre-commit run --all-files
```

</div>

### Virtual environment

You can create a virtual environment in a directory using Python's `venv` module:

Expand All @@ -18,7 +93,7 @@ $ python -m venv env

That will create a directory `./env/` with the Python binaries and then you will be able to install packages for that isolated environment.

### Activate the environment
#### Activate the environment

Activate the new environment with:

Expand Down Expand Up @@ -87,54 +162,18 @@ If it shows the `pip` binary at `env/bin/pip` then it worked. 🎉

This makes sure that if you use a terminal program installed by that package (like `flit`), you use the one from your local environment and not any other that could be installed globally.

### Flit
### Install Typer

**Typer** uses <a href="https://flit.readthedocs.io/en/latest/index.html" class="external-link" target="_blank">Flit</a> to build, package and publish the project.

After activating the environment as described above, install `flit`:
With the virtual environment activated, you can install Typer in "editable" mode:

<div class="termy">

```console
$ pip install flit

---> 100%
$ pip install --editable .
Copy link
Member

Choose a reason for hiding this comment

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

This does require at least pip 21.3, as it'll otherwise fail with a note about not finding setup.py or setup.cfg. So it might be good to add that as a note here as well.

```

</div>

Now re-activate the environment to make sure you are using the `flit` you just installed (and not a global one).

And now use `flit` to install the development dependencies:

=== "Linux, macOS"

<div class="termy">

```console
$ flit install --deps develop --symlink

---> 100%
```

</div>

=== "Windows"

If you are on Windows, use `--pth-file` instead of `--symlink`:

<div class="termy">

```console
$ flit install --deps develop --pth-file

---> 100%
```

</div>

It will install all the dependencies and your local Typer in your local environment.

#### Using your local Typer

If you create a Python file that imports and uses Typer, and run it with the Python from your local environment, it will use your local Typer source code.
Expand All @@ -143,36 +182,6 @@ And if you update that local Typer source code, as it is installed with `--symli

That way, you don't have to "install" your local version to be able to test every change.

### Format

There is a script that you can run that will format and clean all your code:

<div class="termy">

```console
$ bash scripts/format.sh
```

</div>

It will also auto-sort all your imports.

For it to sort them correctly, you need to have Typer installed locally in your environment, with the command in the section above using `--symlink` (or `--pth-file` on Windows).

### Format imports

There is another script that formats all the imports and makes sure you don't have unused imports:

<div class="termy">

```console
$ bash scripts/format-imports.sh
```

</div>

As it runs one command after the other and modifies and reverts many files, it takes a bit longer to run, so it might be easier to use `scripts/format.sh` frequently and `scripts/format-imports.sh` only before committing.

## Docs

The documentation uses <a href="https://www.mkdocs.org/" class="external-link" target="_blank">MkDocs</a>.
Expand Down Expand Up @@ -218,6 +227,32 @@ That way, you can edit the documentation/source files and see the changes live.

## Tests

Typer uses <a href="https://docs.pytest.org/" class="external-link" target="_blank">pytest</a> for testing.

Make sure you have the development dependencies installed:

<div class="termy">

```console
$ pip install -e requirements-tests.txt
```

</div>

### Running tests

To run the tests, you can use the `pytest` command:

<div class="termy">

```console
$ pytest -v
```

</div>

### Coverage report

There is a script that you can run locally to test all the code and generate coverage reports in HTML:

<div class="termy">
Expand Down
2 changes: 0 additions & 2 deletions requirements-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,3 @@ pytest-cov >=2.10.0,<5.0.0
coverage[toml] >=6.2,<8.0
pytest-xdist >=1.32.0,<4.0.0
pytest-sugar >=0.9.4,<0.10.0
mypy ==1.4.1
ruff ==0.2.0
6 changes: 0 additions & 6 deletions scripts/format.sh

This file was deleted.

8 changes: 0 additions & 8 deletions scripts/lint.sh

This file was deleted.

15 changes: 5 additions & 10 deletions tests/test_ambiguous_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ def test_forbid_default_value_in_annotated_argument():
# This test case only works with `typer.Argument`. `typer.Option` uses positionals
# for param_decls too.
@app.command()
def cmd(my_param: Annotated[str, typer.Argument("foo")]):
... # pragma: no cover
def cmd(my_param: Annotated[str, typer.Argument("foo")]): ... # pragma: no cover

with pytest.raises(AnnotatedParamWithDefaultValueError) as excinfo:
runner.invoke(app)
Expand Down Expand Up @@ -64,8 +63,7 @@ def test_forbid_annotated_param_and_default_param(param, param_info_type):
app = typer.Typer()

@app.command()
def cmd(my_param: Annotated[str, param()] = param("foo")):
... # pragma: no cover
def cmd(my_param: Annotated[str, param()] = param("foo")): ... # pragma: no cover

with pytest.raises(MixedAnnotatedAndDefaultStyleError) as excinfo:
runner.invoke(app)
Expand All @@ -83,8 +81,7 @@ def test_forbid_multiple_typer_params_in_annotated():
@app.command()
def cmd(
my_param: Annotated[str, typer.Argument(), typer.Argument()],
):
... # pragma: no cover
): ... # pragma: no cover

with pytest.raises(MultipleTyperAnnotationsError) as excinfo:
runner.invoke(app)
Expand Down Expand Up @@ -121,8 +118,7 @@ def make_string():
@app.command()
def cmd(
my_param: Annotated[str, param(default_factory=make_string)] = "hello",
):
... # pragma: no cover
): ... # pragma: no cover

with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo:
runner.invoke(app)
Expand Down Expand Up @@ -171,8 +167,7 @@ def make_string():
@app.command()
def cmd(
my_param: str = param("hi", default_factory=make_string),
):
... # pragma: no cover
): ... # pragma: no cover

with pytest.raises(DefaultFactoryAndDefaultValueError) as excinfo:
runner.invoke(app)
Expand Down
12 changes: 4 additions & 8 deletions typer/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ def Option(
path_type: Union[None, Type[str], Type[bytes]] = None,
# Rich settings
rich_help_panel: Union[str, None] = None,
) -> Any:
...
) -> Any: ...


# Overload for Option created with custom type 'click_type'
Expand Down Expand Up @@ -132,8 +131,7 @@ def Option(
path_type: Union[None, Type[str], Type[bytes]] = None,
# Rich settings
rich_help_panel: Union[str, None] = None,
) -> Any:
...
) -> Any: ...


def Option(
Expand Down Expand Up @@ -305,8 +303,7 @@ def Argument(
path_type: Union[None, Type[str], Type[bytes]] = None,
# Rich settings
rich_help_panel: Union[str, None] = None,
) -> Any:
...
) -> Any: ...


# Overload for Argument created with custom type 'click_type'
Expand Down Expand Up @@ -361,8 +358,7 @@ def Argument(
path_type: Union[None, Type[str], Type[bytes]] = None,
# Rich settings
rich_help_panel: Union[str, None] = None,
) -> Any:
...
) -> Any: ...


def Argument(
Expand Down
6 changes: 3 additions & 3 deletions typer/rich_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@
STYLE_ABORTED = "red"
_TERMINAL_WIDTH = getenv("TERMINAL_WIDTH")
MAX_WIDTH = int(_TERMINAL_WIDTH) if _TERMINAL_WIDTH else None
COLOR_SYSTEM: Optional[
Literal["auto", "standard", "256", "truecolor", "windows"]
] = "auto" # Set to None to disable colors
COLOR_SYSTEM: Optional[Literal["auto", "standard", "256", "truecolor", "windows"]] = (
"auto" # Set to None to disable colors
)
_TYPER_FORCE_DISABLE_TERMINAL = getenv("_TYPER_FORCE_DISABLE_TERMINAL")
FORCE_TERMINAL = (
True
Expand Down
Loading