flat_export

Download python-snippets-0.2.zip

Sub-Module name import with clean namespace for from ... import *.

Source code excerpt

See also source code of __init__.py.

Define package name and sub-modules to be imported (avoiding error-prone duplication):

_package_ = 'flat_export'
_modules_ = ['sub1', 'sub2', 'sub3']

Use relative imports when available (this is imperative, see is_importing_package()):

_loaded = False
if is_importing_package(_package_, locals()):
    for _module in _modules_:
        exec ('from .' + _module + ' import *')
    _loaded = True
    del(_module)
Try importing the package, including __all__.
This happens when executing a module file as script with the package in the search path (e.g. python flat_export/__init__.py)
if not _loaded:
    try:
        exec('from ' + _package_ + ' import *')
        exec('from ' + _package_ + ' import __all__')
        _loaded = True
    except (ImportError):
        pass
As a last resort, try importing the sub-modules directly.
This happens when executing a module file as script inside the package directory without the package in the search path (e.g. cd flat_export; python __init__.py)
if not _loaded:
    for _module in _modules_:
        exec('from ' + _module + ' import *')
    del(_module)

Construct __all__ (leaving out modules), unless it has been imported before:

if not __all__:
    _module_type = type(__import__('sys'))
    for _sym, _val in sorted(locals().items()):
        if not _sym.startswith('_') and not isinstance(_val, _module_type) :
            __all__.append(_sym)
    del(_sym)
    del(_val)
    del(_module_type)

Import mode direct – triggered by script execution

When

  • the package is not installed

  • the package is not otherwise in the search path

  • the file __init__.py is executed as script:

    cd flat_export
    python __init__.py
    

Assuming this, the _import_mode_ should be direct:

>>> _import_mode_
'direct'

and sub2_func() should be available:

>>> sub2_func()
# sub2 !

sub1_func() should be overwritten by sub-module sub1:

>>> sub1_func()
# sub1 !

Initially The namespace is still pretty clean (python3 extra keys removed):

>>> print('\n'.join(sorted(k for k in locals().keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__all__
__builtins__
__doc__
__file__
__name__
__package__
_import_mode_
_modules_
_package_
sub1_func
sub2_func
sub3_func

But as soon, as you start doing stuff …:

>>> import os
>>> import sys
>>> from os import unlink

… things become messier:

>>> print('\n'.join(sorted(k for k in locals().keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__all__
__builtins__
__doc__
__file__
__name__
__package__
_import_mode_
_modules_
_package_
os
sub1_func
sub2_func
sub3_func
sys
unlink

but __all__ is still clean:

>>> print('\n'.join(__all__))
sub1_func
sub2_func
sub3_func

Note

locals() and globals() are identical, when the module is imported normally. They may be different if executed via exec with a separate parameter for locals.

Prepare for tests outside package directory

>>> import sys
>>> import os

Remove modules loaded by direct import:

>>> del(sys.modules['sub1'])
>>> del(sys.modules['sub2'])
>>> del(sys.modules['sub3'])

Remove script directory from sys.path:

>>> sys.path = [_p for _p in sys.path if _p != os.path.abspath(os.path.dirname(__file__))]

Add parent directory (as current directory) to path for module import:

>>> sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

Set current directory to parent directory of package directory:

>>> os.chdir(sys.path[0])

Setup namespace for next test (emulating empty script):

>>> for _name in list(locals().keys()):
...     if _name not in ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '_name']:
...         del(locals()[_name])
>>> del(_name)

Import mode internal – triggered by normal import

Executing in the package parent directory means, that the package is available for standard import.

Here are the currently defined names (python3 extra keys removed):

>>> print('\n'.join(sorted(k for k in locals().keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__builtins__
__doc__
__file__
__name__
__package__

After a standard import of all symbols …:

>>> from flat_export import *

… the additionally defined names sub1_func, sub2_func, sub3_func …:

>>> print('\n'.join(sorted(k for k in locals().keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__builtins__
__doc__
__file__
__name__
__package__
sub1_func
sub2_func
sub3_func

… are exactly what was intended:

>>> import flat_export
>>> flat_export.__all__
['sub1_func', 'sub2_func', 'sub3_func']

The sub-module imports were relative …:

>>> flat_export._import_mode_
'internal'

… and the function sub1_func is overwritten by sub-module sub1:

>>> sub1_func()
# sub1 !

Prepare for exec test

Setup namespace for next test (emulating empty script):

>>> import sys
>>> del(sys.modules['flat_export'])
>>> del(sys.modules['flat_export.sub1'])
>>> del(sys.modules['flat_export.sub2'])
>>> del(sys.modules['flat_export.sub3'])
>>> for _name in list(locals().keys()):
...     if _name not in ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '_name']:
...         del(locals()[_name])
>>> del(_name)

Import mode package – triggered by exec

In the package parent directory, define the module file and name in exec_locals_:

>>> mod_file = 'flat_export/__init__.py'
>>> exec_locals_ = dict(
...     __file__=mod_file,
...     __name__='__init__')

Run via exec, with __init__ as module name, collecting definitions in exec_locals_:

>>> exec(compile(open(mod_file, "rb").read(), mod_file, 'exec'), globals(), exec_locals_ )

The imports happened via standard import from the executed code:

>>> exec_locals_['_import_mode_']
'package'

__all__ is properly defined:

>>> exec_locals_['__all__']
['sub1_func', 'sub2_func', 'sub3_func']

The namespace is clean:

>>> print('\n'.join(sorted(k for k in exec_locals_.keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__all__
__doc__
__file__
__name__
_import_mode_
_modules_
_package_
sub1_func
sub2_func
sub3_func

This module’s locals are unaffected (python3 extra keys removed):

>>> print('\n'.join(sorted(k for k in locals().keys() if k not in '__cached__ __loader__ __spec__ __warningregistry__'.split())))
__builtins__
__doc__
__file__
__name__
__package__
exec_locals_
mod_file
flat_export.is_importing_package(_package_, locals_, dummy_name=None)[source]
Returns:

True, if relative package imports are working.

Parameters:
  • _package_ – the package name (unfortunately, __package__ does not work, since it is None, when loading :().
  • locals – module local variables for auto-removing function after use.
  • dummy_name – dummy module name (default: ‘dummy’).

Tries to do a relative import from an empty module .dummy. This avoids any secondary errors, other than:

ValueError: Attempted relative import in non-package
flat_export.sub1_func()[source]

Example function in module sub1.

flat_export.sub2_func()[source]

Example function in module sub1.

flat_export.sub3_func()[source]

Example function in module sub1.

Copyright

Copyright (C) 2017, Wolfgang Scherer, <wolfgang.scherer@gmx.de>. See the document source for conditions of use under the GNU Free Documentation License.