logo

Inappropriate coding practices - Wildcard export - Python


Need

Enforce explicit exports in code modules


Context

  1. Usage of Python for general-purpose programming and scripting
  2. Usage of my_module for custom functionality or feature implementation

Description

Insecure Code Example

# my_module.py

def function_one():
    pass

def function_two():
    pass

def function_three():
    pass

# __init__.py

from .my_module import *

In the above code snippet, the developer uses the wildcard operator (*) to import all functions from the `my_module.py` file into the `__init__.py` file. This is done in the line `from .my_module import *`. Using the wildcard operator in this way is known as a wildcard import. It's a convenient way to import all functions, classes, and variables from a module without having to specify them individually. However, this practice can lead to problems. Firstly, it can make the code harder to understand and maintain. If there are many functions in `my_module.py`, it's not immediately clear which ones are being used in `__init__.py`. A developer would have to open `my_module.py` and look through all the functions to figure this out. Secondly, it can lead to namespace conflicts. If `my_module.py` and `__init__.py` both have a function with the same name, the one in `__init__.py` will be overwritten by the one in `my_module.py`. This can lead to unexpected behavior and bugs that are hard to track down. Lastly, it can make the code less efficient. If `my_module.py` has many functions but only a few are used in `__init__.py`, importing all of them wastes memory and slows down the program. Therefore, it's recommended to avoid wildcard imports and instead import only the functions that are actually needed.

Steps

  1. Identify the specific functions that need to be exported from the module.
  2. Instead of using the wildcard operator (*), explicitly list out the functions to be exported in the import statement.
  3. This way, only the necessary functions are exposed, reducing the risk of misuse and making the module easier to maintain.

Secure Code Example

# my_module.py

def function_one():
    pass

def function_two():
    pass

def function_three():
    pass

# __init__.py

from .my_module import function_one, function_two

In the original code, the wildcard operator (*) was used to import all functions from `my_module`. This is a bad practice as it exposes all functions, even those that are not necessary for the module's operation, which can lead to misuse and make the module harder to maintain. In the fixed code, instead of using the wildcard operator, we explicitly list out the functions to be imported from `my_module` in the import statement. Here, only `function_one` and `function_two` are imported, and `function_three` is not, as it's assumed not to be necessary for the module's operation. This way, we are only exposing the necessary functions, reducing the risk of misuse and making the module easier to maintain. This is a better coding practice as it promotes clarity about which functions are being used and avoids potential naming conflicts.


References

  • 384 - Inappropriate coding practices - Wildcard export

  • Last updated

    2023/09/18