Python
module-import
programming-tips
python-modules
code-troubleshooting

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:

python
import my-module

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.py to my_module.py
  • then import it normally
python
import my_module

print(my_module.__name__)

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.

python
1from importlib.util import module_from_spec, spec_from_file_location
2
3spec = spec_from_file_location("legacy_module", "./my-module.py")
4module = module_from_spec(spec)
5spec.loader.exec_module(module)
6
7print(module.answer())

Assuming my-module.py contains:

python
def answer():
    return 42

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:

python
1from importlib.util import module_from_spec, spec_from_file_location
2
3spec = spec_from_file_location("legacy_module", "./my-module.py")
4legacy_module = module_from_spec(spec)
5spec.loader.exec_module(legacy_module)
6
7answer = legacy_module.answer

Now the rest of the application can do:

python
import legacy_wrapper

print(legacy_wrapper.answer())

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 import statement.
  • 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.

Course illustration
Course illustration

All Rights Reserved.