cdxcore 0.1.5__py3-none-any.whl
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.
Potentially problematic release.
This version of cdxcore might be problematic. Click here for more details.
- cdxcore/__init__.py +15 -0
- cdxcore/config.py +1633 -0
- cdxcore/crman.py +105 -0
- cdxcore/deferred.py +220 -0
- cdxcore/dynaplot.py +1155 -0
- cdxcore/filelock.py +430 -0
- cdxcore/jcpool.py +411 -0
- cdxcore/logger.py +319 -0
- cdxcore/np.py +1098 -0
- cdxcore/npio.py +270 -0
- cdxcore/prettydict.py +388 -0
- cdxcore/prettyobject.py +64 -0
- cdxcore/sharedarray.py +285 -0
- cdxcore/subdir.py +2963 -0
- cdxcore/uniquehash.py +970 -0
- cdxcore/util.py +1041 -0
- cdxcore/verbose.py +403 -0
- cdxcore/version.py +402 -0
- cdxcore-0.1.5.dist-info/METADATA +1418 -0
- cdxcore-0.1.5.dist-info/RECORD +30 -0
- cdxcore-0.1.5.dist-info/WHEEL +5 -0
- cdxcore-0.1.5.dist-info/licenses/LICENSE +21 -0
- cdxcore-0.1.5.dist-info/top_level.txt +4 -0
- conda/conda_exists.py +10 -0
- conda/conda_modify_yaml.py +42 -0
- tests/_cdxbasics.py +1086 -0
- tests/test_uniquehash.py +469 -0
- tests/test_util.py +329 -0
- up/git_message.py +7 -0
- up/pip_modify_setup.py +55 -0
cdxcore/prettyobject.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Prettydict
|
|
3
|
+
Objects like dictionaries
|
|
4
|
+
Hans Buehler 2025
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from collections.abc import Mapping
|
|
8
|
+
|
|
9
|
+
class PrettyObject(Mapping):
|
|
10
|
+
"""
|
|
11
|
+
Object base class to minimc an unordered dictionary.
|
|
12
|
+
Explicit object version of the implied PrettyDict.
|
|
13
|
+
|
|
14
|
+
Usage pattern:
|
|
15
|
+
|
|
16
|
+
class M( PrettyObject ):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
m = M()
|
|
20
|
+
m.x = 1 # standard object handling
|
|
21
|
+
m['y'] = 1 # mimic dictionary
|
|
22
|
+
print( m['x'] ) # mimic dictionary
|
|
23
|
+
print( m.y ) # standard object handling
|
|
24
|
+
|
|
25
|
+
Mimics a dictionary:
|
|
26
|
+
|
|
27
|
+
u = dict( m )
|
|
28
|
+
print(u) --> {'x': 1, 'y': 2}
|
|
29
|
+
|
|
30
|
+
u = { k: 2*v for k,v in m.items() }
|
|
31
|
+
print(u) --> {'x': 2, 'y': 4}
|
|
32
|
+
|
|
33
|
+
l = list( m )
|
|
34
|
+
print(l) --> ['x', 'y']
|
|
35
|
+
"""
|
|
36
|
+
def __init__(self, **kwargs):
|
|
37
|
+
for k, v in kwargs.items():
|
|
38
|
+
setattr(self, k, v)
|
|
39
|
+
|
|
40
|
+
def __getitem__(self, key):
|
|
41
|
+
return getattr( self, key )
|
|
42
|
+
def __setitem__(self,key,value):
|
|
43
|
+
setattr(self, key, value)
|
|
44
|
+
return self[key]
|
|
45
|
+
def __delitem__(self,key):
|
|
46
|
+
delattr(self, key)
|
|
47
|
+
def __iter__(self):
|
|
48
|
+
return self.__dict__.__iter__()
|
|
49
|
+
def __contains__(self, key):
|
|
50
|
+
return self.__dict__.__contains__(key)
|
|
51
|
+
def __len__(self):
|
|
52
|
+
return self.__dict__.__len__()
|
|
53
|
+
|
|
54
|
+
def keys(self):
|
|
55
|
+
return self.__dict__.keys()
|
|
56
|
+
def items(self):
|
|
57
|
+
return self.__dict__.items()
|
|
58
|
+
def values(self):
|
|
59
|
+
return self.__dict__.values()
|
|
60
|
+
|
|
61
|
+
def __repr__(self):
|
|
62
|
+
return f"PrettyObject({self.__dict__.__repr__()})"
|
|
63
|
+
def __str__(self):
|
|
64
|
+
return self.__dict__.__str__()
|
cdxcore/sharedarray.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared named numpy arrays
|
|
3
|
+
Hans Buehler 2023
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from .logger import Logger
|
|
7
|
+
from .version import version
|
|
8
|
+
from .verbose import Context
|
|
9
|
+
from .util import fmt_digits
|
|
10
|
+
import numpy as np
|
|
11
|
+
import gc as gc
|
|
12
|
+
from multiprocessing import shared_memory
|
|
13
|
+
_log = Logger(__file__)
|
|
14
|
+
|
|
15
|
+
@version("0.0.1")
|
|
16
|
+
class ndsharedarray( object ):
|
|
17
|
+
"""
|
|
18
|
+
Wrapper around https://docs.python.org/3/library/multiprocessing.shared_memory.html
|
|
19
|
+
Use sharedarray() to create objects of this type
|
|
20
|
+
|
|
21
|
+
This array vaguley behaves like a numpy array, but it is usally better to use ndsharedarray.array
|
|
22
|
+
to access the actual underlying numpy array.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
serial_number = 0
|
|
26
|
+
|
|
27
|
+
def __init__(self, name : str,
|
|
28
|
+
shape : tuple,
|
|
29
|
+
create : bool,
|
|
30
|
+
dtype = np.float32,
|
|
31
|
+
full = 0.,
|
|
32
|
+
*,
|
|
33
|
+
verbose : Context = None ):
|
|
34
|
+
"""
|
|
35
|
+
Create a new shared memory array.
|
|
36
|
+
See sharedarray().
|
|
37
|
+
|
|
38
|
+
Recall that Python objects are not freed until they are garbage collected.
|
|
39
|
+
Make sure you use gc.collect() whenever you want to make sure to delete
|
|
40
|
+
a particular shared memory.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
name : globally unique name accross all processes.
|
|
45
|
+
Note that the name used for the shared memory itself will be id'd by dtype and shape of the array to avoid collisions.
|
|
46
|
+
Use shared_id to obtain this name.
|
|
47
|
+
shape : numpy shape
|
|
48
|
+
create : whether to create a new shared memory block or not.
|
|
49
|
+
dtype : numpy dtype
|
|
50
|
+
full : if not None: value used to fill newly created array. Not used when create is False
|
|
51
|
+
verbose : None or a Context. If the latter is present, the object provides logging information on when objects are created/delted
|
|
52
|
+
"""
|
|
53
|
+
dtype = dtype() if isinstance(dtype, type) else dtype
|
|
54
|
+
size = int( np.uint64( dtype.itemsize ) * np.product( [ np.uint64(i) for i in shape ], dtype=np.uint64 ) + 32 )
|
|
55
|
+
shape = tuple(shape)
|
|
56
|
+
self._name = name
|
|
57
|
+
self._id = name + str(shape) + "[" + str(type(dtype).__name__) + "]"
|
|
58
|
+
self._serial = ndsharedarray.serial_number # for debugging purposes
|
|
59
|
+
self._verbose = verbose
|
|
60
|
+
ndsharedarray.serial_number += 1
|
|
61
|
+
|
|
62
|
+
assert size>0, "Cannot have zero size"
|
|
63
|
+
|
|
64
|
+
if create:
|
|
65
|
+
self._shared = shared_memory.SharedMemory(name=self._id, create=True, size=size )
|
|
66
|
+
self._array = np.ndarray( shape, dtype=dtype, buffer = self._shared.buf )
|
|
67
|
+
assert self._array.dtype == dtype, ("Dtype mismatch", self._array.dtype , dtype )
|
|
68
|
+
assert self._array.nbytes < size, ("size mismatch", self._array.nbytes , size )
|
|
69
|
+
if not full is None:
|
|
70
|
+
self._array[:] = full
|
|
71
|
+
else:
|
|
72
|
+
self._shared = shared_memory.SharedMemory(name=self._id, create=False, size=size )
|
|
73
|
+
self._array = np.ndarray( shape, dtype=dtype, buffer = self._shared.buf )
|
|
74
|
+
assert self.array.dtype == dtype, ("Dtype mismatch", self.array.dtype , dtype )
|
|
75
|
+
assert self._array.nbytes < size, ("size mismatch", self._array.nbytes , size )
|
|
76
|
+
|
|
77
|
+
if not self._verbose is None:
|
|
78
|
+
self._verbose.write("Initialized %s #%ld size %ld %s", self._id, self._serial, size, "(created)" if create else "(referenced)")
|
|
79
|
+
|
|
80
|
+
def __del__(self):
|
|
81
|
+
""" Ensure shared memory is released """
|
|
82
|
+
self.close(unlink=False)
|
|
83
|
+
|
|
84
|
+
def close(self, unlink : bool = False):
|
|
85
|
+
"""
|
|
86
|
+
Closes the shared memory file.
|
|
87
|
+
Optionally calls unlink()
|
|
88
|
+
NOTE: unlink destroys the file and should be called after all procssess called close() ... don't ask.
|
|
89
|
+
c.f. https://docs.python.org/3/library/multiprocessing.shared_memory.html
|
|
90
|
+
"""
|
|
91
|
+
self._array = None
|
|
92
|
+
if '_shared' in self.__dict__:
|
|
93
|
+
if not self._verbose is None:
|
|
94
|
+
self._verbose.write("Closing %s #%ld (do %sunlink)", self._id, self._serial, "" if unlink else "not " )
|
|
95
|
+
try:
|
|
96
|
+
self._shared.close()
|
|
97
|
+
except FileNotFoundError:
|
|
98
|
+
pass
|
|
99
|
+
if unlink:
|
|
100
|
+
try:
|
|
101
|
+
self._shared.unlink()
|
|
102
|
+
except FileNotFoundError:
|
|
103
|
+
pass
|
|
104
|
+
del self._shared
|
|
105
|
+
|
|
106
|
+
def __str__(self) -> str: #NOQA
|
|
107
|
+
return "ndsharedarray( " + self._id + ")" + str(self._array)
|
|
108
|
+
|
|
109
|
+
# Basic
|
|
110
|
+
# -----
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def name(self) -> str:
|
|
114
|
+
""" User-specified name, without shape and dtype qualification. Use shared_id() for the latter """
|
|
115
|
+
return self._name
|
|
116
|
+
@property
|
|
117
|
+
def shared_id(self) -> str:
|
|
118
|
+
""" Return fully qualified name of shared memory, e.g. including dtype and shape information """
|
|
119
|
+
return self._id
|
|
120
|
+
@property
|
|
121
|
+
def shared_size(self) -> int:
|
|
122
|
+
""" Return fully qualified name of shared memory, e.g. including dtype and shape information """
|
|
123
|
+
return self._shared.size
|
|
124
|
+
@property
|
|
125
|
+
def shared_buf(self):
|
|
126
|
+
""" binary buffer of the shared stream """
|
|
127
|
+
return self._shared.buf
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def array(self) -> np.ndarray:
|
|
131
|
+
""" Return underlying numpy array """
|
|
132
|
+
return self._array
|
|
133
|
+
@property
|
|
134
|
+
def shape(self) -> tuple:
|
|
135
|
+
""" Shape of the underlying array """
|
|
136
|
+
return self._array.shape
|
|
137
|
+
@property
|
|
138
|
+
def dtype(self):
|
|
139
|
+
""" Dtype """
|
|
140
|
+
return self._array.dtype
|
|
141
|
+
@property
|
|
142
|
+
def data(self):
|
|
143
|
+
""" binary buffer of the underlying numpy array """
|
|
144
|
+
return self._array.data
|
|
145
|
+
@property
|
|
146
|
+
def nbytes(self):
|
|
147
|
+
""" Size in bytes of the numpy array. Note that the internal buffer might be larger """
|
|
148
|
+
return self._array.nbytes
|
|
149
|
+
@property
|
|
150
|
+
def itemsize(self):
|
|
151
|
+
""" itemsize """
|
|
152
|
+
return self._array.itemsize
|
|
153
|
+
|
|
154
|
+
# mimic numpy array
|
|
155
|
+
# -----------------
|
|
156
|
+
|
|
157
|
+
def __getitem__(self, k, *kargs):
|
|
158
|
+
return self._array.__getitem__(k, *kargs)
|
|
159
|
+
def __setitem__(self, k, v, *kargs):
|
|
160
|
+
return self._array.__setitem__(k,v,*kargs)
|
|
161
|
+
# def __getattr__(self, name):
|
|
162
|
+
# return getattr(self._array,name)
|
|
163
|
+
@property
|
|
164
|
+
def __array_interface__(self):
|
|
165
|
+
return self._array.__array_interface__
|
|
166
|
+
def __array__(self, *kargs, **kwargs):
|
|
167
|
+
return self._array.__array__(*kargs, **kwargs)
|
|
168
|
+
|
|
169
|
+
# pickling
|
|
170
|
+
# --------
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def from_state( state ):
|
|
174
|
+
""" Restore object from disk """
|
|
175
|
+
return ndsharedarray( name=state['name'], shape=state['shape'], create=True, dtype=state['dtype'], full=state['data'] )
|
|
176
|
+
|
|
177
|
+
def __reduce__(self):
|
|
178
|
+
"""
|
|
179
|
+
Pickling this object explicitly
|
|
180
|
+
See https://docs.python.org/3/library/pickle.html#object.__reduce__
|
|
181
|
+
"""
|
|
182
|
+
state = dict( name=self._name,
|
|
183
|
+
dtype=self._dtype,
|
|
184
|
+
shape=self.shape,
|
|
185
|
+
data=self._array
|
|
186
|
+
)
|
|
187
|
+
return (self.from_state, (state,) )
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@version("0.0.1", dependencies=[ndsharedarray] )
|
|
191
|
+
def sharedarray( name : str,
|
|
192
|
+
shape : tuple,
|
|
193
|
+
create : bool,
|
|
194
|
+
dtype = np.float32,
|
|
195
|
+
full = None,
|
|
196
|
+
*,
|
|
197
|
+
raiseOnError : bool = False,
|
|
198
|
+
verbose : Context = None ):
|
|
199
|
+
"""
|
|
200
|
+
Create a new shared memory array.
|
|
201
|
+
|
|
202
|
+
Recall that Python objects are not freed until they are garbage collected.
|
|
203
|
+
Make sure you use gc.collect() whenever you want to make sure to delete
|
|
204
|
+
a particular shared memory.
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
name : globally unique name accross all processes.
|
|
209
|
+
shape : numpy shape
|
|
210
|
+
create : whether to create a new shared memory block or not.
|
|
211
|
+
If True, and if a block with the given name already exists, this function returns None or raises FileExistsError (if raiseOnError is True)
|
|
212
|
+
Otherwise it will return a new block with the specified name.
|
|
213
|
+
If False, and no block with the given name exists, this function returns None or raises FileNotFoundError (if raiseOnError is True)
|
|
214
|
+
If the block has different total size, the function will raise an IncompatibleSharedSizeError
|
|
215
|
+
Otherwise the function will return an array pointing to the shared block
|
|
216
|
+
If None, then the function first attempts to create a new block with the given name.
|
|
217
|
+
If this is successful, the function will return (array, True).
|
|
218
|
+
If creating a new memory block fails, it will attempt to read a block with the given name.
|
|
219
|
+
and return (array, False) where array is pointing to the shared block.
|
|
220
|
+
dtype : dtype
|
|
221
|
+
full : If not None, fill a newly created object with this data.
|
|
222
|
+
Ignored if a shared object is used.
|
|
223
|
+
raiseOnError : if False, fail by returning None, else throw FileExistsError or FileNotFoundError, respectively
|
|
224
|
+
verbose : None or a Context. If the latter is present, the object provides logging information on when objects are created/delted
|
|
225
|
+
|
|
226
|
+
Returns
|
|
227
|
+
-------
|
|
228
|
+
If 'create' is a boolean: returns ndsharedarray or None
|
|
229
|
+
If 'create' is None: return ndsharedarray, created where 'created' is a boolean indicating whether the array was newly created.
|
|
230
|
+
|
|
231
|
+
Raises
|
|
232
|
+
------
|
|
233
|
+
May raise FileExistsError or FileNotFoundError if raiseOnError is True
|
|
234
|
+
"""
|
|
235
|
+
name = str(name)
|
|
236
|
+
create = bool(create) if not create is None else None
|
|
237
|
+
|
|
238
|
+
assert len(name) > 0, "Must specifiy name"
|
|
239
|
+
|
|
240
|
+
if create is None or create:
|
|
241
|
+
try:
|
|
242
|
+
array = ndsharedarray( name=name, shape=shape, create=True, dtype=dtype, full=full, verbose=verbose )
|
|
243
|
+
if not create is None:
|
|
244
|
+
return array
|
|
245
|
+
else:
|
|
246
|
+
return array, True
|
|
247
|
+
except FileExistsError as e:
|
|
248
|
+
if not create is None:
|
|
249
|
+
if raiseOnError:
|
|
250
|
+
raise e
|
|
251
|
+
return None
|
|
252
|
+
|
|
253
|
+
try:
|
|
254
|
+
array = ndsharedarray( name=name, shape=shape, create=False, dtype=dtype, full=None, verbose=verbose )
|
|
255
|
+
if not create is None:
|
|
256
|
+
return array
|
|
257
|
+
else:
|
|
258
|
+
return array, False
|
|
259
|
+
except FileNotFoundError as e:
|
|
260
|
+
if not create is None:
|
|
261
|
+
if raiseOnError:
|
|
262
|
+
raise e
|
|
263
|
+
return None
|
|
264
|
+
|
|
265
|
+
raise Exception("Cannot create or read shared memory block '%s'", name)
|
|
266
|
+
|
|
267
|
+
from .npio import *
|
|
268
|
+
def shared_fromfile( file, name, dtype=np.float32 ):
|
|
269
|
+
"""
|
|
270
|
+
Read array from disk into a new named sharedarray.
|
|
271
|
+
|
|
272
|
+
Parameters
|
|
273
|
+
----------
|
|
274
|
+
file : file name passed to open()
|
|
275
|
+
name : memory name
|
|
276
|
+
dtype : target dtype
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
Newly created numpy array
|
|
281
|
+
"""
|
|
282
|
+
def construct(shape):
|
|
283
|
+
return ndsharedarray( name=name, shape=shape, dtype=dtype, create=True, raiseOnError=True )
|
|
284
|
+
return _fromfile( file, construct=construct )
|
|
285
|
+
|