ChessAnalysisPipeline 0.0.4__py3-none-any.whl → 0.0.6__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 ChessAnalysisPipeline might be problematic. Click here for more details.

Files changed (43) hide show
  1. CHAP/TaskManager.py +214 -0
  2. CHAP/common/models/__init__.py +0 -2
  3. CHAP/common/models/integration.py +392 -249
  4. CHAP/common/models/map.py +350 -198
  5. CHAP/common/processor.py +229 -191
  6. CHAP/common/reader.py +52 -39
  7. CHAP/common/utils/__init__.py +0 -37
  8. CHAP/common/utils/fit.py +1197 -991
  9. CHAP/common/utils/general.py +629 -372
  10. CHAP/common/utils/material.py +158 -121
  11. CHAP/common/utils/scanparsers.py +735 -339
  12. CHAP/common/writer.py +31 -25
  13. CHAP/edd/models.py +65 -51
  14. CHAP/edd/processor.py +136 -113
  15. CHAP/edd/reader.py +1 -1
  16. CHAP/edd/writer.py +1 -1
  17. CHAP/inference/processor.py +35 -28
  18. CHAP/inference/reader.py +1 -1
  19. CHAP/inference/writer.py +1 -1
  20. CHAP/pipeline.py +14 -28
  21. CHAP/processor.py +44 -75
  22. CHAP/reader.py +49 -40
  23. CHAP/runner.py +73 -32
  24. CHAP/saxswaxs/processor.py +1 -1
  25. CHAP/saxswaxs/reader.py +1 -1
  26. CHAP/saxswaxs/writer.py +1 -1
  27. CHAP/server.py +130 -0
  28. CHAP/sin2psi/processor.py +1 -1
  29. CHAP/sin2psi/reader.py +1 -1
  30. CHAP/sin2psi/writer.py +1 -1
  31. CHAP/tomo/__init__.py +1 -4
  32. CHAP/tomo/models.py +53 -31
  33. CHAP/tomo/processor.py +1326 -902
  34. CHAP/tomo/reader.py +4 -2
  35. CHAP/tomo/writer.py +4 -2
  36. CHAP/writer.py +47 -41
  37. {ChessAnalysisPipeline-0.0.4.dist-info → ChessAnalysisPipeline-0.0.6.dist-info}/METADATA +1 -1
  38. ChessAnalysisPipeline-0.0.6.dist-info/RECORD +52 -0
  39. ChessAnalysisPipeline-0.0.4.dist-info/RECORD +0 -50
  40. {ChessAnalysisPipeline-0.0.4.dist-info → ChessAnalysisPipeline-0.0.6.dist-info}/LICENSE +0 -0
  41. {ChessAnalysisPipeline-0.0.4.dist-info → ChessAnalysisPipeline-0.0.6.dist-info}/WHEEL +0 -0
  42. {ChessAnalysisPipeline-0.0.4.dist-info → ChessAnalysisPipeline-0.0.6.dist-info}/entry_points.txt +0 -0
  43. {ChessAnalysisPipeline-0.0.4.dist-info → ChessAnalysisPipeline-0.0.6.dist-info}/top_level.txt +0 -0
CHAP/TaskManager.py ADDED
@@ -0,0 +1,214 @@
1
+ """
2
+ Python thread pool, see
3
+ http://code.activestate.com/recipes/577187-python-thread-pool/
4
+ Author: Valentin Kuznetsov <vkuznet [AT] gmail [DOT] com>
5
+ """
6
+ from builtins import range, object
7
+
8
+
9
+ # system modules
10
+ import time
11
+ import json
12
+ import hashlib
13
+ import logging
14
+ import threading
15
+ from queue import Queue
16
+
17
+
18
+ def genkey(query):
19
+ """
20
+ Generate a new key-hash for a given query. We use md5 hash for the
21
+ query and key is just hex representation of this hash.
22
+ """
23
+ if isinstance(query, dict):
24
+ record = dict(query)
25
+ query = json.JSONEncoder(sort_keys=True).encode(record)
26
+ keyhash = hashlib.md5()
27
+ keyhash.update(query.encode("utf-8", "strict"))
28
+ return keyhash.hexdigest()
29
+
30
+ def set_thread_name(ident, name):
31
+ "Set thread name for given identified"
32
+ for thr in threading.enumerate():
33
+ if thr.ident == ident:
34
+ thr.name = name
35
+ break
36
+
37
+ class StoppableThread(threading.Thread):
38
+ """Thread class with a stop() method. The thread itself has to check
39
+ regularly for the stopped() condition."""
40
+
41
+ def __init__(self, target, name, args):
42
+ super(StoppableThread, self).__init__(target=target, name=name, args=args)
43
+ self._stop_event = threading.Event()
44
+
45
+ def stop(self):
46
+ "Set event to stop the thread"
47
+ self._stop_event.set()
48
+
49
+ def stopped(self):
50
+ "Return stopped status of the thread"
51
+ return self._stop_event.is_set()
52
+
53
+ def running(self):
54
+ "Return running status of the thread"
55
+ return not self._stop_event.is_set()
56
+
57
+ def start_new_thread(name, func, args, unique=False):
58
+ "Wrapper wroung standard thread.strart_new_thread call"
59
+ if unique:
60
+ threads = sorted(threading.enumerate())
61
+ for thr in threads:
62
+ if name == thr.name:
63
+ return thr
64
+ # thr = threading.Thread(target=func, name=name, args=args)
65
+ thr = StoppableThread(target=func, name=name, args=args)
66
+ thr.daemon = True
67
+ thr.start()
68
+ return thr
69
+
70
+ class UidSet(object):
71
+ "UID holder keeps track of uid frequency"
72
+ def __init__(self):
73
+ self.set = {}
74
+
75
+ def add(self, uid):
76
+ "Add given uid or increment uid occurence in a set"
77
+ if not uid:
78
+ return
79
+ if uid in self.set:
80
+ self.set[uid] += 1
81
+ else:
82
+ self.set[uid] = 1
83
+
84
+ def discard(self, uid):
85
+ "Either discard or downgrade uid occurence in a set"
86
+ if uid in self.set:
87
+ self.set[uid] -= 1
88
+ if uid in self.set and not self.set[uid]:
89
+ del self.set[uid]
90
+
91
+ def __contains__(self, uid):
92
+ "Check if uid present in a set"
93
+ if uid in self.set:
94
+ return True
95
+ return False
96
+
97
+ def get(self, uid):
98
+ "Get value for given uid"
99
+ return self.set.get(uid, 0)
100
+
101
+ class Worker(threading.Thread):
102
+ """Thread executing worker from a given tasks queue"""
103
+ def __init__(self, name, taskq, pidq, uidq, logger=None):
104
+ self.logger = logging.getLogger()
105
+ threading.Thread.__init__(self, name=name)
106
+ self.exit = 0
107
+ self.tasks = taskq
108
+ self.pids = pidq
109
+ self.uids = uidq
110
+ self.daemon = True
111
+ self.start()
112
+
113
+ def force_exit(self):
114
+ """Force run loop to exit in a hard way"""
115
+ self.exit = 1
116
+
117
+ def run(self):
118
+ """Run thread loop"""
119
+ while True:
120
+ if self.exit:
121
+ return
122
+ task = self.tasks.get()
123
+ if task is None:
124
+ return
125
+ if self.exit:
126
+ return
127
+ if isinstance(task, str):
128
+ print(f"Worker daemon run {task}")
129
+ elif isinstance(task, tuple) and len(task) == 5:
130
+ evt, pid, func, args, kwargs = task
131
+ try:
132
+ func(*args, **kwargs)
133
+ self.pids.discard(pid)
134
+ except Exception as exc:
135
+ self.pids.discard(pid)
136
+ msg = "func=%s args=%s kwargs=%s" % (func, args, kwargs)
137
+ self.logger.error('error %s, call %s', str(exc), msg)
138
+ evt.set()
139
+ else:
140
+ print(f"Unsupported task {task}")
141
+
142
+ class TaskManager(object):
143
+ """
144
+ Task manager class based on thread module which
145
+ executes assigned tasks concurently. It uses a
146
+ pool of thread workers, queue of tasks and pid
147
+ set to monitor jobs execution.
148
+
149
+ .. doctest::
150
+
151
+ Use case:
152
+ mgr = TaskManager()
153
+ jobs = []
154
+ jobs.append(mgr.spawn(func, args))
155
+ mgr.joinall(jobs)
156
+
157
+ """
158
+ def __init__(self, nworkers=10, name='TaskManager', logger=None):
159
+ self.logger = logging.getLogger()
160
+ self.name = name
161
+ self.pids = set()
162
+ self.uids = UidSet()
163
+ self.tasks = Queue()
164
+ self.workers = [Worker(name, self.tasks, self.pids, self.uids, logger) \
165
+ for _ in range(0, nworkers)]
166
+
167
+ def status(self):
168
+ "Return status of task manager queue"
169
+ info = {'qsize':self.tasks.qsize(), 'full':self.tasks.full(),
170
+ 'unfinished':self.tasks.unfinished_tasks,
171
+ 'nworkers':len(self.workers)}
172
+ return {self.name: info}
173
+
174
+ def nworkers(self):
175
+ """Return number of workers associated with this manager"""
176
+ return len(self.workers)
177
+
178
+ def spawn(self, func, *args, **kwargs):
179
+ """Spawn new process for given function"""
180
+ pid = kwargs.get('pid', genkey(str(args) + str(kwargs)))
181
+ evt = threading.Event()
182
+ if not pid in self.pids:
183
+ self.pids.add(pid)
184
+ task = (evt, pid, func, args, kwargs)
185
+ self.tasks.put(task)
186
+ else:
187
+ # the event was not added to task list, invoke set()
188
+ # to pass it in wait() call, see joinall
189
+ evt.set()
190
+ return evt, pid
191
+
192
+ def remove(self, pid):
193
+ """Remove pid and associative process from the queue"""
194
+ self.pids.discard(pid)
195
+
196
+ def is_alive(self, pid):
197
+ """Check worker queue if given pid of the process is still running"""
198
+ return pid in self.pids
199
+
200
+ def clear(self, tasks):
201
+ """
202
+ Clear all tasks in a queue. It allows current jobs to run, but will
203
+ block all new requests till workers event flag is set again
204
+ """
205
+ _ = [t[0].clear() for t in tasks] # each task is return from spawn, i.e. a pair (evt, pid)
206
+
207
+ def joinall(self, tasks):
208
+ """Join all tasks in a queue and quit"""
209
+ _ = [t[0].wait() for t in tasks] # each task is return from spawn, i.e. a pair (evt, pid)
210
+
211
+ def quit(self):
212
+ """Put None task to all workers and let them quit"""
213
+ _ = [self.tasks.put(None) for _ in self.workers]
214
+ time.sleep(1) # let workers threads cool-off and quit
@@ -1,2 +0,0 @@
1
- from CHAP.common.models.map import MapConfig
2
- from CHAP.common.models.integration import IntegrationConfig