How to import module when module name has a '-' dash or hyphen in it?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Python's normal import statement cannot import a module whose filename contains a hyphen, because a hyphen is not valid in a Python identifier. In most cases the correct fix is to rename the module, but if you cannot do that, you can still load the file explicitly with importlib.
Why the Normal Import Fails
This is invalid Python syntax:
The parser reads the hyphen as subtraction, not as part of a module name. That is why the failure happens before Python even tries to find the file.
The same problem affects package names in dotted imports. Module and package identifiers are expected to follow identifier rules, which allow letters, digits, and underscores but not hyphens.
Best Fix: Rename the Module
If you control the file, rename it to use an underscore.
Example:
- rename
my-module.pytomy_module.py - then import it normally
This is the most maintainable choice. It works with static analysis, normal imports, packaging tools, and every other part of the ecosystem that expects conventional module names.
Important Distinction: Package Name Versus Import Name
A related source of confusion is that pip distribution names and Python import names are not always the same. A package may be installed from a name containing hyphens but imported with underscores or an entirely different package name.
For example, a project on PyPI might be published as my-package, but the import could be my_package or something else documented by the project.
That means if the package came from pip, check the project documentation before assuming the import name must match the distribution name literally.
Loading a Hyphenated File Explicitly
If renaming is impossible, load the module by file path using importlib.util.
Assuming my-module.py contains:
This works because you assign the loaded file a valid runtime module name such as legacy_module, even though the source filename still contains a hyphen.
When This Approach Is Appropriate
Explicit loading is useful for:
- legacy scripts you cannot rename yet
- one-off migration tooling
- loading plugin files from external paths
- compatibility shims around third-party artifacts
It is usually not the best long-term structure for normal application code. If a module is part of your maintained codebase, rename it.
Avoid Overcomplicating Packaging
If the module is part of a package you distribute, do not build a packaging strategy around special-case imports for hyphenated files. That creates unnecessary confusion for every future maintainer.
Instead:
- rename the internal module to use underscores
- keep the distribution name separate if needed
- document the supported import path clearly
This matches Python's conventions and keeps tooling predictable.
A Small Wrapper Pattern
If renaming must happen gradually, one practical step is to create a valid wrapper module that loads the old file and exposes a clean import path.
legacy_wrapper.py:
Now the rest of the application can do:
That gives you a stable import surface while you phase out the odd filename.
Common Pitfalls
The most common mistake is assuming the import statement should somehow be able to quote the name. It cannot; the grammar does not allow it.
Another mistake is confusing a PyPI distribution name with the Python import name. The published package name and the importable module name are related but not identical concepts.
Developers also sometimes load a file with importlib and then forget that the rest of the codebase still lacks a normal import path. If the module matters long term, create a proper wrapper or rename it.
Finally, do not hide this behavior in critical code without documentation. Explicit path-based imports are less obvious than standard imports and deserve a comment or small helper module.
Summary
- A hyphenated filename cannot be imported with the normal
importstatement. - If you control the code, rename the module to use underscores.
- If the name comes from a package manager, confirm the documented import name first.
- If renaming is impossible, load the file explicitly with
importlib.util.spec_from_file_location. - For maintainable code, prefer a normal import path over a permanent special-case loader.

