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.
Files changed (64) hide show
  1. {immlib-1.0.0.dev1/src/immlib.egg-info → immlib-1.0.0.dev2}/PKG-INFO +27 -12
  2. immlib-1.0.0.dev2/README.md +26 -0
  3. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/pyproject.toml +10 -6
  4. immlib-1.0.0.dev2/src/immlib/__init__.py +131 -0
  5. immlib-1.0.0.dev2/src/immlib/_init.py +108 -0
  6. immlib-1.0.0.dev2/src/immlib/_version.py +235 -0
  7. immlib-1.0.0.dev2/src/immlib/doc/__init__.py +38 -0
  8. immlib-1.0.0.dev2/src/immlib/doc/_core.py +311 -0
  9. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/iolib/__init__.py +2 -4
  10. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/iolib/_core.py +5 -5
  11. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/__init__.py +3 -11
  12. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_cache.py +4 -4
  13. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_core.py +291 -262
  14. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/pathlib/_osf.py +64 -55
  15. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/__init__.py +1 -0
  16. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/doc/test_core.py +2 -1
  17. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/test_core.py +12 -0
  18. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/test_osf.py +0 -5
  19. immlib-1.0.0.dev2/src/immlib/test/types/__init__.py +5 -0
  20. immlib-1.0.0.dev2/src/immlib/test/types/test_core.py +110 -0
  21. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/__init__.py +1 -0
  22. immlib-1.0.0.dev2/src/immlib/test/util/test_core.py +681 -0
  23. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/test_numeric.py +707 -186
  24. immlib-1.0.0.dev2/src/immlib/test/util/test_url.py +51 -0
  25. immlib-1.0.0.dev2/src/immlib/test/workflow/test_core.py +418 -0
  26. immlib-1.0.0.dev2/src/immlib/test/workflow/test_plantype.py +248 -0
  27. immlib-1.0.0.dev2/src/immlib/types/__init__.py +29 -0
  28. immlib-1.0.0.dev2/src/immlib/types/_core.py +333 -0
  29. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/util/__init__.py +54 -23
  30. immlib-1.0.0.dev2/src/immlib/util/_core.py +2524 -0
  31. immlib-1.0.0.dev2/src/immlib/util/_numeric.py +2651 -0
  32. immlib-1.0.0.dev2/src/immlib/util/_quantity.py +523 -0
  33. immlib-1.0.0.dev2/src/immlib/util/_url.py +114 -0
  34. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/workflow/__init__.py +11 -12
  35. immlib-1.0.0.dev2/src/immlib/workflow/_core.py +1635 -0
  36. immlib-1.0.0.dev2/src/immlib/workflow/_plantype.py +334 -0
  37. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2/src/immlib.egg-info}/PKG-INFO +27 -12
  38. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/SOURCES.txt +6 -0
  39. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/requires.txt +8 -4
  40. immlib-1.0.0.dev1/README.md +0 -17
  41. immlib-1.0.0.dev1/src/immlib/__init__.py +0 -88
  42. immlib-1.0.0.dev1/src/immlib/_version.py +0 -94
  43. immlib-1.0.0.dev1/src/immlib/doc/__init__.py +0 -22
  44. immlib-1.0.0.dev1/src/immlib/doc/_core.py +0 -103
  45. immlib-1.0.0.dev1/src/immlib/test/util/test_core.py +0 -208
  46. immlib-1.0.0.dev1/src/immlib/test/workflow/test_core.py +0 -219
  47. immlib-1.0.0.dev1/src/immlib/test/workflow/test_plantype.py +0 -105
  48. immlib-1.0.0.dev1/src/immlib/util/_core.py +0 -1943
  49. immlib-1.0.0.dev1/src/immlib/util/_numeric.py +0 -1686
  50. immlib-1.0.0.dev1/src/immlib/util/_quantity.py +0 -496
  51. immlib-1.0.0.dev1/src/immlib/util/_url.py +0 -98
  52. immlib-1.0.0.dev1/src/immlib/workflow/_core.py +0 -1104
  53. immlib-1.0.0.dev1/src/immlib/workflow/_plantype.py +0 -258
  54. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/LICENSE +0 -0
  55. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/setup.cfg +0 -0
  56. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/__main__.py +0 -0
  57. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/doc/__init__.py +0 -0
  58. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/iolib/__init__.py +0 -0
  59. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/iolib/test_core.py +0 -0
  60. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/pathlib/__init__.py +0 -0
  61. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/util/test_quantity.py +0 -0
  62. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib/test/workflow/__init__.py +0 -0
  63. {immlib-1.0.0.dev1 → immlib-1.0.0.dev2}/src/immlib.egg-info/dependency_links.txt +0 -0
  64. {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
1
+ Metadata-Version: 2.4
2
2
  Name: immlib
3
- Version: 1.0.0.dev1
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.7
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.18.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
- Requires-Dist: pyyaml; extra == "test"
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
- # immlib
51
+ ![immlib](https://noahbenson.github.io/immlib/_static/logo.svg "immlib")
46
52
 
47
53
  ![Build Status](https://github.com/noahbenson/immlib/actions/workflows/tests.yml/badge.svg)
48
54
  [![codecov](https://codecov.io/gh/noahbenson/immlib/graph/badge.svg?token=8KO3K6DUX4)](https://codecov.io/gh/noahbenson/immlib)
49
55
  [![PyPI version](https://badge.fury.io/py/immlib.svg)](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 &lt;[nben@uw.edu](mailto:nben@uw.edu)&gt;
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
+ ![immlib](https://noahbenson.github.io/immlib/_static/logo.svg "immlib")
2
+
3
+ ![Build Status](https://github.com/noahbenson/immlib/actions/workflows/tests.yml/badge.svg)
4
+ [![codecov](https://codecov.io/gh/noahbenson/immlib/graph/badge.svg?token=8KO3K6DUX4)](https://codecov.io/gh/noahbenson/immlib)
5
+ [![PyPI version](https://badge.fury.io/py/immlib.svg)](https://badge.fury.io/py/immlib)
6
+
7
+ ---
8
+
9
+ **Author**: Noah C. Benson &lt;[nben@uw.edu](mailto:nben@uw.edu)&gt;
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.dev1"
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.7',
31
+ 'pcollections >= 0.3.2',
30
32
  'numpy >= 1.24.0',
31
33
  'scipy >= 1.7.0',
32
- 'pint >= 0.18.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", "pyyaml"]
39
- test = ["torch >= 2.2.0", "pyyaml"]
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)