-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from DavidCEllis/improve_coverage
Improve coverage, simplify readme, enhance docs
- Loading branch information
Showing
8 changed files
with
322 additions
and
155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Extending by subclassing ImportBase # | ||
|
||
Perhaps the included Import classes don't cover the import type you're looking | ||
for and you need an extension. These can be made by subclassing `ImportBase`. | ||
|
||
Subclasses of `ImportBase` require 3 things: | ||
|
||
`module_name` attribute must be the name of the default module to be imported. | ||
|
||
`asname` or `asnames` must be either the identifier or a list of identifiers | ||
(respectively) to use to store attributes. This can be an attribute or a property. | ||
|
||
`do_import` must be a method that takes 2 arguments `(self, globs=None)`, performs | ||
the import and returns a dictionary of the form `{asname: <object>, ...}` for all of | ||
the names defined in `asname`/`asnames`. | ||
|
||
For example say you want an importer that can do this kind of import: | ||
|
||
```python | ||
import sys | ||
if sys.version_info >= (3, 12): | ||
import tomllib | ||
else: | ||
import tomli as tomllib | ||
``` | ||
|
||
You could write something like this: | ||
|
||
```python | ||
# NOTE: This is a simplified example using importlib.import_module | ||
import importlib | ||
from ducktools.lazyimporter import ImportBase, LazyImporter | ||
|
||
|
||
class IfElseImporter(ImportBase): | ||
def __init__(self, condition, module_name, else_module_name, asname): | ||
self.condition = condition | ||
self.module_name = module_name | ||
self.else_module_name = else_module_name | ||
self.asname = asname | ||
|
||
if not self.asname.isidentifier(): | ||
raise ValueError(f"{self.asname} is not a valid python identifier.") | ||
|
||
def do_import(self, globs=None): | ||
if globs is not None: | ||
package = globs.get('__name__') | ||
else: | ||
package = None | ||
|
||
if self.condition: | ||
mod = importlib.import_module(self.module_name, package) | ||
else: | ||
mod = importlib.import_module(self.else_module_name, package) | ||
|
||
return {self.asname: mod} | ||
|
||
``` | ||
|
||
And then use it with: | ||
|
||
```python | ||
import sys | ||
|
||
laz = LazyImporter([ | ||
IfElseImporter( | ||
condition=sys.version_info >= (3, 12), | ||
module_name="tomllib", | ||
else_module_name="tomli", | ||
asname="tomllib", | ||
) | ||
]) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
## The import classes ## | ||
|
||
In all of these instances `modules` is intended as the first argument | ||
to `LazyImporter` and all attributes would be accessed from the | ||
`LazyImporter` instance and not in the global namespace. | ||
|
||
eg: | ||
```python | ||
from ducktools.lazyimporter import LazyImporter, ModuleImport | ||
|
||
modules = [ModuleImport("functools")] | ||
laz = LazyImporter(modules) | ||
laz.functools # provides access to the module "functools" | ||
``` | ||
|
||
### ModuleImport ### | ||
|
||
`ModuleImport` is used for your basic module style imports. | ||
|
||
```python | ||
from ducktools.lazyimporter import ModuleImport | ||
|
||
modules = [ | ||
ModuleImport("module"), | ||
ModuleImport("other_module", "other_name"), | ||
ModuleImport("base_module.submodule", asname="short_name"), | ||
] | ||
``` | ||
|
||
is equivalent to | ||
|
||
``` | ||
import module | ||
import other_module as other_name | ||
import base_module.submodule as short_name | ||
``` | ||
|
||
when provided to a LazyImporter. | ||
|
||
### FromImport and MultiFromImport ### | ||
|
||
`FromImport` is used for standard 'from' imports, `MultiFromImport` for importing | ||
multiple items from the same module. By using a `MultiFromImport`, when the first | ||
attribute is accessed, all will be assigned on the LazyImporter. | ||
|
||
```python | ||
from ducktools.lazyimporter import FromImport, MultiFromImport | ||
|
||
modules = [ | ||
FromImport("dataclasses", "dataclass"), | ||
FromImport("functools", "partial", "partfunc"), | ||
MultiFromImport("collections", ["namedtuple", ("defaultdict", "dd")]), | ||
] | ||
``` | ||
|
||
is equivalent to | ||
|
||
```python | ||
from dataclasses import dataclass | ||
from functools import partial as partfunc | ||
from collections import namedtuple, defaultdict as dd | ||
``` | ||
|
||
when provided to a LazyImporter. | ||
|
||
### TryExceptImport ### | ||
|
||
`TryExceptImport` is used for compatibility where a module may not be available | ||
and so a fallback module providing the same functionality should be used. For | ||
example when a newer version of python has a stdlib module that has replaced | ||
a third party module that was used previously. | ||
|
||
```python | ||
from ducktools.lazyimporter import TryExceptImport | ||
|
||
modules = [ | ||
TryExceptImport("tomllib", "tomli", "tomllib"), | ||
] | ||
``` | ||
|
||
is equivalent to | ||
|
||
```python | ||
try: | ||
import tomllib as tomllib | ||
except ImportError: | ||
import tomli as tomllib | ||
``` | ||
|
||
when provided to a LazyImporter. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Importer internal state # | ||
|
||
The function `get_importer_state` is provided to show the state | ||
of the lazy importer, showing which imports have run and which | ||
are still deferred. | ||
|
||
For example: | ||
|
||
```python | ||
from ducktools.lazyimporter import ( | ||
LazyImporter, | ||
ModuleImport, | ||
FromImport, | ||
MultiFromImport, | ||
get_importer_state, | ||
) | ||
|
||
# Setup attributes but don't perform any imports | ||
laz = LazyImporter([ | ||
MultiFromImport( | ||
"collections", [("namedtuple", "nt"), "OrderedDict"] | ||
), | ||
FromImport("pprint", "pprint"), | ||
FromImport("functools", "partial"), | ||
ModuleImport("inspect"), | ||
]) | ||
|
||
print("Possible attributes:") | ||
laz.pprint(dir(laz)) | ||
print() | ||
|
||
print("pprint imported:") | ||
laz.pprint(get_importer_state(laz)) | ||
print() | ||
|
||
_ = laz.nt | ||
print("Collections elements imported:") | ||
laz.pprint(get_importer_state(laz)) | ||
print() | ||
|
||
_ = laz.partial | ||
print("Functools elements imported:") | ||
laz.pprint(get_importer_state(laz)) | ||
print() | ||
``` | ||
|
||
Output: | ||
``` | ||
Possible attributes: | ||
['OrderedDict', 'inspect', 'nt', 'partial', 'pprint'] | ||
pprint imported: | ||
{'imported_attributes': {'pprint': <function pprint at ...>}, | ||
'lazy_attributes': ['OrderedDict', 'inspect', 'nt', 'partial']} | ||
Collections elements imported: | ||
{'imported_attributes': {'OrderedDict': <class 'collections.OrderedDict'>, | ||
'nt': <function namedtuple at ...>, | ||
'pprint': <function pprint at ...>}, | ||
'lazy_attributes': ['inspect', 'partial']} | ||
Functools elements imported: | ||
{'imported_attributes': {'OrderedDict': <class 'collections.OrderedDict'>, | ||
'nt': <function namedtuple at ...>, | ||
'partial': <class 'functools.partial'>, | ||
'pprint': <function pprint at ...}, | ||
'lazy_attributes': ['inspect']} | ||
``` |
Oops, something went wrong.