Skip to content
Open
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add rule GCI110: Avoid wildcard imports in Python (`from module import *`)

### Changed

- add documentation link for each rule in RULES.md file
Expand Down
1 change: 1 addition & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Some are applicable for different technologies.
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
| 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) |
Expand Down
22 changes: 22 additions & 0 deletions src/main/rules/GCI110/GCI110.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"title": "Avoid wildcard imports in Python (from module import *)",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant/Issue",
"constantCost": "2min"
},
"tags": [
"creedengo",
"eco-design",
"performance",
"python",
"bad-practice",
"memory",
"import",
"namespace"
],
"defaultSeverity": "Minor"
}


98 changes: 98 additions & 0 deletions src/main/rules/GCI110/python/GCI110.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
= GCI110 — Avoid wildcard imports in Python (`from module import *`)

== Why this rule?

Wildcard imports bind many names into the current namespace and execute all top‑level module initialization.
This can slightly increase import time, parsing, and memory. Multiplied across many modules or cold starts,
this adds avoidable CPU/energy. It also hurts analyzability and maintainability by obscuring where names come from.

This rule is advisory for eco‑design: the effect is modest compared to algorithmic issues, so severity is Minor.

== Eco‑performance and energy

What changes (small but measurable in some contexts):
- Star imports perform mass‑binding of all exported names into the importer's namespace (O(N) assignments).
- This adds a little extra CPU at import time and slightly increases the importer's namespace size in memory.

When it can matter (accumulates across many imports/cold starts):
- Many files using star imports across a large codebase.
- Cold‑start heavy workloads (serverless/functions, frequent short‑lived jobs).
- In data and AI projects, small import-time costs can repeat many times and add up.

When it is typically negligible:
- Long‑running services (module import is cached in sys.modules; mass‑binding cost is paid once).


=== Performance measurement example

A simple benchmark comparing import methods shows measurable differences:

[source,python]
----
import timeit
# Normal import
print("normal import:", timeit.timeit("import math", number=1000))
# Wildcard import (using exec to avoid syntax restrictions)
def test_wildcard_import():
exec("from math import *")
print("from import *:", timeit.timeit(test_wildcard_import, number=1000))
----

Typical results on Python 3.12:
- Normal import: ~0.0018 seconds (1000 iterations)
- Wildcard import: ~0.0245 seconds (1000 iterations)

This represents approximately a **13x performance difference** for import operations, demonstrating the overhead of wildcard imports.

== Rule scope

- Flags top‑level statements: `from module import *`.
- Focuses on readability/maintainability with secondary eco‑impact (CPU/memory at import time).

== Exceptions (when it’s acceptable)

- Package aggregation files (`__init__.py`) that re‑export a curated API.
- If the target module defines `__all__`, making the export surface explicit.
- Generated code, quick scripts/REPL/notebooks, or educational material.

== Non‑compliant

[source,python]
----
from utils import *
process(data)
----

== Compliant alternatives

[source,python]
----
# Explicit named imports
from utils import parse, process
# Or module import with alias
import utils as u
u.process(data)
----

== Public API re‑exports

[source,python]
----
# In package/__init__.py
from .parse import parse
from .process import process
__all__ = ["parse", "process"]
----


== References
- Python Performance Tips: https://wiki.python.org/moin/PythonSpeed/PerformanceTips
- CPython source code — `import.c`: https://github.com/python/cpython/blob/main/Python/import.c
- Python Anti-Patterns — "Using wildcard imports (`from … import *`)": https://docs.quantifiedcode.com/python-anti-patterns/maintainability/from_module_import_all_used.html
- PEP 8 — Style Guide for Python Code: https://peps.python.org/pep-0008/#imports
- Stack Overflow — "Should wildcard import be avoided?": https://stackoverflow.com/questions/3615125/should-wildcard-import-be-avoided
- Pybites — "Why You Should Avoid `import *` in Python": https://pybit.es/articles/why-you-should-avoid-import-in-python/