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
cantools/util/data.py ADDED
@@ -0,0 +1,109 @@
1
+ def getxls(data, name=None, parse=True):
2
+ import xlrd, datetime
3
+ wb = xlrd.open_workbook(file_contents=data)
4
+ s = wb.sheet_by_name(name or wb.sheet_names()[0])
5
+ if not parse:
6
+ return s
7
+ d = [[c.value for c in s.row(0)]]
8
+ for r in range(1, s.nrows):
9
+ row = s.row(r)
10
+ rl = []
11
+ for c in row:
12
+ if c.ctype == 3: # date
13
+ rl.append(datetime.datetime(*xlrd.xldate_as_tuple(c.value, wb.datemode)))
14
+ else:
15
+ rl.append(c.value)
16
+ d.append(rl)
17
+ return d
18
+
19
+ def _svlines(data):
20
+ return data.replace("\r\n", "\n").replace("\r", "\n").split("\n")
21
+
22
+ def gettsv(data):
23
+ return [l.split("\t") for l in _svlines(data) if l]
24
+
25
+ def getcsv_from_data(data, unquote=False): # deprecated! doesn't work _that_ well.
26
+ return [[unquote and i.strip('"') or i for i in l.split(",")] for l in _svlines(data) if l]
27
+
28
+ # eh, module reads it better sometimes (especially if we write(_svlines(read())) first)
29
+ def getcsv(fname):
30
+ import csv
31
+ d = []
32
+ f = open(fname, "r")
33
+ reader = csv.reader(f)
34
+ for row in reader:
35
+ d.append(row)
36
+ f.close()
37
+ return d
38
+
39
+ def flatten(obj):
40
+ keys = []
41
+ vals = []
42
+ for key, val in list(obj.items()):
43
+ if isinstance(val, dict):
44
+ subkeys, subvals = flatten(val)
45
+ for subkey in subkeys:
46
+ fullsubkey = "%s.%s"%(key, subkey)
47
+ if fullsubkey not in keys:
48
+ keys.append(fullsubkey)
49
+ vals += subvals
50
+ else:
51
+ if key not in keys:
52
+ keys.append(key)
53
+ vals.append(val)
54
+ return keys, vals
55
+
56
+ def arr2csv(arr):
57
+ return "\n".join([",".join(flatten(arr[0])[0])] + [",".join([str(i) for i in flatten(obj)[1]]) for obj in arr])
58
+
59
+ def token(n=10):
60
+ import random, string
61
+ samp = string.ascii_letters + string.digits
62
+ pop = len(samp)
63
+ s = ""
64
+ while n:
65
+ chunk = min(n, pop)
66
+ s += "".join(random.sample(samp, chunk))
67
+ n -= chunk
68
+ return s
69
+
70
+ # below (props, drower, tsv) for tsv dumping
71
+ def props(mod):
72
+ from model import db
73
+ s = db.get_schema(mod)
74
+ return filter(lambda p : p not in mod._data_omit and p not in ["index",
75
+ "key"] and not p.startswith("_") and s[p] != "blob", s.keys())
76
+
77
+ def dcell(e, p):
78
+ v = getattr(e, p)
79
+ t = e._schema[p]
80
+ if t == "key":
81
+ v = v and v.get().labeler() or None
82
+ elif t == "keylist":
83
+ from model import db
84
+ v = v and [i.labeler() for i in db.get_multi(v)] or []
85
+ return '"%s"'%(str(v),)
86
+
87
+ def drower(e, pz):
88
+ return map(lambda p : dcell(e, p), pz)
89
+
90
+ def rgen(ents, pz, rower=None):
91
+ rower = rower or drower
92
+ return [pz] + map(lambda e : rower(e, pz), ents)
93
+
94
+ def tsv(ents, pz, rower=None):
95
+ return "\n".join(map(lambda r : "\t".join(r),
96
+ rgen(ents, pz, rower)))
97
+
98
+ def ez2csv(ents, pz, rower=None):
99
+ return "\n".join(map(lambda r : ",".join(r),
100
+ rgen(ents, pz, rower)))
101
+
102
+ def spreadsheet(fmat, ents, pz, rower=None):
103
+ return (fmat == "tsv" and tsv or ez2csv)(ents, pz, rower)
104
+
105
+ def rgb2hex(rgbstr="rgb(224, 62, 45)"):
106
+ return '%02x%02x%02x' % tuple([int(c) for c in rgbstr[4:-1].split(", ")])
107
+
108
+ def hex2rgb(h="#ffaabb"):
109
+ return "rgb%s"%(tuple(int(h[i:i+2], 16) for i in (1, 3, 5)),)
cantools/util/media.py ADDED
@@ -0,0 +1,303 @@
1
+ from __future__ import absolute_import # for io.BytesIO
2
+ from io import BytesIO
3
+ import os, magic
4
+ from fyg.util import log, read, write, rm
5
+ from .system import cmd, output, cp, mkdir
6
+ try:
7
+ from PIL import Image
8
+ except:
9
+ pass#print("no PIL.Image")
10
+
11
+ #
12
+ # general
13
+ #
14
+ _ii = 0
15
+ def get(url, ext="jpg", pref=""):
16
+ global _ii
17
+ from cantools.web import fetch
18
+ _ii += 1
19
+ f = "%s%s.%s"%(pref, _ii, ext)
20
+ cp(fetch(url), f)
21
+ return f
22
+
23
+ def dl(ilist, ext="jpg", pref=""):
24
+ fnames = []
25
+ for url in read(ilist).split("\n"):
26
+ if " " in url:
27
+ fnames.append([get(u, ext, pref) for u in url.split(" ")])
28
+ else:
29
+ fnames.append(get(url, ext, pref))
30
+ return fnames
31
+
32
+ def o2f(outname, inames, ext="jpg", pref=""):
33
+ if outname.endswith(".list"):
34
+ inames = dl(outname, ext, pref)
35
+ outname = outname.split(".").pop(0)
36
+ return outname, inames
37
+
38
+ #
39
+ # video (ffmpeg)
40
+ #
41
+
42
+ def dlp(url, opath=None, tarform="mp4", size="+size"):
43
+ ytc = "yt-dlp -f %s -S %s"%(tarform, size)
44
+ if opath:
45
+ ytc = "%s -o %s"%(ytc, opath)
46
+ cmd("%s %s"%(ytc, url))
47
+
48
+ def thumb(vname, src=".", dest=".", vext="mp4", forceDest=False, overwrite=False):
49
+ if "." in vname:
50
+ vpath = vname
51
+ vname = vname.split(".")[0]
52
+ else:
53
+ vpath = "%s/%s.%s"%(src, vname, vext)
54
+ dpath = os.path.join(dest, vname.rsplit("/", 1)[0])
55
+ dname = "%s/%s.jpg"%(dest, vname)
56
+ if forceDest:
57
+ os.path.isdir(dpath) or mkdir(dpath, True)
58
+ if overwrite or not os.path.exists(dname):
59
+ cmd('ffmpeg -i %s -vf "thumbnail" -frames:v 1 %s'%(vpath, dname))
60
+
61
+ def concat(outname, *vnames):
62
+ outname, vnames = o2f(outname, vnames, "mp4")
63
+ flist = "\n".join(map(lambda vn : "file %s"%(vn,), vnames))
64
+ cp(flist, "files.list")
65
+ cmd("ffmpeg -f concat -i files.list -c copy %s.mp4"%(outname,))
66
+
67
+ TRANS = "ffmpeg -y -i %s -loglevel error -stats -c:a aac -movflags +faststart -f mp4 _tmp"
68
+ BASELINE = "ffmpeg -y -i %s -loglevel error -stats -c:a aac -profile:v baseline -level 3.0 -movflags +faststart -f mp4 _tmp"
69
+ SLOW = "ffmpeg -y -i %s -loglevel error -stats -c:v libx264 -preset veryslow -c:a aac -movflags +faststart -f mp4 _tmp"
70
+ FAST = "ffmpeg -y -i %s -loglevel error -stats -c:v copy -c:a copy -movflags +faststart -f mp4 _tmp"
71
+ #SEG = "ffmpeg -i %s -loglevel error -stats -map 0 -codec:v libx264 -codec:a aac -f ssegment -segment_list %s/list.m3u8 -segment_list_flags +live -segment_time 10 %s/%%03d.ts"
72
+ SEG = 'ffmpeg -i %s -loglevel error -stats -c:v libx264 -c:a copy -r 30 -x264opts "keyint=60:min-keyint=60" -forced-idr 1 -f ssegment -segment_list %s/list.m3u8 -segment_time 10 %s/%%03d.ts'
73
+ MOOV = "ffmpeg -v trace -i %s 2>&1 | grep -e \"'mdat' parent\" -e \"'moov' parent\""
74
+
75
+ def shouldMoveMoov(fpath):
76
+ return "moov" in output(MOOV%(fpath,)).split("\n").pop()
77
+
78
+ def transcode(orig, tmp=False, fast=True, slow=False, baseline=False):
79
+ if tmp: # orig is _data_, not _path_
80
+ log("media.transcode > writing to tmp file", 1)
81
+ data = orig
82
+ orig = "_tctmp"
83
+ write(data, orig, binary=True)
84
+ log("media.transcode > optimizing for mobile (%s)"%(orig,), 1)
85
+ cmd((baseline and BASELINE or slow and SLOW or fast and FAST or TRANS)%(orig,))
86
+ data = read(binary=True)
87
+ if not tmp:
88
+ log("media.transcode > overwriting original; removing tmp file", 1)
89
+ write(data, orig, binary=True)
90
+ rm("_tmp")
91
+ if tmp:
92
+ rm(orig)
93
+ return data
94
+
95
+ def segment(orig, p):
96
+ log("media.segment > segmenting to %s (hls)"%(p,), 1)
97
+ cmd(SEG%(orig, p, p))
98
+
99
+ def hlsify(blobpath, check=False):
100
+ p = blobpath.replace("blob/", "blob/hls/")
101
+ isd = os.path.isdir(p)
102
+ if check:
103
+ return isd
104
+ if not isd:
105
+ log("transcode > attempt with video: '%s'"%(blobpath,), important=True)
106
+ mkdir(p, True)
107
+ segment(blobpath, p)
108
+ log("transcode > done!")
109
+
110
+ #
111
+ # audio (ffmpeg)
112
+ #
113
+
114
+ def repitch(fname, pitch, ext="mp3"):
115
+ log("repitch(%s, %s, %s)"%(pitch, fname, ext))
116
+ cmd('ffmpeg -i %s.%s -af "rubberband=pitch=%s" %s-tmp.%s'%(fname,
117
+ ext, pitch, fname, ext))
118
+ cmd("mv %s-tmp.%s %s.%s"%(fname, ext, fname, ext))
119
+
120
+ def mp3ize(ext=".wav", path="."):
121
+ fnames = os.listdir(path)
122
+ log("you asked for it! scanning %s files for %s"%(len(fnames), ext), important=True)
123
+ for fname in fnames:
124
+ if fname.endswith(ext):
125
+ cmd('ffmpeg -i "%s" "%s.mp3"'%(fname, fname[:-4]))
126
+
127
+ #
128
+ # images (identify, convert, montage, PIL)
129
+ #
130
+
131
+ class Tiler(object):
132
+ def __init__(self, images, outname, vertical=True):
133
+ self.vertical = vertical
134
+ self.outname = outname
135
+ self.images = images
136
+ self.final = []
137
+ self.geos = {}
138
+ self.reduce()
139
+ self.assess()
140
+ self.resize()
141
+
142
+ def dims(self, ipath):
143
+ xy = output("identify %s"%(ipath,)).split(" ")[2].split("x")
144
+ return {
145
+ "x": int(xy[0]),
146
+ "y": int(xy[1])
147
+ }
148
+
149
+ def reduce(self):
150
+ for i in range(len(self.images)):
151
+ iline = self.images[i]
152
+ if type(iline) == list:
153
+ newname = "".join([n.split(".").pop(0) for n in iline])
154
+ Tiler(iline, newname, not self.vertical).render()
155
+ self.images[i] = "%s.jpg"%(newname,)
156
+
157
+ def assess(self):
158
+ dim = self.vertical and "x" or "y"
159
+ self.smallest = None
160
+ for image in self.images:
161
+ self.geos[image] = self.dims(image)
162
+ if not self.smallest or self.geos[image][dim] < self.geos[self.smallest][dim]:
163
+ self.smallest = image
164
+
165
+ def _resizer(self):
166
+ sdim = str(self.geos[self.smallest][self.vertical and "x" or "y"])
167
+ resizer = ['convert "%s" -resize']
168
+ resizer.append(self.vertical and sdim or ("x" + sdim))
169
+ resizer.append('"%s"')
170
+ return " ".join(resizer)
171
+
172
+ def resize(self):
173
+ resizer = self._resizer()
174
+ for image in self.images:
175
+ if image == self.smallest:
176
+ self.final.append(image)
177
+ else:
178
+ sname = image.replace(".jpg", "s.jpg")
179
+ cmd(resizer%(image, sname))
180
+ self.final.append(sname)
181
+
182
+ def _renderer(self):
183
+ montager = ['montage "%s" -geometry +2+2']
184
+ self.vertical and montager.append("-tile 1x")
185
+ montager.append('"%s.jpg"')
186
+ return " ".join(montager)
187
+
188
+ def render(self):
189
+ cmd(self._renderer()%('" "'.join(self.final), self.outname))
190
+
191
+ def autotile(outname, vertical=True, inames=[]):
192
+ outname, inames = o2f(outname, inames)
193
+ Tiler(inames or os.listdir(), outname, vertical).render()
194
+
195
+ def vtile(outname, *inames):
196
+ autotile(outname, inames=inames)
197
+
198
+ def htile(outname, *inames):
199
+ autotile(outname, False, inames)
200
+
201
+ def crop(img, constraint):
202
+ w = img.size[0]
203
+ h = img.size[1]
204
+ smaller = min(w, h)
205
+ if smaller == w: # clean these up...
206
+ fromx = 0
207
+ tox = w
208
+ fromy = (h - w) / 2.0
209
+ toy = fromy + w
210
+ else:
211
+ fromy = 0
212
+ toy = h
213
+ fromx = (w - h) / 2.0
214
+ tox = fromx + h
215
+ return img.crop((int(fromx), int(fromy), int(tox),
216
+ int(toy))).resize((constraint, constraint), Image.ANTIALIAS)
217
+
218
+ def jpgize(path, fromform=None, overwrite=False):
219
+ opath = path
220
+ if not overwrite and input("overwrite %s? [Y/n] "%(path,)).lower().startswith("n"):
221
+ opath = input("ok, what should we call the output file? ")
222
+ if fromform == "TIFF":
223
+ Image.open(BytesIO(read(path, binary=True))).save(opath, format="JPEG")
224
+ else:
225
+ cmd("convert %s tmp.jpg; mv tmp.jpg %s"%(path, opath))
226
+
227
+ _p2 = []
228
+ class ImageResizer(object):
229
+ def __init__(self, img):
230
+ self.img = img
231
+ self.high = max(img.size)
232
+ [self.width, self.height] = img.size
233
+ log("loaded with size: %sx%s"%img.size)
234
+
235
+ def closest(self, n):
236
+ for p in _p2:
237
+ if n >= p:
238
+ return p
239
+
240
+ def s2p2(self):
241
+ divisor = self.high / self.closest(self.high)
242
+ return (self.closest(self.width / divisor), self.closest(self.height / divisor))
243
+
244
+ def resize(self):
245
+ dims = self.s2p2()
246
+ log("resizing to: %sx%s"%dims)
247
+ rimg = self.img.resize(dims)
248
+ with BytesIO() as outbytes:
249
+ rimg.save(outbytes, format=self.img.format)
250
+ return outbytes.getvalue()
251
+
252
+ def _initp2():
253
+ if not _p2:
254
+ n = 16
255
+ while n <= 1024:
256
+ _p2.append(n)
257
+ n *= 2
258
+ _p2.reverse()
259
+
260
+ def resizep2(data):
261
+ _initp2()
262
+ return ImageResizer(Image.open(BytesIO(data))).resize()
263
+
264
+ def p2(path, overwrite=False):
265
+ opath = path
266
+ resized = resizep2(read(path, binary=True))
267
+ if not overwrite and input("overwrite %s? [Y/n] "%(path,)).lower().startswith("n"):
268
+ opath = input("ok, what should we call the output file? ")
269
+ write(resized, opath, binary=True)
270
+
271
+ def imeta(f, silent=False):
272
+ _initp2()
273
+ magstr = magic.from_file(f)
274
+ if "image" not in magstr:
275
+ return
276
+ fm = magstr.split(" ").pop(0)
277
+ d = {}
278
+ m = {
279
+ "format": fm,
280
+ "dims": d
281
+ }
282
+ w = None
283
+ h = None
284
+ if fm == "JPEG":
285
+ [w, h] = magstr.split(", ")[-2].split("x")
286
+ elif fm == "PNG":
287
+ [w, h] = magstr.split(", ")[1].split(" x ")
288
+ elif fm == "TIFF":
289
+ parts = magstr.split("=")
290
+ [w, h] = [parts[-1], parts[2].split(", ").pop(0)]
291
+ if w:
292
+ d["width"] = w = int(w)
293
+ d["height"] = h = int(h)
294
+ m["p2"] = w in _p2 and h in _p2
295
+ silent or log(m)
296
+ return m
297
+
298
+ def scanp2(overwrite=False):
299
+ for f in os.listdir():
300
+ m = imeta(f, True)
301
+ if m:
302
+ print(f, m)
303
+ overwrite and not m["p2"] and p2(f)
@@ -0,0 +1,125 @@
1
+ import os, sys, sysconfig, importlib
2
+ from cantools.util import cmd, log, pymod, read, write
3
+
4
+ def managedpip():
5
+ fname = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED")
6
+ print("checking for", fname)
7
+ isext = os.path.isfile(fname)
8
+ print("found:", isext)
9
+ return isext
10
+
11
+ def virtenv():
12
+ invenv = sys.prefix != sys.base_prefix
13
+ print("virtual environment:", invenv)
14
+ return invenv
15
+
16
+ def pipper(execute=False, force=False):
17
+ p = "pip install -e ."
18
+ valid = True
19
+ notvenv = not virtenv()
20
+ if managedpip() and notvenv:
21
+ log("your Python is externally managed by your OS")
22
+ if force or input("install anyway? [y/N] ").lower().startswith("y"):
23
+ p += " --break-system-packages --use-pep517"
24
+ else:
25
+ valid = False
26
+ def dopip():
27
+ if valid:
28
+ pymod(p, notvenv)
29
+ else:
30
+ log("pip skip!")
31
+ if execute:
32
+ dopip()
33
+ else:
34
+ log(p)
35
+ return dopip
36
+
37
+ def pushv(version):
38
+ cmd("git add -u")
39
+ cmd('git commit -m "vpush %s"'%(version,))
40
+ cmd("git push")
41
+
42
+ def upv(oldver, newver, pname, fnames=None):
43
+ fnames = fnames or [
44
+ "setup.py",
45
+ "about.txt",
46
+ os.path.join(pname, "__init__.py"),
47
+ os.path.join(pname, "version.py"),
48
+ ]
49
+ for fname in fnames:
50
+ if os.path.exists(fname):
51
+ log("updating: %s"%(fname,), 1)
52
+ txt = read(fname)
53
+ if fname == "setup.py": # extra careful
54
+ txt = txt.replace('version="%s"'%(oldver,), 'version="%s"'%(newver,))
55
+ else:
56
+ txt = txt.replace(oldver, newver)
57
+ write(txt, fname)
58
+
59
+ def incv(curver):
60
+ log("current version: %s"%(curver,))
61
+ vnumz = [int(n) for n in curver.split(".")]
62
+ while len(vnumz) < 4:
63
+ vnumz.append(0)
64
+ vnumz[-1] += 1
65
+ minor = ".".join([str(n) for n in vnumz])
66
+ vnumz[-2] += 1
67
+ major = ".".join([str(n) for n in vnumz[:-1]])
68
+ log("How should we increment? You have three options:", important=True)
69
+ log("Major ('M' - %s)"%(major,), 1)
70
+ log("Minor ('m' - %s)"%(minor,), 1)
71
+ log("Custom ('c')", 1)
72
+ selection = input("So? (M/m/c - default: m): ")
73
+ if selection == "c":
74
+ version = input("ok, then. what's the new version #? ")
75
+ elif selection == "M":
76
+ version = major
77
+ else: # default (minor)
78
+ version = minor
79
+ log("going with: %s"%(version,), important=True)
80
+ return version
81
+
82
+ def pwheel(pname, version, withCheese=False):
83
+ log("laying egg (universal py2/3 wheel)", important=True)
84
+ pymod("build -n", True)
85
+ if withCheese or input("push to cheese shop? [N/y] ").lower().startswith("y"):
86
+ log("pushing to cheese shop", important=True)
87
+ cmd("twine upload dist/%s-%s-py3-none-any.whl"%(pname, version))
88
+
89
+ def here():
90
+ return os.path.abspath(".").split(os.path.sep)[-1]
91
+
92
+ def getmod():
93
+ h = here()
94
+ return os.path.isdir(h) and h or input("module name? ")
95
+
96
+ def getver(modname=None):
97
+ v = importlib.import_module(modname or getmod()).__version__
98
+ print(v)
99
+ return v
100
+
101
+ def vpush(modname=None, packname=None, curver=None, doxxer=None):
102
+ modname = modname or getmod()
103
+ curver = curver or getver(modname)
104
+ log("vpushin %s!"%(modname,), important=True)
105
+ version = incv(curver)
106
+ upv(curver, version, modname)
107
+ if doxxer:
108
+ doxxer()
109
+ elif input("generate documentation? [y/N] ").lower().startswith("y"):
110
+ cmd("ctdoc")
111
+ else:
112
+ print("okay, i'll just update your README.md directly")
113
+ upv(curver, version, modname, ["README.md"])
114
+ pushv(version)
115
+ pwheel(packname or modname, version)
116
+ log("we did it (%s -> %s)!"%(curver, version), important=True)
117
+
118
+ def refresh_plugins():
119
+ pcmd = pipper()
120
+ def refresher():
121
+ cmd("git pull")
122
+ pcmd()
123
+ from cantools.util.admin import plugdirs
124
+ plugdirs(refresher, input("search directory? [default: .ctplug] ") or ".ctplug",
125
+ input("filter by preface? [suggested: ct] "))
@@ -0,0 +1,73 @@
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
7
+
8
+ def cp(content, fname): # more write than copy, buuuut...
9
+ log("writing %s"%(fname,), 2)
10
+ write(content, fname, binary=hasattr(content, "decode"))
11
+
12
+ def _init_win_sym():
13
+ def win_sym(src, dest):
14
+ mode = os.path.isdir(src) and "J" or "H"
15
+ cmd("mklink /%s %s %s"%(mode, dest, src))
16
+ os.symlink = win_sym
17
+
18
+ def sym(src, dest, safe=False):
19
+ log("symlinking %s to %s"%(src, dest), 2)
20
+ if not hasattr(os, "symlink"):
21
+ _init_win_sym()
22
+ try:
23
+ os.symlink(src, dest)
24
+ except Exception as e:
25
+ log("symlinking failed (%s) - file exists: %s"%(e, dest), 3)
26
+ if not safe:
27
+ try:
28
+ rm(dest)
29
+ sym(src, dest, True)
30
+ except:
31
+ log("ok, really failed - skipping", 3)
32
+
33
+ def mkdir(pname, recursive=False):
34
+ log("new directory: %s"%(pname,), 2)
35
+ if recursive:
36
+ os.makedirs(pname)
37
+ else:
38
+ os.mkdir(pname)
39
+
40
+ def sed(fname, flag, replacement, target=None):
41
+ write(read(fname).replace(flag, replacement), target or fname)
42
+
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
+ def envget(name):
61
+ return output("echo $%s"%(name,))
62
+
63
+ def envset(name, val):
64
+ os.environ[name] = val
65
+ #cmd("export %s=%s"%(name, val))
66
+
67
+ PYVER = sys.version_info[0] == 2 and "python" or "python3"
68
+
69
+ def py(cline, sudo=False):
70
+ cmd("%s %s"%(PYVER, cline), sudo)
71
+
72
+ def pymod(mod, sudo=False):
73
+ py("-m %s"%(mod,), sudo)
@@ -0,0 +1,9 @@
1
+ from .util import config
2
+
3
+ if config.web.server == "gae":
4
+ from .gae_server import *
5
+ elif config.web.server == "dez":
6
+ from cantools.web.dez_server import *
7
+ else:
8
+ from cantools import util
9
+ util.error("no web server specified")
@@ -0,0 +1 @@
1
+ from .server import *