genocide 201__tar.gz → 203__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 (121) hide show
  1. {genocide-201 → genocide-203}/PKG-INFO +1 -1
  2. genocide-203/genocide/__init__.py +4 -0
  3. genocide-201/genocide/runtime.py → genocide-203/genocide/__main__.py +139 -62
  4. genocide-201/genocide/caching.py → genocide-203/genocide/cache.py +6 -3
  5. genocide-203/genocide/client.py +30 -0
  6. genocide-201/genocide/persist.py → genocide-203/genocide/disk.py +5 -17
  7. genocide-201/genocide/excepts.py → genocide-203/genocide/error.py +16 -14
  8. genocide-203/genocide/event.py +47 -0
  9. genocide-201/genocide/locater.py → genocide-203/genocide/find.py +25 -17
  10. genocide-203/genocide/fleet.py +61 -0
  11. genocide-203/genocide/html/_static/alabaster.css +703 -0
  12. genocide-203/genocide/html/_static/basic.css +903 -0
  13. genocide-203/genocide/html/_static/custom.css +1 -0
  14. genocide-203/genocide/html/_static/doctools.js +156 -0
  15. genocide-203/genocide/html/_static/documentation_options.js +14 -0
  16. genocide-203/genocide/html/_static/file.png +0 -0
  17. genocide-203/genocide/html/_static/language_data.js +199 -0
  18. genocide-203/genocide/html/_static/minus.png +0 -0
  19. genocide-203/genocide/html/_static/opensearch.xml +11 -0
  20. genocide-203/genocide/html/_static/plus.png +0 -0
  21. genocide-203/genocide/html/_static/pygments.css +74 -0
  22. genocide-203/genocide/html/_static/searchtools.js +566 -0
  23. genocide-203/genocide/html/_static/skull3.png +0 -0
  24. genocide-203/genocide/html/_static/sphinx_highlight.js +144 -0
  25. genocide-203/genocide/html/about.html +83 -0
  26. genocide-203/genocide/html/evidence.html +68 -0
  27. genocide-203/genocide/html/genindex-all.html +58 -0
  28. genocide-203/genocide/html/genindex.html +63 -0
  29. genocide-203/genocide/html/guilty.html +66 -0
  30. genocide-203/genocide/html/index.html +111 -0
  31. genocide-203/genocide/html/manual.html +230 -0
  32. genocide-203/genocide/html/objects.inv +0 -0
  33. genocide-203/genocide/html/reconsider.html +109 -0
  34. genocide-203/genocide/html/request.html +85 -0
  35. genocide-203/genocide/html/search.html +87 -0
  36. genocide-203/genocide/html/searchindex.js +1 -0
  37. genocide-203/genocide/html/writings.html +162 -0
  38. genocide-203/genocide/modules/__init__.py +241 -0
  39. genocide-203/genocide/modules/pth.py +20 -0
  40. {genocide-201 → genocide-203}/genocide/modules/req.py +0 -1
  41. genocide-203/genocide/modules/slg.py +11 -0
  42. genocide-203/genocide/modules/tbl.py +20 -0
  43. genocide-201/genocide/objects.py → genocide-203/genocide/object.py +81 -8
  44. genocide-203/genocide/reactor.py +77 -0
  45. genocide-201/genocide/threads.py → genocide-203/genocide/thread.py +5 -51
  46. genocide-203/genocide/timer.py +58 -0
  47. genocide-203/genocide/utils.py +244 -0
  48. {genocide-201 → genocide-203}/genocide/workdir.py +9 -6
  49. {genocide-201 → genocide-203}/genocide.egg-info/PKG-INFO +1 -1
  50. genocide-203/genocide.egg-info/SOURCES.txt +76 -0
  51. genocide-203/genocide.egg-info/entry_points.txt +2 -0
  52. genocide-203/pyproject.toml +53 -0
  53. genocide-201/docs/_templates/base.rst +0 -29
  54. genocide-201/docs/_templates/class.rst +0 -32
  55. genocide-201/docs/_templates/mine.rst +0 -59
  56. genocide-201/docs/_templates/module.rst +0 -59
  57. genocide-201/docs/about.rst +0 -60
  58. genocide-201/docs/ack.png +0 -0
  59. genocide-201/docs/beuker.png +0 -0
  60. genocide-201/docs/bylaw.png +0 -0
  61. genocide-201/docs/conf.py +0 -133
  62. genocide-201/docs/evidence.rst +0 -80
  63. genocide-201/docs/genocide.jpg +0 -0
  64. genocide-201/docs/genocidesmile.png +0 -0
  65. genocide-201/docs/guilty.rst +0 -62
  66. genocide-201/docs/index.rst +0 -80
  67. genocide-201/docs/manual.rst +0 -185
  68. genocide-201/docs/opdehoogte.jpg +0 -0
  69. genocide-201/docs/reconsider.rst +0 -54
  70. genocide-201/docs/request.rst +0 -47
  71. genocide-201/docs/since.png +0 -0
  72. genocide-201/docs/verbatim4.png +0 -0
  73. genocide-201/docs/verbatim7.png +0 -0
  74. genocide-201/docs/verzoek.jpg +0 -0
  75. genocide-201/docs/writings.rst +0 -99
  76. genocide-201/docs/zyprexa.png +0 -0
  77. genocide-201/genocide/clients.py +0 -110
  78. genocide-201/genocide/command.py +0 -124
  79. genocide-201/genocide/decoder.py +0 -46
  80. genocide-201/genocide/default.py +0 -28
  81. genocide-201/genocide/encoder.py +0 -49
  82. genocide-201/genocide/lookups.py +0 -25
  83. genocide-201/genocide/modules/err.py +0 -19
  84. genocide-201/genocide/modules/flt.py +0 -18
  85. genocide-201/genocide/modules/irc.py +0 -635
  86. genocide-201/genocide/modules/mod.py +0 -22
  87. genocide-201/genocide/modules/rss.py +0 -493
  88. genocide-201/genocide/modules/thr.py +0 -42
  89. genocide-201/genocide/modules/upt.py +0 -18
  90. genocide-201/genocide/package.py +0 -104
  91. genocide-201/genocide/reactor.py +0 -160
  92. genocide-201/genocide/utility.py +0 -58
  93. genocide-201/genocide.egg-info/SOURCES.txt +0 -78
  94. genocide-201/genocide.egg-info/entry_points.txt +0 -2
  95. genocide-201/pyproject.toml +0 -104
  96. {genocide-201 → genocide-203}/README.rst +0 -0
  97. {genocide-201/docs → genocide-203/genocide/html/_images}/ECHAabilify.png +0 -0
  98. {genocide-201/docs → genocide-203/genocide/html/_images}/ECHAclozapine.png +0 -0
  99. {genocide-201/docs → genocide-203/genocide/html/_images}/ECHAhaldol.png +0 -0
  100. {genocide-201/docs → genocide-203/genocide/html/_images}/ECHAzyprexa.png +0 -0
  101. {genocide-201/docs → genocide-203/genocide/html/_images}/OTP111.png +0 -0
  102. {genocide-201/docs → genocide-203/genocide/html/_images}/OTP222.png +0 -0
  103. {genocide-201/docs → genocide-203/genocide/html/_images}/ack3.png +0 -0
  104. {genocide-201/docs → genocide-203/genocide/html/_images}/bevestigd.jpg +0 -0
  105. {genocide-201/docs → genocide-203/genocide/html/_images}/genocide.png +0 -0
  106. {genocide-201/docs → genocide-203/genocide/html/_images}/informed.jpg +0 -0
  107. {genocide-201/docs → genocide-203/genocide/html/_images}/kamer2.png +0 -0
  108. {genocide-201/docs → genocide-203/genocide/html/_images}/skull3.png +0 -0
  109. {genocide-201/docs → genocide-203/genocide/html}/_static/genocide.css +0 -0
  110. {genocide-201/docs/files → genocide-203/genocide/html/_static}/sitemap.xml +0 -0
  111. {genocide-201/docs → genocide-203/genocide/html}/robots.txt +0 -0
  112. {genocide-201/docs → genocide-203/genocide}/pdf/EM_Ack_OTP-CR-117_19.pdf +0 -0
  113. {genocide-201/docs → genocide-203/genocide}/pdf/EM_T04_OTP-CR-117_19.pdf +0 -0
  114. {genocide-201/docs → genocide-203/genocide}/pdf/EM_T07_OTP-CR-117_19_001.pdf +0 -0
  115. {genocide-201/docs → genocide-203/genocide}/pdf/Kamer.pdf +0 -0
  116. {genocide-201/docs → genocide-203/genocide}/pdf/Rome-Statute.pdf +0 -0
  117. {genocide-201/docs → genocide-203/genocide}/pdf/bevestigd.pdf +0 -0
  118. {genocide-201 → genocide-203}/genocide.egg-info/dependency_links.txt +0 -0
  119. {genocide-201 → genocide-203}/genocide.egg-info/top_level.txt +0 -0
  120. {genocide-201 → genocide-203}/setup.cfg +0 -0
  121. {genocide-201 → genocide-203}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: genocide
3
- Version: 201
3
+ Version: 203
4
4
  Summary: Since 4 march 2019.
5
5
  Author-email: Bart Thate <bthate@dds.nl>
6
6
  License: Public Domain
@@ -0,0 +1,4 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ __doc__ = __package__.upper()
@@ -1,40 +1,37 @@
1
1
  # This file is placed in the Public Domain.
2
- # pylint: disable=C,R0903,W0105,W0212,W0611,W0613,W0718,E0402
3
2
 
4
3
 
5
- "main"
4
+ "main program"
6
5
 
7
6
 
7
+ import hashlib
8
8
  import os
9
9
  import pathlib
10
+ import signal
10
11
  import sys
11
12
  import time
12
- import traceback
13
+ import types
13
14
  import _thread
14
15
 
15
16
 
16
- from .clients import Client, Config, debug
17
- from .command import Commands, command, parse
18
- from .encoder import dumps
19
- from .excepts import errors, later
20
- from .package import Table
21
- from .reactor import Event, Fleet
22
- from .threads import launch
23
- from .utility import spl
24
- from .workdir import Workdir, pidname
17
+ sys.path.insert(0, os.getcwd())
25
18
 
26
19
 
27
- from . import clients
28
- from . import modules as MODS
20
+ from .client import Client
21
+ from .error import Errors
22
+ from .event import Event
23
+ from .modules import Commands, Main, command, load, mods, modules, parse, scan
24
+ from .object import dumps
25
+ from .thread import launch
26
+ from .utils import nodebug, spl
27
+ from .workdir import Workdir, pidname
29
28
 
30
29
 
31
- cfg = Config()
32
- p = os.path.join
33
- pname = f"{Config.name}.modules"
30
+ p = os.path.join
34
31
 
35
32
 
36
- Workdir.wdr = os.path.expanduser(f"~/.{Config.name}")
37
- clients.output = output = print
33
+ def output(txt):
34
+ print(txt)
38
35
 
39
36
 
40
37
  class CLI(Client):
@@ -43,9 +40,6 @@ class CLI(Client):
43
40
  Client.__init__(self)
44
41
  self.register("command", command)
45
42
 
46
- def announce(self, txt):
47
- pass
48
-
49
43
  def raw(self, txt):
50
44
  output(txt.encode('utf-8', 'replace').decode("utf-8"))
51
45
 
@@ -53,7 +47,7 @@ class CLI(Client):
53
47
  class Console(CLI):
54
48
 
55
49
  def announce(self, txt):
56
- pass
50
+ output(txt)
57
51
 
58
52
  def callback(self, evt):
59
53
  CLI.callback(self, evt)
@@ -66,9 +60,29 @@ class Console(CLI):
66
60
  return evt
67
61
 
68
62
 
63
+ "output"
64
+
65
+
66
+ def nil(txt):
67
+ pass
68
+
69
+
70
+ def enable():
71
+ global output
72
+ output = print
73
+
74
+
75
+ def disable():
76
+ global output
77
+ output = nil
78
+
79
+
80
+ "utilities"
81
+
82
+
69
83
  def banner():
70
84
  tme = time.ctime(time.time()).replace(" ", " ")
71
- output(f"{Config.name.upper()} since {tme}")
85
+ output(f"{Main.name.upper()} since {tme}")
72
86
 
73
87
 
74
88
  def check(txt):
@@ -110,6 +124,31 @@ def forever():
110
124
  _thread.interrupt_main()
111
125
 
112
126
 
127
+ def inits(names) -> [types.ModuleType]:
128
+ mods = []
129
+ for name in spl(names):
130
+ mod = load(name)
131
+ if not mod:
132
+ continue
133
+ if "init" in dir(mod):
134
+ thr = launch(mod.init)
135
+ mods.append((mod, thr))
136
+ return mods
137
+
138
+
139
+ def md5sum(mod):
140
+ with open(mod.__file__, "r", encoding="utf-8") as file:
141
+ txt = file.read().encode("utf-8")
142
+ return str(hashlib.md5(txt).hexdigest())
143
+
144
+
145
+ def modnames(path) -> [str]:
146
+ return [
147
+ x[:-3] for x in os.listdir(path)
148
+ if x.endswith(".py") and not x.startswith("__")
149
+ ]
150
+
151
+
113
152
  def pidfile(filename):
114
153
  if os.path.exists(filename):
115
154
  os.unlink(filename)
@@ -127,30 +166,46 @@ def privileges():
127
166
  os.setuid(pwnam2.pw_uid)
128
167
 
129
168
 
169
+ def setwd(name, path=""):
170
+ Main.name = name
171
+ path = path or os.path.expanduser(f"~/.{name}")
172
+ Workdir.wdr = path
173
+
174
+
175
+ "handlers"
176
+
177
+
178
+ def handler(signum, frame):
179
+ _thread.interrupt_main()
180
+
181
+
130
182
  "scripts"
131
183
 
132
184
 
133
185
  def background():
134
- daemon(True)
186
+ daemon("-v" in sys.argv)
187
+ setwd(Main.name)
135
188
  privileges()
136
- pidfile(pidname(Config.name))
189
+ disable()
190
+ pidfile(pidname(Main.name))
137
191
  Commands.add(cmd)
138
- Table.inits(Config.init, pname)
192
+ inits(Main.init or "irc,rss")
139
193
  forever()
140
194
 
141
195
 
142
196
  def console():
143
197
  import readline # noqa: F401
198
+ setwd(Main.name)
199
+ enable()
144
200
  Commands.add(cmd)
145
- parse(cfg, " ".join(sys.argv[1:]))
146
- Config.init = cfg.sets.init or Config.init
147
- Config.opts = cfg.opts
148
- if "v" in cfg.opts:
201
+ parse(Main, " ".join(sys.argv[1:]))
202
+ Main.init = Main.sets.init or Main.init
203
+ Main.verbose = Main.sets.verbose or Main.verbose
204
+ if "v" in Main.opts:
149
205
  banner()
150
- if "i" in cfg.opts or Config.init:
151
- for _mod, thr in Table.inits(Config.init, pname):
152
- if "w" in cfg.opts:
153
- thr.join()
206
+ for _mod, thr in inits(Main.init):
207
+ if "w" in Main.opts:
208
+ thr.join()
154
209
  csl = Console()
155
210
  csl.start()
156
211
  forever()
@@ -159,23 +214,31 @@ def console():
159
214
  def control():
160
215
  if len(sys.argv) == 1:
161
216
  return
217
+ setwd(Main.name)
218
+ Workdir.wdr = os.path.expanduser(f"~/.{Main.name}")
219
+ enable()
162
220
  Commands.add(cmd)
221
+ Commands.add(md5)
163
222
  Commands.add(srv)
164
223
  Commands.add(tbl)
165
- parse(cfg, " ".join(sys.argv[1:]))
224
+ parse(Main, " ".join(sys.argv[1:]))
166
225
  csl = CLI()
167
226
  evt = Event()
168
227
  evt.orig = repr(csl)
169
228
  evt.type = "command"
170
- evt.txt = cfg.otxt
229
+ evt.txt = Main.otxt
171
230
  command(evt)
172
231
  evt.wait()
173
232
 
233
+
174
234
  def service():
235
+ signal.signal(signal.SIGHUP, handler)
236
+ nodebug()
237
+ setwd(Main.name)
175
238
  privileges()
176
- pidfile(pidname(Config.name))
239
+ pidfile(pidname(Main.name))
177
240
  Commands.add(cmd)
178
- Table.inits(Config.init, pname)
241
+ inits(Main.init or "irc,rss")
179
242
  forever()
180
243
 
181
244
 
@@ -183,18 +246,24 @@ def service():
183
246
 
184
247
 
185
248
  def cmd(event):
186
- event.reply(",".join(sorted(Commands.names)))
249
+ event.reply(",".join(sorted([x for x in Commands.names if x not in Main.ignore])))
250
+
251
+
252
+ def md5(event):
253
+ table = mods("tbl")[0]
254
+ event.reply(md5sum(table))
187
255
 
188
256
 
189
257
  def srv(event):
190
258
  import getpass
191
259
  name = getpass.getuser()
192
- event.reply(TXT % (Config.name.upper(), name, name, name, Config.name))
260
+ event.reply(TXT % (Main.name.upper(), name, name, name, Main.name))
193
261
 
194
262
 
195
263
  def tbl(event):
196
- for mod in Table.all(MODS):
197
- Commands.scan(mod)
264
+ import genocide.modules
265
+ for mod in mods():
266
+ scan(mod)
198
267
  event.reply("# This file is placed in the Public Domain.")
199
268
  event.reply("")
200
269
  event.reply("")
@@ -202,7 +271,13 @@ def tbl(event):
202
271
  event.reply("")
203
272
  event.reply("")
204
273
  event.reply(f"NAMES = {dumps(Commands.names, indent=4, sort_keys=True)}")
205
-
274
+ event.reply("")
275
+ event.reply("")
276
+ event.reply("MD5 = {")
277
+ for mod in mods():
278
+ event.reply(f' "{mod.__name__.split(".")[-1]}": "{md5sum(mod)}",')
279
+ event.reply("}")
280
+
206
281
 
207
282
  "data"
208
283
 
@@ -224,6 +299,15 @@ WantedBy=multi-user.target"""
224
299
  "runtime"
225
300
 
226
301
 
302
+ def wrapped(func):
303
+ try:
304
+ func()
305
+ except (KeyboardInterrupt, EOFError):
306
+ output("")
307
+ for exc in Errors.errors:
308
+ print(Errors.format(exc))
309
+
310
+
227
311
  def wrap(func):
228
312
  import termios
229
313
  old = None
@@ -232,37 +316,30 @@ def wrap(func):
232
316
  except termios.error:
233
317
  pass
234
318
  try:
235
- func()
236
- except (KeyboardInterrupt, EOFError):
237
- output("")
238
- except Exception as exc:
239
- later(exc)
319
+ wrapped(func)
240
320
  finally:
241
321
  if old:
242
322
  termios.tcsetattr(sys.stdin.fileno(), termios.TCSADRAIN, old)
243
- for line in errors():
244
- output(line)
245
-
246
-
247
- def wrapped():
248
- wrap(main)
249
-
250
-
251
- def wraps():
252
- wrap(service)
253
323
 
254
324
 
255
325
  def main():
326
+ if check("a"):
327
+ Main.ignore = ""
328
+ Main.init = ",".join(modules())
329
+ for mod in mods():
330
+ mod.DEBUG = False
331
+ if check("v"):
332
+ setattr(Main.opts, "v", True)
333
+ enable()
256
334
  if check("c"):
257
335
  wrap(console)
258
336
  elif check("d"):
259
337
  background()
260
338
  elif check("s"):
261
- wrap(service)
339
+ wrapped(service)
262
340
  else:
263
- control()
341
+ wrapped(control)
264
342
 
265
343
 
266
344
  if __name__ == "__main__":
267
345
  main()
268
- sys.exit(0)
@@ -4,20 +4,23 @@
4
4
  "caching"
5
5
 
6
6
 
7
+ import typing
8
+
9
+
7
10
  class Cache:
8
11
 
9
12
  objs = {}
10
13
 
11
14
  @staticmethod
12
- def add(path, obj):
15
+ def add(path, obj) -> None:
13
16
  Cache.objs[path] = obj
14
17
 
15
18
  @staticmethod
16
- def get(path):
19
+ def get(path) -> typing.Any:
17
20
  return Cache.objs.get(path, None)
18
21
 
19
22
  @staticmethod
20
- def typed(matcher):
23
+ def typed(matcher) -> [typing.Any]:
21
24
  for key in Cache.objs:
22
25
  if matcher not in key:
23
26
  continue
@@ -0,0 +1,30 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "client"
5
+
6
+
7
+ from .fleet import Fleet
8
+ from .reactor import Reactor
9
+
10
+
11
+ class Client(Reactor):
12
+
13
+ def __init__(self):
14
+ Reactor.__init__(self)
15
+ Fleet.add(self)
16
+
17
+ def announce(self, txt) -> None:
18
+ pass
19
+
20
+ def raw(self, txt) -> None:
21
+ raise NotImplementedError("raw")
22
+
23
+ def say(self, channel, txt) -> None:
24
+ self.raw(txt)
25
+
26
+
27
+ def __dir__():
28
+ return (
29
+ 'Client',
30
+ )
@@ -1,23 +1,17 @@
1
1
  # This file is placed in the Public Domain.
2
2
 
3
3
 
4
- "persistence"
4
+ "read/write"
5
5
 
6
6
 
7
- import datetime
8
- import os
9
7
  import json
10
8
  import pathlib
11
9
  import threading
12
10
 
13
11
 
14
- from .decoder import loads
15
- from .encoder import dumps
16
- from .objects import fqn, update
17
- from .workdir import store
12
+ from .object import loads, dumps, update
18
13
 
19
14
 
20
- p = os.path.join
21
15
  lock = threading.RLock()
22
16
 
23
17
 
@@ -26,15 +20,11 @@ class DecodeError(Exception):
26
20
  pass
27
21
 
28
22
 
29
- def cdir(pth):
23
+ def cdir(pth) -> None:
30
24
  path = pathlib.Path(pth)
31
25
  path.parent.mkdir(parents=True, exist_ok=True)
32
26
 
33
27
 
34
- def ident(obj):
35
- return p(fqn(obj),*str(datetime.datetime.now()).split())
36
-
37
-
38
28
  def read(obj, pth):
39
29
  with lock:
40
30
  with open(pth, 'r', encoding='utf-8') as ofile:
@@ -46,10 +36,8 @@ def read(obj, pth):
46
36
  return pth
47
37
 
48
38
 
49
- def write(obj, pth=None):
39
+ def write(obj, pth):
50
40
  with lock:
51
- if pth is None:
52
- pth = store(ident(obj))
53
41
  cdir(pth)
54
42
  txt = dumps(obj, indent=4)
55
43
  with open(pth, 'w', encoding='utf-8') as ofile:
@@ -59,8 +47,8 @@ def write(obj, pth=None):
59
47
 
60
48
  def __dir__():
61
49
  return (
50
+ 'DecodeError',
62
51
  'cdir',
63
- 'ident',
64
52
  'read',
65
53
  'write'
66
54
  )
@@ -1,18 +1,15 @@
1
1
  # This file is placed in the Public Domain.
2
2
 
3
3
 
4
- "exception handling"
4
+ "deferred exception handling"
5
5
 
6
6
 
7
7
  import traceback
8
8
 
9
9
 
10
- DEBUG = True
11
-
12
-
13
10
  class Errors:
14
11
 
15
- name = __file__.rsplit(".", maxsplit=2)[-2]
12
+ name = __file__.rsplit("/", maxsplit=2)[-2]
16
13
  errors = []
17
14
 
18
15
  @staticmethod
@@ -22,12 +19,14 @@ class Errors:
22
19
  result = ""
23
20
  for i in trace:
24
21
  fname = i[0]
22
+ if fname.endswith(".py"):
23
+ fname = fname[:-3]
25
24
  linenr = i[1]
26
- plugfile = fname[:-3].split("/")
25
+ plugfile = fname.split("/")
27
26
  mod = []
28
27
  for i in plugfile[::-1]:
29
28
  mod.append(i)
30
- if Errors.name in i:
29
+ if Errors.name in i or "bin" in i:
31
30
  break
32
31
  ownname = '.'.join(mod[::-1])
33
32
  if ownname.endswith("__"):
@@ -37,6 +36,9 @@ class Errors:
37
36
  result += f"{ownname}:{linenr} "
38
37
  del trace
39
38
  res = f"{exctype} {result[:-1]} {excvalue}"
39
+ if "__notes__" in dir(exc):
40
+ for note in exc.__notes__:
41
+ res += f" {note}"
40
42
  return res
41
43
 
42
44
  @staticmethod
@@ -48,12 +50,12 @@ class Errors:
48
50
  )
49
51
 
50
52
 
51
- def errors() -> []:
52
- return Errors.errors
53
+ def later(exc, txt="") -> None:
54
+ Errors.errors.append(exc)
53
55
 
54
56
 
55
- def later(exc) -> None:
56
- excp = exc.with_traceback(exc.__traceback__)
57
- fmt = Errors.format(excp)
58
- if fmt not in Errors.errors:
59
- Errors.errors.append(fmt)
57
+ def __dir__():
58
+ return (
59
+ 'Errors',
60
+ 'later'
61
+ )
@@ -0,0 +1,47 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "event"
5
+
6
+
7
+ import threading
8
+ import time
9
+
10
+
11
+ from .fleet import Fleet
12
+ from .object import Default
13
+
14
+
15
+ class Event(Default):
16
+
17
+ def __init__(self):
18
+ Default.__init__(self)
19
+ self._ready = threading.Event()
20
+ self._thr = None
21
+ self.ctime = time.time()
22
+ self.result = {}
23
+ self.type = "event"
24
+ self.txt = ""
25
+
26
+ def display(self):
27
+ Fleet.display(self)
28
+
29
+ def done(self) -> None:
30
+ self.reply("ok")
31
+
32
+ def ready(self) -> None:
33
+ self._ready.set()
34
+
35
+ def reply(self, txt) -> None:
36
+ self.result[time.time()] = txt
37
+
38
+ def wait(self) -> None:
39
+ self._ready.wait()
40
+ if self._thr:
41
+ self._thr.join()
42
+
43
+
44
+ def __dir__():
45
+ return (
46
+ 'Event',
47
+ )
@@ -1,24 +1,24 @@
1
1
  # This file is placed in the Public Domain.
2
2
 
3
3
 
4
- "find objects"
4
+ "locate objects"
5
5
 
6
6
 
7
+ import datetime
7
8
  import os
8
9
  import time
9
10
 
10
11
 
11
- from .caching import Cache
12
- from .objects import Object, fqn, items, update
13
- from .persist import read
12
+ from .cache import Cache
13
+ from .disk import read
14
+ from .object import Object, fqn, items, update
14
15
  from .workdir import long, skel, store
15
16
 
16
17
 
17
18
  p = os.path.join
18
19
 
19
20
 
20
- def fns(clz):
21
- dname = ''
21
+ def fns(clz) -> [str]:
22
22
  pth = store(clz)
23
23
  for rootdir, dirs, _files in os.walk(pth, topdown=False):
24
24
  if dirs:
@@ -29,9 +29,9 @@ def fns(clz):
29
29
  yield p(ddd, fll)
30
30
 
31
31
 
32
- def fntime(daystr):
33
- daystr = daystr.replace('_', ':')
32
+ def fntime(daystr) -> int:
34
33
  datestr = ' '.join(daystr.split(os.sep)[-2:])
34
+ datestr = datestr.replace("_", " ")
35
35
  if '.' in datestr:
36
36
  datestr, rest = datestr.rsplit('.', 1)
37
37
  else:
@@ -42,25 +42,32 @@ def fntime(daystr):
42
42
  return timed
43
43
 
44
44
 
45
- def find(clz, selector=None, deleted=False, matching=False):
45
+ def find(clz, selector=None, deleted=False, matching=False) -> [Object]:
46
46
  skel()
47
- pth = long(clz)
48
47
  res = []
49
- for fnm in fns(pth):
50
- obj = Cache.get(fnm)
48
+ clz = long(clz)
49
+ for pth in fns(clz):
50
+ obj = Cache.get(pth)
51
51
  if not obj:
52
52
  obj = Object()
53
- read(obj, fnm)
54
- Cache.add(fnm, obj)
53
+ read(obj, pth)
54
+ Cache.add(pth, obj)
55
55
  if not deleted and '__deleted__' in dir(obj) and obj.__deleted__:
56
56
  continue
57
57
  if selector and not search(obj, selector, matching):
58
58
  continue
59
- res.append((fnm, obj))
59
+ res.append((pth, obj))
60
60
  return sorted(res, key=lambda x: fntime(x[0]))
61
61
 
62
62
 
63
- def last(obj, selector=None):
63
+ "methods"
64
+
65
+
66
+ def ident(obj) -> str:
67
+ return p(fqn(obj),*str(datetime.datetime.now()).split())
68
+
69
+
70
+ def last(obj, selector=None) -> Object:
64
71
  if selector is None:
65
72
  selector = {}
66
73
  result = sorted(
@@ -75,7 +82,7 @@ def last(obj, selector=None):
75
82
  return res
76
83
 
77
84
 
78
- def search(obj, selector, matching=None):
85
+ def search(obj, selector, matching=None) -> bool:
79
86
  res = False
80
87
  if not selector:
81
88
  return res
@@ -99,5 +106,6 @@ def __dir__():
99
106
  'fntime',
100
107
  'find',
101
108
  'last',
109
+ 'ident',
102
110
  'search'
103
111
  )