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)
python
flat_export/__init__.py
)if not _loaded:
try:
exec('from ' + _package_ + ' import *')
exec('from ' + _package_ + ' import __all__')
_loaded = True
except (ImportError):
pass
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
- _package_ – the package name (unfortunately, __package__
does not work, since it is None, when loading
Copyright
Copyright (C) 2017, Wolfgang Scherer, <wolfgang.scherer@gmx.de>. See the document source for conditions of use under the GNU Free Documentation License.