{"id":13468236,"url":"https://github.com/asmeurer/removestar","last_synced_at":"2025-05-15T17:07:52.618Z","repository":{"id":47330523,"uuid":"197666949","full_name":"asmeurer/removestar","owner":"asmeurer","description":"Tool to automatically replace 'import *' in Python files with explicit imports","archived":false,"fork":false,"pushed_at":"2025-03-10T09:10:48.000Z","size":389,"stargazers_count":179,"open_issues_count":13,"forks_count":10,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-13T17:04:02.383Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.asmeurer.com/removestar/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asmeurer.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-07-18T22:54:43.000Z","updated_at":"2024-12-22T21:21:34.000Z","dependencies_parsed_at":"2022-09-19T08:01:44.283Z","dependency_job_id":"e8a19527-90cb-4a34-9318-147c05c2bc47","html_url":"https://github.com/asmeurer/removestar","commit_stats":{"total_commits":274,"total_committers":10,"mean_commits":27.4,"dds":"0.33941605839416056","last_synced_commit":"0792b96b90b7ca5f4f0557dd85f14c79c5b22d13"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asmeurer%2Fremovestar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asmeurer%2Fremovestar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asmeurer%2Fremovestar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asmeurer%2Fremovestar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asmeurer","download_url":"https://codeload.github.com/asmeurer/removestar/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384988,"owners_count":22062422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T15:01:07.429Z","updated_at":"2025-05-15T17:07:47.610Z","avatar_url":"https://github.com/asmeurer.png","language":"Python","funding_links":[],"categories":["Python","Imports formatters"],"sub_categories":[],"readme":"# removestar\n\n[![Actions Status][actions-badge]][actions-link]\n[![PyPI version][pypi-version]][pypi-link]\n[![Anaconda-Server Badge][conda-version]][conda-link]\n[![PyPI platforms][pypi-platforms]][pypi-link]\n[![Downloads][pypi-downloads]][pypi-link]\n[![Conda Downloads][conda-downloads]][conda-link]\n[![Ruff][ruff-badge]][ruff-link]\n\n\u003c!-- TODO:\n[![pre-commit.ci status][pre-commit-badge]][pre-commit-link]\n[![codecov percentage][codecov-badge]][codecov-link]\n[![GitHub Discussion][github-discussions-badge]][github-discussions-link]\n--\u003e\n\nTool to automatically replace `import *` imports in Python files with explicit imports\n\n## Installation\n\nInstall `removestar` globally to use it through CLI using `pypi` -\n\n```bash\npip install removestar\npip install \"removestar[nb]\"  # notebook support\n```\n\nor `conda` -\n\n```bash\nconda install -c conda-forge removestar\n```\n\nor add `removestar` in `.pre-commit-config.yaml` -\n\n```yaml\n- repo: https://github.com/asmeurer/removestar\n  rev: \"1.5\"\n  hooks:\n    - id: removestar\n      args: [-i] # See docs for all args (-i edits file in-place)\n      additional_dependencies: # The libraries or packages your code imports\n        - ... # Add . if running inside a library (to install the library itself in the environment)\n        - ... # Add nbformat and nbconvert for notebook support\n```\n\n## Usage\n\n### pre-commit hook\n\nOnce `removestar` is added in `.pre-commit-config.yaml`, executing the following\nwill always run it (and other pre-commits) before every commit -\n\n```bash\npre-commit install\n```\n\nOptionally, the pre-commits (including `removestar`) can be manually triggered for\nall the files using -\n\n```bash\npre-commit run --all-files\n```\n\n### CLI\n\n```bash\n\n# scripts\n\n$ removestar file.py # Shows diff but does not edit file.py\n\n$ removestar -i file.py # Edits file.py in-place\n\n$ removestar -i module/ # Modifies every Python file in module/ recursively\n\n# notebooks (make sure nbformat and nbconvert are installed)\n\n$ removestar file.ipynb # Shows diff but does not edit file.ipynb\n\n$ removestar -i file.ipynb # Edits file.ipynb in-place\n```\n\n## Why is `import *` so bad?\n\nDoing `from module import *` is generally frowned upon in Python. It is\nconsidered acceptable when working interactively at a `python` prompt, or in\n`__init__.py` files (removestar skips `__init__.py` files by default).\n\nSome reasons why `import *` is bad:\n\n- It hides which names are actually imported.\n- It is difficult both for human readers and static analyzers such as\n  pyflakes to tell where a given name comes from when `import *` is used. For\n  example, pyflakes cannot detect unused names (for instance, from typos) in\n  the presence of `import *`.\n- If there are multiple `import *` statements, it may not be clear which names\n  come from which module. In some cases, both modules may have a given name,\n  but only the second import will end up being used. This can break people's\n  intuition that the order of imports in a Python file generally does not\n  matter.\n- `import *` often imports more names than you would expect. Unless the module\n  you import defines `__all__` or carefully `del`s unused names at the module\n  level, `import *` will import every public (doesn't start with an\n  underscore) name defined in the module file. This can often include things\n  like standard library imports or loop variables defined at the top-level of\n  the file. For imports from modules (from `__init__.py`), `from module import\n*` will include every submodule defined in that module. Using `__all__` in\n  modules and `__init__.py` files is also good practice, as these things are\n  also often confusing even for interactive use where `import *` is\n  acceptable.\n- In Python 3, `import *` is syntactically not allowed inside of a function.\n\nHere are some official Python references stating not to use `import *` in\nfiles:\n\n- [The official Python\n  FAQ](https://docs.python.org/3/faq/programming.html?highlight=faq#what-are-the-best-practices-for-using-import-in-a-module):\n\n  \u003e In general, don’t use `from modulename import *`. Doing so clutters the\n  \u003e importer’s namespace, and makes it much harder for linters to detect\n  \u003e undefined names.\n\n- [PEP 8](https://www.python.org/dev/peps/pep-0008/#imports) (the official\n  Python style guide):\n\n  \u003e Wildcard imports (`from \u003cmodule\u003e import *`) should be avoided, as they\n  \u003e make it unclear which names are present in the namespace, confusing both\n  \u003e readers and many automated tools.\n\nUnfortunately, if you come across a file in the wild that uses `import *`, it\ncan be hard to fix it, because you need to find every name in the file that is\nimported from the `*`. Removestar makes this easy by finding which names come\nfrom `*` imports and replacing the import lines in the file automatically.\n\nOne exception where `import *` can be bneficial:\nAt the early stages of code development, a definite set of required\nfunctions can be difficult to determine. In such a context, wildcard imports could be\nbeneficial by avoiding constantly curating the set of required functions. For example,\nat the development stage usage of `from os.path import *` can save time from curating\nrequired functions. Post-development, the wld card imports could be determined using\n`removestar`. Having said that, because of the multiple said reasons, wildcard imports\nshould be avoided.\n\n## Example\n\nSuppose you have a module `mymod` like\n\n```bash\nmymod/\n  | __init__.py\n  | a.py\n  | b.py\n```\n\nWith\n\n```py\n# mymod/a.py\nfrom .b import *\n\n\ndef func(x):\n    return x + y\n```\n\n```py\n# mymod/b.py\nx = 1\ny = 2\n```\n\nThen `removestar` works like:\n\n```bash\n$ removestar mymod/\n\n--- original/mymod/a.py\n+++ fixed/mymod/a.py\n@@ -1,5 +1,5 @@\n # mymod/a.py\n-from .b import *\n+from .b import y\n\n def func(x):\n     return x + y\n\n```\n\nThis does not edit `a.py` by default. The `-i` flag causes it to edit `a.py` in-place:\n\n```bash\n$ removestar -i mymod/\n$ cat mymod/a.py\n# mymod/a.py\nfrom .b import y\n\ndef func(x):\n    return x + y\n```\n\n## Command line options\n\n\u003c!-- TODO: Autogenerate this somehow --\u003e\n\n```bash\n$ removestar --help\nusage: removestar [-h] [-i] [--version] [--no-skip-init]\n                  [--no-dynamic-importing] [-v] [-q]\n                  [--max-line-length MAX_LINE_LENGTH]\n                  PATH [PATH ...]\n\nTool to automatically replace \"import *\" imports with explicit imports\n\nRequires pyflakes.\n\nUsage:\n\n$ removestar file.py # Shows diff but does not edit file.py\n\n$ removestar -i file.py # Edits file.py in-place\n\n$ removestar -i module/ # Modifies every Python file in module/ recursively\n\npositional arguments:\n  PATH                  Files or directories to fix\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -i, --in-place        Edit the files in-place. (default: False)\n  --version             Show removestar version number and exit.\n  --no-skip-init        Don't skip __init__.py files (they are skipped by\n                        default) (default: True)\n  --no-dynamic-importing\n                        Don't dynamically import modules to determine the list\n                        of names. This is required for star imports from\n                        external modules and modules in the standard library.\n                        (default: True)\n  -v, --verbose         Print information about every imported name that is\n                        replaced. (default: False)\n  -q, --quiet           Don't print any warning messages. (default: False)\n  --max-line-length MAX_LINE_LENGTH\n                        The maximum line length for replaced imports before\n                        they are wrapped. Set to 0 to disable line wrapping.\n                        (default: 100)\n```\n\n## Whitelisting star imports\n\n`removestar` does not replace star import lines that are marked with\n[Flake8 `noqa` comments][noqa-comments] that permit star imports (`F401` or\n`F403`).\n\n[noqa-comments]: https://flake8.pycqa.org/en/3.1.1/user/ignoring-errors.html#in-line-ignoring-errors\n\nFor example, the star imports in this module would be kept:\n\n```py\nfrom os import *  # noqa: F401\nfrom .b import *  # noqa\n\n\ndef func(x):\n    return x + y\n```\n\n## Current limitations\n\n- Assumes only names in the current file are used by star imports (e.g., it\n  won't work to replace star imports in `__init__.py`).\n\n- For files within the same module, removestar determines missing imported names\n  statically. For external library imports, including imports of standard\n  library modules, it dynamically imports the module to determine the names.\n  This can be disabled with the `--no-dynamic-importing` flag.\n\n## Contributing\n\nSee the [issue tracker](https://github.com/asmeurer/removestar/issues). Pull\nrequests are welcome.\n\n## Changelog\n\nSee the [CHANGELOG](CHANGELOG.md) file.\n\n## License\n\n[MIT](LICENSE)\n\n[actions-badge]: https://github.com/asmeurer/removestar/workflows/CI/badge.svg\n[actions-link]: https://github.com/asmeurer/removestar/actions\n[codecov-badge]: https://codecov.io/gh/asmeurer/removestar/branch/main/graph/badge.svg?token=YBv60ueORQ\n[codecov-link]: https://codecov.io/gh/asmeurer/removestar\n[conda-downloads]: https://img.shields.io/conda/dn/conda-forge/removestar?color=green\n[conda-link]: https://anaconda.org/conda-forge/removestar\n[conda-version]: https://anaconda.org/conda-forge/removestar/badges/version.svg\n[github-discussions-badge]: https://img.shields.io/static/v1?label=Discussions\u0026message=Ask\u0026color=blue\u0026logo=github\n[github-discussions-link]: https://github.com/asmeurer/removestar/discussions\n[license-badge]: https://img.shields.io/badge/MIT-blue.svg\n[license-link]: https://opensource.org/licenses/MIT\n[pypi-downloads]: https://static.pepy.tech/badge/removestar\n[pre-commit-badge]: https://results.pre-commit.ci/badge/github/asmeurer/removestar/develop.svg\n[pre-commit-link]: https://results.pre-commit.ci/repo/github/asmeurer/removestar\n[pypi-link]: https://pypi.org/project/removestar/\n[pypi-platforms]: https://img.shields.io/pypi/pyversions/removestar\n[pypi-version]: https://img.shields.io/pypi/v/removestar?color=blue\n[ruff-badge]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n[ruff-link]: https://github.com/astral-sh/ruff\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasmeurer%2Fremovestar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasmeurer%2Fremovestar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasmeurer%2Fremovestar/lists"}