importlib.util.find_spec()

Twirlip2 ahrodg at googlemail.com
Wed Aug 27 18:30:41 EDT 2014


I want to write a function (preferably not very complicated, nor
requiring deep understanding of the innards of Python) that will
tell me whether a given string <name> can be used as the name of
a module (filename <name>.py), which can be placed in the search
path, without conflicting with some other use which the Python
language might have for the same string <name>.

An example of this yesterday was my writing a module, code.py,
which caused a confusing error because the Python installation
already contains a file named code.py, which is needed by IDLE.

Another example would be creating a module test.py, and placing
it in the search path, where it would obscure the package 'test'.

I've been doing some experiments, using IDLE, starting with the
following command:

 from importlib.util import find_spec

It seems that something like the following statements are true (or
at least approximately true, with some refinements which I haven't
stumbled across yet):

 1. If find_spec(<name>) is None, then no conflict will arise.

I hope this is true; it would certainly be reassuring!  But I
would also like to be able to tell something about the entity
denoted by <name> in the case where find_spec(<name>) is /not/
None.

I'm tentatively trying to subdivide the latter case, as follows.

(I assume hasattr(find_spec(<name>), 'has_location') is True -
whenever the expression is defined, that is.)

 2. If find_spec(<name>).has_location is False, then <name> is
    a built-in module - or perhaps, some other kind of 'system'
    entity (which I won't attempt to investigate further).

>From now on, assume that find_spec(<name>).has_location is True.

 3. If hasattr(find_spec(<name>), 'submodule_search_locations'),
    then <name> is a package, but it is not built-in.

However, even if 3 is true, there are a number of strange special
cases - examples are 're' and 'struct' - for which the attribute
'submodule_search_locations' is None!  This is one of the things
that puzzles me.

Finally (I hope):

 4. If hasattr(find_spec(<name>), 'submodule_search_locations')
    is False, then <name> is a module, not a package, and not
    built-in; therefore (?) the file <name>.py already exists
    as part of the Python installation (and can be opened and
    looked at).

Does all (or even some) of this seem even roughly right?

Here, anyway, are the results of some of my 'experiments':

>>> find_spec('code')
ModuleSpec(name='code', loader=<_frozen_importlib.SourceFileLoader object at 0x01149AF0>, origin='I:\\Python34\\lib\\code.py')

>>> find_spec('test')
ModuleSpec(name='test', loader=<_frozen_importlib.SourceFileLoader object at 0x0161F990>, origin='I:\\Python34\\lib\\test\\__init__.py', submodule_search_locations=['I:\\Python34\\lib\\test'])

>>> hasattr(find_spec('test'), 'has_location')
True

>>> find_spec('test').has_location
True

>>> find_spec('code').has_location
True

>>> find_spec('code').origin
'I:\\Python34\\lib\\code.py'

>>> find_spec('array')
ModuleSpec(name='array', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in')
>>> find_spec('array').has_location
False
>>> find_spec('array').origin
'built-in'

>>> find_spec('sys')
ModuleSpec(name='sys', loader=<class '_frozen_importlib.BuiltinImporter'>)
>>> find_spec('sys').origin
>>> find_spec('sys').has_location
False

>>> find_spec('sys').origin is None
True

>>> find_spec('re')
ModuleSpec(name='re', loader=<_frozen_importlib.SourceFileLoader object at 0x00BC6430>, origin='I:\\Python34\\lib\\re.py')
>>> find_spec('re').has_location
True
>>> find_spec('re').origin
'I:\\Python34\\lib\\re.py'

>>> hasattr(find_spec('re'), 'submodule_search_locations')
True
>>> find_spec('re').submodule_search_locations
>>> find_spec('re').submodule_search_locations is None
True

>>> find_spec('struct')
ModuleSpec(name='struct', loader=<_frozen_importlib.SourceFileLoader object at 0x00E76650>, origin='I:\\Python34\\lib\\struct.py')

>>> hasattr(find_spec('struct'), 'submodule_search_locations')
True
>>> find_spec('struct').submodule_search_locations
>>> find_spec('struct').submodule_search_locations is None
True

>>> find_spec('__builtin__')
>>> find_spec('__builtin__') is None
True

- Not that I would be mad enough to try to create a module
whose name begins and ends with double underscores!  But I
was curious to see what find_spec would do with such names.

Finally, a pretty weird (I think) error message:

>>> find_spec('__main__')
Traceback (most recent call last):
  File "<pyshell#37>", line 1, in <module>
    find_spec('__main__')
  File "I:\Python34\lib\importlib\util.py", line 100, in find_spec
    raise ValueError('{}.__spec__ is None'.format(name))
ValueError: __main__.__spec__ is None



More information about the Python-list mailing list