ct 0.10.8.114__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 (55) hide show
  1. cantools/__init__.py +24 -0
  2. cantools/_db.py +142 -0
  3. cantools/_memcache.py +76 -0
  4. cantools/_pay.py +46 -0
  5. cantools/admin.py +31 -0
  6. cantools/cfg.py +347 -0
  7. cantools/config.py +131 -0
  8. cantools/db/__init__.py +18 -0
  9. cantools/db/admin.py +27 -0
  10. cantools/db/gae/__init__.py +0 -0
  11. cantools/db/gae/model.py +127 -0
  12. cantools/db/gae/properties.py +35 -0
  13. cantools/db/wp.py +99 -0
  14. cantools/geo.py +188 -0
  15. cantools/hooks.py +13 -0
  16. cantools/scripts/__init__.py +0 -0
  17. cantools/scripts/bench.py +167 -0
  18. cantools/scripts/builder.py +272 -0
  19. cantools/scripts/deploy.py +154 -0
  20. cantools/scripts/doc.py +239 -0
  21. cantools/scripts/index.py +226 -0
  22. cantools/scripts/init.py +345 -0
  23. cantools/scripts/migrate.py +593 -0
  24. cantools/scripts/pubsub/__init__.py +28 -0
  25. cantools/scripts/pubsub/actor.py +13 -0
  26. cantools/scripts/pubsub/bots.py +143 -0
  27. cantools/scripts/pubsub/channel.py +85 -0
  28. cantools/scripts/pubsub/ps.py +145 -0
  29. cantools/scripts/pubsub/user.py +51 -0
  30. cantools/scripts/start.py +53 -0
  31. cantools/scripts/util.py +24 -0
  32. cantools/util/__init__.py +78 -0
  33. cantools/util/admin.py +620 -0
  34. cantools/util/data.py +109 -0
  35. cantools/util/media.py +303 -0
  36. cantools/util/package.py +125 -0
  37. cantools/util/system.py +73 -0
  38. cantools/web/__init__.py +9 -0
  39. cantools/web/dez_server/__init__.py +1 -0
  40. cantools/web/dez_server/controller.py +129 -0
  41. cantools/web/dez_server/cron.py +115 -0
  42. cantools/web/dez_server/daemons.py +64 -0
  43. cantools/web/dez_server/mail.py +24 -0
  44. cantools/web/dez_server/response.py +63 -0
  45. cantools/web/dez_server/routes.py +21 -0
  46. cantools/web/dez_server/server.py +229 -0
  47. cantools/web/dez_server/sms.py +12 -0
  48. cantools/web/gae_server.py +68 -0
  49. cantools/web/util.py +552 -0
  50. ct-0.10.8.114.dist-info/LICENSE +9 -0
  51. ct-0.10.8.114.dist-info/METADATA +25 -0
  52. ct-0.10.8.114.dist-info/RECORD +55 -0
  53. ct-0.10.8.114.dist-info/WHEEL +5 -0
  54. ct-0.10.8.114.dist-info/entry_points.txt +10 -0
  55. ct-0.10.8.114.dist-info/top_level.txt +1 -0
@@ -0,0 +1,239 @@
1
+ """
2
+ ### Usage: ctdoc [-w]
3
+
4
+ ### Options:
5
+ -h, --help show this help message and exit
6
+ -w, --web build web docs
7
+ -a, --auto use auto mode (even with a plugin)
8
+ -o, --omit omit any files from autodoc?
9
+
10
+ Run from cantools root (contains setup.py, cantools/, README.md, etc), from root
11
+ of a CT plugin, or from within a custom project. In cantools, builds docs for all
12
+ frontend (js) and CLI (py) files. In plugin, docs consist of about file (about.txt),
13
+ initialization config (init.py) and default frontend config (js/config.js). In custom
14
+ (project) mode (when ctdoc is run somewhere other than cantools root or a plugin root,
15
+ and additionally a configuration file, doc.cfg, is present), for each path declared in
16
+ doc.cfg, include the docstring of each file specified, as well as the contents of
17
+ about.txt (if present). Lastly, auto mode doesn't require configuration (doc.cfg) --
18
+ instead, it recurses through the directories of your project, and includes the contents of
19
+ any about.txt files, as well as (the top of) any py/js file that starts with a docstring.
20
+ """
21
+
22
+ import os, json
23
+ from optparse import OptionParser
24
+ from cantools import __version__, config
25
+ from cantools.util import read, write, log, cp, cmd
26
+ from cantools.util.package import here
27
+
28
+ WEB = []
29
+ ALTS = {
30
+ "pubsub": os.path.join("pubsub", "__init__")
31
+ }
32
+ HERE = here()
33
+ CUSTOM = os.path.isfile("doc.cfg") and read("doc.cfg")
34
+ ISPLUGIN = not CUSTOM and HERE.startswith("ct") and HERE
35
+ AUTO = HERE != "cantools" and not CUSTOM and not ISPLUGIN
36
+
37
+ if not CUSTOM and not AUTO:
38
+ if ISPLUGIN:
39
+ JSPATH = os.path.join(HERE, "js")
40
+ BPATH = "."
41
+ ALTS["init"] = os.path.join(ISPLUGIN, "init")
42
+ else:
43
+ JSPATH = os.path.join(HERE, "CT")
44
+ BPATH = os.path.join(HERE, "scripts")
45
+
46
+ def space(data):
47
+ return " " + data.replace("\n", "\n ")
48
+
49
+ def bt2ds(t):
50
+ return t.split('"""')[1].strip()
51
+
52
+ def dsBack(cmd):
53
+ cpath = os.path.join(BPATH, "%s.py"%(ALTS.get(cmd, cmd),))
54
+ log(cpath, 2)
55
+ bdata = read(cpath)
56
+ fdata = ISPLUGIN and space(bdata) or "## ct%s\n%s"%(cmd, bt2ds(bdata))
57
+ WEB[-1]["children"].append({
58
+ "name": cmd,
59
+ "content": fdata
60
+ })
61
+ return fdata
62
+
63
+ def dsFront(mod, modname=None, iline=None):
64
+ modname = modname or "CT.%s"%(mod[:-3],)
65
+ iline = iline or (mod == "ct.js" and '<script src="/js/CT/ct.js"></script>' or 'CT.require("%s");'%(modname,))
66
+ log(modname, 2)
67
+ mdata = read(os.path.join(JSPATH, mod))
68
+ rdata = "\n".join([
69
+ "## %s"%(modname,),
70
+ "### Import line: '%s'"%(iline,),
71
+ (ISPLUGIN and mod == "config.js") and space(mdata) or mdata[3:].split("\n*/")[0]
72
+ ])
73
+ WEB[-1]["children"].append({
74
+ "name": mod,
75
+ "content": rdata
76
+ })
77
+ return rdata
78
+
79
+ def back():
80
+ log("back", 1)
81
+ wobj = { "children": [] }
82
+ WEB.append(wobj)
83
+ f = []
84
+ if ISPLUGIN:
85
+ wobj["name"] = "Back (Init Config)"
86
+ fdata = [dsBack("init")]
87
+ else:
88
+ wobj["name"] = "Back (CLI)"
89
+ fdata = list(map(dsBack, ["init", "start", "deploy", "pubsub", "migrate", "index", "doc"]))
90
+ f.append("# %s"%(wobj["name"],))
91
+ f += fdata
92
+ return f
93
+
94
+ def front():
95
+ log("front", 1)
96
+ wobj = { "children": [] }
97
+ WEB.append(wobj)
98
+ f = []
99
+ if not ISPLUGIN:
100
+ wobj["name"] = "Front (JS Library)"
101
+ plist = os.listdir(JSPATH)
102
+ plist.sort()
103
+ fdata = list(map(dsFront, [i for i in plist if i.endswith("js")]))
104
+ elif os.path.isfile(os.path.join(JSPATH, "config.js")):
105
+ wobj["name"] = "Front (JS Config)"
106
+ fdata = [dsFront("config.js", "core.config.%s"%(ISPLUGIN,), 'CT.require("core.config");')]
107
+ if "name" in wobj:
108
+ f.append("# %s"%(wobj["name"],))
109
+ f += fdata
110
+ return f
111
+
112
+ def customChunk(path, fnames):
113
+ log("custom chunk: %s"%(path,), 1)
114
+ kids = []
115
+ wobj = { "name": path, "children": kids }
116
+ WEB.append(wobj)
117
+ f = ["## %s"%(path,)]
118
+ afile = os.path.join(path, "about.txt")
119
+ if os.path.isfile(afile):
120
+ adata = read(afile)
121
+ f.append(adata)
122
+ kids.append({
123
+ "name": "about",
124
+ "content": adata
125
+ })
126
+ for fname in fnames:
127
+ fdata = read(os.path.join(path, fname))
128
+ if fname == "config.js" or fname.startswith("ct.cfg"): # for non-local backend cfgs
129
+ fdata = space(fdata)
130
+ elif fname.endswith(".js"):
131
+ fdata = fdata[3:].split("\n*/")[0]
132
+ elif fname.endswith(".py"):
133
+ fdata = bt2ds(fdata)
134
+ f.append("### %s\n%s"%(fname, fdata))
135
+ kids.append({
136
+ "name": fname,
137
+ "content": fdata
138
+ })
139
+ return f
140
+
141
+ frules = {
142
+ ".js": {
143
+ "top": "/*\n",
144
+ "bottom": "\n*/"
145
+ },
146
+ ".py": {
147
+ "top": '"""\n',
148
+ "bottom": '\n"""'
149
+ }
150
+ }
151
+
152
+ hashead = set()
153
+ def sethead(curdir, data):
154
+ dirname = curdir.rsplit(os.path.sep, 1)[-1]
155
+ if dirname not in hashead:
156
+ hashead.add(dirname)
157
+ data.append("%s %s"%("#" * len(curdir.split(os.path.sep)), dirname))
158
+ wobj = { "name": dirname, "children": [] }
159
+ WEB.append(wobj)
160
+ return WEB[-1]["children"]
161
+
162
+ OMIT = ""
163
+ def autodoc(data, curdir, contents):
164
+ about = "about.txt"
165
+ if curdir != HERE: # probs revise this...
166
+ about = os.path.join(curdir, about)
167
+ if os.path.isfile(about):
168
+ kids = sethead(curdir, data)
169
+ adata = read(about)
170
+ data.append(adata)
171
+ kids.append({
172
+ "name": "about",
173
+ "content": adata
174
+ })
175
+ for fname in contents:
176
+ if fname in OMIT:
177
+ continue
178
+ for flag, rule in list(frules.items()):
179
+ if fname.endswith(flag):
180
+ fdata = read(os.path.join(curdir, fname))
181
+ if fdata.startswith(rule["top"]):
182
+ kids = sethead(curdir, data)
183
+ fstr = fdata[len(rule["top"]):].split(rule["bottom"])[0]
184
+ data.append("%s# %s"%("#" * len(curdir.split(os.path.sep)), fname))
185
+ data.append(fstr)
186
+ kids.append({
187
+ "name": fname,
188
+ "content": fstr
189
+ })
190
+
191
+ def build():
192
+ global OMIT, HERE
193
+ parser = OptionParser("ctdoc [-w]")
194
+ parser.add_option("-w", "--web", action="store_true",
195
+ dest="web", default=False, help="build web docs")
196
+ parser.add_option("-a", "--auto", action="store_true",
197
+ dest="auto", default=False, help="use auto mode (even with a plugin)")
198
+ parser.add_option("-o", "--omit", dest="omit", default="",
199
+ help="omit any files from autodoc?")
200
+ options, args = parser.parse_args()
201
+ if not os.path.isdir(HERE):
202
+ HERE = input("module name? ")
203
+ log("building docs")
204
+ ds = []
205
+ if AUTO or options.auto:
206
+ OMIT = options.omit
207
+ for dirpath, dirnames, filenames in os.walk(HERE):
208
+ autodoc(ds, dirpath, filenames)
209
+ else:
210
+ abdata = (ISPLUGIN or CUSTOM) and "# %s\n%s"%(HERE, read("about.txt")) or config.about%(__version__,)
211
+ ds.append(abdata)
212
+ WEB.append({
213
+ "name": HERE,
214
+ "children": [{
215
+ "name": "about",
216
+ "content": abdata
217
+ }]
218
+ })
219
+ if CUSTOM:
220
+ for line in CUSTOM.split("\n"):
221
+ path, fnames = line.split(" = ")
222
+ ds.extend(customChunk(path, fnames.split("|")))
223
+ else:
224
+ ds.extend(back())
225
+ ds.extend(front())
226
+ log("writing data", important=True)
227
+ log("README.md", 1)
228
+ write("\n\n".join(ds), "README.md")
229
+ if options.web:
230
+ log("web docs enabled!", 1)
231
+ log("building docs web application", 2)
232
+ if not os.path.isdir("docs"):
233
+ cmd("ctinit docs -p ctdocs")
234
+ log("copying data", 2)
235
+ cp("core.data = %s;"%(json.dumps(WEB, indent=4),), os.path.join("docs", "js", "core", "data.js"))
236
+ log("goodbye")
237
+
238
+ if __name__ == "__main__":
239
+ build()
@@ -0,0 +1,226 @@
1
+ """
2
+ ### Usage: ctindex [--mode=MODE] [--domain=DOMAIN] [--port=PORT] [--skip=SKIP]
3
+
4
+ ### Options:
5
+ -h, --help show this help message and exit
6
+ -m MODE, --mode=MODE may be: 'refcount' (default - count up all foreignkey
7
+ references for sort orders and such); 'index' (assign
8
+ each record a sequential integer index); 'urlsafekeys'
9
+ (update all key/keylist properties to use urlsafe keys
10
+ introduced in ct 0.8); 'cleanup' (delete zero-count
11
+ reference counters). Note regarding 'index' mode: it
12
+ _must_ happen remotely; it's generally unnecessary
13
+ unless you're trying to migrate an unindexed database
14
+ away from gae and need an index/key per record; it
15
+ should be invoked from _outside_ -- that's right,
16
+ outside -- of your project's directory (to avoid
17
+ loading up a bunch of google network tools that may be
18
+ crappy or cause issues outside of their normal
19
+ 'dev_appserver' environment)
20
+ -d DOMAIN, --domain=DOMAIN
21
+ ('index' mode only) what's the domain of the target
22
+ server? (default: localhost)
23
+ -p PORT, --port=PORT ('index' mode only) what's the port of the target
24
+ server? (default: 8080)
25
+ -s SKIP, --skip=SKIP skip these tables ('index' mode only) - use '|' as
26
+ separator, such as 'table1|table2|table3' (default:
27
+ none)
28
+ -i INDEX, --index=INDEX
29
+ start with this index ('index' mode only) (default: 0)
30
+
31
+ As you can see, this script's behavior changes according to the backend of the target project.
32
+
33
+ ### dez
34
+ Run this if your CTRefCount records get messed up for
35
+ some reason. It will go through and recount everything
36
+ (in the default 'refcount' mode -- the other modes,
37
+ 'urlsafekeys' and 'cleanup', are for migrating a CT-mediated
38
+ database from an older deployment to CT 0.8 or newer).
39
+
40
+ ### gae
41
+ Run this in 'index' mode on a database with lots of missing index values.
42
+ """
43
+
44
+ from getpass import getpass
45
+ from optparse import OptionParser
46
+ from fyg.util import log, error, batch
47
+ from cantools.db import get_schema, get_model, put_multi, delete_multi, unpad_key
48
+ from cantools.web import fetch
49
+ from cantools import config
50
+ if config.web.server == "dez":
51
+ from cantools.db import session, func, refresh_counter
52
+
53
+ try:
54
+ input = raw_input # py2/3 compatibility
55
+ except NameError:
56
+ pass
57
+
58
+ counts = { "_counters": 0 }
59
+ RETRIES = 5
60
+
61
+ #
62
+ # dez
63
+ #
64
+
65
+ def get_keys(kind, reference):
66
+ log("acquiring %s (%s) keys"%(kind, reference), 1)
67
+ mod = get_model(kind)
68
+ q = session.query(getattr(mod, "key"))
69
+ qcount = q.count()
70
+ log("found %s"%(qcount,), 2)
71
+ fname, fkey = reference.split(".")
72
+ fmod = get_model(fname)
73
+ fprop = getattr(fmod, fkey)
74
+ sub = session.query(fprop, func.count("*").label("sub_count")).group_by(fprop).subquery()
75
+ q = q.join(sub, mod.key==getattr(sub.c, fkey))
76
+ newcount = q.count()
77
+ log("filtering out %s untargetted entities"%(qcount - newcount), 2)
78
+ qcount = newcount
79
+ log("returning %s keys"%(qcount,), 2)
80
+ return q.all()
81
+
82
+ def refmap():
83
+ log("compiling back reference map")
84
+ rmap = {}
85
+ for tname, schema in list(get_schema().items()):
86
+ for pname, kinds in list(schema["_kinds"].items()):
87
+ reference = "%s.%s"%(tname, pname)
88
+ counts[reference] = 0
89
+ for kind in [k for k in kinds if k != "*"]: # skip wildcard for now
90
+ if kind not in rmap:
91
+ rmap[kind] = {}
92
+ rmap[kind][reference] = get_keys(kind, reference)
93
+ return rmap
94
+
95
+ def do_batch(chunk, reference):
96
+ log("refreshing %s %s keys"%(len(chunk), reference), 1)
97
+ i = 0
98
+ rc = []
99
+ for item in chunk: # item is single-member tuple
100
+ rc.append(refresh_counter(item[0], reference))
101
+ i += 1
102
+ if not i % 100:
103
+ log("processed %s"%(i,), 3)
104
+ counts[reference] += len(chunk)
105
+ counts["_counters"] += len(rc)
106
+ log("refreshed %s total"%(counts[reference],), 2)
107
+ log("updated %s counters"%(counts["_counters"],), 2)
108
+ put_multi(rc)
109
+ log("saved", 2)
110
+
111
+ def refcount():
112
+ log("indexing foreignkey references throughout database", important=True)
113
+ import model # load schema
114
+ for kind, references in list(refmap().items()):
115
+ log("processing table: %s"%(kind,), important=True)
116
+ for reference, keys in list(references.items()):
117
+ batch(keys, do_batch, reference)
118
+ tcount = sum(counts.values()) - counts["_counters"]
119
+ log("refreshed %s rows and updated %s counters"%(tcount, counts["_counters"]), important=True)
120
+
121
+ #
122
+ # gae
123
+ #
124
+
125
+ def _log_fetch(host, url, port):
126
+ res = fetch(host, url, port)
127
+ log(res)
128
+ return res
129
+
130
+ def _index_kind(kind, host, port, pw, index):
131
+ log("indexing %s"%(kind,), important=True)
132
+ retry = 0
133
+ while "Error" in _log_fetch(host, "/_db?action=index&pw=%s&kind=%s&index=%s"%(pw, kind, index), port):
134
+ log("error indexing %s"%(kind,), important=True)
135
+ if retry == RETRIES:
136
+ error("tried %s times! sorry."%(retry,))
137
+ retry += 1
138
+ log("trying again (retry: %s)"%(retry,))
139
+
140
+ def index(host, port, skips, index):
141
+ pw = getpass("what's the admin password? ")
142
+ log("indexing db at %s:%s"%(host, port), important=True)
143
+ # log(fetch(host, "/_db?action=index&pw=%s"%(pw,), port))
144
+ log("acquiring schema")
145
+ schema = fetch(host, "/_db?action=schema", port, ctjson=True)
146
+ for kind in schema:
147
+ if kind in skips:
148
+ log("skipping %s"%(kind,), important=True)
149
+ else:
150
+ _index_kind(kind, host, port, pw, index)
151
+
152
+ #
153
+ # url safety
154
+ #
155
+ def urlsafe():
156
+ log("updating key/keylist properties with urlsafe keys", important=True)
157
+ import model
158
+ schema = get_schema()
159
+ puts = []
160
+ for mod in schema:
161
+ mods = get_model(mod).query().all()
162
+ log("%s (%s)"%(mod, len(mods)), 1)
163
+ for m in mods:
164
+ if m.polytype != mod:
165
+ log("skipping! (%s != %s)"%(m.polytype, mod), 2)
166
+ continue
167
+ m.key = unpad_key(m.key.urlsafe())
168
+ for prop in schema[mod]["_kinds"]:
169
+ if schema[mod][prop] == "key":
170
+ setattr(m, prop, unpad_key(getattr(m, prop).urlsafe()))
171
+ else: # keylist
172
+ setattr(m, prop, [unpad_key(k.urlsafe()) for k in getattr(m, prop)])
173
+ puts.append(m)
174
+ log("saving records")
175
+ put_multi(puts)
176
+ log("updated %s keys"%(len(puts),), important=True)
177
+ if input("want to prune zero-count reference counters? (y/N)").lower().startswith("y"):
178
+ cleanup()
179
+
180
+ def cleanup():
181
+ log("cleaning up zero-count reference counters", important=True)
182
+ from cantools.db import lookup
183
+ ctrz = lookup.CTRefCount.query(lookup.CTRefCount.count == 0).all()
184
+ log("deleting %s zero-count reference counters"%(len(ctrz),))
185
+ delete_multi(ctrz)
186
+ log("all gone!")
187
+
188
+ def go():
189
+ parser = OptionParser("ctindex [--mode=MODE] [--domain=DOMAIN] [--port=PORT] [--skip=SKIP]")
190
+ parser.add_option("-m", "--mode", dest="mode", default="refcount",
191
+ help="may be: 'refcount' (default - count up all foreignkey references for sort "
192
+ "orders and such); 'index' (assign each record a sequential integer index); "
193
+ "'urlsafekeys' (update all key/keylist properties to use urlsafe keys "
194
+ "introduced in ct 0.8); 'cleanup' (delete zero-count reference counters). "
195
+ "Note regarding 'index' mode: it _must_ happen remotely; it's generally "
196
+ "unnecessary unless you're trying to migrate an unindexed database away from "
197
+ "gae and need an index/key per record; it should be invoked from _outside_ "
198
+ "-- that's right, outside -- of your project's directory (to avoid loading "
199
+ "up a bunch of google network tools that may be crappy or cause issues outside "
200
+ "of their normal 'dev_appserver' environment)")
201
+ parser.add_option("-d", "--domain", dest="domain", default="localhost",
202
+ help="('index' mode only) what's the domain of the target server? (default: localhost)")
203
+ parser.add_option("-p", "--port", dest="port", default="8080",
204
+ help="('index' mode only) what's the port of the target server? (default: 8080)")
205
+ parser.add_option("-s", "--skip", dest="skip", default="",
206
+ help="skip these tables ('index' mode only) - use '|' as separator, such as 'table1|table2|table3' (default: none)")
207
+ parser.add_option("-i", "--index", dest="index", default=0,
208
+ help="start with this index ('index' mode only) (default: 0)")
209
+ options, args = parser.parse_args()
210
+
211
+ log("mode: %s"%(options.mode,), important=True)
212
+ if options.mode == "refcount":
213
+ refcount()
214
+ elif options.mode == "index":
215
+ index(options.domain, int(options.port),
216
+ options.skip and options.skip.split("|") or [], options.index)
217
+ elif options.mode == "urlsafekeys":
218
+ urlsafe()
219
+ elif options.mode == "cleanup":
220
+ cleanup()
221
+ else:
222
+ error("unknown mode: %s"%(options.mode,))
223
+ log("goodbye")
224
+
225
+ if __name__ == "__main__":
226
+ go()