mypy_clean_slate


Namemypy_clean_slate JSON
Version 0.3.3 PyPI version JSON
download
home_pagehttps://github.com/geo7/mypy_clean_slate
SummaryCLI tool for providing a clean slate for mypy usage within a project.
upload_time2024-03-11 11:46:25
maintainer
docs_urlNone
authorGeorge Lenton
requires_python>=3.9,<4.0
licenseMIT
keywords mypy typing typehint type-hint
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Mypy Clean Slate


[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![PyPI Latest Release](https://img.shields.io/pypi/v/mypy-clean-slate.svg)](https://pypi.org/project/mypy-clean-slate/)
[![License](https://img.shields.io/pypi/l/mypy-clean-slate.svg)](https://github.com/geo7/mypy_clean_slate/blob/main/LICENSE)
[![image](https://img.shields.io/pypi/pyversions/mypy-clean-slate.svg)](https://pypi.python.org/pypi/mypy-clean-slate)
[![Actions status](https://github.com/geo7/mypy_clean_slate/workflows/CI/badge.svg)](https://github.com/geo7/mypy_clean_slate/actions)



CLI tool for providing a clean slate for mypy usage within a project

## Motivation

It can be difficult to get a large project to the point where `mypy --strict`
can be run on it. Rather than incrementally increasing the severity of mypy,
either overall or per module, `mypy_clean_slate` enables one to ignore all
previous errors so that `mypy --strict` (or similar) can be used almost
immediately. This enables all code written from that point on to be checked with
`mypy --strict` (or whichever flags are preferred), gradually removing the
`type: ignore` comments from that point onwards.

Often running `mypy_clean_slate` will cover all errors cleanly in a single pass,
but there are cases when not all error output is generated first time, and it
can be necessary to run a couple of times, checking the diffs. Example of this
scenario is given.

By default `mypy_clean_slate` works by parsing the output of `mypy --strict` and
adding the relevant `type: ignore[code]` to each line, though custom flags can
be passed to mypy instead. Only errors from the report are considered, notes are
not handled. Meaning something such as `error: Function is missing a type
annotation  [no-untyped-def]` will have `# type: ignore[no-untyped-def]`
appended to the end of the line, whereas `note: (Skipping most remaining errors
due to unresolved imports or missing stubs; fix these first)` will be ignored.
Errors relating to unused ignores (which might occur if code changes after
adding the initial ignore) can also be handled.

# Installation

```bash
pip install mypy-clean-slate
```

# Usage

[comment]: # (CLI help split)

```
usage: mypy_clean_slate [options]

CLI tool for providing a clean slate for mypy usage within a project.

Default expectation is to want to get a project into a state that it
will pass mypy when run with `--strict`, if this isn't the case custom
flags can be passed to mypy via the `--mypy_flags` argument.

options:
  -h, --help            show this help message and exit
  -r, --generate_mypy_error_report
                        Generate 'mypy_error_report.txt' in the cwd.
  -p PATH_TO_CODE, --path_to_code PATH_TO_CODE
                        Where code is that needs report generating for it.
  -a, --add_type_ignore
                        Add "# type: ignore[<error-code>]" to suppress all raised mypy errors.
  --remove_unused       Remove unused instances of "# type: ignore[<error-code>]" if raised as an error by mypy.
  -o MYPY_REPORT_OUTPUT, --mypy_report_output MYPY_REPORT_OUTPUT
                        File to save report output to (default is mypy_error_report.txt)
  --mypy_flags MYPY_FLAGS
                        Custom flags to pass to mypy (provide them as a single string, default is to use --strict)
```

[comment]: # (CLI help split)

See `./tests/test_mypy_clean_slate.py` for some examples with before/after.



# Examples

## Simple example

Given a project with only:

```txt
➜  simple_example git:(master) ✗ tree
.
`-- simple.py

0 directories, 1 file
```

Containing:

```python
# simple.py
def f(x):
    return x + 1
```

The report can be generated, and `simple.py` updated, using `mypy_clean_slate -ra`, resulting in:


```python
def f(x):  # type: ignore[no-untyped-def]
    return x + 1
```

And `mypy --strict` will now pass.

## Project example, using `pingouin`

Project `pingouin` is located at: https://github.com/raphaelvallat/pingouin, and
commit `ea8b5605a1776aaa0e89dd5c0e3df4320950fb38` is used for this example.
`mypy_clean_slate` needs to be run a couple of times here.

First, generate report and apply `type: ignore[<error code>]`

```sh
mypy_clean_slate -ra
```

Looking at a subset of `git diff`:

```diff

(venv) ➜ pingouin git:(master) ✗ git diff | grep 'type' | head
+import sphinx_bootstrap_theme # type: ignore[import]
+from outdated import warn_if_outdated # type: ignore[import]
+import numpy as np # type: ignore[import]
+from scipy.integrate import quad # type: ignore[import]
+ from scipy.special import gamma, betaln, hyp2f1 # type: ignore[import]
+ from mpmath import hyp3f2 # type: ignore[import]
+ from scipy.stats import binom # type: ignore[import]
+import numpy as np # type: ignore[import]
+from scipy.stats import norm # type: ignore[import]
+import numpy as np # type: ignore[import]
```

Changes are added and committed with message `'mypy_clean_slate first pass'` (commit message used makes no functional difference), and the report re-generated:

```bash
mypy_clean_slate -r
```

Which reports `Found 1107 errors in 39 files (checked 42 source files)`. So, re-running `mypy_clean_slate`

```bash
mypy_clean_slate -a
```

And looking again at the diff:

```diff

(venv) ➜ pingouin git:(master) ✗ gd | grep 'type' | head
+latex_elements = { # type: ignore[var-annotated]
+def setup(app): # type: ignore[no-untyped-def]
@@ -27,4 +27,4 @@ from outdated import warn_if_outdated # type: ignore[import]
+set_default_options() # type: ignore[no-untyped-call]
+def _format_bf(bf, precision=3, trim='0'): # type: ignore[no-untyped-def]
if type(bf) == str:
+def bayesfactor_ttest(t, nx, ny=None, paired=False, tail='two-sided', r=.707): # type: ignore[no-untyped-def]
+ def fun(g, t, n, r, df): # type: ignore[no-untyped-def]
+def bayesfactor_pearson(r, n, tail='two-sided', method='ly', kappa=1.): # type: ignore[no-untyped-def]
+ def fun(g, r, n): # type: ignore[no-untyped-def]
```

 Committing these with `'mypy_clean_slate second pass'`, and re-running `mypy_clean_slate -r` outputs the following:

```txt
(venv) ➜ pingouin git:(master) ✗ cat mypy_error_report.txt
Success: no issues found in 42 source files
```

Can now rebase / amend commits as necessary, but could now update CI/pre-commit or whatever to use `mypy --strict` (or a subset of its flags) going forwards.


# Handling of existing comments and `pylint`

Lines which contain existing comments such as:

```python
def ThisFunction(something): # pylint: disable=invalid-name
    return f"this is {something}"
```

Will be updated to:

```python
def ThisFunction(something):   # type: ignore[no-untyped-def] # pylint: disable=invalid-name
    return f"this is {something}"
```

As the `type:` comment needs to precede pylints.

# Issues

## Generating report

The report generation is pretty straightforward, `mypy . --strict --show-error-codes`, so might not be worth having as part of this script. The user can generate the report to a text file and just pass the path to that as an argument.

## Handling `-> None`

Report output for functions which don't return is pretty consistent, so these could be automated if considered worth it.

## Integration with other tooling

I've tried to consider `pylint` comments, but no doubt there are many other arguments for different tools which aren't taken into consideration.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/geo7/mypy_clean_slate",
    "name": "mypy_clean_slate",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "mypy,typing,typehint,type-hint",
    "author": "George Lenton",
    "author_email": "georgelenton@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/12/11/4fd24508ebad069fe0107263139e723e601a9ca5be11769e1730039350de/mypy_clean_slate-0.3.3.tar.gz",
    "platform": null,
    "description": "# Mypy Clean Slate\n\n\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![PyPI Latest Release](https://img.shields.io/pypi/v/mypy-clean-slate.svg)](https://pypi.org/project/mypy-clean-slate/)\n[![License](https://img.shields.io/pypi/l/mypy-clean-slate.svg)](https://github.com/geo7/mypy_clean_slate/blob/main/LICENSE)\n[![image](https://img.shields.io/pypi/pyversions/mypy-clean-slate.svg)](https://pypi.python.org/pypi/mypy-clean-slate)\n[![Actions status](https://github.com/geo7/mypy_clean_slate/workflows/CI/badge.svg)](https://github.com/geo7/mypy_clean_slate/actions)\n\n\n\nCLI tool for providing a clean slate for mypy usage within a project\n\n## Motivation\n\nIt can be difficult to get a large project to the point where `mypy --strict`\ncan be run on it. Rather than incrementally increasing the severity of mypy,\neither overall or per module, `mypy_clean_slate` enables one to ignore all\nprevious errors so that `mypy --strict` (or similar) can be used almost\nimmediately. This enables all code written from that point on to be checked with\n`mypy --strict` (or whichever flags are preferred), gradually removing the\n`type: ignore` comments from that point onwards.\n\nOften running `mypy_clean_slate` will cover all errors cleanly in a single pass,\nbut there are cases when not all error output is generated first time, and it\ncan be necessary to run a couple of times, checking the diffs. Example of this\nscenario is given.\n\nBy default `mypy_clean_slate` works by parsing the output of `mypy --strict` and\nadding the relevant `type: ignore[code]` to each line, though custom flags can\nbe passed to mypy instead. Only errors from the report are considered, notes are\nnot handled. Meaning something such as `error: Function is missing a type\nannotation  [no-untyped-def]` will have `# type: ignore[no-untyped-def]`\nappended to the end of the line, whereas `note: (Skipping most remaining errors\ndue to unresolved imports or missing stubs; fix these first)` will be ignored.\nErrors relating to unused ignores (which might occur if code changes after\nadding the initial ignore) can also be handled.\n\n# Installation\n\n```bash\npip install mypy-clean-slate\n```\n\n# Usage\n\n[comment]: # (CLI help split)\n\n```\nusage: mypy_clean_slate [options]\n\nCLI tool for providing a clean slate for mypy usage within a project.\n\nDefault expectation is to want to get a project into a state that it\nwill pass mypy when run with `--strict`, if this isn't the case custom\nflags can be passed to mypy via the `--mypy_flags` argument.\n\noptions:\n  -h, --help            show this help message and exit\n  -r, --generate_mypy_error_report\n                        Generate 'mypy_error_report.txt' in the cwd.\n  -p PATH_TO_CODE, --path_to_code PATH_TO_CODE\n                        Where code is that needs report generating for it.\n  -a, --add_type_ignore\n                        Add \"# type: ignore[<error-code>]\" to suppress all raised mypy errors.\n  --remove_unused       Remove unused instances of \"# type: ignore[<error-code>]\" if raised as an error by mypy.\n  -o MYPY_REPORT_OUTPUT, --mypy_report_output MYPY_REPORT_OUTPUT\n                        File to save report output to (default is mypy_error_report.txt)\n  --mypy_flags MYPY_FLAGS\n                        Custom flags to pass to mypy (provide them as a single string, default is to use --strict)\n```\n\n[comment]: # (CLI help split)\n\nSee `./tests/test_mypy_clean_slate.py` for some examples with before/after.\n\n\n\n# Examples\n\n## Simple example\n\nGiven a project with only:\n\n```txt\n\u279c  simple_example git:(master) \u2717 tree\n.\n`-- simple.py\n\n0 directories, 1 file\n```\n\nContaining:\n\n```python\n# simple.py\ndef f(x):\n    return x + 1\n```\n\nThe report can be generated, and `simple.py` updated, using `mypy_clean_slate -ra`, resulting in:\n\n\n```python\ndef f(x):  # type: ignore[no-untyped-def]\n    return x + 1\n```\n\nAnd `mypy --strict` will now pass.\n\n## Project example, using `pingouin`\n\nProject `pingouin` is located at: https://github.com/raphaelvallat/pingouin, and\ncommit `ea8b5605a1776aaa0e89dd5c0e3df4320950fb38` is used for this example.\n`mypy_clean_slate` needs to be run a couple of times here.\n\nFirst, generate report and apply `type: ignore[<error code>]`\n\n```sh\nmypy_clean_slate -ra\n```\n\nLooking at a subset of `git diff`:\n\n```diff\n\n(venv) \u279c pingouin git:(master) \u2717 git diff | grep 'type' | head\n+import sphinx_bootstrap_theme # type: ignore[import]\n+from outdated import warn_if_outdated # type: ignore[import]\n+import numpy as np # type: ignore[import]\n+from scipy.integrate import quad # type: ignore[import]\n+ from scipy.special import gamma, betaln, hyp2f1 # type: ignore[import]\n+ from mpmath import hyp3f2 # type: ignore[import]\n+ from scipy.stats import binom # type: ignore[import]\n+import numpy as np # type: ignore[import]\n+from scipy.stats import norm # type: ignore[import]\n+import numpy as np # type: ignore[import]\n```\n\nChanges are added and committed with message `'mypy_clean_slate first pass'` (commit message used makes no functional difference), and the report re-generated:\n\n```bash\nmypy_clean_slate -r\n```\n\nWhich reports `Found 1107 errors in 39 files (checked 42 source files)`. So, re-running `mypy_clean_slate`\n\n```bash\nmypy_clean_slate -a\n```\n\nAnd looking again at the diff:\n\n```diff\n\n(venv) \u279c pingouin git:(master) \u2717 gd | grep 'type' | head\n+latex_elements = { # type: ignore[var-annotated]\n+def setup(app): # type: ignore[no-untyped-def]\n@@ -27,4 +27,4 @@ from outdated import warn_if_outdated # type: ignore[import]\n+set_default_options() # type: ignore[no-untyped-call]\n+def _format_bf(bf, precision=3, trim='0'): # type: ignore[no-untyped-def]\nif type(bf) == str:\n+def bayesfactor_ttest(t, nx, ny=None, paired=False, tail='two-sided', r=.707): # type: ignore[no-untyped-def]\n+ def fun(g, t, n, r, df): # type: ignore[no-untyped-def]\n+def bayesfactor_pearson(r, n, tail='two-sided', method='ly', kappa=1.): # type: ignore[no-untyped-def]\n+ def fun(g, r, n): # type: ignore[no-untyped-def]\n```\n\n Committing these with `'mypy_clean_slate second pass'`, and re-running `mypy_clean_slate -r` outputs the following:\n\n```txt\n(venv) \u279c pingouin git:(master) \u2717 cat mypy_error_report.txt\nSuccess: no issues found in 42 source files\n```\n\nCan now rebase / amend commits as necessary, but could now update CI/pre-commit or whatever to use `mypy --strict` (or a subset of its flags) going forwards.\n\n\n# Handling of existing comments and `pylint`\n\nLines which contain existing comments such as:\n\n```python\ndef ThisFunction(something): # pylint: disable=invalid-name\n    return f\"this is {something}\"\n```\n\nWill be updated to:\n\n```python\ndef ThisFunction(something):   # type: ignore[no-untyped-def] # pylint: disable=invalid-name\n    return f\"this is {something}\"\n```\n\nAs the `type:` comment needs to precede pylints.\n\n# Issues\n\n## Generating report\n\nThe report generation is pretty straightforward, `mypy . --strict --show-error-codes`, so might not be worth having as part of this script. The user can generate the report to a text file and just pass the path to that as an argument.\n\n## Handling `-> None`\n\nReport output for functions which don't return is pretty consistent, so these could be automated if considered worth it.\n\n## Integration with other tooling\n\nI've tried to consider `pylint` comments, but no doubt there are many other arguments for different tools which aren't taken into consideration.\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "CLI tool for providing a clean slate for mypy usage within a project.",
    "version": "0.3.3",
    "project_urls": {
        "Homepage": "https://github.com/geo7/mypy_clean_slate"
    },
    "split_keywords": [
        "mypy",
        "typing",
        "typehint",
        "type-hint"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "38f11d8369e1c1e77d682d95bac260944b48f0b77115603b5e1a1c0d33b807d1",
                "md5": "4e88061b274b792bda391f612e44f6b3",
                "sha256": "7f5b016961ad3f2d3bd640e43a574c3cb5d8839c8bb3976a47546113abb4c0bb"
            },
            "downloads": -1,
            "filename": "mypy_clean_slate-0.3.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "4e88061b274b792bda391f612e44f6b3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 9619,
            "upload_time": "2024-03-11T11:46:23",
            "upload_time_iso_8601": "2024-03-11T11:46:23.378241Z",
            "url": "https://files.pythonhosted.org/packages/38/f1/1d8369e1c1e77d682d95bac260944b48f0b77115603b5e1a1c0d33b807d1/mypy_clean_slate-0.3.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "12114fd24508ebad069fe0107263139e723e601a9ca5be11769e1730039350de",
                "md5": "ffb21cd8c7d5e352bda252fb959e7aaf",
                "sha256": "2698de362f2b31dc9c813b459a6040a7317d3e48d8259b90efcdff1b9a830e54"
            },
            "downloads": -1,
            "filename": "mypy_clean_slate-0.3.3.tar.gz",
            "has_sig": false,
            "md5_digest": "ffb21cd8c7d5e352bda252fb959e7aaf",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 9270,
            "upload_time": "2024-03-11T11:46:25",
            "upload_time_iso_8601": "2024-03-11T11:46:25.215462Z",
            "url": "https://files.pythonhosted.org/packages/12/11/4fd24508ebad069fe0107263139e723e601a9ca5be11769e1730039350de/mypy_clean_slate-0.3.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-11 11:46:25",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "geo7",
    "github_project": "mypy_clean_slate",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "mypy_clean_slate"
}
        
Elapsed time: 0.20710s