Skip to content

Commit d71c45c

Browse files
committed
Add GCI110: avoid wildcard imports in Python
1 parent 798bac2 commit d71c45c

File tree

4 files changed

+123
-0
lines changed

4 files changed

+123
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- Add rule GCI110: Avoid wildcard imports in Python (`from module import *`)
13+
1214
### Changed
1315

1416
- add documentation link for each rule in RULES.md file

RULES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Some are applicable for different technologies.
8585
| GCI106 | Avoid Square Root Operations In Loop | Using scalar `math.sqrt` (or `numpy.sqrt` on individual values) inside loops leads to inefficient code | | 🚫 | 🚫 | 🚫 || 🚫 | 🚫 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI106) |
8686
| GCI107 | Data : Avoid Iterative Matrix Operations | Use vectorization by the usage of the built-in functions of TensorFlow, NumPy or Pandas | | 🚫 | 🚫 | 🚫 || 🚫 | 🚫 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI107) |
8787
| GCI108 | Prefer Append Left | When you want to insert an element at the beginning of a list, it's better to use a deques or a double linkedlist. | |||||||| [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI108) |
88+
| GCI110 | Python: Avoid wildcard imports (`from module import *`) | Wildcard imports bind many names and run module top‑level init, slightly increasing import time and memory. Prefer explicit named imports | | 🚫 | 🚫 | 🚫 || 🚫 | 🚫 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI110) |
8889
| GCI203 | Detect unoptimized file formats | When it is possible, to use svg format image over other image format | | 🚧 | 🚀 | 🚀 || 🚀 | 🚀 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI203) |
8990
| GCI404 | Avoid list comprehension in iterations | Use generator comprehension instead of list comprehension in for loop declaration | | 🚫 | 🚫 | 🚫 || 🚫 | 🚫 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI404) |
9091
| GCI522 | Sobriety: Brightness Override | To avoid draining the battery, iOS and Android devices adapt the brightness of the screen depending on the environment light. | | 🚫 | 🚫 || 🚫 | 🚫 | 🚫 | 🚫 | [documentation](https://github.com/green-code-initiative/creedengo-rules-specifications/tree/main/src/main/rules/GCI522) |

src/main/rules/GCI110/GCI110.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"title": "Avoid wildcard imports in Python (from module import *)",
3+
"type": "CODE_SMELL",
4+
"status": "ready",
5+
"remediation": {
6+
"func": "Constant/Issue",
7+
"constantCost": "2min"
8+
},
9+
"tags": [
10+
"creedengo",
11+
"eco-design",
12+
"performance",
13+
"python",
14+
"bad-practice",
15+
"memory",
16+
"import",
17+
"namespace"
18+
],
19+
"defaultSeverity": "Minor"
20+
}
21+
22+
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
= GCI110 — Avoid wildcard imports in Python (`from module import *`)
2+
3+
== Why this rule?
4+
5+
Wildcard imports bind many names into the current namespace and execute all top‑level module initialization.
6+
This can slightly increase import time, parsing, and memory. Multiplied across many modules or cold starts,
7+
this adds avoidable CPU/energy. It also hurts analyzability and maintainability by obscuring where names come from.
8+
9+
This rule is advisory for eco‑design: the effect is modest compared to algorithmic issues, so severity is Minor.
10+
11+
== Eco‑performance and energy
12+
13+
What changes (small but measurable in some contexts):
14+
- Star imports perform mass‑binding of all exported names into the importer's namespace (O(N) assignments).
15+
- This adds a little extra CPU at import time and slightly increases the importer's namespace size in memory.
16+
17+
When it can matter (accumulates across many imports/cold starts):
18+
- Many files using star imports across a large codebase.
19+
- Cold‑start heavy workloads (serverless/functions, frequent short‑lived jobs).
20+
- In data and AI projects, small import-time costs can repeat many times and add up.
21+
22+
When it is typically negligible:
23+
- Long‑running services (module import is cached in sys.modules; mass‑binding cost is paid once).
24+
25+
26+
=== Performance measurement example
27+
28+
A simple benchmark comparing import methods shows measurable differences:
29+
30+
[source,python]
31+
----
32+
import timeit
33+
34+
# Normal import
35+
print("normal import:", timeit.timeit("import math", number=1000))
36+
37+
# Wildcard import (using exec to avoid syntax restrictions)
38+
def test_wildcard_import():
39+
exec("from math import *")
40+
41+
print("from import *:", timeit.timeit(test_wildcard_import, number=1000))
42+
----
43+
44+
Typical results on Python 3.12:
45+
- Normal import: ~0.0018 seconds (1000 iterations)
46+
- Wildcard import: ~0.0245 seconds (1000 iterations)
47+
48+
This represents approximately a **13x performance difference** for import operations, demonstrating the overhead of wildcard imports.
49+
50+
== Rule scope
51+
52+
- Flags top‑level statements: `from module import *`.
53+
- Focuses on readability/maintainability with secondary eco‑impact (CPU/memory at import time).
54+
55+
== Exceptions (when it’s acceptable)
56+
57+
- Package aggregation files (`__init__.py`) that re‑export a curated API.
58+
- If the target module defines `__all__`, making the export surface explicit.
59+
- Generated code, quick scripts/REPL/notebooks, or educational material.
60+
61+
== Non‑compliant
62+
63+
[source,python]
64+
----
65+
from utils import *
66+
process(data)
67+
----
68+
69+
== Compliant alternatives
70+
71+
[source,python]
72+
----
73+
# Explicit named imports
74+
from utils import parse, process
75+
76+
# Or module import with alias
77+
import utils as u
78+
u.process(data)
79+
----
80+
81+
== Public API re‑exports
82+
83+
[source,python]
84+
----
85+
# In package/__init__.py
86+
from .parse import parse
87+
from .process import process
88+
__all__ = ["parse", "process"]
89+
----
90+
91+
92+
== References
93+
- Python Performance Tips: https://wiki.python.org/moin/PythonSpeed/PerformanceTips
94+
- CPython source code — `import.c`: https://github.com/python/cpython/blob/main/Python/import.c
95+
- Python Anti-Patterns — "Using wildcard imports (`from … import *`)": https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html
96+
- PEP 8 — Style Guide for Python Code: https://peps.python.org/pep-0008/#imports
97+
- Stack Overflow — "Should wildcard import be avoided?": https://stackoverflow.com/questions/3615125/should-wildcard-import-be-avoided
98+
- Pybites — "Why You Should Avoid `import *` in Python": https://pybit.es/articles/why-you-should-avoid-import-in-python/

0 commit comments

Comments
 (0)