immlib 1.0.0.dev1__tar.gz → 1.0.0.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {immlib-1.0.0.dev1/src/immlib.egg-info → immlib-1.0.0.dev2}/PKG-INFO +27 -12
- immlib-1.0.0.dev2/README.md +26 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/pyproject.toml +10 -6
- immlib-1.0.0.dev2/src/immlib/__init__.py +131 -0
- immlib-1.0.0.dev2/src/immlib/_init.py +108 -0
- immlib-1.0.0.dev2/src/immlib/_version.py +235 -0
- immlib-1.0.0.dev2/src/immlib/doc/__init__.py +38 -0
- immlib-1.0.0.dev2/src/immlib/doc/_core.py +311 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/iolib/__init__.py +2 -4
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/iolib/_core.py +5 -5
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/__init__.py +3 -11
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_cache.py +4 -4
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_core.py +291 -262
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_osf.py +64 -55
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/__init__.py +1 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/doc/test_core.py +2 -1
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/test_core.py +12 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/test_osf.py +0 -5
- immlib-1.0.0.dev2/src/immlib/test/types/__init__.py +5 -0
- immlib-1.0.0.dev2/src/immlib/test/types/test_core.py +110 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/__init__.py +1 -0
- immlib-1.0.0.dev2/src/immlib/test/util/test_core.py +681 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/test_numeric.py +707 -186
- immlib-1.0.0.dev2/src/immlib/test/util/test_url.py +51 -0
- immlib-1.0.0.dev2/src/immlib/test/workflow/test_core.py +418 -0
- immlib-1.0.0.dev2/src/immlib/test/workflow/test_plantype.py +248 -0
- immlib-1.0.0.dev2/src/immlib/types/__init__.py +29 -0
- immlib-1.0.0.dev2/src/immlib/types/_core.py +333 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/util/__init__.py +54 -23
- immlib-1.0.0.dev2/src/immlib/util/_core.py +2524 -0
- immlib-1.0.0.dev2/src/immlib/util/_numeric.py +2651 -0
- immlib-1.0.0.dev2/src/immlib/util/_quantity.py +523 -0
- immlib-1.0.0.dev2/src/immlib/util/_url.py +114 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/workflow/__init__.py +11 -12
- immlib-1.0.0.dev2/src/immlib/workflow/_core.py +1635 -0
- immlib-1.0.0.dev2/src/immlib/workflow/_plantype.py +334 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2/src/immlib.egg-info}/PKG-INFO +27 -12
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/SOURCES.txt +6 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/requires.txt +8 -4
- immlib-1.0.0.dev1/README.md +0 -17
- immlib-1.0.0.dev1/src/immlib/__init__.py +0 -88
- immlib-1.0.0.dev1/src/immlib/_version.py +0 -94
- immlib-1.0.0.dev1/src/immlib/doc/__init__.py +0 -22
- immlib-1.0.0.dev1/src/immlib/doc/_core.py +0 -103
- immlib-1.0.0.dev1/src/immlib/test/util/test_core.py +0 -208
- immlib-1.0.0.dev1/src/immlib/test/workflow/test_core.py +0 -219
- immlib-1.0.0.dev1/src/immlib/test/workflow/test_plantype.py +0 -105
- immlib-1.0.0.dev1/src/immlib/util/_core.py +0 -1943
- immlib-1.0.0.dev1/src/immlib/util/_numeric.py +0 -1686
- immlib-1.0.0.dev1/src/immlib/util/_quantity.py +0 -496
- immlib-1.0.0.dev1/src/immlib/util/_url.py +0 -98
- immlib-1.0.0.dev1/src/immlib/workflow/_core.py +0 -1104
- immlib-1.0.0.dev1/src/immlib/workflow/_plantype.py +0 -258
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/LICENSE +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/setup.cfg +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/__main__.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/doc/__init__.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/iolib/__init__.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/iolib/test_core.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/__init__.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/test_quantity.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/workflow/__init__.py +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/dependency_links.txt +0 -0
- {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: immlib
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev2
|
|
4
4
|
Summary: A library of utilites for immutable scientific data.
|
|
5
5
|
Author-email: "Noah C. Benson" <nben@uw.edu>
|
|
6
6
|
License: MIT
|
|
@@ -16,6 +16,8 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.9
|
|
17
17
|
Classifier: Programming Language :: Python :: 3.10
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
21
|
Classifier: Topic :: Software Development
|
|
20
22
|
Classifier: Topic :: Software Development :: Libraries
|
|
21
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
@@ -28,34 +30,47 @@ Classifier: Operating System :: MacOS
|
|
|
28
30
|
Requires-Python: >=3.8
|
|
29
31
|
Description-Content-Type: text/markdown
|
|
30
32
|
License-File: LICENSE
|
|
31
|
-
Requires-Dist: pcollections>=0.2
|
|
33
|
+
Requires-Dist: pcollections>=0.3.2
|
|
32
34
|
Requires-Dist: numpy>=1.24.0
|
|
33
35
|
Requires-Dist: scipy>=1.7.0
|
|
34
|
-
Requires-Dist: pint>=0.
|
|
36
|
+
Requires-Dist: pint>=0.20.0
|
|
35
37
|
Requires-Dist: docrep>=0.3.2
|
|
36
38
|
Requires-Dist: joblib>=1.3.0
|
|
37
39
|
Requires-Dist: cloudpathlib[azure,gs,s3]>=0.18.0
|
|
40
|
+
Requires-Dist: pyyaml>=6.0
|
|
38
41
|
Provides-Extra: dev
|
|
39
42
|
Requires-Dist: torch>=2.2.0; extra == "dev"
|
|
40
|
-
Requires-Dist: pyyaml; extra == "dev"
|
|
41
43
|
Provides-Extra: test
|
|
42
44
|
Requires-Dist: torch>=2.2.0; extra == "test"
|
|
43
|
-
|
|
45
|
+
Provides-Extra: docs
|
|
46
|
+
Requires-Dist: torch>=2.2.0; extra == "docs"
|
|
47
|
+
Requires-Dist: jupyter-book>=1.0.0; extra == "docs"
|
|
48
|
+
Requires-Dist: matplotlib>=3.4.0; extra == "docs"
|
|
49
|
+
Dynamic: license-file
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+

|
|
46
52
|
|
|
47
53
|

|
|
48
54
|
[](https://codecov.io/gh/noahbenson/immlib)
|
|
49
55
|
[](https://badge.fury.io/py/immlib)
|
|
50
56
|
|
|
51
|
-
`immlib` is a library of utilities for managing and manipulating immutable
|
|
52
|
-
scientific data with a focus on lazy calculations and workflows. It is based on
|
|
53
|
-
a prototype library [`pimms`](https://github.com/noahbenson/pimms).
|
|
54
|
-
|
|
55
57
|
---
|
|
56
58
|
|
|
57
59
|
**Author**: Noah C. Benson <[nben@uw.edu](mailto:nben@uw.edu)>
|
|
58
|
-
**License**: MIT
|
|
60
|
+
**License**: MIT
|
|
61
|
+
**[Documentation](https://noahbenson.github.io/immlib)**
|
|
59
62
|
|
|
60
63
|
---
|
|
61
64
|
|
|
65
|
+
`immlib` is a lightweight Python library that simplifies the design of
|
|
66
|
+
application programming interfaces (APIs) for scientific libraries. The name
|
|
67
|
+
immlib comes from the library’s philosophy of using immutable data to simplify
|
|
68
|
+
scientific workflows.
|
|
69
|
+
|
|
70
|
+
`immlib` is heavily based on the library
|
|
71
|
+
[`pimms`](https://github.com/noahbenson/pimms), which effectively served as a
|
|
72
|
+
prototype for `immlib`. Both libraries were motivated by a number of observations
|
|
73
|
+
about the design of scientific software and are an attempt to make some of these
|
|
74
|
+
problems easier to manage.
|
|
75
|
+
|
|
76
|
+
For more information, see the [documentation](https://noahbenson.github.io/immlib).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
[](https://codecov.io/gh/noahbenson/immlib)
|
|
5
|
+
[](https://badge.fury.io/py/immlib)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
**Author**: Noah C. Benson <[nben@uw.edu](mailto:nben@uw.edu)>
|
|
10
|
+
**License**: MIT
|
|
11
|
+
**[Documentation](https://noahbenson.github.io/immlib)**
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
`immlib` is a lightweight Python library that simplifies the design of
|
|
16
|
+
application programming interfaces (APIs) for scientific libraries. The name
|
|
17
|
+
immlib comes from the library’s philosophy of using immutable data to simplify
|
|
18
|
+
scientific workflows.
|
|
19
|
+
|
|
20
|
+
`immlib` is heavily based on the library
|
|
21
|
+
[`pimms`](https://github.com/noahbenson/pimms), which effectively served as a
|
|
22
|
+
prototype for `immlib`. Both libraries were motivated by a number of observations
|
|
23
|
+
about the design of scientific software and are an attempt to make some of these
|
|
24
|
+
problems easier to manage.
|
|
25
|
+
|
|
26
|
+
For more information, see the [documentation](https://noahbenson.github.io/immlib).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "immlib"
|
|
3
|
-
version = "1.0.0.
|
|
3
|
+
version = "1.0.0.dev2"
|
|
4
4
|
description = """A library of utilites for immutable scientific data."""
|
|
5
5
|
authors = [{name="Noah C. Benson", email="nben@uw.edu"}]
|
|
6
6
|
license = {"text"="MIT"}
|
|
@@ -16,6 +16,8 @@ classifiers = [
|
|
|
16
16
|
'Programming Language :: Python :: 3.9',
|
|
17
17
|
'Programming Language :: Python :: 3.10',
|
|
18
18
|
'Programming Language :: Python :: 3.11',
|
|
19
|
+
'Programming Language :: Python :: 3.12',
|
|
20
|
+
'Programming Language :: Python :: 3.13',
|
|
19
21
|
'Topic :: Software Development',
|
|
20
22
|
'Topic :: Software Development :: Libraries',
|
|
21
23
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
@@ -26,17 +28,19 @@ classifiers = [
|
|
|
26
28
|
'Operating System :: Unix',
|
|
27
29
|
'Operating System :: MacOS']
|
|
28
30
|
dependencies = [
|
|
29
|
-
'pcollections >= 0.2
|
|
31
|
+
'pcollections >= 0.3.2',
|
|
30
32
|
'numpy >= 1.24.0',
|
|
31
33
|
'scipy >= 1.7.0',
|
|
32
|
-
'pint >= 0.
|
|
34
|
+
'pint >= 0.20.0',
|
|
33
35
|
'docrep >= 0.3.2',
|
|
34
36
|
'joblib >= 1.3.0',
|
|
35
|
-
'cloudpathlib[s3,gs,azure] >= 0.18.0'
|
|
37
|
+
'cloudpathlib[s3,gs,azure] >= 0.18.0',
|
|
38
|
+
'pyyaml >= 6.0']
|
|
36
39
|
|
|
37
40
|
[project.optional-dependencies]
|
|
38
|
-
dev = ["torch >= 2.2.0"
|
|
39
|
-
test = ["torch >= 2.2.0"
|
|
41
|
+
dev = ["torch >= 2.2.0"]
|
|
42
|
+
test = ["torch >= 2.2.0"]
|
|
43
|
+
docs = ["torch >= 2.2.0", "jupyter-book >= 1.0.0", "matplotlib >= 3.4.0"]
|
|
40
44
|
|
|
41
45
|
[project.urls]
|
|
42
46
|
homepage = "https://github.com/noahbenson/immlib"
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
###############################################################################
|
|
3
|
+
# immlib/__init__.py
|
|
4
|
+
|
|
5
|
+
'''``immlib`` is a library of tools for manipulating immutable scientific data.
|
|
6
|
+
|
|
7
|
+
The ``immlib`` library is designed to enable immutable data structures and lazy
|
|
8
|
+
computation in a scientific context, and it works primarily via a collection of
|
|
9
|
+
utility functions and through the use of decorators, which are generally
|
|
10
|
+
applied to classes and their members to declare how an immutable
|
|
11
|
+
data-structure's members are related. Taken together, these utilities form a
|
|
12
|
+
DSL-like system for declaring workflows and immutable data-structures with full
|
|
13
|
+
inheritance support.
|
|
14
|
+
|
|
15
|
+
Attributes
|
|
16
|
+
----------
|
|
17
|
+
units : pint.UnitRegistry
|
|
18
|
+
The registry for units tracked by ``immlib``. The ``immlib.units`` object
|
|
19
|
+
is a global ``pint``-module unit registry that can be used as a single
|
|
20
|
+
global place for tracking units. Immlib functions that interact with units
|
|
21
|
+
generally take an argument ``ureg`` that can be used to modify this
|
|
22
|
+
registry. Additionally, the default registry (this object,
|
|
23
|
+
``immlib.units``) can be temporarily changed in a local block using ``with
|
|
24
|
+
immlib.default_ureg(ureg): ...``.
|
|
25
|
+
version : immlib.Version
|
|
26
|
+
A representation of the ``immlib`` version. The version string may be
|
|
27
|
+
obtained via ``immlib.version.string``; major, minor, and micro numbers
|
|
28
|
+
(when present) may be obtained via ``immlib.version.major``,
|
|
29
|
+
``immlib.version.minor``, and ``immlib.version.micro`` (when not provided
|
|
30
|
+
the are set to ``None``), and a stage tag (a string), if given, can be
|
|
31
|
+
obtained via ``immlib.version.stage``.
|
|
32
|
+
submodules : tuple of str
|
|
33
|
+
A tuple of strings, each of which is the name of one of the submodules in
|
|
34
|
+
``immlib``. The modules are listed in load-order and all ``immlib``
|
|
35
|
+
submodules, including private submodules, are included.
|
|
36
|
+
docproc: docrep.DocstringProcessor object
|
|
37
|
+
This object is used to process all of the doc-strings in the ``immlib``
|
|
38
|
+
library; it should be used only with the ``immlib.docwrap`` decorator,
|
|
39
|
+
which can safely be applied anywhere in a sequence of decorators and which
|
|
40
|
+
correctly applies the ``wraps`` decorator to its argument. Function
|
|
41
|
+
documentation is always processed using the ``sections=('Parameters',
|
|
42
|
+
'Returns', 'Raises', 'Examples', 'Inputs', 'Outputs')`` parameter and the
|
|
43
|
+
``with_indent(4)`` decorator. The base-name for the function ``f`` is
|
|
44
|
+
``f.__module__ + '.' + f.__name__``.
|
|
45
|
+
'''
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Imports #####################################################################
|
|
49
|
+
|
|
50
|
+
# We always load _init first.
|
|
51
|
+
from ._init import reclaim
|
|
52
|
+
# Then the core library.
|
|
53
|
+
from .doc import *
|
|
54
|
+
from .util import *
|
|
55
|
+
from .pathlib import *
|
|
56
|
+
from .iolib import *
|
|
57
|
+
from .workflow import *
|
|
58
|
+
from .types import *
|
|
59
|
+
# Import the Global UnitRegistry object to the global immlib scope. This is the
|
|
60
|
+
# value that gets updated when one runs `immlib.default_ureg()`, and this is
|
|
61
|
+
# the UnitRegistry that is used as the default registry for all ``immlib``
|
|
62
|
+
# functions.
|
|
63
|
+
from .util._quantity import _initial_global_ureg as units
|
|
64
|
+
# Do the same for the global DocstringProcessor (from the docrep library) from
|
|
65
|
+
# the doc subpackage.
|
|
66
|
+
from .doc._core import _initial_global_docproc as docproc
|
|
67
|
+
# We want the version object from the ._version namespace; this is always last.
|
|
68
|
+
from ._version import (version, Version)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Modules/Reloading ###########################################################
|
|
72
|
+
|
|
73
|
+
submodules = (
|
|
74
|
+
'immlib._init',
|
|
75
|
+
'immlib.doc._core',
|
|
76
|
+
'immlib.doc',
|
|
77
|
+
'immlib.util._core',
|
|
78
|
+
'immlib.util._numeric',
|
|
79
|
+
'immlib.util._quantity',
|
|
80
|
+
'immlib.util',
|
|
81
|
+
'immlib.pathlib._osf',
|
|
82
|
+
'immlib.pathlib._cache',
|
|
83
|
+
'immlib.pathlib._core',
|
|
84
|
+
'immlib.pathlib',
|
|
85
|
+
'immlib.iolib._core',
|
|
86
|
+
'immlib.iolib',
|
|
87
|
+
'immlib.workflow._core',
|
|
88
|
+
'immlib.workflow._plantype',
|
|
89
|
+
'immlib.workflow',
|
|
90
|
+
'immlib.types._core',
|
|
91
|
+
'immlib.types',
|
|
92
|
+
'immlib._version')
|
|
93
|
+
def reload_immlib():
|
|
94
|
+
"""Reload and return the entire ``immlib`` package.
|
|
95
|
+
|
|
96
|
+
``immlib.reload_immlib()`` reloads every submodule in the ``immlib``
|
|
97
|
+
package then reloads ``immlib`` itself, and returns the reloaded package.
|
|
98
|
+
|
|
99
|
+
.. Warning:: This function exists primarily for debugging purposes; its use
|
|
100
|
+
is not generally needed or advised by users of the library.
|
|
101
|
+
|
|
102
|
+
Returns
|
|
103
|
+
-------
|
|
104
|
+
module
|
|
105
|
+
The newly reloaded ``immlib`` module.
|
|
106
|
+
|
|
107
|
+
Examples
|
|
108
|
+
--------
|
|
109
|
+
>>> import immlib as il
|
|
110
|
+
>>> il.units = None # This will break parts of the library.
|
|
111
|
+
>>> il = il.reload_immlib() # But this resets it.
|
|
112
|
+
>>> il.units is not None
|
|
113
|
+
True
|
|
114
|
+
"""
|
|
115
|
+
import sys, importlib
|
|
116
|
+
for mod in submodules:
|
|
117
|
+
importlib.reload(sys.modules[mod])
|
|
118
|
+
return importlib.reload(sys.modules[__name__])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# Package Meta-Code ###########################################################
|
|
122
|
+
|
|
123
|
+
__version__ = version.string
|
|
124
|
+
__all__ = tuple(
|
|
125
|
+
[k for k in locals()
|
|
126
|
+
if k[0] != '_'
|
|
127
|
+
if k != 'submodules'
|
|
128
|
+
if k != 'version'
|
|
129
|
+
if ('immlib.' + k) not in submodules])
|
|
130
|
+
# We want to mark our functions as being from the immlib module.
|
|
131
|
+
reclaim(__name__, __all__, del_reclaim=True)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
###############################################################################
|
|
3
|
+
# immlib/_init.py
|
|
4
|
+
|
|
5
|
+
"""Utilities and global definitions needed by theoretically the entire rest of
|
|
6
|
+
the `immlib` library during the import process.
|
|
7
|
+
|
|
8
|
+
The `immlib._init` module is the first submodule of the `immlib` library that
|
|
9
|
+
is loaded during the import process and is the firt that is reloaded when the
|
|
10
|
+
`immlib.reload_immlib()` library is called. Accordingly, functions and
|
|
11
|
+
variables that are needed by other modules can be put here. These functions and
|
|
12
|
+
variables, if they are intended to be public, should be reclaimed by another
|
|
13
|
+
module (see the `immlib._init.reclaim` / `immlib.util.reclaim` function).
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Dependencies ################################################################
|
|
18
|
+
|
|
19
|
+
import sys
|
|
20
|
+
from types import ModuleType
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Utility Functions ###########################################################
|
|
24
|
+
|
|
25
|
+
def reclaim(modname, attributes=Ellipsis, *,
|
|
26
|
+
del_reclaim=False,
|
|
27
|
+
skip_externs=True,
|
|
28
|
+
skip_private=True,
|
|
29
|
+
skip_modules=True):
|
|
30
|
+
"""Sets the ``__module__`` attributes of objects in the module whose name
|
|
31
|
+
is `modname` to be `modname`.
|
|
32
|
+
|
|
33
|
+
``reclaim(__name__, __all__)``, when run at the end of an ``__init__.py``
|
|
34
|
+
file, will set the module names of all objects in that module's ``__all__``
|
|
35
|
+
list to be ``__name__``, effectively hiding any submodule ownership of
|
|
36
|
+
those objects.
|
|
37
|
+
|
|
38
|
+
``reclaim(__name__)`` attempts to reclaim all attributes in the module, not
|
|
39
|
+
just those in the ``__all__`` list.
|
|
40
|
+
|
|
41
|
+
Parameters
|
|
42
|
+
----------
|
|
43
|
+
modname : str
|
|
44
|
+
The name of the module to reclaim. Typically, ``reclaim`` is called
|
|
45
|
+
from an ``__init__.py`` file using the syntax ``reclaim(__name__)`` or
|
|
46
|
+
``reclaim(__name__, __all__)``.
|
|
47
|
+
attributes : Ellipsis | iterable of str, optional
|
|
48
|
+
The attributes to reclaim. If this is explicitly given then it must be
|
|
49
|
+
an iterable of attribute names (strings). In this case, no additional
|
|
50
|
+
checks implied by the subsequent ``skip_`` and ``only_`` parameters are
|
|
51
|
+
performed. If `attributes` is not provided or is given the value of
|
|
52
|
+
``Ellipsis`` (the default), then all attributes of the module are
|
|
53
|
+
considered, and the filters specified by the subsequent options are
|
|
54
|
+
applied.
|
|
55
|
+
del_reclaim : bool, optional
|
|
56
|
+
If the optional argument `del_reclaim` is set to ``True``, then the
|
|
57
|
+
``reclaim`` attribute is deleted from the module as well. This can be
|
|
58
|
+
used to automatically sanitize a module.
|
|
59
|
+
skip_externs : bool, optional
|
|
60
|
+
The `skip_externs` option (default: ``True``) can be set to ``False``
|
|
61
|
+
to instruct the ``reclaim`` function to include attributes that are not
|
|
62
|
+
from a submodule of the module named by `modname`.
|
|
63
|
+
|
|
64
|
+
If this option is set to ``True``, then attributes of the module on
|
|
65
|
+
which ``reclaim`` is run are only reclaimed if they belong to a
|
|
66
|
+
submodule of of that module.
|
|
67
|
+
|
|
68
|
+
.. Warning:: If `skip_externs` is set to ``False``, attributes like
|
|
69
|
+
``np`` from the import statement ``import numpy as np`` at the top
|
|
70
|
+
of an ``__init__.py`` file can result in the ``numpy`` module being
|
|
71
|
+
reclaimed (if ``skip_modules`` is also ``False``). Similarly, if
|
|
72
|
+
the line ``from immlib.util import reclaim`` appears in an
|
|
73
|
+
``__init__.py`` file followed by ``reclaim(__name__,
|
|
74
|
+
skip_externs=False)`` then the ``reclaim`` function will be
|
|
75
|
+
reclaimed by the module.
|
|
76
|
+
skip_private : boolean, optional
|
|
77
|
+
The `skip_private` option may be set to ``False`` to instruct the
|
|
78
|
+
function to claim ownership over attributes whose names begin with the
|
|
79
|
+
underscore (``_``) charcter. If this is not provided or is ``True``,
|
|
80
|
+
then such attributes are skipped.
|
|
81
|
+
skip_modules : boolean, optional
|
|
82
|
+
The `skip_modules` option (default: ``True``) may be set to false to
|
|
83
|
+
instruct the ``reclaim`` function to attempt to reclaim modules as well
|
|
84
|
+
as functions and attributes.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
str
|
|
89
|
+
The module named by the given `modname` argument.
|
|
90
|
+
"""
|
|
91
|
+
mod = sys.modules[modname]
|
|
92
|
+
for k in dir(mod):
|
|
93
|
+
if skip_private and k[0] == '_':
|
|
94
|
+
continue
|
|
95
|
+
obj = getattr(mod, k)
|
|
96
|
+
if skip_modules and isinstance(obj, ModuleType):
|
|
97
|
+
continue
|
|
98
|
+
if del_reclaim and obj is reclaim:
|
|
99
|
+
continue
|
|
100
|
+
objmodname = getattr(obj, '__module__', modname)
|
|
101
|
+
if objmodname == modname:
|
|
102
|
+
continue
|
|
103
|
+
if skip_externs and not objmodname.startswith(modname):
|
|
104
|
+
continue
|
|
105
|
+
obj.__module__ = modname
|
|
106
|
+
if del_reclaim and hasattr(mod, 'reclaim'):
|
|
107
|
+
delattr(mod, 'reclaim')
|
|
108
|
+
return mod
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
################################################################################
|
|
3
|
+
# immlib/_version.py
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Dependencies #################################################################
|
|
7
|
+
|
|
8
|
+
from ast import literal_eval
|
|
9
|
+
from collections import namedtuple
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from warnings import warn
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Version Type #################################################################
|
|
15
|
+
|
|
16
|
+
VersionTuple = namedtuple(
|
|
17
|
+
'VersionTuple',
|
|
18
|
+
['string', 'tuple', 'major', 'minor', 'micro', 'stage'])
|
|
19
|
+
class Version(VersionTuple):
|
|
20
|
+
"""A type that represents a Python package version.
|
|
21
|
+
|
|
22
|
+
Python packages are represented simultaneously as version strings, version
|
|
23
|
+
tuples, and by the version components `major`, `minor`, `micro`, and
|
|
24
|
+
`stage`.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
string : str or None, optional
|
|
29
|
+
The version string to be represented. If this argument is not provided,
|
|
30
|
+
then one or both of the `package_name` and `pyproject_path` options must
|
|
31
|
+
be provided so that the version string can be obtained via the package
|
|
32
|
+
version or the `pyproject.toml` file.
|
|
33
|
+
package_name : str or None, optional
|
|
34
|
+
If the first argument (`string`) is provided, then this argument is
|
|
35
|
+
ignored; otherwise, the version string is first searched for by this
|
|
36
|
+
package name using the `importlib` or `importlib_metadata` packages. If
|
|
37
|
+
found, then this version string is represented in the `Version` object.
|
|
38
|
+
pyproject_path : path-like or None, optional
|
|
39
|
+
If the first argument (`string`) is not given and the `package_name` is
|
|
40
|
+
not given, then the version is searched for in the `pyproject.toml` file
|
|
41
|
+
given by this path. In order for such a file to be valid, it must
|
|
42
|
+
contain a line that, when stripped of whitespace, begins with the string
|
|
43
|
+
`'version='` followed by a string representation (e.g.,
|
|
44
|
+
`'version="1.12.5"'`). If such a line is found in the `[project]`
|
|
45
|
+
section of the TOM: file pointed to by this argument, then it is
|
|
46
|
+
represented as the version string in the `Version` object.
|
|
47
|
+
on_error : {'warn' | 'ignore' | 'raise'}, optional
|
|
48
|
+
How to handle failures to deduce or parse the version number. If
|
|
49
|
+
`'raise'` is given, then the errors are allowed to be raised. If
|
|
50
|
+
`'warn'`, then a warning is raised and a null version is returned. If
|
|
51
|
+
`'ignore'`, then errors are ignored and a null version is returned. The
|
|
52
|
+
default is `'raise'`.
|
|
53
|
+
tag_prefixes : tuple of str, optional
|
|
54
|
+
An optional tuple of strings that can appear as the prefixes of stage
|
|
55
|
+
tagss at the end of the version string. By default, this is `('rc', 'a',
|
|
56
|
+
'b')`, so version strings like `'1.1.12a6'` and `'1.1.12rc6'` are valid
|
|
57
|
+
but `'1.1.12c6'` is not.
|
|
58
|
+
|
|
59
|
+
Attributes
|
|
60
|
+
----------
|
|
61
|
+
string : str
|
|
62
|
+
The string representing the package version. For example `"1.2.15"` or
|
|
63
|
+
`"0.2.2.dev1"`.
|
|
64
|
+
tuple : tuple of int and str
|
|
65
|
+
The components of the version string, for example, `(1, 2, 15)` or
|
|
66
|
+
`(0, 2, 2, 'dev1')`. Any missing component is excluded.
|
|
67
|
+
major : int
|
|
68
|
+
The major version number, typically indicates major API version.
|
|
69
|
+
minor : int
|
|
70
|
+
The minor version number, typically indicates minor API version.
|
|
71
|
+
micro : int
|
|
72
|
+
The micro version number, typically indicates patch increment number.
|
|
73
|
+
stage : str
|
|
74
|
+
The development stage of the version. For example `'dev1'` or `'rc2'`.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# Static Methods -----------------------------------------------------------
|
|
78
|
+
def getstring(package_name=None, pyproject_path=None):
|
|
79
|
+
"""Returns the current version string for the given package name.
|
|
80
|
+
|
|
81
|
+
`Version.getstring(package_name)` returns the version string of the
|
|
82
|
+
package with the given package name.
|
|
83
|
+
|
|
84
|
+
`Version.getstring(pyproject_path=path)` returns the version string
|
|
85
|
+
found in the pyproject.toml file found at the given `path`.
|
|
86
|
+
|
|
87
|
+
`Version.getstring(package_name, path)` returns
|
|
88
|
+
`Version.getstring(package_name)` if the given `package_name` is found,
|
|
89
|
+
otherwise returns `Version.getstring(pyproject_path=path)`.
|
|
90
|
+
"""
|
|
91
|
+
if package_name is None and pyproject_path is None:
|
|
92
|
+
raise ValueError("Version.getstring() requires 1 or 2 arguments")
|
|
93
|
+
if package_name is not None:
|
|
94
|
+
try:
|
|
95
|
+
from importlib.metadata import version
|
|
96
|
+
from importlib.metadata import PackageNotFoundError
|
|
97
|
+
except ModuleNotFoundError:
|
|
98
|
+
from importlib_metadata import version
|
|
99
|
+
from importlib_metadata import PackageNotFoundError
|
|
100
|
+
if pyproject_path is None:
|
|
101
|
+
return version(package_name)
|
|
102
|
+
# Try to deduce the version string but don't raise if this fails.
|
|
103
|
+
try:
|
|
104
|
+
return version(package_name)
|
|
105
|
+
except PackageNotFoundError:
|
|
106
|
+
pass
|
|
107
|
+
# Either a package name wasn't given or the package wasn't found; check
|
|
108
|
+
# the pyproject.toml if possible.
|
|
109
|
+
path = Path(pyproject_path)
|
|
110
|
+
with path.open('rt') as fl:
|
|
111
|
+
toml_lines = fl.read().split('\n')
|
|
112
|
+
in_project_section = False
|
|
113
|
+
for ln in toml_lines:
|
|
114
|
+
ln = ln.strip()
|
|
115
|
+
if ln == '[project]':
|
|
116
|
+
in_project_section = True
|
|
117
|
+
elif ln[0] == '[' and ln[-1] == ']':
|
|
118
|
+
in_project_section = False
|
|
119
|
+
elif in_project_section and '=' in ln:
|
|
120
|
+
parts = ln.split('=')
|
|
121
|
+
if parts[0].strip() == 'version':
|
|
122
|
+
v = '='.join(parts[1:]).strip()
|
|
123
|
+
return literal_eval(v)
|
|
124
|
+
# If we reach this point, we didn't fine a version line.
|
|
125
|
+
if package_name is not None:
|
|
126
|
+
raise RuntimeError(
|
|
127
|
+
f"Version.getstring() found no package named '{package_name}'"
|
|
128
|
+
f" and no 'version = ...' line in file {path}")
|
|
129
|
+
else:
|
|
130
|
+
raise RuntimeError(
|
|
131
|
+
f"Version.getstring() found no 'version = ...' line in file"
|
|
132
|
+
f" {path}")
|
|
133
|
+
|
|
134
|
+
# Construction -------------------------------------------------------------
|
|
135
|
+
__slots__ = ()
|
|
136
|
+
null = None
|
|
137
|
+
def __new__(cls, string=None, /, *,
|
|
138
|
+
package_name=None,
|
|
139
|
+
pyproject_path=None,
|
|
140
|
+
on_error='warn',
|
|
141
|
+
tag_prefixes=('rc', 'a', 'b')):
|
|
142
|
+
if on_error not in ('raise', 'warn', 'ignore'):
|
|
143
|
+
raise ValueError(
|
|
144
|
+
"invalid value for on_error; must be one of 'raise', 'warn',"
|
|
145
|
+
" or 'ignore'")
|
|
146
|
+
if string is None:
|
|
147
|
+
# Try to deduce the version string.
|
|
148
|
+
if on_error == 'raise':
|
|
149
|
+
string = Version.getstring(package_name, pyproject_path)
|
|
150
|
+
else:
|
|
151
|
+
try:
|
|
152
|
+
string = Version.getstring(package_name, pyproject_path)
|
|
153
|
+
except Exception as e:
|
|
154
|
+
if on_error == 'warn':
|
|
155
|
+
warn(
|
|
156
|
+
f"Version: could not deduce version string for"
|
|
157
|
+
f" package_name={repr(package_name)} and"
|
|
158
|
+
f" pyproject_path={repr(pyproject_path)}")
|
|
159
|
+
return Version.null
|
|
160
|
+
else:
|
|
161
|
+
return Version.null
|
|
162
|
+
ss = string.split('.')
|
|
163
|
+
nss = len(ss)
|
|
164
|
+
if nss == 4:
|
|
165
|
+
(major, minor, micro, stage) = ss
|
|
166
|
+
else:
|
|
167
|
+
if nss == 3:
|
|
168
|
+
(major, minor, micro) = ss
|
|
169
|
+
last = micro
|
|
170
|
+
elif nss == 2:
|
|
171
|
+
(major, minor) = ss
|
|
172
|
+
micro = '0'
|
|
173
|
+
last = minor
|
|
174
|
+
elif nss == 1:
|
|
175
|
+
major = ss
|
|
176
|
+
(minor, micro) = ('0', '0')
|
|
177
|
+
last = major
|
|
178
|
+
else:
|
|
179
|
+
raise ValueError(
|
|
180
|
+
f"invalid version string: '{string}' contains {nss}"
|
|
181
|
+
f" components")
|
|
182
|
+
stage = None
|
|
183
|
+
for tag in tag_prefixes:
|
|
184
|
+
if tag in last:
|
|
185
|
+
(num, stage) = last.split(tag)
|
|
186
|
+
stage = tag + stage
|
|
187
|
+
if last is micro:
|
|
188
|
+
micro = num
|
|
189
|
+
elif last is minor:
|
|
190
|
+
minor = num
|
|
191
|
+
else:
|
|
192
|
+
major = num
|
|
193
|
+
break
|
|
194
|
+
major = int(major)
|
|
195
|
+
minor = int(minor)
|
|
196
|
+
micro = int(micro)
|
|
197
|
+
tup = tuple(u for u in (major, minor, micro, stage) if u is not None)
|
|
198
|
+
return super(Version, cls).__new__(
|
|
199
|
+
cls,
|
|
200
|
+
string=string,
|
|
201
|
+
tuple=tup,
|
|
202
|
+
major=major,
|
|
203
|
+
minor=minor,
|
|
204
|
+
micro=micro,
|
|
205
|
+
stage=stage)
|
|
206
|
+
def __str__(self):
|
|
207
|
+
return self.string
|
|
208
|
+
def __repr__(self):
|
|
209
|
+
return f"Version({repr(self.string)})"
|
|
210
|
+
def __iter__(self):
|
|
211
|
+
return iter(self.tuple)
|
|
212
|
+
def __reversed__(self):
|
|
213
|
+
return reversed(self.tuple)
|
|
214
|
+
def __contains__(self, k):
|
|
215
|
+
if isinstance(k, str):
|
|
216
|
+
return k in self.string
|
|
217
|
+
else:
|
|
218
|
+
return k in self.tuple
|
|
219
|
+
Version.null = VersionTuple.__new__(
|
|
220
|
+
Version,
|
|
221
|
+
string='',
|
|
222
|
+
tuple=(),
|
|
223
|
+
major=None,
|
|
224
|
+
minor=None,
|
|
225
|
+
micro=None,
|
|
226
|
+
stage=None)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
# Variables ####################################################################
|
|
230
|
+
|
|
231
|
+
# The path of immlib's pyproject.toml file.
|
|
232
|
+
pyproject_path = Path(__file__).parent.parent.parent / 'pyproject.toml'
|
|
233
|
+
|
|
234
|
+
# Declare the version object; this will automatically detect the version.
|
|
235
|
+
version = Version(package_name=__package__, pyproject_path=pyproject_path)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
###############################################################################
|
|
3
|
+
# immlib/doc/__init__.py
|
|
4
|
+
|
|
5
|
+
"""Documentation tools that operate via decorators.
|
|
6
|
+
|
|
7
|
+
The module ``immlib.doc`` primarily contains a decorator, ``docwrap``, which
|
|
8
|
+
can be used to parse the inputs, outputs, parameters, and return values in a
|
|
9
|
+
function's docstring and to save them in a global cache of all such docstring
|
|
10
|
+
components. These components can then be referenced in the docstring of another
|
|
11
|
+
function decorated with ``@docwrap`` such that the text needn't be repeated in
|
|
12
|
+
every related function.
|
|
13
|
+
|
|
14
|
+
Attributes
|
|
15
|
+
----------
|
|
16
|
+
docproc: docrep.DocstringProcessor
|
|
17
|
+
This object is used to process all of the doc-strings in the ``immlib``
|
|
18
|
+
library; it should be used only with the ``immlib.docwrap`` decorator,
|
|
19
|
+
which can safely be applied anywhere in a sequence of decorators and which
|
|
20
|
+
correctly applies the ``wraps`` decorator to its argument. Function
|
|
21
|
+
documentation is always processed using the ``sections=('Parameters',
|
|
22
|
+
'Returns', 'Raises', 'Examples', 'Inputs', 'Outputs')`` parameter and the
|
|
23
|
+
``with_indent(4)`` decorator. The base-name for the function ``f`` is
|
|
24
|
+
``f.__module__ + '.' + f.__name__``.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from ._core import (
|
|
28
|
+
docwrap, make_docproc, default_docproc,
|
|
29
|
+
detect_indentation, reindent)
|
|
30
|
+
|
|
31
|
+
# make_docproc lives in this subpackage (the others live in the immlib package
|
|
32
|
+
# and will be reclaimed there).
|
|
33
|
+
make_docproc.__module__ = __name__
|
|
34
|
+
|
|
35
|
+
__all__ = ("docwrap", "default_docproc")
|
|
36
|
+
|
|
37
|
+
from .._init import reclaim
|
|
38
|
+
reclaim(__name__, del_reclaim=True)
|