bigtalk 1__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.
bigtalk/brokers.py ADDED
@@ -0,0 +1,36 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "an object for a string"
5
+
6
+
7
+ class Broker:
8
+
9
+ objects = {}
10
+
11
+ @staticmethod
12
+ def add(obj):
13
+ Broker.objects[repr(obj)] = obj
14
+
15
+ @staticmethod
16
+ def all(attr):
17
+ for obj in Broker.objects.values():
18
+ if attr in dir(obj):
19
+ yield obj
20
+
21
+ @staticmethod
22
+ def get(origin):
23
+ return Broker.objects.get(origin)
24
+
25
+
26
+ @staticmethod
27
+ def like(txt):
28
+ for orig in Broker.objects:
29
+ if orig.split()[0] in orig.split()[0]:
30
+ yield orig
31
+
32
+
33
+ def __dir__():
34
+ return (
35
+ 'Broker',
36
+ )
bigtalk/clients.py ADDED
@@ -0,0 +1,87 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "client-side event handling"
5
+
6
+
7
+ import logging
8
+ import queue
9
+ import threading
10
+ import _thread
11
+
12
+
13
+ from .brokers import Broker
14
+ from .command import Commands
15
+ from .handler import Handler
16
+ from .threads import Threads
17
+
18
+
19
+ class Client(Handler):
20
+
21
+ def __init__(self):
22
+ super().__init__()
23
+ self.olock = threading.RLock()
24
+ self.oqueue = queue.Queue()
25
+ self.silent = True
26
+ Broker.add(self)
27
+
28
+ def announce(self, text):
29
+ if not self.silent:
30
+ self.raw(text)
31
+
32
+ def display(self, event):
33
+ with self.olock:
34
+ for tme in event.result:
35
+ txt = event.result.get(tme)
36
+ self.dosay(event.channel, txt)
37
+
38
+ def dosay(self, channel, text):
39
+ self.say(channel, text)
40
+
41
+ def raw(self, text):
42
+ raise NotImplementedError("raw")
43
+
44
+ def say(self, channel, text):
45
+ self.raw(text)
46
+
47
+ def wait(self):
48
+ try:
49
+ self.oqueue.join()
50
+ except Exception as ex:
51
+ logging.exception(ex)
52
+ _thread.interrupt_main()
53
+
54
+
55
+ class CLI(Client):
56
+
57
+ def __init__(self):
58
+ super().__init__()
59
+ self.register("command", Commands.command)
60
+
61
+
62
+ class Output(Client):
63
+
64
+ def output(self):
65
+ while True:
66
+ event = self.oqueue.get()
67
+ if event is None:
68
+ self.oqueue.task_done()
69
+ break
70
+ self.display(event)
71
+ self.oqueue.task_done()
72
+
73
+ def start(self):
74
+ Threads.launch(self.output)
75
+ super().start()
76
+
77
+ def stop(self):
78
+ self.oqueue.put(None)
79
+ super().stop()
80
+
81
+
82
+ def __dir__():
83
+ return (
84
+ 'Client',
85
+ 'CLI',
86
+ 'Output'
87
+ )
bigtalk/command.py ADDED
@@ -0,0 +1,49 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "write your own commands"
5
+
6
+
7
+ import inspect
8
+
9
+
10
+ from .methods import Methods
11
+
12
+
13
+ class Commands:
14
+
15
+ cmds = {}
16
+ names = {}
17
+
18
+ @staticmethod
19
+ def add(*args):
20
+ for func in args:
21
+ name = func.__name__
22
+ Commands.cmds[name] = func
23
+ Commands.names[name] = func.__module__.split(".")[-1]
24
+
25
+ @staticmethod
26
+ def command(evt):
27
+ Methods.parse(evt, evt.text)
28
+ func = Commands.get(evt.cmd)
29
+ if func:
30
+ func(evt)
31
+ evt.display()
32
+ evt.ready()
33
+
34
+ @staticmethod
35
+ def get(cmd):
36
+ return Commands.cmds.get(cmd, None)
37
+
38
+ @staticmethod
39
+ def scan(module):
40
+ for key, cmdz in inspect.getmembers(module, inspect.isfunction):
41
+ if 'event' not in inspect.signature(cmdz).parameters:
42
+ continue
43
+ Commands.add(cmdz)
44
+
45
+
46
+ def __dir__():
47
+ return (
48
+ 'Commands',
49
+ )
bigtalk/handler.py ADDED
@@ -0,0 +1,54 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "handle your own events"
5
+
6
+
7
+ import queue
8
+
9
+
10
+ from .threads import Threads
11
+
12
+
13
+ class Handler:
14
+
15
+ def __init__(self):
16
+ self.cbs = {}
17
+ self.queue = queue.Queue()
18
+
19
+ def callback(self, event):
20
+ func = self.cbs.get(event.kind, None)
21
+ if not func:
22
+ event.ready()
23
+ return
24
+ name = event.text and event.text.split()[0]
25
+ event._thr = Threads.launch(func, event, name=name)
26
+
27
+ def loop(self):
28
+ while True:
29
+ event = self.poll()
30
+ if not event:
31
+ break
32
+ event.orig = repr(self)
33
+ self.callback(event)
34
+
35
+ def poll(self):
36
+ return self.queue.get()
37
+
38
+ def put(self, event):
39
+ self.queue.put(event)
40
+
41
+ def register(self, kind, callback):
42
+ self.cbs[kind] = callback
43
+
44
+ def start(self):
45
+ Threads.launch(self.loop)
46
+
47
+ def stop(self):
48
+ self.queue.put(None)
49
+
50
+
51
+ def __dir__():
52
+ return (
53
+ 'Handler',
54
+ )
bigtalk/kernels.py ADDED
@@ -0,0 +1,69 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "in the beginning"
5
+
6
+
7
+ import time
8
+
9
+
10
+ from .command import Commands
11
+ from .loggers import Logging
12
+ from .objects import Default
13
+ from .package import Mods
14
+ from .threads import Threads
15
+ from .utility import Utils
16
+ from .workdir import Workdir
17
+
18
+
19
+ class Config(Default):
20
+
21
+ debug = False
22
+ init = ""
23
+ level = "info"
24
+ name = ""
25
+ opts = ""
26
+ sets = Default()
27
+ version = 0
28
+
29
+
30
+ class Kernel:
31
+
32
+ @staticmethod
33
+ def configure(local=False, network=False):
34
+ assert Config.name
35
+ Logging.level(Config.sets.level or "info")
36
+ Workdir.configure(Config.name)
37
+ Mods.configure(local, network)
38
+
39
+ @staticmethod
40
+ def forever():
41
+ while True:
42
+ try:
43
+ time.sleep(0.1)
44
+ except (KeyboardInterrupt, EOFError):
45
+ break
46
+
47
+ @staticmethod
48
+ def init(names, wait=False):
49
+ thrs = []
50
+ for name in Utils.spl(names):
51
+ mod = Mods.get(name)
52
+ if "init" not in dir(mod):
53
+ continue
54
+ thrs.append(Threads.launch(mod.init))
55
+ if wait:
56
+ for thr in thrs:
57
+ thr.join()
58
+
59
+ @staticmethod
60
+ def scanner(names):
61
+ for mod in Mods.mods(names):
62
+ Commands.scan(mod)
63
+
64
+
65
+ def __dir__():
66
+ return (
67
+ 'Config',
68
+ 'Kernel'
69
+ )
bigtalk/locater.py ADDED
@@ -0,0 +1,86 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "find objects"
5
+
6
+
7
+ import os
8
+ import time
9
+
10
+
11
+ from .methods import Methods
12
+ from .objects import Object
13
+ from .persist import Cache, Disk
14
+ from .workdir import Workdir
15
+
16
+
17
+ keys = Object.keys
18
+ update = Object.update
19
+
20
+
21
+ class Locater:
22
+
23
+ @staticmethod
24
+ def attrs(kind):
25
+ objs = list(Locater.find(kind))
26
+ if objs:
27
+ return list(keys(objs[0][1]))
28
+ return []
29
+
30
+ @staticmethod
31
+ def find(kind, selector={}, removed=False, matching=False):
32
+ fullname = Workdir.long(kind)
33
+ for pth in Locater.fns(fullname):
34
+ obj = Cache.get(pth)
35
+ if not obj:
36
+ obj = Object()
37
+ Disk.read(obj, pth)
38
+ Cache.add(pth, obj)
39
+ if not removed and Methods.deleted(obj):
40
+ continue
41
+ if selector and not Methods.search(obj, selector, matching):
42
+ continue
43
+ yield pth, obj
44
+
45
+ @staticmethod
46
+ def fns(kind):
47
+ path = Workdir.store(kind)
48
+ for rootdir, dirs, _files in os.walk(path, topdown=True):
49
+ for dname in dirs:
50
+ if dname.count("-") != 2:
51
+ continue
52
+ ddd = os.path.join(rootdir, dname)
53
+ for fll in os.listdir(ddd):
54
+ yield os.path.join(ddd, fll)
55
+
56
+ @staticmethod
57
+ def fntime(daystr):
58
+ datestr = " ".join(daystr.split(os.sep)[-2:])
59
+ datestr = datestr.replace("_", " ")
60
+ if "." in datestr:
61
+ datestr, rest = datestr.rsplit(".", 1)
62
+ else:
63
+ rest = ""
64
+ timed = time.mktime(time.strptime(datestr, "%Y-%m-%d %H:%M:%S"))
65
+ if rest:
66
+ timed += float("." + rest)
67
+ return float(timed)
68
+
69
+ @staticmethod
70
+ def last(obj, selector={}):
71
+ result = sorted(
72
+ Locater.find(Object.fqn(obj), selector),
73
+ key=lambda x: Locater.fntime(x[0])
74
+ )
75
+ res = ""
76
+ if result:
77
+ inp = result[-1]
78
+ update(obj, inp[-1])
79
+ res = inp[0]
80
+ return res
81
+
82
+
83
+ def __dir__():
84
+ return (
85
+ 'Locater',
86
+ )
bigtalk/loggers.py ADDED
@@ -0,0 +1,37 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "log exceptions"
5
+
6
+
7
+ import logging
8
+
9
+
10
+ class Format(logging.Formatter):
11
+
12
+ def format(self, record):
13
+ record.module = record.module.upper()
14
+ return logging.Formatter.format(self, record)
15
+
16
+
17
+ class Logging:
18
+
19
+ datefmt = "%H:%M:%S"
20
+ format = "%(module).3s %(message)s"
21
+
22
+ @staticmethod
23
+ def level(loglevel):
24
+ formatter = Format(Logging.format, Logging.datefmt)
25
+ stream = logging.StreamHandler()
26
+ stream.setFormatter(formatter)
27
+ logging.basicConfig(
28
+ level=loglevel.upper(),
29
+ handlers=[stream,],
30
+ force=True
31
+ )
32
+
33
+
34
+ def __dir__():
35
+ return (
36
+ 'Logging',
37
+ )
bigtalk/message.py ADDED
@@ -0,0 +1,46 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "only message"
5
+
6
+
7
+ import threading
8
+ import time
9
+
10
+
11
+ from .brokers import Broker
12
+ from .objects import Default
13
+
14
+
15
+ class Message(Default):
16
+
17
+ def __init__(self):
18
+ super().__init__()
19
+ self._ready = threading.Event()
20
+ self.result = {}
21
+ self.thr = None
22
+ self.args = []
23
+ self.index = 0
24
+ self.kind = "event"
25
+ self.orig = ""
26
+
27
+ def display(evt):
28
+ bot = Broker.get(evt.orig)
29
+ bot.display(evt)
30
+
31
+ def ready(self):
32
+ self._ready.set()
33
+
34
+ def reply(self, text):
35
+ self.result[time.time()] = text
36
+
37
+ def wait(self, timeout=0.0):
38
+ if self.thr:
39
+ self.thr.join(timeout)
40
+ self._ready.wait(timeout or None)
41
+
42
+
43
+ def __dir__():
44
+ return (
45
+ 'Message',
46
+ )
bigtalk/methods.py ADDED
@@ -0,0 +1,139 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "functions with an object as the first argument"
5
+
6
+
7
+ from .objects import Default, Object
8
+
9
+
10
+ class Methods:
11
+
12
+ @staticmethod
13
+ def deleted(obj):
14
+ return "__deleted__" in dir(obj) and obj.__deleted__
15
+
16
+ @staticmethod
17
+ def edit(obj, setter={}, skip=False):
18
+ for key, val in Object, items(setter):
19
+ if skip and val == "":
20
+ continue
21
+ try:
22
+ setattr(obj, key, int(val))
23
+ continue
24
+ except ValueError:
25
+ pass
26
+ try:
27
+ setattr(obj, key, float(val))
28
+ continue
29
+ except ValueError:
30
+ pass
31
+ if val in ["True", "true"]:
32
+ setattr(obj, key, True)
33
+ elif val in ["False", "false"]:
34
+ setattr(obj, key, False)
35
+ else:
36
+ setattr(obj, key, val)
37
+
38
+ @staticmethod
39
+ def fmt(obj, args=[], skip=[], plain=False, empty=False):
40
+ if args == []:
41
+ args = list(obj.__dict__.keys())
42
+ txt = ""
43
+ for key in args:
44
+ if key.startswith("__"):
45
+ continue
46
+ if key in skip:
47
+ continue
48
+ value = getattr(obj, key, None)
49
+ if value is None:
50
+ continue
51
+ if not empty and not value:
52
+ continue
53
+ if plain:
54
+ txt += f"{value} "
55
+ elif isinstance(value, str):
56
+ txt += f'{key}="{value}" '
57
+ elif isinstance(value, (int, float, dict, bool, list)):
58
+ txt += f"{key}={value} "
59
+ else:
60
+ txt += f"{key}={Object.fqn(value)}((value))"
61
+ if txt == "":
62
+ txt = "{}"
63
+ return txt.strip()
64
+
65
+ @staticmethod
66
+ def parse(obj, text):
67
+ data = {
68
+ "args": [],
69
+ "cmd": "",
70
+ "gets": Default(),
71
+ "index": None,
72
+ "init": "",
73
+ "opts": "",
74
+ "otxt": text,
75
+ "rest": "",
76
+ "silent": Default(),
77
+ "sets": Default(),
78
+ "text": text
79
+ }
80
+ for k, v in data.items():
81
+ setattr(obj, k, getattr(obj, k, v) or v)
82
+ args = []
83
+ nr = -1
84
+ for spli in text.split():
85
+ if spli.startswith("-"):
86
+ try:
87
+ obj.index = int(spli[1:])
88
+ except ValueError:
89
+ obj.opts += spli[1:]
90
+ continue
91
+ if "-=" in spli:
92
+ key, value = spli.split("-=", maxsplit=1)
93
+ setattr(obj.silent, key, value)
94
+ setattr(obj.gets, key. value)
95
+ continue
96
+ if "==" in spli:
97
+ key, value = spli.split("==", maxsplit=1)
98
+ setattr(obj.gets, key, value)
99
+ continue
100
+ if "=" in spli:
101
+ key, value = spli.split("=", maxsplit=1)
102
+ setattr(obj.sets, key, value)
103
+ continue
104
+ nr += 1
105
+ if nr == 0:
106
+ obj.cmd = spli
107
+ continue
108
+ args.append(spli)
109
+ if args:
110
+ obj.args = args
111
+ obj.text = obj.cmd or ""
112
+ obj.rest = " ".join(obj.args)
113
+ obj.text = obj.cmd + " " + obj.rest
114
+ else:
115
+ obj.text = obj.cmd or ""
116
+
117
+ @staticmethod
118
+ def search(obj, selector={}, matching=False):
119
+ res = False
120
+ for key, value in items(selector):
121
+ val = getattr(obj, key, None)
122
+ if not val:
123
+ res = False
124
+ break
125
+ elif matching and value != val:
126
+ res = False
127
+ break
128
+ elif str(value).lower() not in str(val).lower():
129
+ res = False
130
+ break
131
+ else:
132
+ res = True
133
+ return res
134
+
135
+
136
+ def __dir__():
137
+ return (
138
+ 'Methods',
139
+ )
bigtalk/objects.py ADDED
@@ -0,0 +1,99 @@
1
+ # This file is placed in the Public Domain.
2
+
3
+
4
+ "a clean namespace"
5
+
6
+
7
+ import types
8
+
9
+
10
+ class Reserved(Exception):
11
+
12
+ pass
13
+
14
+
15
+ class Object:
16
+
17
+ def __contains__(self, key):
18
+ return key in dir(self)
19
+
20
+ def __iter__(self):
21
+ return iter(self.__dict__)
22
+
23
+ def __len__(self):
24
+ return len(self.__dict__)
25
+
26
+ def __str__(self):
27
+ return str(self.__dict__)
28
+
29
+ @staticmethod
30
+ def construct(obj, *args, **kwargs):
31
+ if args:
32
+ val = args[0]
33
+ if isinstance(val, zip):
34
+ Object.update(obj, dict(val))
35
+ elif isinstance(val, dict):
36
+ Object.update(obj, val)
37
+ else:
38
+ Object.update(obj, vars(val))
39
+ if kwargs:
40
+ Object.update(obj, kwargs)
41
+
42
+ @staticmethod
43
+ def fqn(obj):
44
+ kin = str(type(obj)).split()[-1][1:-2]
45
+ if kin == "type":
46
+ tpe = type(obj)
47
+ kin = f"{tpe.__module__}.{tpe.__name__}"
48
+ return kin
49
+
50
+ @staticmethod
51
+ def items(obj):
52
+ if isinstance(obj, dict):
53
+ return obj.items()
54
+ if isinstance(obj, types.MappingProxyType):
55
+ return obj.items()
56
+ return obj.__dict__.items()
57
+
58
+ @staticmethod
59
+ def keys(obj):
60
+ if isinstance(obj, dict):
61
+ return obj.keys()
62
+ return obj.__dict__.keys()
63
+
64
+ @staticmethod
65
+ def update(obj, data, empty=True):
66
+ if isinstance(obj, type):
67
+ for k, v in Object.items(data):
68
+ if isinstance(getattr(obj, k, None), types.MethodType):
69
+ raise Reserved(k)
70
+ setattr(obj, k, v)
71
+ elif isinstance(obj, dict):
72
+ for k, v in items(data):
73
+ setattr(obj, k, v)
74
+ else:
75
+ for key, value in Object.items(data):
76
+ if not empty and not value:
77
+ continue
78
+ setattr(obj, key, value)
79
+
80
+ @staticmethod
81
+ def values(obj):
82
+ if isinstance(obj, dict):
83
+ return obj.values()
84
+ return obj.__dict__.values()
85
+
86
+
87
+ class Default(Object):
88
+
89
+ def __getattr__(self, key):
90
+ return self.__dict__.get(key, "")
91
+
92
+
93
+
94
+ def __dir__():
95
+ return (
96
+ 'Default',
97
+ 'Object',
98
+ 'Reserved'
99
+ )