configos 1.0.2__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 (44) hide show
  1. configos-1.0.2/PKG-INFO +37 -0
  2. configos-1.0.2/README +12 -0
  3. configos-1.0.2/configos/__init__.py +103 -0
  4. configos-1.0.2/configos/cache.py +34 -0
  5. configos-1.0.2/configos/cli/__init__.py +90 -0
  6. configos-1.0.2/configos/cli/generate.py +46 -0
  7. configos-1.0.2/configos/cli/optimization.py +68 -0
  8. configos-1.0.2/configos/cli/plan.py +199 -0
  9. configos-1.0.2/configos/cli/result.py +81 -0
  10. configos-1.0.2/configos/debugs.py +31 -0
  11. configos-1.0.2/configos/directory.py +130 -0
  12. configos-1.0.2/configos/docs.py +26 -0
  13. configos-1.0.2/configos/document.py +49 -0
  14. configos-1.0.2/configos/env.py +100 -0
  15. configos-1.0.2/configos/exception.py +20 -0
  16. configos-1.0.2/configos/holyvalue/__init__.py +10 -0
  17. configos-1.0.2/configos/holyvalue/access.py +111 -0
  18. configos-1.0.2/configos/holyvalue/cloud.py +74 -0
  19. configos-1.0.2/configos/holyvalue/collect.py +161 -0
  20. configos-1.0.2/configos/holyvalue/data.py +307 -0
  21. configos-1.0.2/configos/holyvalue/store.py +110 -0
  22. configos-1.0.2/configos/holyvalue/table.py +106 -0
  23. configos-1.0.2/configos/server.py +54 -0
  24. configos-1.0.2/configos/utils.py +31 -0
  25. configos-1.0.2/configos.egg-info/PKG-INFO +37 -0
  26. configos-1.0.2/configos.egg-info/SOURCES.txt +42 -0
  27. configos-1.0.2/configos.egg-info/dependency_links.txt +1 -0
  28. configos-1.0.2/configos.egg-info/entry_points.txt +2 -0
  29. configos-1.0.2/configos.egg-info/not-zip-safe +1 -0
  30. configos-1.0.2/configos.egg-info/requires.txt +2 -0
  31. configos-1.0.2/configos.egg-info/top_level.txt +1 -0
  32. configos-1.0.2/setup.cfg +4 -0
  33. configos-1.0.2/setup.py +24 -0
  34. configos-1.0.2/tests/test_access.py +42 -0
  35. configos-1.0.2/tests/test_cli.py +62 -0
  36. configos-1.0.2/tests/test_cloud.py +31 -0
  37. configos-1.0.2/tests/test_debug.py +18 -0
  38. configos-1.0.2/tests/test_document.py +24 -0
  39. configos-1.0.2/tests/test_env.py +87 -0
  40. configos-1.0.2/tests/test_holyexample.py +23 -0
  41. configos-1.0.2/tests/test_holyvalue.py +233 -0
  42. configos-1.0.2/tests/test_plan.py +21 -0
  43. configos-1.0.2/tests/test_server.py +51 -0
  44. configos-1.0.2/tests/test_share.py +114 -0
@@ -0,0 +1,37 @@
1
+ Metadata-Version: 2.4
2
+ Name: configos
3
+ Version: 1.0.2
4
+ Summary: configos
5
+ Home-page: https://github.com/anaticulae/configos
6
+ Author: Helmut Konrad Schewe
7
+ Author-email: helmutus@outlook.com
8
+ Platform: any
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Requires-Dist: utilo<3.0.0,>=2.106.2
16
+ Requires-Dist: setuptools==82.0.0
17
+ Dynamic: author
18
+ Dynamic: author-email
19
+ Dynamic: classifier
20
+ Dynamic: description
21
+ Dynamic: home-page
22
+ Dynamic: platform
23
+ Dynamic: requires-dist
24
+ Dynamic: summary
25
+
26
+ # configos
27
+
28
+ Configo holds the configuration/parameterization of the different tools of
29
+ `kiwi` project. This includes environment variables and python implementation.
30
+ The environment variables are used for decoupling the dependencies in the
31
+ project.
32
+
33
+ Features:
34
+
35
+ * Share: public file share location
36
+ * Server: ports and ip-address of different server
37
+ * Document: sizes of DIN-AX-Pages
configos-1.0.2/README ADDED
@@ -0,0 +1,12 @@
1
+ # configos
2
+
3
+ Configo holds the configuration/parameterization of the different tools of
4
+ `kiwi` project. This includes environment variables and python implementation.
5
+ The environment variables are used for decoupling the dependencies in the
6
+ project.
7
+
8
+ Features:
9
+
10
+ * Share: public file share location
11
+ * Server: ports and ip-address of different server
12
+ * Document: sizes of DIN-AX-Pages
@@ -0,0 +1,103 @@
1
+ #==============================================================================
2
+ # C O P Y R I G H T
3
+ #------------------------------------------------------------------------------
4
+ # Copyright (c) 2019-2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ #==============================================================================
9
+
10
+ import os
11
+
12
+ # Public API:
13
+ # Cache
14
+ from configos.cache import CACHE_LARGE
15
+ from configos.cache import CACHE_MEDIUM
16
+ from configos.cache import CACHE_SMALL
17
+ from configos.cache import cache_large
18
+ from configos.cache import cache_medium
19
+ from configos.cache import cache_small
20
+ # debug
21
+ from configos.debugs import debug
22
+ from configos.debugs import debug_set
23
+ from configos.debugs import debug_unset
24
+ # directory
25
+ from configos.directory import check_startup
26
+ from configos.directory import environment
27
+ from configos.directory import export
28
+ from configos.directory import makedirs
29
+ from configos.directory import ready
30
+ from configos.directory import share
31
+ from configos.directory import tmp
32
+ from configos.directory import todo
33
+ # docs
34
+ from configos.docs import docs_url
35
+ # Document
36
+ from configos.document import OneSideDINA4
37
+ from configos.document import OneSideDINA5
38
+ # env
39
+ from configos.env import env
40
+ from configos.env import env_del
41
+ from configos.env import env_dump
42
+ from configos.env import env_load
43
+ from configos.env import env_path_append
44
+ from configos.env import env_path_remove
45
+ from configos.env import env_set
46
+ from configos.env import env_unload
47
+ # Exception
48
+ from configos.exception import HolyValueError
49
+ from configos.exception import InvalidHolyValue
50
+ from configos.exception import MissingHolyValue
51
+ # Holy
52
+ from configos.holyvalue.access import HV
53
+ from configos.holyvalue.access import HV_API
54
+ from configos.holyvalue.access import HV_BOOL
55
+ from configos.holyvalue.access import HV_FLOAT
56
+ from configos.holyvalue.access import HV_FLOAT_MINUS
57
+ from configos.holyvalue.access import HV_FLOAT_PLUS
58
+ from configos.holyvalue.access import HV_GB
59
+ from configos.holyvalue.access import HV_HOUR
60
+ from configos.holyvalue.access import HV_INT
61
+ from configos.holyvalue.access import HV_INT_MINUS
62
+ from configos.holyvalue.access import HV_INT_PLUS
63
+ from configos.holyvalue.access import HV_KB
64
+ from configos.holyvalue.access import HV_MB
65
+ from configos.holyvalue.access import HV_MINUTE
66
+ from configos.holyvalue.access import HV_PERCENT
67
+ from configos.holyvalue.access import HV_PERCENT_MINUS
68
+ from configos.holyvalue.access import HV_PERCENT_PLUS
69
+ from configos.holyvalue.access import HV_SECOND
70
+ from configos.holyvalue.access import HV_SECRET
71
+ from configos.holyvalue.access import HV_STR
72
+ from configos.holyvalue.cloud import cloud_base
73
+ from configos.holyvalue.cloud import cloud_base_set
74
+ from configos.holyvalue.cloud import cloud_lookup
75
+ from configos.holyvalue.cloud import cloud_set
76
+ from configos.holyvalue.cloud import cloud_unset
77
+ from configos.holyvalue.cloud import holyname
78
+ from configos.holyvalue.collect import generate
79
+ from configos.holyvalue.data import NOMATH
80
+ from configos.holyvalue.data import DataType
81
+ from configos.holyvalue.data import HolyValue
82
+ from configos.holyvalue.store import database
83
+ from configos.holyvalue.store import init
84
+ from configos.holyvalue.store import load
85
+ from configos.holyvalue.store import parse
86
+ from configos.holyvalue.table import HolyList
87
+ from configos.holyvalue.table import HolyRate
88
+ from configos.holyvalue.table import HolyTable
89
+ # Server
90
+ from configos.server import package_address
91
+ from configos.server import package_configuration
92
+
93
+ __version__ = '1.0.1'
94
+
95
+ ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
96
+ PROCESS = 'configos'
97
+
98
+ init(cloud_base())
99
+
100
+ # TODO: REMOVE LATER AND INCREASE MAJOR VERSION NUMBER
101
+ load_env = env_load
102
+ unload_env = env_unload
103
+ dump_env = env_dump
@@ -0,0 +1,34 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2019-2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+ """\
10
+ >>> @cache_large
11
+ ... def hello():
12
+ ... pass
13
+ >>> hello()
14
+ >>> @cache_small
15
+ ... def wello():
16
+ ... print('hello')
17
+ >>> wello()
18
+ hello
19
+ >>> wello()
20
+ >>> wello()
21
+ """
22
+
23
+ import functools
24
+
25
+ import utilo
26
+
27
+ CACHE_SMALL = 32
28
+ CACHE_MEDIUM = 512
29
+ CACHE_LARGE = 4096
30
+
31
+ # TODO: MAY ONLY USE UTILA.CACHE???
32
+ cache_small = functools.partial(utilo.cacheme, maxsize=CACHE_SMALL)
33
+ cache_medium = functools.partial(utilo.cacheme, maxsize=CACHE_MEDIUM)
34
+ cache_large = functools.partial(utilo.cacheme, maxsize=CACHE_LARGE)
@@ -0,0 +1,90 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2021-2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import sys
11
+
12
+ import utilo
13
+
14
+ import configos
15
+ import configos.cli.generate
16
+ import configos.cli.optimization
17
+
18
+
19
+ @utilo.saveme
20
+ def main():
21
+ current, data = evaluate()
22
+ for action, method in runner():
23
+ if current != action:
24
+ continue
25
+ if method.evaluate(*data):
26
+ return utilo.FAILURE
27
+ return utilo.SUCCESS
28
+ return utilo.INVALID_COMMAND
29
+
30
+
31
+ def runner():
32
+ runme = (
33
+ ('generate', configos.cli.generate),
34
+ ('optimize', configos.cli.optimization),
35
+ )
36
+ return runme
37
+
38
+
39
+ def evaluate() -> tuple:
40
+ parser = create_parser()
41
+ args = utilo.parse(parser)
42
+ action, data = '', None
43
+ gen = (args.get('input'), args.get('noskip', False))
44
+ if args['generate']:
45
+ action = 'generate'
46
+ data = gen
47
+ optimize = (
48
+ args.get('create'),
49
+ args.get('run'),
50
+ args.get('show'),
51
+ args.get('r'),
52
+ args.get('t'),
53
+ )
54
+ if any(optimize):
55
+ action = 'optimize'
56
+ data = optimize
57
+ if not action:
58
+ utilo.error('nothing todo')
59
+ sys.exit(utilo.INVALID_COMMAND)
60
+ return action, data
61
+
62
+
63
+ def create_parser():
64
+ result = utilo.cli.create_parser(
65
+ todo=[
66
+ utilo.cli.Flag(
67
+ longcut='--generate',
68
+ message='create default config out of source',
69
+ ),
70
+ utilo.cli.Flag(
71
+ longcut='--noskip',
72
+ message='do not skip any path',
73
+ ),
74
+ ],
75
+ config=utilo.ParserConfiguration(
76
+ inputparameter=True,
77
+ outputparameter=False,
78
+ cacheflag=False,
79
+ cprofile=False,
80
+ multiprocessed=False,
81
+ pages=False,
82
+ prefix=False,
83
+ verboseflag=True,
84
+ waitingflag=False,
85
+ ),
86
+ prog=configos.PROCESS,
87
+ version=configos.__version__,
88
+ )
89
+ configos.cli.optimization.add_option(result)
90
+ return result
@@ -0,0 +1,46 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2021-2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import utilo
11
+
12
+ import configos
13
+
14
+
15
+ def evaluate(inpath: list, noskip=False) -> int:
16
+ """\
17
+ Could not locate any holy value on this file. 1 means failure.
18
+ >>> evaluate([__file__])
19
+ 1
20
+ """
21
+ skip = None if noskip else skips
22
+ for path in inpath:
23
+ if not utilo.exists(path):
24
+ utilo.error(f'input does not exists: {path}')
25
+ return utilo.FAILURE
26
+ done = False
27
+ for item in inpath:
28
+ collected = configos.generate(item, skips=skip)
29
+ if not collected:
30
+ continue
31
+ utilo.print_banner(text=item, symbol='#')
32
+ utilo.log(collected)
33
+ done = True
34
+ if not done:
35
+ utilo.error('could not locate any HolyValue')
36
+ return utilo.FAILURE
37
+ return utilo.SUCCESS
38
+
39
+
40
+ def skips(item: str) -> bool:
41
+ """\
42
+ >>> skips('config/tests/__init.py')
43
+ True
44
+ """
45
+ item = str(item)
46
+ return 'build' in item or 'tests' in item
@@ -0,0 +1,68 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2021-2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import utilo
11
+
12
+ import configos.cli.plan
13
+ import configos.cli.result
14
+
15
+
16
+ def evaluate(
17
+ create: list,
18
+ run: str,
19
+ show: str,
20
+ reduce: int,
21
+ cmd_test: str,
22
+ ): # pylint:disable=W0613
23
+ if create:
24
+ plan = configos.cli.plan.create(create)
25
+ utilo.log(configos.cli.plan.dump(plan))
26
+ if run:
27
+ if cmd_test is None:
28
+ cmd_test = 'baw test -n1'
29
+ configos.cli.plan.run(
30
+ run,
31
+ reduce=reduce,
32
+ cmd_test=cmd_test,
33
+ )
34
+ if show:
35
+ configos.cli.result.show(show)
36
+
37
+
38
+ def add_option(parser):
39
+ # TODO: REPLACE WITH UTILA METHOD
40
+ sub = parser.add_subparsers(help='run optimizer to determine holy values')
41
+ show = sub.add_parser('optimize')
42
+ show.add_argument(
43
+ '--create',
44
+ help='create optimization plan',
45
+ action='append',
46
+ )
47
+ show.add_argument(
48
+ '--run',
49
+ help='run optimization',
50
+ action='append',
51
+ )
52
+ show.add_argument(
53
+ '--show',
54
+ help='show optimization result',
55
+ action='append',
56
+ )
57
+ show.add_argument(
58
+ '-r',
59
+ default=100,
60
+ type=int,
61
+ help='number of optimization steps',
62
+ )
63
+ show.add_argument(
64
+ '-t',
65
+ default=None,
66
+ type=str,
67
+ help='run test after each holy value update (baw test -n1)',
68
+ )
@@ -0,0 +1,199 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import collections
11
+ import os
12
+ import re
13
+
14
+ import utilo
15
+
16
+ import configos
17
+ import configos.holyvalue.access
18
+ import configos.holyvalue.collect
19
+
20
+
21
+ def create(todo: list) -> dict:
22
+ result = {}
23
+ for path in todo:
24
+ program = utilo.path_current(path)
25
+ collected = configos.holyvalue.collect.collect(path)
26
+ for groupname, group in collected.items():
27
+ for key, value in group.items():
28
+ progname = f'{program}.{groupname}'
29
+ hvgroup = value.get('hvgroup', progname)
30
+ if hvgroup == configos.holyvalue.access.NO_GROUP:
31
+ hvgroup = progname
32
+ hvgroup = hvgroup.upper()
33
+ variable = f'{hvgroup}.{key}'
34
+ todo = ranges(
35
+ default=value.get('default'),
36
+ limit=value.get('limit', None),
37
+ datatype=value.get('datatype', None),
38
+ )
39
+ if not todo:
40
+ utilo.debug(f'skip for optimization, no range: {variable}')
41
+ continue
42
+ result[variable] = todo
43
+ return result
44
+
45
+
46
+ def run(
47
+ path,
48
+ reduce=100,
49
+ seed=None,
50
+ test_before: bool = False,
51
+ cmd_test=None,
52
+ ):
53
+ path = os.path.abspath(path[0])
54
+ plan = utilo.yaml_load(path)
55
+ todo = list(plan.values())
56
+ keys = list(plan.keys())
57
+ mapped = first_one(todo)
58
+ utilo.log(f'different steps: {len(mapped)}')
59
+ if len(mapped) > reduce:
60
+ utilo.log(f'reduce values: {reduce}')
61
+ mapped = utilo.choose_random(mapped, count=reduce, seed=seed)
62
+ # verify code without hv-modification
63
+ if test_before:
64
+ utilo.log('test project')
65
+ utilo.run(cmd_test) # utilo.run('baw test')
66
+ # utilo.log(utilo.from_tuple(keys, ';'))
67
+ with utilo.make_tmpdir(configos.ROOT) as tmpdir:
68
+ utilo.log(f'outdir: {tmpdir}')
69
+ header = f"number,{utilo.from_tuple(keys, separator=',')},failure\n"
70
+ utilo.file_append(
71
+ os.path.join(tmpdir, 'result'),
72
+ header,
73
+ create=True,
74
+ )
75
+ for index, step in enumerate(mapped):
76
+ run_test(
77
+ key=keys,
78
+ config=step,
79
+ step=index,
80
+ tmpdir=tmpdir,
81
+ cmd_test=cmd_test,
82
+ )
83
+
84
+
85
+ def run_test(
86
+ key,
87
+ config,
88
+ step: int,
89
+ tmpdir,
90
+ cmd_test,
91
+ hcvalue='RAWMAKER',
92
+ ):
93
+ # write hv config
94
+ cfg = create_config(key, config)
95
+ step = str(step).zfill(4)
96
+ cfgpath = os.path.join(tmpdir, f'{step}.hv')
97
+ utilo.file_create(cfgpath, cfg)
98
+ configos.cloud_set(program=hcvalue, namepath=cfgpath)
99
+ # run tests
100
+ utilo.log(f'run step: {step}')
101
+ utilo.log(utilo.from_tuple(config, ';'))
102
+ completed = utilo.run(
103
+ cmd_test,
104
+ expect=None,
105
+ env=dict(os.environ),
106
+ )
107
+ # cfgpath
108
+ logpath = os.path.join(tmpdir, f'{step}.log')
109
+ utilo.file_create(logpath, completed.stderr)
110
+ utilo.file_append(logpath, completed.stdout)
111
+ tests = 0
112
+ if completed.returncode:
113
+ stdout = completed.stdout
114
+ tests = FAILED.search(stdout)['failed']
115
+ config = f'{step},' + utilo.from_tuple(config, ',') + f',{tests}\n'
116
+ if completed.returncode:
117
+ utilo.error(config)
118
+ # append result
119
+ utilo.file_append(
120
+ os.path.join(tmpdir, 'result'),
121
+ config,
122
+ create=True,
123
+ )
124
+
125
+
126
+ # === 5 failed, 178 passed, 168 skipped,
127
+ FAILED = re.compile(r'===\ (?P<failed>\d+)\ fail')
128
+
129
+ STEPS = (1.0, 0.1, 0.3, 0.5, 0.9, 1.2, 1.8, 2.2, 2.8, 3.5)
130
+
131
+
132
+ def ranges(
133
+ default,
134
+ limit=None,
135
+ datatype: configos.DataType = None,
136
+ steps=None,
137
+ ) -> tuple:
138
+ """\
139
+ >>> ranges(50, 300, configos.DataType.INT_PLUS, steps=((1.0, 1.5, 2.0)))
140
+ (50, 75, 100)
141
+ >>> ranges(1.2, 3.0, configos.DataType.FLOAT, steps=((1.0, 1.5, 2.0)))
142
+ (1.2, 1.8, 2.4)
143
+ >>> ranges(True, datatype=configos.DataType.BOOL)
144
+ (True, False)
145
+ """
146
+ if steps is None:
147
+ steps = STEPS
148
+ if default is None:
149
+ return tuple()
150
+ if datatype and datatype == configos.DataType.STR:
151
+ return tuple()
152
+ if datatype == configos.DataType.BOOL:
153
+ return (True, False)
154
+ data = tuple(utilo.roundme(default * item) for item in steps)
155
+ if 'INT' in str(datatype):
156
+ data = tuple(int(item) for item in data)
157
+ if limit is not None:
158
+ data = tuple(item for item in data if item < limit)
159
+ return data
160
+
161
+
162
+ def create_config(keys, configs) -> str:
163
+ grouped = collections.defaultdict(list)
164
+ for key, config in zip(keys, configs):
165
+ group, key = key.rsplit('.', 1)
166
+ grouped[group].append(f'{key} = {config}')
167
+ collected = []
168
+ for key, value in grouped.items():
169
+ collected.append('[' + key + ']')
170
+ collected.extend(value)
171
+ result = utilo.NEWLINE.join(collected)
172
+ return result
173
+
174
+
175
+ def first_one(items) -> list:
176
+ """\
177
+ >>> first_one(([1,], [2,]))
178
+ [[1, 2]]
179
+ >>> first_one([[1, 2], [3,]])
180
+ [[1, 3], [2, 3]]
181
+ >>> first_one([(4, ), (1, 2, 3), (5, 6)])
182
+ [[4, 1, 5], [4, 2, 5], [4, 3, 5], [4, 1, 6]]
183
+ """
184
+ # TODO: MOVE TO UTILA
185
+ items = [list(item) for item in items]
186
+ result = []
187
+ for index, _ in enumerate(items):
188
+ base = [item[0] for item in items]
189
+ for current in items[index]:
190
+ copy = list(base)
191
+ copy[index] = current
192
+ result.append(copy)
193
+ result = utilo.unique(result)
194
+ return result
195
+
196
+
197
+ def dump(plan: dict) -> str:
198
+ dumped = utilo.yaml_dump(plan)
199
+ return dumped
@@ -0,0 +1,81 @@
1
+ # =============================================================================
2
+ # C O P Y R I G H T
3
+ # -----------------------------------------------------------------------------
4
+ # Copyright (c) 2022 by Helmut Konrad Fahrendholz. All rights reserved.
5
+ # This file is property of Helmut Konrad Fahrendholz. Any unauthorized copy,
6
+ # use or distribution is an offensive act against international law and may
7
+ # be prosecuted under federal law. Its content is company confidential.
8
+ # =============================================================================
9
+
10
+ import collections
11
+ import csv
12
+ import os
13
+
14
+ import utilo
15
+
16
+ import configos
17
+
18
+
19
+ def show(result):
20
+ single = result[0]
21
+ parsed, header, size = parse_result(single)
22
+ rendered = render_table(list(parsed.values()), size, header=header)
23
+ with utilo.make_tmpdir(root=configos.ROOT) as output:
24
+ outpath = os.path.join(output, 'index.html')
25
+ utilo.file_create(outpath, rendered)
26
+ testrun = utilo.testing()
27
+ if not testrun:
28
+ utilo.run(f'start {outpath}')
29
+
30
+
31
+ def parse_result(path) -> dict:
32
+ collected = collections.defaultdict(set)
33
+ with open(path, newline='', encoding='utf8') as csvfile:
34
+ reader = csv.reader(csvfile)
35
+ data = list(reader)
36
+ width, height = 0, 0
37
+ header = data[0][1:-1]
38
+ for row in data[1:]:
39
+ number, *content, failure = row # pylint:disable=W0612
40
+ failure = int(failure)
41
+ for index, value in enumerate(content):
42
+ # TODO: ADD BOOL CHECKUP
43
+ value = int(value) if utilo.isint(value) else float(value)
44
+ collected[index].add((value, failure))
45
+ width = len(content)
46
+ height += 1
47
+ result = {key: prepare(value) for key, value in collected.items()}
48
+ return result, header, (width, height)
49
+
50
+
51
+ def prepare(value):
52
+ grouped = utilo.groupby_x(value, selector=lambda x: x[0])
53
+ result = []
54
+ for group in grouped:
55
+ result.append((group[0][0], min((item[1] for item in group))))
56
+ return sorted(result, key=lambda x: x[0], reverse=True)
57
+
58
+
59
+ def render_table(data, size, header=None) -> str:
60
+ width = 150 * size[0]
61
+ result = f'<html><table width={width}>'
62
+ if header:
63
+ result += '<tr>'
64
+ result += ''.join([
65
+ f'<td style="min-width:150px;font-size:10px;overflow:hidden">{item.replace(".", " ")}</td>'
66
+ for item in header
67
+ ])
68
+ result += '</tr>'
69
+ for _ in range(size[1]): # pylint:disable=W0612
70
+ result += '<tr>'
71
+ for pos in range(size[0]):
72
+ current = data[pos]
73
+ if current:
74
+ value, failure = current.pop()
75
+ color = 'green' if not failure else 'orange'
76
+ result += f'<td style="background:{color};" height=50px><center>{value} [{failure}]</center></td>'
77
+ else:
78
+ result += '<td></td>'
79
+ result += '</tr>'
80
+ result += '</table></html>'
81
+ return result