Allow loading non Python module formats as modules
Project description
Allow loading non Python module formats as modules.
Install
Use pip for installing:
$ pip install abm
Usage
Once installed, you can activate abm by importing abm.activate:
from abm import activate
Now you can register new loaders by doing:
from abm.loaders import IniLoader
IniLoader.register()
Since now, you can load *.ini files as if they were modules:
# config.ini
[section]
option = value
import config
assert(config['example'] is not None)
assert(config['example']['option'] is 'value')
Writing a loader
Extend the base loader AbmLoader provided in abm.loaders and implement create_module and execute_module methods. Provide the extension class member to allow automatic registration:
from configparser import ConfigParser
from types import ModuleType
from abm.loaders import AbmLoader
class IniLoader(AbmLoader):
extensions = ('.ini', )
def __init__(self, name, path):
self.file_path = path
def create_module(self, spec):
module = ConfigModule(spec.name)
self.init_module_attrs(spec, module)
return module
def exec_module(self, module):
module.read(self.file_path)
return module
class ConfigModule(ModuleType, ConfigParser):
def __init__(self, specname):
ModuleType.__init__(self, specname)
ConfigParser.__init__(self)
Loaders are initialized passing the name of the module in the form:
'path.to.the.module'
And its absolute path.
Implementing create_module
create_module function should produce a module of the correct type. Nothing more. This method is passed with the module specification object used to find the module:
def create_module(self, spec)
module = ConfigModule(spec.name)
self.init_module_attrs(spec, module)
return module
Implementing execute_module
execute_module function should contain the code for loading the contents of the module:
def execute_module(self, module):
module.read(self.file_path)
return module
A good tip for determining how to implement this method is imagining you trigger a reload of the module: the code syncing the module contents with the file is what you should put here.
Overriding builtin extensions
Overriding builtin extensions such as .py, .pyc or .so is possible by passing override_builtins=True to the register() method.
from abm.loaders import AbmLoader
class BreakPyModules(AbmLoader):
extensions = ('.py', )
def create_module():
raise NotImplementedError('Can load .py modules no more.')
BreakPythonModules.register(override_builtins=True)
Use this with caution since you can break the import system. Not passing override_builtins results in a ValueError exception.
How does it work
Extension mechanism work by monkeypatching the FileFinder class in charge of reading Python several format modules from the local file system.
Internally, FileFinder uses file loaders to read the several formats of Python modules identified by their file extension. Although these classes are public, FileFinder does not expose any extension mechanism to link new extensions with new loaders.
In the spirit of sys.path_hooks and other extension hooks, activating abm will expose a dictionary in sys.abm_hooks to register new loaders dynamically. For instance:
import sys
from abm.loaders import IniLoader
from abm.core import activate
activate()
sys.abm_hooks['.ini'] = IniLoader
It works by turning the internal instance attribute _loaders of FileFinder instances into a class property. Setting the property will diverge the new value to a different attribute while reading the value will combine the original one with the extensions in sys.abm_hooks.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file abm-0.3.0.tar.gz
.
File metadata
- Download URL: abm-0.3.0.tar.gz
- Upload date:
- Size: 6.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/40.6.2 requests-toolbelt/0.9.1 tqdm/4.42.1 CPython/3.7.2
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 57dca3bcc24649f0b58eebd7e0decfdc473bb15a9dc586e2af8c6c7d79090759 |
|
MD5 | e38de4261f65bd08179ea6088fcb964f |
|
BLAKE2b-256 | 2074227e679e53b204e58ade7998dc304f5aa5a7b8b09f7adcb64df555229224 |