cdxcore 0.1.5__py3-none-any.whl → 0.1.9__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 +1 -9
- cdxcore/config.py +1188 -521
- cdxcore/crman.py +95 -25
- cdxcore/err.py +371 -0
- cdxcore/pretty.py +468 -0
- cdxcore/pretty.py_bak.py +750 -0
- cdxcore/subdir.py +2225 -1334
- cdxcore/uniquehash.py +515 -363
- cdxcore/util.py +358 -417
- cdxcore/verbose.py +683 -248
- cdxcore/version.py +398 -139
- cdxcore-0.1.9.dist-info/METADATA +27 -0
- cdxcore-0.1.9.dist-info/RECORD +36 -0
- {cdxcore-0.1.5.dist-info → cdxcore-0.1.9.dist-info}/top_level.txt +3 -1
- docs/source/conf.py +123 -0
- docs2/source/conf.py +35 -0
- tests/test_config.py +502 -0
- tests/test_crman.py +54 -0
- tests/test_err.py +86 -0
- tests/test_pretty.py +404 -0
- tests/test_subdir.py +289 -0
- tests/test_uniquehash.py +159 -144
- tests/test_util.py +122 -83
- tests/test_verbose.py +119 -0
- tests/test_version.py +153 -0
- up/git_message.py +2 -2
- cdxcore/logger.py +0 -319
- cdxcore/prettydict.py +0 -388
- cdxcore/prettyobject.py +0 -64
- cdxcore-0.1.5.dist-info/METADATA +0 -1418
- cdxcore-0.1.5.dist-info/RECORD +0 -30
- conda/conda_exists.py +0 -10
- conda/conda_modify_yaml.py +0 -42
- tests/_cdxbasics.py +0 -1086
- {cdxcore-0.1.5.dist-info → cdxcore-0.1.9.dist-info}/WHEEL +0 -0
- {cdxcore-0.1.5.dist-info → cdxcore-0.1.9.dist-info}/licenses/LICENSE +0 -0
- {cdxcore → tmp}/deferred.py +0 -0
- {cdxcore → tmp}/dynaplot.py +0 -0
- {cdxcore → tmp}/filelock.py +0 -0
- {cdxcore → tmp}/jcpool.py +0 -0
- {cdxcore → tmp}/np.py +0 -0
- {cdxcore → tmp}/npio.py +0 -0
- {cdxcore → tmp}/sharedarray.py +0 -0
tests/test_config.py
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Tue Apr 14 21:24:52 2020
|
|
4
|
+
@author: hansb
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import unittest as unittest
|
|
9
|
+
import dataclasses as dataclasses
|
|
10
|
+
import sys as sys
|
|
11
|
+
import os as os
|
|
12
|
+
import pickle as pickle
|
|
13
|
+
import tempfile as tempfile
|
|
14
|
+
import shutil as shutil
|
|
15
|
+
sys.setrecursionlimit(100)
|
|
16
|
+
|
|
17
|
+
def import_local():
|
|
18
|
+
"""
|
|
19
|
+
In order to be able to run our tests manually from the 'tests' directory
|
|
20
|
+
we force import from the local package.
|
|
21
|
+
We also force reloading all modules to make sure we are not running old code.
|
|
22
|
+
"""
|
|
23
|
+
me = "cdxcore"
|
|
24
|
+
import os
|
|
25
|
+
import sys
|
|
26
|
+
cwd = os.getcwd()
|
|
27
|
+
if cwd[-len(me):] == me:
|
|
28
|
+
return
|
|
29
|
+
assert cwd[-5:] == "tests",("Expected current working directory to be in a 'tests' directory", cwd[-5:], "from", cwd)
|
|
30
|
+
assert cwd[-6] in ['/', '\\'],("Expected current working directory 'tests' to be lead by a '\\' or '/'", cwd[-6:], "from", cwd)
|
|
31
|
+
sys.path.insert( 0, cwd[:-6] )
|
|
32
|
+
|
|
33
|
+
# reload modules
|
|
34
|
+
import importlib as imp
|
|
35
|
+
modules = sys.modules.copy()
|
|
36
|
+
for name, mdata in modules.items():
|
|
37
|
+
if name[:len(me)] == me:
|
|
38
|
+
imp.reload(mdata)
|
|
39
|
+
print("Reloaded", name)
|
|
40
|
+
import_local()
|
|
41
|
+
|
|
42
|
+
from cdxcore.config import Config, Int, Float
|
|
43
|
+
from cdxcore.pretty import PrettyObject as pdct
|
|
44
|
+
from cdxcore.uniquehash import unique_hash16
|
|
45
|
+
|
|
46
|
+
class Test(unittest.TestCase):
|
|
47
|
+
|
|
48
|
+
def test_config(self):
|
|
49
|
+
|
|
50
|
+
config = Config(x=0., z=-1.)
|
|
51
|
+
x = config("x", 10., float, "test x")
|
|
52
|
+
self.assertEqual( x, 0. )
|
|
53
|
+
y = config("y", 10., float, "test y")
|
|
54
|
+
self.assertEqual( y, 10. )
|
|
55
|
+
|
|
56
|
+
with self.assertRaises(Exception):
|
|
57
|
+
# 'z' was not read
|
|
58
|
+
config.done()
|
|
59
|
+
|
|
60
|
+
# calling twice with different values
|
|
61
|
+
config = Config(x=0.)
|
|
62
|
+
x = config("x", 1., float, "test x")
|
|
63
|
+
x = config("x", 1., float, "test x") # ok: same parameters
|
|
64
|
+
with self.assertRaises(Exception):
|
|
65
|
+
x = config("x", 1., Float<0.5, "test x") # not ok: Float condition
|
|
66
|
+
with self.assertRaises(Exception):
|
|
67
|
+
x = config("x", 2., float, "test x") # not ok: different default
|
|
68
|
+
config.done()
|
|
69
|
+
|
|
70
|
+
# test usage per access method:
|
|
71
|
+
# __call__('a')
|
|
72
|
+
# get('a')
|
|
73
|
+
# get_default('a', ...)
|
|
74
|
+
# all register usage;
|
|
75
|
+
# get_raw('a')
|
|
76
|
+
# ['a']
|
|
77
|
+
# do not.
|
|
78
|
+
config = Config(a=1)
|
|
79
|
+
_ = config.get("a")
|
|
80
|
+
self.assertTrue( not 'a' in config.not_done )
|
|
81
|
+
config = Config(a=1)
|
|
82
|
+
_ = config.get_default("a", 0)
|
|
83
|
+
self.assertTrue( not 'a' in config.not_done )
|
|
84
|
+
config = Config(a=1)
|
|
85
|
+
_ = config("a")
|
|
86
|
+
self.assertTrue( not 'a' in config.not_done )
|
|
87
|
+
config = Config(a=1)
|
|
88
|
+
_ = config("a", 0)
|
|
89
|
+
self.assertTrue( not 'a' in config.not_done )
|
|
90
|
+
|
|
91
|
+
config = Config(a=1)
|
|
92
|
+
_ = config.get_raw('a')
|
|
93
|
+
self.assertTrue( 'a' in config.not_done )
|
|
94
|
+
config = Config(a=1)
|
|
95
|
+
_ = config['a']
|
|
96
|
+
self.assertTrue( 'a' in config.not_done )
|
|
97
|
+
|
|
98
|
+
# test sub configs
|
|
99
|
+
config = Config()
|
|
100
|
+
config.x = 1
|
|
101
|
+
config.a = "a"
|
|
102
|
+
config.sub.x = 2.
|
|
103
|
+
|
|
104
|
+
self.assertEqual(1., config("x", 0., float, "x"))
|
|
105
|
+
self.assertEqual("a", config("a", None, str, "a"))
|
|
106
|
+
self.assertEqual(2, config.sub("x", 0, int, "x"))
|
|
107
|
+
self.assertTrue( isinstance( config.sub, Config ) )
|
|
108
|
+
config.done()
|
|
109
|
+
|
|
110
|
+
# test detach
|
|
111
|
+
config = Config()
|
|
112
|
+
config.sub.x = 1
|
|
113
|
+
with self.assertRaises(Exception):
|
|
114
|
+
config.done() # 'sub.x' not read
|
|
115
|
+
|
|
116
|
+
config = Config()
|
|
117
|
+
config.sub.x = 1
|
|
118
|
+
sub = config.sub.detach()
|
|
119
|
+
config.done() # ok
|
|
120
|
+
_ = sub("x", 1)
|
|
121
|
+
config.done() # fine now
|
|
122
|
+
|
|
123
|
+
# test list (_Enum)
|
|
124
|
+
config = Config(t="a", q="q")
|
|
125
|
+
_ = config("t", "b", ['a', 'b', 'c'] )
|
|
126
|
+
self.assertEqual(_, 'a')
|
|
127
|
+
with self.assertRaises(Exception):
|
|
128
|
+
_ = config("q", "b", ['a', 'b', 'c'] ) # exception: 'q' not in set
|
|
129
|
+
|
|
130
|
+
# test tuple (_Alt)
|
|
131
|
+
config = Config(t="a")
|
|
132
|
+
_ = config("t", "b", (None, str) )
|
|
133
|
+
self.assertEqual(_, 'a')
|
|
134
|
+
config = Config(t=None)
|
|
135
|
+
_ = config("t", "b", (None, str) )
|
|
136
|
+
self.assertEqual(_, None)
|
|
137
|
+
with self.assertRaises(Exception):
|
|
138
|
+
config = Config(t="a")
|
|
139
|
+
_ = config("t", 1, (None, int) )
|
|
140
|
+
self.assertEqual(_, None)
|
|
141
|
+
config = Config()
|
|
142
|
+
_ = config("t", "b", (None, ['a','b']) )
|
|
143
|
+
self.assertEqual(_, 'b')
|
|
144
|
+
config = Config(t=2)
|
|
145
|
+
_ = config("t", 1, (Int>=1, Int<=1) )
|
|
146
|
+
self.assertEqual(_, 2)
|
|
147
|
+
config = Config()
|
|
148
|
+
_ = config("t", 3, (Int>=1, Int<=1) )
|
|
149
|
+
self.assertEqual(_, 3)
|
|
150
|
+
with self.assertRaises(Exception):
|
|
151
|
+
config = Config()
|
|
152
|
+
_ = config("t", 0, (Int>=1, Int<=-1) )
|
|
153
|
+
with self.assertRaises(Exception):
|
|
154
|
+
config = Config(t=0)
|
|
155
|
+
_ = config("t", 3, (Int>=1, Int<=-1) )
|
|
156
|
+
|
|
157
|
+
# combined conditons
|
|
158
|
+
config = Config(x=1., y=1.)
|
|
159
|
+
|
|
160
|
+
x = config("x", 1., ( Float>=0.) & (Float<=1.), "test x")
|
|
161
|
+
with self.assertRaises(Exception):
|
|
162
|
+
# test that violated condition is caught
|
|
163
|
+
y = config("y", 1., ( Float>=0.) & (Float<1.), "test y")
|
|
164
|
+
|
|
165
|
+
config = Config(x=1., y=1.)
|
|
166
|
+
with self.assertRaises(NotImplementedError):
|
|
167
|
+
# left hand must be > or >=
|
|
168
|
+
y = config("y", 1., ( Float<=0.) & (Float<1.), "test x")
|
|
169
|
+
config = Config(x=1., y=1.)
|
|
170
|
+
with self.assertRaises(NotImplementedError):
|
|
171
|
+
# right hand must be < or <=
|
|
172
|
+
y = config("y", 1., ( Float>=0.) & (Float>1.), "test x")
|
|
173
|
+
|
|
174
|
+
# test int
|
|
175
|
+
config = Config(x=1)
|
|
176
|
+
x = config("x", 0, ( Int>=0 ) & ( Int<=1), "int test")
|
|
177
|
+
config = Config(x=1)
|
|
178
|
+
with self.assertRaises(NotImplementedError):
|
|
179
|
+
# cannot mix types
|
|
180
|
+
x = config("x", 1., ( Float>=0.) & (Int<=1), "test x")
|
|
181
|
+
|
|
182
|
+
# test deleting children
|
|
183
|
+
config = Config()
|
|
184
|
+
config.a.x = 1
|
|
185
|
+
config.b.x = 2
|
|
186
|
+
config.c.x = 3
|
|
187
|
+
config.delete_children( 'a' )
|
|
188
|
+
l = sorted( config.children )
|
|
189
|
+
self.assertEqual(l, ['b', 'c'])
|
|
190
|
+
config = Config()
|
|
191
|
+
config.a.x = 1
|
|
192
|
+
config.b.x = 2
|
|
193
|
+
config.c.x = 3
|
|
194
|
+
config.delete_children( ['a','b'] )
|
|
195
|
+
l = sorted( config.children )
|
|
196
|
+
self.assertEqual(l, ['c'])
|
|
197
|
+
|
|
198
|
+
# test conversion to dictionaries
|
|
199
|
+
config = Config()
|
|
200
|
+
config.x = 1
|
|
201
|
+
config.y = 2
|
|
202
|
+
config.sub.x = 10
|
|
203
|
+
config.sub.y = 20
|
|
204
|
+
inp_dict = config.input_dict()
|
|
205
|
+
|
|
206
|
+
test = pdct()
|
|
207
|
+
test.x = 1
|
|
208
|
+
test.y = 2
|
|
209
|
+
test.sub = pdct()
|
|
210
|
+
test.sub.x = 10
|
|
211
|
+
test.sub.y = 20
|
|
212
|
+
|
|
213
|
+
self.assertEqual( test, inp_dict)
|
|
214
|
+
|
|
215
|
+
# clean_copy
|
|
216
|
+
config = Config()
|
|
217
|
+
config.gym.user_version = 1
|
|
218
|
+
config.gym.world_character_id = 2
|
|
219
|
+
config.gym.vol_model.type = "decoder"
|
|
220
|
+
_ = config.clean_copy()
|
|
221
|
+
|
|
222
|
+
"""
|
|
223
|
+
test = PrettyDict()
|
|
224
|
+
test.x = config("x", 1)
|
|
225
|
+
test.y = config("y", 22)
|
|
226
|
+
test.z = config("z", 33)
|
|
227
|
+
test.sub = PrettyDict()
|
|
228
|
+
test.sub.x = config.sub("x", 10)
|
|
229
|
+
test.sub.y = config.sub("y", 222)
|
|
230
|
+
test.sub.z = config.sub("z", 333)
|
|
231
|
+
usd_dict = config.usage_dict()
|
|
232
|
+
self.assertEqual( usd_dict, test )
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
# test keys()
|
|
236
|
+
|
|
237
|
+
config = Config()
|
|
238
|
+
config.a = 1
|
|
239
|
+
config.x.b = 2
|
|
240
|
+
keys = list(config)
|
|
241
|
+
sorted(keys)
|
|
242
|
+
self.assertEqual( keys, ['a'])
|
|
243
|
+
keys = list(config.keys())
|
|
244
|
+
sorted(keys)
|
|
245
|
+
self.assertEqual( keys, ['a'])
|
|
246
|
+
|
|
247
|
+
# test update
|
|
248
|
+
|
|
249
|
+
config = Config()
|
|
250
|
+
config.a = 1
|
|
251
|
+
config.x.a = 1
|
|
252
|
+
config.z.a =1
|
|
253
|
+
|
|
254
|
+
config2 = Config()
|
|
255
|
+
config2.b = 2
|
|
256
|
+
config2.x.a = 2
|
|
257
|
+
config2.x.b = 2
|
|
258
|
+
config2.y.b = 2
|
|
259
|
+
config2.z = 2
|
|
260
|
+
config.update( config2 )
|
|
261
|
+
ur1 = config.input_report()
|
|
262
|
+
|
|
263
|
+
econfig = Config()
|
|
264
|
+
econfig.a = 1
|
|
265
|
+
econfig.b = 2
|
|
266
|
+
econfig.x.a = 2
|
|
267
|
+
econfig.x.b = 2
|
|
268
|
+
econfig.y.b = 2
|
|
269
|
+
econfig.z = 2
|
|
270
|
+
ur2 = econfig.input_report()
|
|
271
|
+
self.assertEqual( ur1, ur2 )
|
|
272
|
+
|
|
273
|
+
config = Config()
|
|
274
|
+
config.a = 1
|
|
275
|
+
config.x.a = 1
|
|
276
|
+
|
|
277
|
+
d = dict(b=2,x=dict(a=2,b=2),y=dict(b=2),z=2)
|
|
278
|
+
config.update(d)
|
|
279
|
+
ur2 = econfig.input_report()
|
|
280
|
+
self.assertEqual( ur1, ur2 )
|
|
281
|
+
|
|
282
|
+
# test str and repr
|
|
283
|
+
|
|
284
|
+
config = Config()
|
|
285
|
+
config.x = 1
|
|
286
|
+
config.y = 2
|
|
287
|
+
config.sub.x = 10
|
|
288
|
+
config.sub.y = 20
|
|
289
|
+
|
|
290
|
+
self.assertEqual( str(config), "config{'x': 1, 'y': 2, 'sub': {'x': 10, 'y': 20}}")
|
|
291
|
+
self.assertEqual( repr(config), "Config( **{'x': 1, 'y': 2, 'sub': {'x': 10, 'y': 20}}, config_name='config' )")
|
|
292
|
+
|
|
293
|
+
# test recorded usage
|
|
294
|
+
|
|
295
|
+
config = Config()
|
|
296
|
+
config.x = 1
|
|
297
|
+
config.sub.a = 1
|
|
298
|
+
config.det.o = 1
|
|
299
|
+
|
|
300
|
+
_ = config("x", 11)
|
|
301
|
+
_ = config("y", 22)
|
|
302
|
+
_ = config.sub("a", 11)
|
|
303
|
+
_ = config.sub("b", 22)
|
|
304
|
+
det = config.det.detach() # shares the same recorder !
|
|
305
|
+
_ = det("o", 11)
|
|
306
|
+
_ = det("p", 22)
|
|
307
|
+
|
|
308
|
+
self.assertEqual( config.get_recorded("x"), 1)
|
|
309
|
+
self.assertEqual( config.get_recorded("y"), 22)
|
|
310
|
+
self.assertEqual( config.sub.get_recorded("a"), 1)
|
|
311
|
+
self.assertEqual( config.sub.get_recorded("b"), 22)
|
|
312
|
+
self.assertEqual( config.det.get_recorded("o"), 1)
|
|
313
|
+
self.assertEqual( config.det.get_recorded("p"), 22)
|
|
314
|
+
|
|
315
|
+
# unique ID
|
|
316
|
+
|
|
317
|
+
config = Config()
|
|
318
|
+
# world
|
|
319
|
+
config.world.samples = 10000
|
|
320
|
+
config.world.steps = 20
|
|
321
|
+
config.world.black_scholes = True
|
|
322
|
+
config.world.rvol = 0.2 # 20% volatility
|
|
323
|
+
config.world.drift = 0. # real life drift
|
|
324
|
+
config.world.cost_s = 0.
|
|
325
|
+
# gym
|
|
326
|
+
config.gym.objective.utility = "cvar"
|
|
327
|
+
config.gym.objective.lmbda = 1.
|
|
328
|
+
config.gym.agent.network.depth = 6
|
|
329
|
+
config.gym.agent.network.width = 40
|
|
330
|
+
config.gym.agent.network.activation = "softplus"
|
|
331
|
+
# trainer
|
|
332
|
+
config.trainer.train.optimizer = "adam"
|
|
333
|
+
config.trainer.train.batch_size = None
|
|
334
|
+
config.trainer.train.epochs = 400
|
|
335
|
+
config.trainer.caching.epoch_freq = 10
|
|
336
|
+
config.trainer.caching.mode = "on"
|
|
337
|
+
config.trainer.visual.epoch_refresh = 1
|
|
338
|
+
config.trainer.visual.time_refresh = 10
|
|
339
|
+
config.trainer.visual.confidence_pcnt_lo = 0.25
|
|
340
|
+
config.trainer.visual.confidence_pcnt_hi = 0.75
|
|
341
|
+
|
|
342
|
+
id1 = config.unique_hash()
|
|
343
|
+
|
|
344
|
+
config = Config()
|
|
345
|
+
# world
|
|
346
|
+
config.world.samples = 10000
|
|
347
|
+
config.world.steps = 20
|
|
348
|
+
config.world.black_scholes = True
|
|
349
|
+
config.world.rvol = 0.2 # 20% volatility
|
|
350
|
+
config.world.drift = 0. # real life drift
|
|
351
|
+
config.world.cost_s = 0.
|
|
352
|
+
# gym
|
|
353
|
+
config.gym.objective.utility = "cvar"
|
|
354
|
+
config.gym.objective.lmbda = 1.
|
|
355
|
+
config.gym.agent.network.depth = 5 # <====== changed this
|
|
356
|
+
config.gym.agent.network.width = 40
|
|
357
|
+
config.gym.agent.network.activation = "softplus"
|
|
358
|
+
# trainer
|
|
359
|
+
config.trainer.train.optimizer = "adam"
|
|
360
|
+
config.trainer.train.batch_size = None
|
|
361
|
+
config.trainer.train.epochs = 400
|
|
362
|
+
config.trainer.caching.epoch_freq = 10
|
|
363
|
+
config.trainer.caching.mode = "on"
|
|
364
|
+
config.trainer.visual.epoch_refresh = 1
|
|
365
|
+
config.trainer.visual.time_refresh = 10
|
|
366
|
+
config.trainer.visual.confidence_pcnt_lo = 0.25
|
|
367
|
+
config.trainer.visual.confidence_pcnt_hi = 0.75
|
|
368
|
+
|
|
369
|
+
id2 = config.unique_hash()
|
|
370
|
+
self.assertNotEqual(id1,id2)
|
|
371
|
+
self.assertEqual(id2,"cfef59b69770d0a973342ad68f38fba2")
|
|
372
|
+
|
|
373
|
+
_ = config.nothing("get_nothing", 0) # this triggered a new ID in old versions
|
|
374
|
+
|
|
375
|
+
id3 = config.unique_hash()
|
|
376
|
+
self.assertEqual(id2,id3)
|
|
377
|
+
|
|
378
|
+
idempty = Config().unique_hash()
|
|
379
|
+
self.assertEqual(idempty,"64550d6ffe2c0a01a14aba1eade0200c")
|
|
380
|
+
self.assertNotEqual(idempty,id3)
|
|
381
|
+
|
|
382
|
+
# pickle test
|
|
383
|
+
|
|
384
|
+
binary = pickle.dumps(config)
|
|
385
|
+
restored = pickle.loads(binary)
|
|
386
|
+
idrest = restored.unique_hash()
|
|
387
|
+
self.assertEqual(idrest,id2)
|
|
388
|
+
|
|
389
|
+
# unique ID test
|
|
390
|
+
|
|
391
|
+
config1 = Config()
|
|
392
|
+
config1.x = 1
|
|
393
|
+
config1.sub.y = 2
|
|
394
|
+
config2 = Config()
|
|
395
|
+
config2.x = 1
|
|
396
|
+
config2.sub.y = 3
|
|
397
|
+
self.assertNotEqual( unique_hash16(config1), unique_hash16(config2) )
|
|
398
|
+
|
|
399
|
+
config1 = Config()
|
|
400
|
+
config1.x = 1
|
|
401
|
+
config1.sub.y = 2
|
|
402
|
+
config2 = Config()
|
|
403
|
+
config2.x = 2
|
|
404
|
+
config2.sub.y = 2
|
|
405
|
+
self.assertNotEqual( unique_hash16(config1), unique_hash16(config2) )
|
|
406
|
+
|
|
407
|
+
config1 = Config()
|
|
408
|
+
config1.x = 1
|
|
409
|
+
config1.sub.y = 2
|
|
410
|
+
config2 = Config()
|
|
411
|
+
config2.x = 1
|
|
412
|
+
config2.sub.y = 2
|
|
413
|
+
self.assertEqual( unique_hash16(config1), unique_hash16(config2) )
|
|
414
|
+
|
|
415
|
+
# unique_hash16() ignores protected and private members
|
|
416
|
+
config1 = Config()
|
|
417
|
+
config1.x = 1
|
|
418
|
+
config1.sub._y = 2
|
|
419
|
+
config2 = Config()
|
|
420
|
+
config2.x = 1
|
|
421
|
+
config2.sub._y = 3
|
|
422
|
+
self.assertEqual( unique_hash16(config1), unique_hash16(config2) )
|
|
423
|
+
|
|
424
|
+
def test_detach(self):
|
|
425
|
+
""" testing detach/copy/clean_cooy """
|
|
426
|
+
|
|
427
|
+
config = Config(a=1,b=2)
|
|
428
|
+
config.child.x = 1
|
|
429
|
+
_ = config("a", 2)
|
|
430
|
+
c1 = config.detach()
|
|
431
|
+
with self.assertRaises(Exception):
|
|
432
|
+
_ = c1("a", 1) # different default
|
|
433
|
+
_ = c1("b", 3)
|
|
434
|
+
with self.assertRaises(Exception):
|
|
435
|
+
_ = config("b", 2) # different default
|
|
436
|
+
|
|
437
|
+
config = Config(a=1,b=2)
|
|
438
|
+
config.child.x = 1
|
|
439
|
+
_ = config("a", 2)
|
|
440
|
+
c1 = config.copy()
|
|
441
|
+
with self.assertRaises(Exception):
|
|
442
|
+
_ = c1("a", 1) # different default
|
|
443
|
+
_ = c1("b", 3)
|
|
444
|
+
_ = config("b", 2) # different default - ok
|
|
445
|
+
|
|
446
|
+
config = Config(a=1,b=2)
|
|
447
|
+
config.child.x = 1
|
|
448
|
+
_ = config("a", 2)
|
|
449
|
+
c1 = config.clean_copy()
|
|
450
|
+
_ = c1("a", 1) # different default - ok
|
|
451
|
+
_ = c1("b", 3)
|
|
452
|
+
_ = config("b", 2) # different default - ok
|
|
453
|
+
|
|
454
|
+
def test_dataclass(self):
|
|
455
|
+
|
|
456
|
+
@dataclasses.dataclass
|
|
457
|
+
class A:
|
|
458
|
+
i : int = 0
|
|
459
|
+
config : Config = Config().as_field()
|
|
460
|
+
|
|
461
|
+
def f(self):
|
|
462
|
+
return self.config("a", 1, int, "Test")
|
|
463
|
+
|
|
464
|
+
a = A()
|
|
465
|
+
self.assertEqual(a.f(),1)
|
|
466
|
+
c = Config()
|
|
467
|
+
a = A(i=2,config=Config(c))
|
|
468
|
+
self.assertEqual(a.f(),1)
|
|
469
|
+
c = Config(a=2)
|
|
470
|
+
a = A(i=2,config=Config(c))
|
|
471
|
+
self.assertEqual(a.f(),2)
|
|
472
|
+
a = A(i=2,config=Config(a=2))
|
|
473
|
+
self.assertEqual(a.f(),2)
|
|
474
|
+
|
|
475
|
+
def test_io(self):
|
|
476
|
+
|
|
477
|
+
config = Config(x=1)
|
|
478
|
+
config.child.y = 2
|
|
479
|
+
config._test = 33
|
|
480
|
+
|
|
481
|
+
try:
|
|
482
|
+
tmp_dir = tempfile.mkdtemp()
|
|
483
|
+
self.assertNotEqual(tmp_dir[-1],"/")
|
|
484
|
+
self.assertNotEqual(tmp_dir[-1],"\\")
|
|
485
|
+
tmp_file = tmp_dir + "/test_pretty_object.pck"
|
|
486
|
+
|
|
487
|
+
with open(tmp_file, "wb") as f:
|
|
488
|
+
pickle.dump(config,f)
|
|
489
|
+
|
|
490
|
+
with open(tmp_file, "rb") as f:
|
|
491
|
+
config2 = pickle.load(f)
|
|
492
|
+
self.assertEqual(config,config2)
|
|
493
|
+
|
|
494
|
+
os.remove(tmp_file)
|
|
495
|
+
finally:
|
|
496
|
+
shutil.rmtree(tmp_dir)
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
if __name__ == '__main__':
|
|
500
|
+
unittest.main()
|
|
501
|
+
|
|
502
|
+
|
tests/test_crman.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Tue Apr 14 21:24:52 2020
|
|
4
|
+
@author: hansb
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest as unittest
|
|
8
|
+
|
|
9
|
+
def import_local():
|
|
10
|
+
"""
|
|
11
|
+
In order to be able to run our tests manually from the 'tests' directory
|
|
12
|
+
we force import from the local package.
|
|
13
|
+
We also force reloading all modules to make sure we are not running old code.
|
|
14
|
+
"""
|
|
15
|
+
me = "cdxcore"
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
cwd = os.getcwd()
|
|
19
|
+
if cwd[-len(me):] == me:
|
|
20
|
+
return
|
|
21
|
+
assert cwd[-5:] == "tests",("Expected current working directory to be in a 'tests' directory", cwd[-5:], "from", cwd)
|
|
22
|
+
assert cwd[-6] in ['/', '\\'],("Expected current working directory 'tests' to be lead by a '\\' or '/'", cwd[-6:], "from", cwd)
|
|
23
|
+
sys.path.insert( 0, cwd[:-6] )
|
|
24
|
+
|
|
25
|
+
# reload modules
|
|
26
|
+
import importlib as imp
|
|
27
|
+
modules = sys.modules.copy()
|
|
28
|
+
for name, mdata in modules.items():
|
|
29
|
+
if name[:len(me)] == me:
|
|
30
|
+
imp.reload(mdata)
|
|
31
|
+
print("Reloaded", name)
|
|
32
|
+
import_local()
|
|
33
|
+
|
|
34
|
+
from cdxcore.crman import CRMan
|
|
35
|
+
|
|
36
|
+
class Test(unittest.TestCase):
|
|
37
|
+
|
|
38
|
+
def test_crman(self):
|
|
39
|
+
|
|
40
|
+
crman = CRMan()
|
|
41
|
+
self.assertEqual( crman("test"), "test" )
|
|
42
|
+
self.assertEqual( crman("test"), "\r \r\x1b[2K\rtesttest" )
|
|
43
|
+
self.assertEqual( crman("\rxxxx"), "\r \r\x1b[2K\rxxxx" )
|
|
44
|
+
self.assertEqual( crman("yyyy\n"), "\r \r\x1b[2K\rxxxxyyyy\n" )
|
|
45
|
+
self.assertEqual( crman("ab\rcde\nxyz\r01\nt"), "cde\n01\nt" )
|
|
46
|
+
|
|
47
|
+
self.assertEqual( crman.current, "t" )
|
|
48
|
+
crman.reset()
|
|
49
|
+
self.assertEqual( crman.current, "" )
|
|
50
|
+
|
|
51
|
+
if __name__ == '__main__':
|
|
52
|
+
unittest.main()
|
|
53
|
+
|
|
54
|
+
|
tests/test_err.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Tue Apr 14 21:24:52 2020
|
|
4
|
+
@author: hansb
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest as unittest
|
|
8
|
+
import warnings as warnings
|
|
9
|
+
|
|
10
|
+
def import_local():
|
|
11
|
+
"""
|
|
12
|
+
In order to be able to run our tests manually from the 'tests' directory
|
|
13
|
+
we force import from the local package.
|
|
14
|
+
We also force reloading all modules to make sure we are not running old code.
|
|
15
|
+
"""
|
|
16
|
+
me = "cdxcore"
|
|
17
|
+
import os
|
|
18
|
+
import sys
|
|
19
|
+
cwd = os.getcwd()
|
|
20
|
+
if cwd[-len(me):] == me:
|
|
21
|
+
return
|
|
22
|
+
assert cwd[-5:] == "tests",("Expected current working directory to be in a 'tests' directory", cwd[-5:], "from", cwd)
|
|
23
|
+
assert cwd[-6] in ['/', '\\'],("Expected current working directory 'tests' to be lead by a '\\' or '/'", cwd[-6:], "from", cwd)
|
|
24
|
+
sys.path.insert( 0, cwd[:-6] )
|
|
25
|
+
|
|
26
|
+
# reload modules
|
|
27
|
+
import importlib as imp
|
|
28
|
+
modules = sys.modules.copy()
|
|
29
|
+
for name, mdata in modules.items():
|
|
30
|
+
if name[:len(me)] == me:
|
|
31
|
+
imp.reload(mdata)
|
|
32
|
+
print("Reloaded", name)
|
|
33
|
+
import_local()
|
|
34
|
+
|
|
35
|
+
from cdxcore.err import fmt, error, verify, warn, warn_if
|
|
36
|
+
|
|
37
|
+
class Test(unittest.TestCase):
|
|
38
|
+
|
|
39
|
+
def test_fmt(self):
|
|
40
|
+
|
|
41
|
+
self.assertEqual(fmt("number %d %d",1,2),"number 1 2")
|
|
42
|
+
self.assertEqual(fmt("number %(two)d %(one)d",one=1,two=2),"number 2 1")
|
|
43
|
+
self.assertEqual(fmt("number {two:d} {one:d}",one=1,two=2),"number 2 1")
|
|
44
|
+
self.assertEqual(fmt("number {two:s} {one:d}",one=1,two="II"),"number II 1")
|
|
45
|
+
with self.assertRaises(KeyError):
|
|
46
|
+
fmt("one {two/2:d} also one {one:d}",one=1,two=2)
|
|
47
|
+
one_ = 1
|
|
48
|
+
two_ = 2
|
|
49
|
+
self.assertEqual(fmt(lambda : f"one {one_} also one {two_//2}"),"one 1 also one 1")
|
|
50
|
+
self.assertEqual(fmt(lambda one, two: f"one {one} also one {two//2}", one=1, two=2),"one 1 also one 1")
|
|
51
|
+
|
|
52
|
+
with self.assertRaises(KeyError):
|
|
53
|
+
fmt("number %(two)d %(one)d",one=1)
|
|
54
|
+
with self.assertRaises(TypeError):
|
|
55
|
+
fmt("number %d %d",1)
|
|
56
|
+
with self.assertRaises(TypeError):
|
|
57
|
+
fmt("number %d %d",1,2,3)
|
|
58
|
+
with self.assertRaises(TypeError):
|
|
59
|
+
fmt("number $(one)d",1)
|
|
60
|
+
with self.assertRaises(ValueError):
|
|
61
|
+
fmt("number %d %(one)d",2,one=1)
|
|
62
|
+
|
|
63
|
+
with self.assertRaises(ValueError):
|
|
64
|
+
error("one {one} two {two}", one=1, two=2, exception=ValueError)
|
|
65
|
+
with self.assertRaises(TypeError):
|
|
66
|
+
error("one {one} two {two}", one=1, two=2, exception=TypeError)
|
|
67
|
+
with self.assertRaises(TypeError):
|
|
68
|
+
verify(False,"one {one} two {two}", one=1, two=2, exception=TypeError)
|
|
69
|
+
verify(True,"one {one} two {two}", one=1, two=2, exception=TypeError)
|
|
70
|
+
|
|
71
|
+
with warnings.catch_warnings():
|
|
72
|
+
warnings.filterwarnings("error", category=UserWarning)
|
|
73
|
+
warnings.filterwarnings("error", category=RuntimeWarning)
|
|
74
|
+
|
|
75
|
+
with self.assertRaises(UserWarning):
|
|
76
|
+
warn("one {one} two {two}", one=1, two=2, warning=UserWarning)
|
|
77
|
+
with self.assertRaises(RuntimeWarning):
|
|
78
|
+
warn("one {one} two {two}", one=1, two=2, warning=RuntimeWarning)
|
|
79
|
+
with self.assertRaises(RuntimeWarning):
|
|
80
|
+
warn_if(True,"one {one} two {two}", one=1, two=2, warning=RuntimeWarning)
|
|
81
|
+
warn_if(False,"one {one} two {two}", one=1, two=2, warning=RuntimeWarning)
|
|
82
|
+
|
|
83
|
+
if __name__ == '__main__':
|
|
84
|
+
unittest.main()
|
|
85
|
+
|
|
86
|
+
|