ct 0.10.8.114__py3-none-any.whl → 0.10.8.116__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.
Files changed (44) hide show
  1. cantools/__init__.py +38 -13
  2. cantools/_db.py +1 -1
  3. cantools/cfg.py +13 -0
  4. cantools/config.py +12 -4
  5. cantools/db/__init__.py +3 -0
  6. cantools/db/gae/model.py +1 -2
  7. cantools/db/wp.py +1 -1
  8. cantools/scripts/index.py +2 -8
  9. cantools/scripts/init.py +1 -1
  10. cantools/scripts/pubsub/actor.py +3 -1
  11. cantools/scripts/pubsub/bots.py +11 -13
  12. cantools/scripts/start.py +2 -2
  13. cantools/util/__init__.py +2 -0
  14. cantools/util/admin.py +10 -18
  15. cantools/util/ai/__init__.py +8 -0
  16. cantools/util/ai/tox/__init__.py +15 -0
  17. cantools/util/ai/tox/duck.py +80 -0
  18. cantools/util/ai/tox/fzn.py +22 -0
  19. cantools/util/ai/tox/g4free.py +73 -0
  20. cantools/util/ai/vox.py +84 -0
  21. cantools/util/apper/__init__.py +1 -0
  22. cantools/util/apper/ander.py +101 -0
  23. cantools/util/apper/data.py +167 -0
  24. cantools/util/system.py +2 -23
  25. cantools/web/__init__.py +6 -2
  26. cantools/web/bw.py +70 -0
  27. cantools/web/gae_server.py +1 -6
  28. cantools/web/util.py +6 -409
  29. {ct-0.10.8.114.dist-info → ct-0.10.8.116.dist-info}/METADATA +7 -8
  30. ct-0.10.8.116.dist-info/RECORD +56 -0
  31. cantools/web/dez_server/__init__.py +0 -1
  32. cantools/web/dez_server/controller.py +0 -129
  33. cantools/web/dez_server/cron.py +0 -115
  34. cantools/web/dez_server/daemons.py +0 -64
  35. cantools/web/dez_server/mail.py +0 -24
  36. cantools/web/dez_server/response.py +0 -63
  37. cantools/web/dez_server/routes.py +0 -21
  38. cantools/web/dez_server/server.py +0 -229
  39. cantools/web/dez_server/sms.py +0 -12
  40. ct-0.10.8.114.dist-info/RECORD +0 -55
  41. {ct-0.10.8.114.dist-info → ct-0.10.8.116.dist-info}/LICENSE +0 -0
  42. {ct-0.10.8.114.dist-info → ct-0.10.8.116.dist-info}/WHEEL +0 -0
  43. {ct-0.10.8.114.dist-info → ct-0.10.8.116.dist-info}/entry_points.txt +0 -0
  44. {ct-0.10.8.114.dist-info → ct-0.10.8.116.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,84 @@
1
+ import random
2
+ from ..system import cmd
3
+
4
+ class Kvox(object):
5
+ def __init__(self, log=print):
6
+ self.logger = log
7
+ self.kpipes = {}
8
+
9
+ def log(self, *msg):
10
+ self.logger("Kvox", *msg)
11
+
12
+ def getpipe(self, lang_code):
13
+ from kokoro import KPipeline
14
+ if lang_code not in self.kpipes:
15
+ self.kpipes[lang_code] = KPipeline(lang_code=lang_code)
16
+ return self.kpipes[lang_code]
17
+
18
+ def vi(self, t, v):
19
+ t = round(t)
20
+ self.log("viseme with time", t, "and value", v)
21
+ return { "time": t, "value": v }
22
+
23
+ def token2visemes(self, token, visemes):
24
+ self.log("token2visemes", token.text, token.phonemes, token.start_ts, token.end_ts)
25
+ phos = token.text # phonemes are full of unicode....
26
+ step = 1000 * (token.end_ts - token.start_ts) / len(phos)
27
+ t = 1000 * token.start_ts
28
+ for pho in phos:
29
+ visemes.append(self.vi(t, pho))
30
+ t += step
31
+ return t
32
+
33
+ def tokens2visemes(self, tokens):
34
+ self.log("tokens2visemes")
35
+ t = 0
36
+ visemes = []
37
+ for token in tokens:
38
+ t = self.token2visemes(token, visemes)
39
+ visemes.append(self.vi(t, "sil"))
40
+ return visemes
41
+
42
+ def __call__(self, text, voice="af_heart", speed=1, lang_code='a', filename="tts"):
43
+ import json, soundfile
44
+ pipeline = self.getpipe(lang_code)
45
+ nothing, tokens = pipeline.g2p(text)
46
+ for result in pipeline.generate_from_tokens(tokens=tokens, voice=voice, speed=float(speed)):
47
+ self.log(result.phonemes)
48
+ vz = self.tokens2visemes(result.tokens)
49
+ vname = "%s.json"%(filename,)
50
+ aname = "%s.mp3"%(filename,)
51
+ self.log("writing", vname)
52
+ with open(vname, "w") as f:
53
+ f.write("%s\n"%("\n".join([json.dumps(v) for v in vz]),))
54
+ self.log("writing", aname)
55
+ soundfile.write(aname, result.audio, 24000)
56
+
57
+ VAGENT = None
58
+ kvox = Kvox()
59
+ kvoices = [
60
+ "af_heart", "af_bella", "af_nicole", "af_aoede", "af_kore", "af_sarah", "af_nova",
61
+ "af_sky", "af_alloy", "af_jessica", "af_river", "am_michael", "am_fenrir", "am_puck",
62
+ "am_echo", "am_eric", "am_liam", "am_onyx", "am_santa", "am_adam", "bf_emma",
63
+ "bf_isabella", "bf_alice", "bf_lily", "bm_george", "bm_fable", "bm_lewis", "bm_daniel"
64
+ ]
65
+
66
+ def vagent():
67
+ global VAGENT
68
+ if not VAGENT:
69
+ from venvr import getagent
70
+ VAGENT = getagent("kovo", ["kokoro", "soundfile"])
71
+ VAGENT.register(Kvox)
72
+ return VAGENT
73
+
74
+ def vox(text, voice="af_heart", speed=1, lang_code='a', filename="tts", say=False):
75
+ if voice == "random":
76
+ voice = random.choice(kvoices)
77
+ try:
78
+ import kokoro
79
+ print("found kokoro")
80
+ kvox(text, voice, speed, lang_code, filename)
81
+ except:
82
+ print("no kokoro - using venvr")
83
+ vagent().run("Kvox", text, voice, speed, lang_code, filename)
84
+ say and cmd("mplayer %s.mp3"%(filename,))
@@ -0,0 +1 @@
1
+ from .ander import android
@@ -0,0 +1,101 @@
1
+ import os
2
+ from fyg.util import log, ask, confirm, selnum
3
+ from cantools.util import cmd, output, mkdir, cp
4
+ from cantools.util.system import envget, envset
5
+ from cantools.util.admin import _which, javaver
6
+ from .data import TEMPLATES
7
+
8
+ class Android(object):
9
+ def __init__(self, url, name=None, package=None, auto=False):
10
+ self.setVars(url, name, package, auto)
11
+ self.setMode()
12
+ self.dirs()
13
+ self.files()
14
+ self.icons()
15
+ os.chdir(self.name)
16
+ self.apk()
17
+ self.install()
18
+ log("goodbye")
19
+
20
+ def setVars(self, url, name=None, package=None, auto=False):
21
+ if "://" not in url:
22
+ url = "https://%s"%(url,)
23
+ parts = url.split("://").pop().split("/").pop(0).split(".")
24
+ self.url = url
25
+ self.auto = auto
26
+ self.name = name or self.ask("name", parts[0])
27
+ parts.reverse()
28
+ self.package = package or self.ask("package name", ".".join(parts))
29
+ self.dir = self.package.replace(".", "/")
30
+ self.tmps = TEMPLATES["android"]
31
+
32
+ def ask(self, question, default=None):
33
+ if default and self.auto:
34
+ log("question '%s' -> choosing '%s'"%(question, default), important=True)
35
+ return default
36
+ return ask(question, default)
37
+
38
+ def conf(self, condition, default=False):
39
+ if self.auto:
40
+ log("confirmation '%s' -> deciding '%s'"%(condition, default), important=True)
41
+ return default
42
+ return confirm(condition, default)
43
+
44
+ def setMode(self, mode="debug"):
45
+ self.mode = mode
46
+ self.debug = mode == "debug"
47
+
48
+ def dirs(self):
49
+ if not self.conf("assemble directory hierarchy", True): return
50
+ mkdir("%s/src/main/java/%s"%(self.name, self.dir), True)
51
+ mkdir("%s/src/main/res"%(self.name,))
52
+
53
+ def files(self):
54
+ if not self.conf("create project files", True): return
55
+ self.jv = javaver()
56
+ cp(self.tmps["manifest"]%(self.name, self.package, self.name),
57
+ "%s/src/main/AndroidManifest.xml"%(self.name))
58
+ cp(self.tmps["activity"]%(self.package, self.url),
59
+ "%s/src/main/java/%s/MainActivity.java"%(self.name, self.dir))
60
+ cp(self.tmps["gradle"]%(self.package, self.jv, self.jv),
61
+ "%s/build.gradle"%(self.name,))
62
+ cp(self.tmps["properties"], "%s/gradle.properties"%(self.name,))
63
+
64
+ def icons(self):
65
+ if not self.conf("generate icons", True): return
66
+ ipath = self.ask("image path", "icon.png")
67
+ for k, v in self.tmps["isizes"].items():
68
+ wpath = "%s/src/main/res/drawable-%s"%(self.name, k)
69
+ mkdir(wpath)
70
+ cmd(self.tmps["icons"]%(ipath, v, wpath))
71
+
72
+ def chenv(self):
73
+ for name, cfg in self.tmps["env"].items():
74
+ if not envget(name):
75
+ log("%s not set!"%(name,))
76
+ envset(name, self.ask("%s location"%(name,),
77
+ output("locate %s"%(cfg["locater"].replace("_JV_",
78
+ self.jv),)).split(cfg["splitter"]).pop(0)))
79
+
80
+ def apk(self):
81
+ if not self.conf("build apk", True): return
82
+ self.chenv()
83
+ self.setMode(selnum(["debug", "release"]))
84
+ gcmd = self.debug and "assembleDebug" or "assemble"
85
+ if self.conf("add stacktrace flag"):
86
+ gcmd = "%s --stacktrace"%(gcmd,)
87
+ if self.conf("specify trustStore cacerts", True):
88
+ tsca = selnum(output("locate cacerts | grep java").split("\n"))
89
+ tspw = self.ask("trustStore password", "changeit")
90
+ gcmd = self.tmps["tstore"]%(gcmd, tsca, tspw)
91
+ cmd("gradle %s"%(gcmd,))
92
+
93
+ def install(self):
94
+ if not self.conf("install on device", True): return
95
+ aname = self.debug and "%s-debug"%(self.name,) or self.name
96
+ cmd("adb install build/outputs/apk/%s/%s.apk"%(self.mode, aname))
97
+
98
+ def android(url=None, auto=False):
99
+ if not _which("java", "gradle", "adb", "convert"):
100
+ return log("build aborted!")
101
+ Android(url or ask("url", "http://ct.mkult.co"), auto=auto)
@@ -0,0 +1,167 @@
1
+ # reference:
2
+ # - https://github.com/raelmax/android-webview
3
+ # - https://czak.pl/posts/minimal-android-project
4
+
5
+ AMAN = """<?xml version="1.0" encoding="utf-8"?>
6
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
7
+ android:versionCode="1"
8
+ android:versionName="1.0" >
9
+
10
+ <uses-sdk />
11
+
12
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
13
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
14
+ <uses-permission android:name="android.permission.INTERNET" />
15
+ <uses-permission android:name="android.permission.CAMERA" />
16
+
17
+ <application
18
+ android:allowBackup="true"
19
+ android:icon="@drawable/ic_launcher"
20
+ android:label="%s"
21
+ android:theme="@android:style/Theme.NoTitleBar" >
22
+ <activity
23
+ android:name="%s.MainActivity"
24
+ android:configChanges="orientation|screenSize"
25
+ android:label="%s"
26
+ android:exported="true" >
27
+ <intent-filter>
28
+ <action android:name="android.intent.action.MAIN" />
29
+ <category android:name="android.intent.category.LAUNCHER" />
30
+ </intent-filter>
31
+ </activity>
32
+ </application>
33
+ </manifest>
34
+ """
35
+
36
+ AMAC = """package %s;
37
+ import android.Manifest;
38
+ import android.app.Activity;
39
+ import android.os.Bundle;
40
+ import android.view.KeyEvent;
41
+ import android.view.Window;
42
+ import android.webkit.WebView;
43
+ import android.webkit.WebViewClient;
44
+ import android.webkit.WebChromeClient;
45
+ import android.webkit.PermissionRequest;
46
+ import android.content.pm.PackageManager;
47
+ import androidx.core.content.ContextCompat;
48
+
49
+ public class MainActivity extends Activity {
50
+ private WebView mWebView;
51
+
52
+ @Override
53
+ public void onCreate(Bundle savedInstanceState) {
54
+ super.onCreate(savedInstanceState);
55
+ MainActivity thaz = this;
56
+ getWindow().requestFeature(Window.FEATURE_NO_TITLE);
57
+ mWebView = new WebView(this);
58
+ mWebView.getSettings().setMediaPlaybackRequiresUserGesture(false);
59
+ mWebView.getSettings().setJavaScriptEnabled(true);
60
+ mWebView.getSettings().setDomStorageEnabled(true);
61
+ mWebView.getSettings().setUseWideViewPort(true);
62
+ mWebView.loadUrl("%s");
63
+ mWebView.setWebViewClient(new WebViewClient() {
64
+ @Override
65
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
66
+ view.loadUrl(url);
67
+ return true;
68
+ }
69
+ });
70
+ mWebView.setWebChromeClient(new WebChromeClient(){
71
+ // Need to accept permissions to use the camera
72
+ @Override
73
+ public void onPermissionRequest(final PermissionRequest request) {
74
+ // grants permission for app. video not showing
75
+ if (ContextCompat.checkSelfPermission(thaz, Manifest.permission.CAMERA)
76
+ != PackageManager.PERMISSION_GRANTED
77
+ ) {
78
+ requestPermissions(new String[]{Manifest.permission.CAMERA}, 1010);
79
+ }
80
+
81
+ if (ContextCompat.checkSelfPermission(thaz, Manifest.permission.RECORD_AUDIO)
82
+ != PackageManager.PERMISSION_GRANTED
83
+ ) {
84
+ requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 1010);
85
+ }
86
+
87
+ request.grant(request.getResources()); // is this right?
88
+ }
89
+ });
90
+ this.setContentView(mWebView);
91
+ }
92
+
93
+ @Override
94
+ public boolean onKeyDown(final int keyCode, final KeyEvent event) {
95
+ if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
96
+ mWebView.goBack();
97
+ return true;
98
+ }
99
+ return super.onKeyDown(keyCode, event);
100
+ }
101
+ }"""
102
+
103
+ ABG = """buildscript {
104
+ repositories {
105
+ google()
106
+ mavenCentral()
107
+ }
108
+ dependencies {
109
+ classpath 'com.android.tools.build:gradle:8.5.2'
110
+ }
111
+ }
112
+
113
+ repositories {
114
+ google()
115
+ }
116
+
117
+ apply plugin: 'com.android.application'
118
+
119
+ dependencies {
120
+ implementation 'androidx.appcompat:appcompat:1.1.0'
121
+ }
122
+
123
+ android {
124
+ namespace = "%s"
125
+
126
+ compileSdkVersion 34
127
+
128
+ defaultConfig {
129
+ targetSdk = 34
130
+ minSdkVersion = 14
131
+ }
132
+
133
+ compileOptions {
134
+ sourceCompatibility JavaVersion.VERSION_%s
135
+ targetCompatibility JavaVersion.VERSION_%s
136
+ }
137
+ }"""
138
+
139
+ AGP = """android.useAndroidX=true
140
+ android.enableJetifier=true"""
141
+
142
+ TEMPLATES = {
143
+ "android": {
144
+ "manifest": AMAN,
145
+ "activity": AMAC,
146
+ "gradle": ABG,
147
+ "properties": AGP,
148
+ "icons": "convert -background none %s -resize %s %s/ic_launcher.png",
149
+ "tstore": "%s -Djavax.net.ssl.trustStore=%s -Djavax.net.ssl.trustStorePassword=%s",
150
+ "isizes": {
151
+ 'ldpi': '36x36',
152
+ 'mdpi': '48x48',
153
+ 'hdpi': '72x72',
154
+ 'xhdpi': '96x96'
155
+ },
156
+ "env": {
157
+ "JAVA_HOME": {
158
+ "locater": "cacerts|grep jvm/java-_JV_-",
159
+ "splitter": "/lib/security"
160
+ },
161
+ "ANDROID_HOME": {
162
+ "locater": "/lib/android-sdk",
163
+ "splitter": "\n"
164
+ }
165
+ }
166
+ }
167
+ }
cantools/util/system.py CHANGED
@@ -1,9 +1,5 @@
1
- import os, sys, subprocess, platform
2
- try:
3
- from commands import getoutput # py2
4
- except:
5
- from subprocess import getoutput # py3
6
- from fyg.util import log, read, write, rm
1
+ import os, sys
2
+ from fyg.util import log, read, write, rm, sudoed, cmd, output
7
3
 
8
4
  def cp(content, fname): # more write than copy, buuuut...
9
5
  log("writing %s"%(fname,), 2)
@@ -40,23 +36,6 @@ def mkdir(pname, recursive=False):
40
36
  def sed(fname, flag, replacement, target=None):
41
37
  write(read(fname).replace(flag, replacement), target or fname)
42
38
 
43
- def sudoed(cline, sudo=False):
44
- if sudo and platform.system() != "Windows" and os.geteuid(): # !root
45
- cline = "sudo %s"%(cline,)
46
- return cline
47
-
48
- def cmd(cline, sudo=False, silent=False):
49
- cline = sudoed(cline, sudo)
50
- silent or log('issuing command: "%s"'%(cline,), 2)
51
- subprocess.call(cline, shell=True)
52
-
53
- def output(cline, sudo=False, silent=False, loud=False):
54
- cline = sudoed(cline, sudo)
55
- silent or log('getting output for: "%s"'%(cline,), 2)
56
- output = getoutput(cline)
57
- loud and log(output)
58
- return output
59
-
60
39
  def envget(name):
61
40
  return output("echo $%s"%(name,))
62
41
 
cantools/web/__init__.py CHANGED
@@ -1,9 +1,13 @@
1
- from .util import config
1
+ from cantools import config
2
2
 
3
3
  if config.web.server == "gae":
4
4
  from .gae_server import *
5
5
  elif config.web.server == "dez":
6
- from cantools.web.dez_server import *
6
+ from .bw import *
7
+ from babyweb import *
8
+ from babyweb import mail
9
+ from babyweb.sms import send_sms
10
+ from babyweb.mail import send_mail, email_admins, email_reportees, mailer, reader, check_inbox, scanner, on_mail
7
11
  else:
8
12
  from cantools import util
9
13
  util.error("no web server specified")
cantools/web/bw.py ADDED
@@ -0,0 +1,70 @@
1
+ import json, gc, os, inspect, threading, psutil
2
+ from babyweb.daemons import WebBase, initWebs, logger_getter
3
+ from babyweb.server import run_dez_webserver
4
+ from babyweb.config import config as babyfyg
5
+ from babyweb.logger import log, syslog
6
+ from ..util import init_rel
7
+ from cantools import config
8
+
9
+ A_STATIC = {
10
+ "dynamic": { "/": "_/dynamic", "/css/": "_/css", "/js/CT/": "js/CT", "/logs/": "logs", "/logs": "logs" },
11
+ "static": { "/": "_/static", "/css/": "_/css", "/js/CT/": "js/CT", "/logs/": "logs", "/logs": "logs" },
12
+ "production": { "/": "_/production", "/css/": "_/css", "/logs/": "logs", "/logs": "logs" },
13
+ }
14
+ A_CB = { "/admin": "admin", "/_db": "_db" }
15
+
16
+ def setcfg():
17
+ syslog("passing configuration to babyweb")
18
+ for prop in ["cache", "encode", "mempad", "web", "cron", "scrambler"]:
19
+ babyfyg.update(prop, config[prop])
20
+ for prop in ["contacts", "reportees"]:
21
+ babyfyg.admin.update(prop, config.admin[prop])
22
+ for prop in ["verify", "certfile", "keyfile", "cacerts"]:
23
+ babyfyg.ssl.update(prop, config.ssl[prop])
24
+ for prop in ["oflist", "openfiles", "tracemalloc", "allow"]:
25
+ babyfyg.log.update(prop, config.log[prop])
26
+ for prop in ["active", "user", "gateway", "minport", "maxport"]:
27
+ babyfyg.proxy.update(prop, config.proxy[prop])
28
+ babyfyg.update("memcache", config.memcache.request)
29
+ bmfg = babyfyg.mail
30
+ bmfg.update("mailer", config.mailer)
31
+ bmfg.update("gmailer", config.gmailer)
32
+ bmfg.update("name", config.mailername)
33
+ bmfg.update("html", config.mailhtml)
34
+ bmfg.update("verbose", config.mailoud)
35
+ bmfg.update("scantick", config.mailscantick)
36
+
37
+ setcfg()
38
+
39
+ class Admin(WebBase):
40
+ def __init__(self, bind_address, port, logger_getter, shield, mempad):
41
+ self.logger = logger_getter("Admin")
42
+ acfg = config.admin
43
+ WebBase.__init__(self, bind_address, port, logger_getter, # share shield/blacklist
44
+ A_STATIC[config.mode], A_CB, acfg.whitelist, config.web.blacklist, shield, mempad)
45
+ self.add_cb_rule("/_report", self.report)
46
+
47
+ def report(self, req):
48
+ report = json.dumps({
49
+ "threads": threading.active_count(),
50
+ "stack_frames": len(inspect.stack()),
51
+ "web": self.controller.webs["web"].daemon.counter.report(),
52
+ "admin": self.daemon.counter.report(),
53
+ "gc": len(gc.get_objects()),
54
+ "mem": psutil.Process(os.getpid()).memory_percent()
55
+ })
56
+ self.logger.info(report)
57
+ self.daemon.respond(req, report)
58
+
59
+ def run_bw():
60
+ syslog("initializing web server")
61
+ init_rel()
62
+ initWebs({
63
+ "admin": {
64
+ "daemon": Admin,
65
+ "config": config.admin
66
+ }
67
+ })
68
+ config.admin.update("pw",
69
+ config.cache("admin password? ", overwrite=config.newpass))
70
+ run_dez_webserver()
@@ -60,9 +60,4 @@ def delmem(key):
60
60
 
61
61
  def clearmem():
62
62
  from google.appengine.api import memcache
63
- memcache.flush_all()
64
-
65
- set_getmem(getmem)
66
- set_setmem(setmem)
67
- set_delmem(delmem)
68
- set_clearmem(clearmem)
63
+ memcache.flush_all()