343

I want to import foo-bar.py, this works:

foobar = __import__("foo-bar")

This does not:

from "foo-bar" import *

My question: Is there any way that I can use the above format i.e., from "foo-bar" import * to import a module that has a - in it?

Gavin S. Yancey
  • 1,216
  • 1
  • 13
  • 34
Bala
  • 3,938
  • 3
  • 19
  • 17
  • 13
    Why do you have a module with a dash in its name? – Matti Virkkunen Dec 02 '11 at 02:00
  • 36
    I'm guessing it was originally written as a script rather than as a module. – Michael Hoffman Dec 02 '11 at 02:19
  • 3
    possible duplicate of [Python Module with a dash, or hyphen (-) in its name](http://stackoverflow.com/questions/7583652/python-module-with-a-dash-or-hyphen-in-its-name) – Piotr Dobrogost Feb 26 '14 at 14:40
  • @MattiVirkkunen makepy.py of win32com will generate module with dash in it. too bad. comtypes solved this by converting it to underscore – swdev Apr 11 '14 at 01:45
  • 6
    @MattiVirkkunen I think Python should not limit the names I can give my directories. It is not its responsibility to do so. – Zelphir Kaltstahl Nov 11 '16 at 12:34
  • @Zelphir: Do you also think Python should not limit the names you can give your variables and other identifiers? Surely you can see why it's silly to name a module (whose name is defined by the directory name) something that's not a valid identifier. – Matti Virkkunen Nov 14 '16 at 05:50
  • @MattiVirkkunen Actually I think variables are something inside Python and thus its "task" to care for, so that's OK. But maybe you have a point there about modules being its part as well. Anyway, it's not a big issue, just something one needs to know : ) – Zelphir Kaltstahl Nov 14 '16 at 09:20
  • 1
    Possible duplicate of [Is it ok to use dashes in Python files when trying to import them?](http://stackoverflow.com/questions/761519/is-it-ok-to-use-dashes-in-python-files-when-trying-to-import-them) – maxkoryukov May 17 '17 at 04:31

8 Answers8

238

Starting from Python 3.1, you can use importlib :

import importlib  
foobar = importlib.import_module("foo-bar")

( https://docs.python.org/3/library/importlib.html )

Julien
  • 2,747
  • 1
  • 12
  • 17
147

In Python 2, you can't. foo-bar is not an identifier. rename the file to foo_bar.py


It's possible since Python 3.1+, see Julien's answer.


If import is not your goal (as in: you don't care what happens with sys.modules, you don't need it to import itself), just getting all of the file's globals into your own scope, you can use execfile

# contents of foo-bar.py
baz = 'quux'
>>> execfile('foo-bar.py')
>>> baz
'quux'
>>> 
Neuron
  • 5,141
  • 5
  • 38
  • 59
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 34
    Python 3.x [What’s New In Python 3.0](https://docs.python.org/3/whatsnew/3.0.html) Removed execfile(). Instead of `execfile(fn)` use `exec(open(fn).read())` Also there is package importlib. – DevPlayer Apr 08 '15 at 14:26
  • 1
    "*if you don't care what happens with sys.modules*", can you clarify what you meant? What is the condition for using `execfile`? – mins May 18 '21 at 09:25
140

Solution: If you can't rename the module to match Python naming conventions, create a new module to act as an intermediary:

New module foo_proxy.py:

 tmp = __import__('foo-bar')
 globals().update(vars(tmp))

Module doing the import main.py:

 from foo_proxy import * 
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • 44
    I would never implement this. But I can't not give +1 for the sheer brilliance of this hack – inspectorG4dget Dec 02 '11 at 02:25
  • 14
    you could actually do this without the `foo_proxy.py` file, assign the output of `__import__(...)` to `sys.modules['foo_proxy']`. Actually, don't do that, it's a terrible idea. – SingleNegationElimination Dec 02 '11 at 14:03
  • 5
    Cool just what I was looking for. There is a usecase, if one uses native libraries which are shipped with a distribution. – Sven May 08 '13 at 14:59
56

If you can't rename the original file, you could also use a symlink:

ln -s foo-bar.py foo_bar.py

Then you can just do:

from foo_bar import *
gitaarik
  • 42,736
  • 12
  • 98
  • 105
  • 1
    Doesn't work with Windows unfortunately. – Mark Ransom Jul 12 '22 at 20:08
  • The *nix command above likely will not, but Windows _does_ have its own symlink support (since Win7): `mklink Link Target` ref: https://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/ – Adam Smooch Aug 31 '22 at 00:03
12

Like other said you can't use a - in python naming, there are many workarounds, one such workaround which would be useful if you had to add multiple modules from a path is using sys.path

For example if your structure is like this:

foo-bar
├── barfoo.py
└── __init__.py

import sys
sys.path.append('foo-bar')

import barfoo
Neuron
  • 5,141
  • 5
  • 38
  • 59
Reda Drissi
  • 1,532
  • 3
  • 20
  • 32
2

This was my scenario: I have a python library cloned in a git submodule which has a dash in its name:

|- python-my-lib
| `- mylib.py
`- my-script.py

It took me a long time to figure out the equivalent of:

# Do NOT use this!
sys.path.insert(1, './my-lib')
from mylib import MyClass

Appending the path is not an option, as it would only work if you run the script within the same directory. If you do /home/user/bin/my-script.py, this will fail.

This is the solution:

import importlib
mylib_module = importlib.import_module("python-my-lib.mylib")
MyClass = mylib_module.MyClass

Feel free to further improve this solution, if you know a simpler solution.

NicoHood
  • 687
  • 5
  • 12
2

Python has issues with dash -. So use importlib instead. You can run your test scripts just like this -

# importlib, because python has issues with dash '-' in module names
import importlib
img2txt = importlib.import_module("img2txt-textextractor")

event_with_txt = {...}

event_with_no_txt = {...}


def test_no_text():
    response = img2txt.handler(event=event_with_txt, context='')
    assert response["body"] == '"Detect Me If You Can. "'

def test_detected_text():
    response = img2txt.handler(event=event_with_no_txt, context='')
    assert response["body"] == '"unable to find anything"'

Name your test code as test_someName.py. To run, from the same directory on terminal type -

pytest
ashraf minhaj
  • 504
  • 2
  • 14
0

in Python 3.6 I had the same problem "invalid syntax" when directly

import 'jaro-winkler' as jw

said "No module named 'jaro-winkler'" when using:

jw = __import__('jaro-winkler')

and importlib.import_module() same.

finally i use pip uninstall the jaro-winkler module...just FYI

Hassen Ch.
  • 1,693
  • 18
  • 31
kk120120
  • 27
  • 2