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.
- cantools/__init__.py +24 -0
- cantools/_db.py +142 -0
- cantools/_memcache.py +76 -0
- cantools/_pay.py +46 -0
- cantools/admin.py +31 -0
- cantools/cfg.py +347 -0
- cantools/config.py +131 -0
- cantools/db/__init__.py +18 -0
- cantools/db/admin.py +27 -0
- cantools/db/gae/__init__.py +0 -0
- cantools/db/gae/model.py +127 -0
- cantools/db/gae/properties.py +35 -0
- cantools/db/wp.py +99 -0
- cantools/geo.py +188 -0
- cantools/hooks.py +13 -0
- cantools/scripts/__init__.py +0 -0
- cantools/scripts/bench.py +167 -0
- cantools/scripts/builder.py +272 -0
- cantools/scripts/deploy.py +154 -0
- cantools/scripts/doc.py +239 -0
- cantools/scripts/index.py +226 -0
- cantools/scripts/init.py +345 -0
- cantools/scripts/migrate.py +593 -0
- cantools/scripts/pubsub/__init__.py +28 -0
- cantools/scripts/pubsub/actor.py +13 -0
- cantools/scripts/pubsub/bots.py +143 -0
- cantools/scripts/pubsub/channel.py +85 -0
- cantools/scripts/pubsub/ps.py +145 -0
- cantools/scripts/pubsub/user.py +51 -0
- cantools/scripts/start.py +53 -0
- cantools/scripts/util.py +24 -0
- cantools/util/__init__.py +78 -0
- cantools/util/admin.py +620 -0
- cantools/util/data.py +109 -0
- cantools/util/media.py +303 -0
- cantools/util/package.py +125 -0
- cantools/util/system.py +73 -0
- cantools/web/__init__.py +9 -0
- cantools/web/dez_server/__init__.py +1 -0
- cantools/web/dez_server/controller.py +129 -0
- cantools/web/dez_server/cron.py +115 -0
- cantools/web/dez_server/daemons.py +64 -0
- cantools/web/dez_server/mail.py +24 -0
- cantools/web/dez_server/response.py +63 -0
- cantools/web/dez_server/routes.py +21 -0
- cantools/web/dez_server/server.py +229 -0
- cantools/web/dez_server/sms.py +12 -0
- cantools/web/gae_server.py +68 -0
- cantools/web/util.py +552 -0
- ct-0.10.8.114.dist-info/LICENSE +9 -0
- ct-0.10.8.114.dist-info/METADATA +25 -0
- ct-0.10.8.114.dist-info/RECORD +55 -0
- ct-0.10.8.114.dist-info/WHEEL +5 -0
- ct-0.10.8.114.dist-info/entry_points.txt +10 -0
- 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)
|
cantools/util/package.py
ADDED
|
@@ -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] "))
|
cantools/util/system.py
ADDED
|
@@ -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)
|
cantools/web/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .server import *
|