appier 1.31.4__py2.py3-none-any.whl → 1.32.0__py2.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.
- appier/__init__.py +333 -52
- appier/amqp.py +29 -30
- appier/api.py +214 -212
- appier/asgi.py +54 -55
- appier/async_neo.py +46 -35
- appier/async_old.py +55 -42
- appier/asynchronous.py +7 -13
- appier/base.py +1762 -1429
- appier/bus.py +51 -52
- appier/cache.py +99 -84
- appier/common.py +9 -11
- appier/component.py +17 -19
- appier/compress.py +25 -28
- appier/config.py +96 -73
- appier/controller.py +9 -15
- appier/crypt.py +25 -21
- appier/data.py +73 -57
- appier/defines.py +191 -226
- appier/exceptions.py +103 -63
- appier/execution.py +94 -88
- appier/export.py +90 -88
- appier/extra.py +6 -13
- appier/extra_neo.py +8 -11
- appier/extra_old.py +18 -16
- appier/geo.py +57 -47
- appier/git.py +101 -90
- appier/graph.py +23 -24
- appier/http.py +520 -398
- appier/legacy.py +373 -180
- appier/log.py +90 -97
- appier/meta.py +42 -42
- appier/mock.py +32 -34
- appier/model.py +793 -681
- appier/model_a.py +208 -183
- appier/mongo.py +183 -107
- appier/observer.py +39 -31
- appier/part.py +23 -24
- appier/preferences.py +44 -47
- appier/queuing.py +78 -96
- appier/redisdb.py +40 -35
- appier/request.py +227 -175
- appier/scheduler.py +13 -18
- appier/serialize.py +37 -31
- appier/session.py +161 -147
- appier/settings.py +2 -11
- appier/smtp.py +53 -49
- appier/storage.py +39 -33
- appier/structures.py +50 -45
- appier/test/__init__.py +2 -11
- appier/test/base.py +111 -108
- appier/test/cache.py +28 -35
- appier/test/config.py +10 -19
- appier/test/crypt.py +3 -12
- appier/test/data.py +3 -12
- appier/test/exceptions.py +8 -17
- appier/test/export.py +16 -33
- appier/test/graph.py +27 -60
- appier/test/http.py +42 -54
- appier/test/legacy.py +20 -30
- appier/test/log.py +14 -35
- appier/test/mock.py +27 -123
- appier/test/model.py +79 -91
- appier/test/part.py +5 -14
- appier/test/preferences.py +5 -13
- appier/test/queuing.py +29 -37
- appier/test/request.py +61 -73
- appier/test/serialize.py +12 -23
- appier/test/session.py +10 -19
- appier/test/smtp.py +8 -14
- appier/test/structures.py +20 -24
- appier/test/typesf.py +14 -28
- appier/test/util.py +480 -438
- appier/typesf.py +251 -171
- appier/util.py +578 -407
- appier/validation.py +280 -143
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/METADATA +6 -1
- appier-1.32.0.dist-info/RECORD +86 -0
- appier-1.31.4.dist-info/RECORD +0 -86
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/LICENSE +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/WHEEL +0 -0
- {appier-1.31.4.dist-info → appier-1.32.0.dist-info}/top_level.txt +0 -0
appier/typesf.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
4
|
# Hive Appier Framework
|
|
5
|
-
# Copyright (c) 2008-
|
|
5
|
+
# Copyright (c) 2008-2024 Hive Solutions Lda.
|
|
6
6
|
#
|
|
7
7
|
# This file is part of Hive Appier Framework.
|
|
8
8
|
#
|
|
@@ -22,16 +22,7 @@
|
|
|
22
22
|
__author__ = "João Magalhães <joamag@hive.pt>"
|
|
23
23
|
""" The author(s) of the module """
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
""" The version of the module """
|
|
27
|
-
|
|
28
|
-
__revision__ = "$LastChangedRevision$"
|
|
29
|
-
""" The revision number of the module """
|
|
30
|
-
|
|
31
|
-
__date__ = "$LastChangedDate$"
|
|
32
|
-
""" The last change date of the module """
|
|
33
|
-
|
|
34
|
-
__copyright__ = "Copyright (c) 2008-2022 Hive Solutions Lda."
|
|
25
|
+
__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda."
|
|
35
26
|
""" The copyright for the module """
|
|
36
27
|
|
|
37
28
|
__license__ = "Apache License, Version 2.0"
|
|
@@ -48,16 +39,16 @@ from . import common
|
|
|
48
39
|
from . import storage
|
|
49
40
|
from . import exceptions
|
|
50
41
|
|
|
51
|
-
class AbstractType(object):
|
|
52
42
|
|
|
43
|
+
class AbstractType(object):
|
|
53
44
|
def json_v(self, *args, **kwargs):
|
|
54
45
|
return str(self)
|
|
55
46
|
|
|
56
47
|
def map_v(self, *args, **kwargs):
|
|
57
48
|
return self.json_v()
|
|
58
49
|
|
|
59
|
-
class Type(AbstractType):
|
|
60
50
|
|
|
51
|
+
class Type(AbstractType):
|
|
61
52
|
def __init__(self, value):
|
|
62
53
|
cls = self.__class__
|
|
63
54
|
self.loads(value)
|
|
@@ -71,14 +62,19 @@ class Type(AbstractType):
|
|
|
71
62
|
def dumps(self):
|
|
72
63
|
raise exceptions.NotImplementedError()
|
|
73
64
|
|
|
74
|
-
class File(AbstractType):
|
|
75
65
|
|
|
66
|
+
class File(AbstractType):
|
|
76
67
|
def __init__(self, file):
|
|
77
|
-
if isinstance(file, legacy.BYTES):
|
|
78
|
-
|
|
79
|
-
elif isinstance(file,
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
if isinstance(file, legacy.BYTES):
|
|
69
|
+
self.build_d(file)
|
|
70
|
+
elif isinstance(file, dict):
|
|
71
|
+
self.build_b64(file)
|
|
72
|
+
elif isinstance(file, tuple):
|
|
73
|
+
self.build_t(file)
|
|
74
|
+
elif isinstance(file, File):
|
|
75
|
+
self.build_i(file)
|
|
76
|
+
else:
|
|
77
|
+
self.build_f(file)
|
|
82
78
|
|
|
83
79
|
def __repr__(self):
|
|
84
80
|
return "<File: %s>" % self.file_name
|
|
@@ -89,7 +85,7 @@ class File(AbstractType):
|
|
|
89
85
|
def __len__(self):
|
|
90
86
|
return self.size
|
|
91
87
|
|
|
92
|
-
def build_d(self, file_d, name
|
|
88
|
+
def build_d(self, file_d, name="default"):
|
|
93
89
|
self.build_t((name, None, file_d))
|
|
94
90
|
|
|
95
91
|
def build_b64(self, file_m):
|
|
@@ -180,13 +176,13 @@ class File(AbstractType):
|
|
|
180
176
|
|
|
181
177
|
self._load()
|
|
182
178
|
|
|
183
|
-
def read(self, size
|
|
179
|
+
def read(self, size=None):
|
|
184
180
|
engine = self._engine()
|
|
185
|
-
return engine.read(self, size
|
|
181
|
+
return engine.read(self, size=size)
|
|
186
182
|
|
|
187
|
-
def seek(self, offset
|
|
183
|
+
def seek(self, offset=None):
|
|
188
184
|
engine = self._engine()
|
|
189
|
-
return engine.seek(self, offset
|
|
185
|
+
return engine.seek(self, offset=offset)
|
|
190
186
|
|
|
191
187
|
def delete(self):
|
|
192
188
|
engine = self._engine()
|
|
@@ -197,19 +193,21 @@ class File(AbstractType):
|
|
|
197
193
|
return engine.cleanup(self)
|
|
198
194
|
|
|
199
195
|
def json_v(self, *args, **kwargs):
|
|
200
|
-
if not self.is_valid():
|
|
196
|
+
if not self.is_valid():
|
|
197
|
+
return None
|
|
201
198
|
store = kwargs.get("store", True)
|
|
202
|
-
if store:
|
|
199
|
+
if store:
|
|
200
|
+
self._store()
|
|
203
201
|
data = self.data_b64 if self.is_stored() else None
|
|
204
202
|
return dict(
|
|
205
|
-
name
|
|
206
|
-
data
|
|
207
|
-
hash
|
|
208
|
-
mime
|
|
209
|
-
etag
|
|
210
|
-
guid
|
|
211
|
-
params
|
|
212
|
-
engine
|
|
203
|
+
name=self.file_name,
|
|
204
|
+
data=data,
|
|
205
|
+
hash=self.hash,
|
|
206
|
+
mime=self.mime,
|
|
207
|
+
etag=self.etag,
|
|
208
|
+
guid=self.guid,
|
|
209
|
+
params=self.params,
|
|
210
|
+
engine=self.engine,
|
|
213
211
|
)
|
|
214
212
|
|
|
215
213
|
def is_seekable(self):
|
|
@@ -227,13 +225,15 @@ class File(AbstractType):
|
|
|
227
225
|
return self.size <= 0
|
|
228
226
|
|
|
229
227
|
def _hash(self, data):
|
|
230
|
-
if not data:
|
|
228
|
+
if not data:
|
|
229
|
+
return None
|
|
231
230
|
hash = hashlib.sha256(data)
|
|
232
231
|
digest = hash.hexdigest()
|
|
233
232
|
return digest
|
|
234
233
|
|
|
235
234
|
def _etag(self, data):
|
|
236
|
-
if not data:
|
|
235
|
+
if not data:
|
|
236
|
+
return None
|
|
237
237
|
hash = hashlib.md5(data)
|
|
238
238
|
digest = hash.hexdigest()
|
|
239
239
|
return digest
|
|
@@ -241,13 +241,13 @@ class File(AbstractType):
|
|
|
241
241
|
def _guid(self):
|
|
242
242
|
return str(uuid.uuid4())
|
|
243
243
|
|
|
244
|
-
def _load(self, force
|
|
244
|
+
def _load(self, force=False):
|
|
245
245
|
engine = self._engine()
|
|
246
|
-
engine.load(self, force
|
|
246
|
+
engine.load(self, force=force)
|
|
247
247
|
|
|
248
|
-
def _store(self, force
|
|
248
|
+
def _store(self, force=False):
|
|
249
249
|
engine = self._engine()
|
|
250
|
-
engine.store(self, force
|
|
250
|
+
engine.store(self, force=force)
|
|
251
251
|
|
|
252
252
|
def _compute(self):
|
|
253
253
|
"""
|
|
@@ -266,14 +266,17 @@ class File(AbstractType):
|
|
|
266
266
|
self.etag = self._etag(self.data)
|
|
267
267
|
|
|
268
268
|
def _engine(self):
|
|
269
|
-
if not self.engine:
|
|
269
|
+
if not self.engine:
|
|
270
|
+
return storage.BaseEngine
|
|
270
271
|
return getattr(storage, self.engine.capitalize() + "Engine")
|
|
271
272
|
|
|
272
|
-
class Files(AbstractType):
|
|
273
273
|
|
|
274
|
+
class Files(AbstractType):
|
|
274
275
|
def __init__(self, files):
|
|
275
|
-
if isinstance(files, Files):
|
|
276
|
-
|
|
276
|
+
if isinstance(files, Files):
|
|
277
|
+
self.build_i(files)
|
|
278
|
+
else:
|
|
279
|
+
self.build_f(files)
|
|
277
280
|
|
|
278
281
|
def __repr__(self):
|
|
279
282
|
return "<Files: %d files>" % len(self._files)
|
|
@@ -296,10 +299,12 @@ class Files(AbstractType):
|
|
|
296
299
|
def build_f(self, files):
|
|
297
300
|
self._files = []
|
|
298
301
|
base = self.base()
|
|
299
|
-
if not type(files) == list:
|
|
302
|
+
if not type(files) == list:
|
|
303
|
+
files = [files]
|
|
300
304
|
for file in files:
|
|
301
305
|
_file = base(file)
|
|
302
|
-
if not _file.is_valid():
|
|
306
|
+
if not _file.is_valid():
|
|
307
|
+
continue
|
|
303
308
|
self._files.append(_file)
|
|
304
309
|
|
|
305
310
|
def json_v(self, *args, **kwargs):
|
|
@@ -309,10 +314,11 @@ class Files(AbstractType):
|
|
|
309
314
|
return len(self._files) == 0
|
|
310
315
|
|
|
311
316
|
def _load(self):
|
|
312
|
-
for file in self._files:
|
|
317
|
+
for file in self._files:
|
|
318
|
+
file._load()
|
|
313
319
|
|
|
314
|
-
class ImageFile(File):
|
|
315
320
|
|
|
321
|
+
class ImageFile(File):
|
|
316
322
|
def build_b64(self, file_m):
|
|
317
323
|
File.build_b64(self, file_m)
|
|
318
324
|
self.width = file_m.get("width", 0)
|
|
@@ -338,13 +344,11 @@ class ImageFile(File):
|
|
|
338
344
|
self._ensure_all()
|
|
339
345
|
|
|
340
346
|
def json_v(self, *args, **kwargs):
|
|
341
|
-
if not self.is_valid():
|
|
347
|
+
if not self.is_valid():
|
|
348
|
+
return None
|
|
342
349
|
value = File.json_v(self, *args, **kwargs)
|
|
343
350
|
value.update(
|
|
344
|
-
width = self.
|
|
345
|
-
height = self.height,
|
|
346
|
-
format = self.format,
|
|
347
|
-
kwargs = self.kwargs
|
|
351
|
+
width=self.width, height=self.height, format=self.format, kwargs=self.kwargs
|
|
348
352
|
)
|
|
349
353
|
return value
|
|
350
354
|
|
|
@@ -354,30 +358,46 @@ class ImageFile(File):
|
|
|
354
358
|
self._ensure_kwargs()
|
|
355
359
|
|
|
356
360
|
def _ensure_size(self):
|
|
357
|
-
if
|
|
358
|
-
hasattr(self, "
|
|
361
|
+
if (
|
|
362
|
+
hasattr(self, "width")
|
|
363
|
+
and self.width
|
|
364
|
+
and hasattr(self, "height")
|
|
365
|
+
and self.height
|
|
366
|
+
):
|
|
367
|
+
return
|
|
359
368
|
self.width, self.height = self._size()
|
|
360
369
|
|
|
361
370
|
def _ensure_mime(self):
|
|
362
|
-
if
|
|
363
|
-
hasattr(self, "
|
|
371
|
+
if (
|
|
372
|
+
hasattr(self, "format")
|
|
373
|
+
and self.format
|
|
374
|
+
and hasattr(self, "mime")
|
|
375
|
+
and self.mime
|
|
376
|
+
):
|
|
377
|
+
return
|
|
364
378
|
self.format, self.mime = self._mime()
|
|
365
379
|
|
|
366
380
|
def _ensure_kwargs(self):
|
|
367
|
-
if hasattr(self, "kwargs"):
|
|
381
|
+
if hasattr(self, "kwargs"):
|
|
382
|
+
return
|
|
368
383
|
self.kwargs = dict()
|
|
369
384
|
|
|
370
385
|
def _size(self):
|
|
371
|
-
try:
|
|
372
|
-
|
|
386
|
+
try:
|
|
387
|
+
return self._size_image()
|
|
388
|
+
except Exception:
|
|
389
|
+
return self._size_default()
|
|
373
390
|
|
|
374
391
|
def _size_image(self):
|
|
375
|
-
if self.data:
|
|
376
|
-
|
|
392
|
+
if self.data:
|
|
393
|
+
return self._size_pil()
|
|
394
|
+
else:
|
|
395
|
+
return self._size_default()
|
|
377
396
|
|
|
378
397
|
def _size_pil(self):
|
|
379
|
-
util.ensure_pip("PIL", package
|
|
398
|
+
util.ensure_pip("PIL", package="pillow")
|
|
380
399
|
import PIL.Image
|
|
400
|
+
|
|
381
401
|
buffer = legacy.BytesIO(self.data)
|
|
382
402
|
try:
|
|
383
403
|
image = PIL.Image.open(buffer)
|
|
@@ -390,16 +410,21 @@ class ImageFile(File):
|
|
|
390
410
|
return (0, 0)
|
|
391
411
|
|
|
392
412
|
def _mime(self):
|
|
393
|
-
try:
|
|
394
|
-
|
|
413
|
+
try:
|
|
414
|
+
return self._mime_image()
|
|
415
|
+
except Exception:
|
|
416
|
+
return self._mime_default()
|
|
395
417
|
|
|
396
418
|
def _mime_image(self):
|
|
397
|
-
if self.data:
|
|
398
|
-
|
|
419
|
+
if self.data:
|
|
420
|
+
return self._mime_pil()
|
|
421
|
+
else:
|
|
422
|
+
return self._mime_default()
|
|
399
423
|
|
|
400
424
|
def _mime_pil(self):
|
|
401
|
-
util.ensure_pip("PIL", package
|
|
425
|
+
util.ensure_pip("PIL", package="pillow")
|
|
402
426
|
import PIL.Image
|
|
427
|
+
|
|
403
428
|
buffer = legacy.BytesIO(self.data)
|
|
404
429
|
try:
|
|
405
430
|
image = PIL.Image.open(buffer)
|
|
@@ -412,15 +437,14 @@ class ImageFile(File):
|
|
|
412
437
|
def _mime_default(self):
|
|
413
438
|
return None, "application/octet-stream"
|
|
414
439
|
|
|
415
|
-
class ImageFiles(Files):
|
|
416
440
|
|
|
441
|
+
class ImageFiles(Files):
|
|
417
442
|
def base(self):
|
|
418
443
|
return ImageFile
|
|
419
444
|
|
|
420
|
-
def image(width = None, height = None, format = "png", **kwargs):
|
|
421
445
|
|
|
446
|
+
def image(width=None, height=None, format="png", **kwargs):
|
|
422
447
|
class _ImageFile(ImageFile):
|
|
423
|
-
|
|
424
448
|
RGB_FORMATS = ("jpg", "jpeg")
|
|
425
449
|
""" The set of format that are considered to be
|
|
426
450
|
RGB based and should be handled with special care """
|
|
@@ -431,18 +455,20 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
431
455
|
# verifies if there's valid data in the current file
|
|
432
456
|
# if that's not the case there's nothing remaining to
|
|
433
457
|
# be done (not going to process the file)
|
|
434
|
-
if not self.data_b64:
|
|
458
|
+
if not self.data_b64:
|
|
459
|
+
return
|
|
435
460
|
|
|
436
461
|
# determines if a resize operation is required for the
|
|
437
462
|
# current image data, if that's not the case returns the
|
|
438
463
|
# control flow immediately (nothing to be done)
|
|
439
464
|
need_resize = self.need_resize(
|
|
440
|
-
width_o
|
|
441
|
-
height_o
|
|
442
|
-
format_o
|
|
443
|
-
kwargs_o
|
|
465
|
+
width_o=self.width,
|
|
466
|
+
height_o=self.height,
|
|
467
|
+
format_o=self.format,
|
|
468
|
+
kwargs_o=self.kwargs,
|
|
444
469
|
)
|
|
445
|
-
if not need_resize:
|
|
470
|
+
if not need_resize:
|
|
471
|
+
return
|
|
446
472
|
|
|
447
473
|
# decodes the base 64 based data and then runs the resize
|
|
448
474
|
# operation with the current data re-encoding it back to
|
|
@@ -468,7 +494,8 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
468
494
|
# different values from the ones contained in data
|
|
469
495
|
# theses should be update by the "ensure" methods
|
|
470
496
|
for name in ("width", "height", "format"):
|
|
471
|
-
if name in file_m:
|
|
497
|
+
if name in file_m:
|
|
498
|
+
del file_m[name]
|
|
472
499
|
|
|
473
500
|
# runs the rebuilding of the information taking into
|
|
474
501
|
# account the new information from the file
|
|
@@ -481,8 +508,10 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
481
508
|
|
|
482
509
|
# tries to run the resize operation to ensure that
|
|
483
510
|
# the proper size and format is present in the data
|
|
484
|
-
try:
|
|
485
|
-
|
|
511
|
+
try:
|
|
512
|
+
_data = self.resize(data) if data else data
|
|
513
|
+
except Exception:
|
|
514
|
+
_data = data
|
|
486
515
|
|
|
487
516
|
# updates the parameters attributes in the instance so
|
|
488
517
|
# that the new file is marked with proper values
|
|
@@ -493,15 +522,17 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
493
522
|
file_t = (name, content_type, _data)
|
|
494
523
|
ImageFile.build_t(self, file_t)
|
|
495
524
|
|
|
496
|
-
def resize(self, data
|
|
497
|
-
util.ensure_pip("PIL", package
|
|
525
|
+
def resize(self, data=None):
|
|
526
|
+
util.ensure_pip("PIL", package="pillow")
|
|
498
527
|
import PIL.Image
|
|
499
528
|
|
|
500
529
|
data = data or self.data
|
|
501
|
-
if not data:
|
|
530
|
+
if not data:
|
|
531
|
+
return data
|
|
502
532
|
|
|
503
533
|
is_resized = True if width or height else False
|
|
504
|
-
if not is_resized:
|
|
534
|
+
if not is_resized:
|
|
535
|
+
return data
|
|
505
536
|
|
|
506
537
|
params = kwargs.get("params", {})
|
|
507
538
|
background = kwargs.get("background", "ffffff")
|
|
@@ -522,27 +553,28 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
522
553
|
return data
|
|
523
554
|
|
|
524
555
|
def need_resize(
|
|
525
|
-
self,
|
|
526
|
-
width_o = None,
|
|
527
|
-
height_o = None,
|
|
528
|
-
format_o = None,
|
|
529
|
-
kwargs_o = None
|
|
556
|
+
self, width_o=None, height_o=None, format_o=None, kwargs_o=None
|
|
530
557
|
):
|
|
531
|
-
if width and not width == width_o:
|
|
532
|
-
|
|
533
|
-
if
|
|
534
|
-
|
|
558
|
+
if width and not width == width_o:
|
|
559
|
+
return True
|
|
560
|
+
if height and not height == height_o:
|
|
561
|
+
return True
|
|
562
|
+
if format and not format == format_o:
|
|
563
|
+
return True
|
|
564
|
+
if kwargs and not kwargs == kwargs_o:
|
|
565
|
+
return True
|
|
535
566
|
return False
|
|
536
567
|
|
|
537
|
-
def _resize(self, image, size):
|
|
538
|
-
util.ensure_pip("PIL", package
|
|
568
|
+
def _resize(self, image, size, resample=None):
|
|
569
|
+
util.ensure_pip("PIL", package="pillow")
|
|
539
570
|
import PIL.Image
|
|
540
571
|
|
|
541
572
|
# unpacks the provided tuple containing the size dimension into the
|
|
542
573
|
# with and the height an in case one of these values is not defined
|
|
543
574
|
# an error is raises indicating the problem
|
|
544
575
|
width, height = size
|
|
545
|
-
if not height and not width:
|
|
576
|
+
if not height and not width:
|
|
577
|
+
raise AttributeError("invalid values")
|
|
546
578
|
|
|
547
579
|
# retrieves the size of the loaded image and uses the values to calculate
|
|
548
580
|
# the aspect ration of the provided image, this value is going to be
|
|
@@ -553,8 +585,10 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
553
585
|
# in case one of the size dimensions has not been specified
|
|
554
586
|
# it must be calculated from the base values taking into account
|
|
555
587
|
# that the aspect ration should be preserved
|
|
556
|
-
if not height:
|
|
557
|
-
|
|
588
|
+
if not height:
|
|
589
|
+
height = int(image_height * width / float(image_width))
|
|
590
|
+
if not width:
|
|
591
|
+
width = int(image_width * height / float(image_height))
|
|
558
592
|
|
|
559
593
|
# re-constructs the size tuple with the new values for the width
|
|
560
594
|
# the height that have been calculated from the ratios
|
|
@@ -581,11 +615,17 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
581
615
|
|
|
582
616
|
# resizes the already cropped image into the target size using an
|
|
583
617
|
# anti alias based algorithm (default expectations)
|
|
584
|
-
|
|
618
|
+
if resample == None:
|
|
619
|
+
resample = (
|
|
620
|
+
PIL.Image.ANTIALIAS # type: ignore
|
|
621
|
+
if hasattr(PIL.Image, "ANTIALIAS")
|
|
622
|
+
else (PIL.Image.LANCZOS if hasattr(PIL.Image, "LANCZOS") else None) # type: ignore
|
|
623
|
+
)
|
|
624
|
+
image = image.resize(size, resample)
|
|
585
625
|
return image
|
|
586
626
|
|
|
587
627
|
def _format(self, image, format, background):
|
|
588
|
-
util.ensure_pip("PIL", package
|
|
628
|
+
util.ensure_pip("PIL", package="pillow")
|
|
589
629
|
import PIL.Image
|
|
590
630
|
|
|
591
631
|
# retrieves the reference to the top level class that is
|
|
@@ -597,11 +637,13 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
597
637
|
# an RGB only format, if that's not the case there's nothing
|
|
598
638
|
# remaining to be done (no conversion required)
|
|
599
639
|
format = format.lower()
|
|
600
|
-
if not format in cls.RGB_FORMATS:
|
|
640
|
+
if not format in cls.RGB_FORMATS:
|
|
641
|
+
return image
|
|
601
642
|
|
|
602
643
|
# in case the format/mode of the original image is already
|
|
603
644
|
# RGB there's no need to run the conversion process
|
|
604
|
-
if image.mode == "RGB":
|
|
645
|
+
if image.mode == "RGB":
|
|
646
|
+
return image
|
|
605
647
|
|
|
606
648
|
# creates a new RGB based image with the target size and
|
|
607
649
|
# with the provided background and copies it as the target
|
|
@@ -611,33 +653,28 @@ def image(width = None, height = None, format = "png", **kwargs):
|
|
|
611
653
|
|
|
612
654
|
return _ImageFile
|
|
613
655
|
|
|
614
|
-
def images(width = None, height = None, format = "png", **kwargs):
|
|
615
656
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
height = height,
|
|
619
|
-
format = format,
|
|
620
|
-
**kwargs
|
|
621
|
-
)
|
|
657
|
+
def images(width=None, height=None, format="png", **kwargs):
|
|
658
|
+
image_c = image(width=width, height=height, format=format, **kwargs)
|
|
622
659
|
|
|
623
660
|
class _ImageFiles(ImageFiles):
|
|
624
|
-
|
|
625
661
|
def base(self):
|
|
626
662
|
return image_c
|
|
627
663
|
|
|
628
664
|
return _ImageFiles
|
|
629
665
|
|
|
666
|
+
|
|
630
667
|
class Reference(AbstractType):
|
|
631
668
|
pass
|
|
632
669
|
|
|
633
|
-
|
|
670
|
+
|
|
671
|
+
def reference(target, name=None, dumpall=False):
|
|
634
672
|
name = name or "id"
|
|
635
673
|
target_t = type(target)
|
|
636
674
|
is_reference = target_t in legacy.STRINGS
|
|
637
675
|
reserved = ("id", "_target", "_object", "_type", "__dict__")
|
|
638
676
|
|
|
639
677
|
class _Reference(Reference):
|
|
640
|
-
|
|
641
678
|
_name = name
|
|
642
679
|
""" The name of the key (join) attribute for the
|
|
643
680
|
reference that is going to be created, this name
|
|
@@ -645,25 +682,34 @@ def reference(target, name = None, dumpall = False):
|
|
|
645
682
|
|
|
646
683
|
def __init__(self, id):
|
|
647
684
|
self.__start__()
|
|
648
|
-
if isinstance(id, _Reference):
|
|
649
|
-
|
|
650
|
-
|
|
685
|
+
if isinstance(id, _Reference):
|
|
686
|
+
self.build_i(id)
|
|
687
|
+
elif isinstance(id, self._target):
|
|
688
|
+
self.build_o(id)
|
|
689
|
+
else:
|
|
690
|
+
self.build(id)
|
|
651
691
|
|
|
652
692
|
def __str__(self):
|
|
653
693
|
self.resolve()
|
|
654
694
|
has_str = hasattr(self._object, "__str__")
|
|
655
|
-
if has_str:
|
|
656
|
-
|
|
695
|
+
if has_str:
|
|
696
|
+
return self._object.__str__()
|
|
697
|
+
else:
|
|
698
|
+
return str(self._object) or str()
|
|
657
699
|
|
|
658
700
|
def __unicode__(self):
|
|
659
701
|
self.resolve()
|
|
660
702
|
has_unicode = hasattr(self._object, "__unicode__")
|
|
661
|
-
if has_unicode:
|
|
662
|
-
|
|
703
|
+
if has_unicode:
|
|
704
|
+
return self._object.__unicode__()
|
|
705
|
+
else:
|
|
706
|
+
return legacy.UNICODE(self._object) or legacy.UNICODE()
|
|
663
707
|
|
|
664
708
|
def __eq__(self, other):
|
|
665
|
-
if other == None:
|
|
666
|
-
|
|
709
|
+
if other == None:
|
|
710
|
+
return self.id in ("", b"", None)
|
|
711
|
+
if isinstance(other, Reference):
|
|
712
|
+
return self.equals(other)
|
|
667
713
|
return id(self) == id(other)
|
|
668
714
|
|
|
669
715
|
def __ne__(self, other):
|
|
@@ -679,17 +725,20 @@ def reference(target, name = None, dumpall = False):
|
|
|
679
725
|
|
|
680
726
|
def __getattr__(self, name):
|
|
681
727
|
is_magic = name.startswith("__") and name.endswith("__")
|
|
682
|
-
if is_magic:
|
|
728
|
+
if is_magic:
|
|
729
|
+
return Reference.__getattr__(name)
|
|
683
730
|
self.resolve()
|
|
684
731
|
exists = hasattr(self._object, name)
|
|
685
|
-
if exists:
|
|
732
|
+
if exists:
|
|
733
|
+
return getattr(self._object, name)
|
|
686
734
|
raise AttributeError("'%s' not found" % name)
|
|
687
735
|
|
|
688
736
|
def __setattr__(self, name, value):
|
|
689
737
|
# in case the name that is being set is not part of the reserved
|
|
690
738
|
# names for the reference underlying structure the object resolution
|
|
691
739
|
# is triggered to make sure the underlying object exists and is loaded
|
|
692
|
-
if not name in reserved:
|
|
740
|
+
if not name in reserved:
|
|
741
|
+
self.resolve()
|
|
693
742
|
|
|
694
743
|
# verifies if the reference object exists in the current
|
|
695
744
|
# reference instance, that's the case if the object name is
|
|
@@ -697,15 +746,18 @@ def reference(target, name = None, dumpall = False):
|
|
|
697
746
|
# an attribute with the name referred, for those situations
|
|
698
747
|
# defers the setting of the attribute to the reference object
|
|
699
748
|
exists = "_object" in self.__dict__ and hasattr(self._object, name)
|
|
700
|
-
if exists:
|
|
749
|
+
if exists:
|
|
750
|
+
return setattr(self._object, name, value)
|
|
701
751
|
|
|
702
752
|
# otherwise this is a normal attribute setting and the current
|
|
703
753
|
# object's dictionary must be changed so that the new value is set
|
|
704
754
|
self.__dict__[name] = value
|
|
705
755
|
|
|
706
756
|
def __start__(self):
|
|
707
|
-
if is_reference:
|
|
708
|
-
|
|
757
|
+
if is_reference:
|
|
758
|
+
self._target = self.__class__._target()
|
|
759
|
+
else:
|
|
760
|
+
self._target = target
|
|
709
761
|
util.verify(self._target)
|
|
710
762
|
meta = getattr(self._target, name)
|
|
711
763
|
self._type = meta.get("type", legacy.UNICODE)
|
|
@@ -716,20 +768,24 @@ def reference(target, name = None, dumpall = False):
|
|
|
716
768
|
|
|
717
769
|
@classmethod
|
|
718
770
|
def _target(cls):
|
|
719
|
-
if is_reference:
|
|
771
|
+
if is_reference:
|
|
772
|
+
return common.base().APP.get_model(target)
|
|
720
773
|
return target
|
|
721
774
|
|
|
722
775
|
@classmethod
|
|
723
776
|
def _btype(cls):
|
|
724
|
-
if is_reference:
|
|
725
|
-
|
|
777
|
+
if is_reference:
|
|
778
|
+
_target = cls._target()
|
|
779
|
+
else:
|
|
780
|
+
_target = target
|
|
726
781
|
meta = getattr(_target, name)
|
|
727
782
|
return meta.get("type", legacy.UNICODE)
|
|
728
783
|
|
|
729
|
-
def build(self, id, cast
|
|
784
|
+
def build(self, id, cast=True):
|
|
730
785
|
is_unset = id in ("", b"", None)
|
|
731
786
|
cast = cast and not is_unset
|
|
732
|
-
if cast:
|
|
787
|
+
if cast:
|
|
788
|
+
id = self._target.cast(name, id)
|
|
733
789
|
self.id = id
|
|
734
790
|
self._object = None
|
|
735
791
|
|
|
@@ -745,19 +801,23 @@ def reference(target, name = None, dumpall = False):
|
|
|
745
801
|
return self.val()
|
|
746
802
|
|
|
747
803
|
def json_v(self, *args, **kwargs):
|
|
748
|
-
if dumpall:
|
|
804
|
+
if dumpall:
|
|
805
|
+
return self.resolve()
|
|
749
806
|
return self.val()
|
|
750
807
|
|
|
751
808
|
def map_v(self, *args, **kwargs):
|
|
752
809
|
resolve = kwargs.get("resolve", True)
|
|
753
810
|
value = self.resolve() if resolve else self._object
|
|
754
|
-
if resolve and not value:
|
|
755
|
-
|
|
811
|
+
if resolve and not value:
|
|
812
|
+
return value
|
|
813
|
+
if not value:
|
|
814
|
+
return self.val()
|
|
756
815
|
return value.map(*args, **kwargs)
|
|
757
816
|
|
|
758
817
|
def val(self, *args, **kargs):
|
|
759
818
|
is_empty = self.id in ("", b"", None)
|
|
760
|
-
if is_empty:
|
|
819
|
+
if is_empty:
|
|
820
|
+
return None
|
|
761
821
|
return self._type(self.id)
|
|
762
822
|
|
|
763
823
|
def resolve(self, *args, **kwargs):
|
|
@@ -766,7 +826,8 @@ def reference(target, name = None, dumpall = False):
|
|
|
766
826
|
# verifies if it's valid (value is valid) if that's
|
|
767
827
|
# the case returns the current value immediately
|
|
768
828
|
exists = "_object" in self.__dict__
|
|
769
|
-
if exists and self._object:
|
|
829
|
+
if exists and self._object:
|
|
830
|
+
return self._object
|
|
770
831
|
|
|
771
832
|
# verifies if there's an id value currently set in
|
|
772
833
|
# the reference in case it does not exists sets the
|
|
@@ -795,9 +856,12 @@ def reference(target, name = None, dumpall = False):
|
|
|
795
856
|
return _object
|
|
796
857
|
|
|
797
858
|
def equals(self, other):
|
|
798
|
-
if not self.__class__ == other.__class__:
|
|
799
|
-
|
|
800
|
-
if not self.
|
|
859
|
+
if not self.__class__ == other.__class__:
|
|
860
|
+
return False
|
|
861
|
+
if not self._target == other._target:
|
|
862
|
+
return False
|
|
863
|
+
if not self.id == other.id:
|
|
864
|
+
return False
|
|
801
865
|
return True
|
|
802
866
|
|
|
803
867
|
def is_resolved(self):
|
|
@@ -810,17 +874,18 @@ def reference(target, name = None, dumpall = False):
|
|
|
810
874
|
|
|
811
875
|
return _Reference
|
|
812
876
|
|
|
877
|
+
|
|
813
878
|
class References(AbstractType):
|
|
814
879
|
pass
|
|
815
880
|
|
|
816
|
-
|
|
881
|
+
|
|
882
|
+
def references(target, name=None, dumpall=False):
|
|
817
883
|
name = name or "id"
|
|
818
884
|
target_t = type(target)
|
|
819
885
|
is_reference = target_t in legacy.STRINGS
|
|
820
|
-
reference_c = reference(target, name
|
|
886
|
+
reference_c = reference(target, name=name, dumpall=dumpall)
|
|
821
887
|
|
|
822
888
|
class _References(References):
|
|
823
|
-
|
|
824
889
|
_name = name
|
|
825
890
|
""" The name of the key (join) attribute for the
|
|
826
891
|
reference that is going to be created, this name
|
|
@@ -828,8 +893,10 @@ def references(target, name = None, dumpall = False):
|
|
|
828
893
|
|
|
829
894
|
def __init__(self, ids):
|
|
830
895
|
self.__start__()
|
|
831
|
-
if isinstance(ids, _References):
|
|
832
|
-
|
|
896
|
+
if isinstance(ids, _References):
|
|
897
|
+
self.build_i(ids)
|
|
898
|
+
else:
|
|
899
|
+
self.build(ids)
|
|
833
900
|
|
|
834
901
|
def __len__(self):
|
|
835
902
|
return self.objects.__len__()
|
|
@@ -847,8 +914,10 @@ def references(target, name = None, dumpall = False):
|
|
|
847
914
|
return self.contains(item)
|
|
848
915
|
|
|
849
916
|
def __start__(self):
|
|
850
|
-
if is_reference:
|
|
851
|
-
|
|
917
|
+
if is_reference:
|
|
918
|
+
self._target = self.__class__._target()
|
|
919
|
+
else:
|
|
920
|
+
self._target = target
|
|
852
921
|
util.verify(self._target)
|
|
853
922
|
|
|
854
923
|
@classmethod
|
|
@@ -866,7 +935,8 @@ def references(target, name = None, dumpall = False):
|
|
|
866
935
|
def build(self, ids):
|
|
867
936
|
is_valid = not ids == None
|
|
868
937
|
is_iterable = util.is_iterable(ids)
|
|
869
|
-
if is_valid and not is_iterable:
|
|
938
|
+
if is_valid and not is_iterable:
|
|
939
|
+
ids = [ids]
|
|
870
940
|
|
|
871
941
|
self.ids = ids
|
|
872
942
|
self.objects = []
|
|
@@ -883,7 +953,8 @@ def references(target, name = None, dumpall = False):
|
|
|
883
953
|
ids = ids or []
|
|
884
954
|
self.ids = []
|
|
885
955
|
for id in ids:
|
|
886
|
-
if id == "" or id == None:
|
|
956
|
+
if id == "" or id == None:
|
|
957
|
+
continue
|
|
887
958
|
object = reference_c(id)
|
|
888
959
|
object_id = object.id
|
|
889
960
|
self.ids.append(object_id)
|
|
@@ -910,12 +981,12 @@ def references(target, name = None, dumpall = False):
|
|
|
910
981
|
|
|
911
982
|
def find(self, *args, **kwargs):
|
|
912
983
|
kwargs = dict(kwargs)
|
|
913
|
-
kwargs[name] = {"$in"
|
|
984
|
+
kwargs[name] = {"$in": [self._target.cast(name, _id) for _id in self.ids]}
|
|
914
985
|
return self._target.find(*args, **kwargs)
|
|
915
986
|
|
|
916
987
|
def paginate(self, *args, **kwargs):
|
|
917
988
|
kwargs = dict(kwargs)
|
|
918
|
-
kwargs[name] = {"$in"
|
|
989
|
+
kwargs[name] = {"$in": [self._target.cast(name, _id) for _id in self.ids]}
|
|
919
990
|
return self._target.paginate(*args, **kwargs)
|
|
920
991
|
|
|
921
992
|
def is_empty(self):
|
|
@@ -924,7 +995,8 @@ def references(target, name = None, dumpall = False):
|
|
|
924
995
|
|
|
925
996
|
def append(self, id):
|
|
926
997
|
is_object = hasattr(id, self._name)
|
|
927
|
-
if is_object:
|
|
998
|
+
if is_object:
|
|
999
|
+
id = getattr(id, self._name)
|
|
928
1000
|
object = reference_c(id)
|
|
929
1001
|
self.ids.append(id)
|
|
930
1002
|
self.objects.append(object)
|
|
@@ -932,7 +1004,8 @@ def references(target, name = None, dumpall = False):
|
|
|
932
1004
|
|
|
933
1005
|
def remove(self, id):
|
|
934
1006
|
is_object = hasattr(id, self._name)
|
|
935
|
-
if is_object:
|
|
1007
|
+
if is_object:
|
|
1008
|
+
id = getattr(id, self._name)
|
|
936
1009
|
object = self.objects_m[id]
|
|
937
1010
|
self.ids.remove(id)
|
|
938
1011
|
self.objects.remove(object)
|
|
@@ -940,35 +1013,39 @@ def references(target, name = None, dumpall = False):
|
|
|
940
1013
|
|
|
941
1014
|
def contains(self, id):
|
|
942
1015
|
is_object = hasattr(id, self._name)
|
|
943
|
-
if is_object:
|
|
1016
|
+
if is_object:
|
|
1017
|
+
id = getattr(id, self._name)
|
|
944
1018
|
return id in self.objects_m
|
|
945
1019
|
|
|
946
1020
|
def is_resolved(self):
|
|
947
|
-
if not self.objects:
|
|
1021
|
+
if not self.objects:
|
|
1022
|
+
return True
|
|
948
1023
|
return self.objects[0].is_resolved()
|
|
949
1024
|
|
|
950
1025
|
return _References
|
|
951
1026
|
|
|
952
|
-
class Encrypted(AbstractType):
|
|
953
1027
|
|
|
1028
|
+
class Encrypted(AbstractType):
|
|
954
1029
|
PADDING = ":encrypted"
|
|
955
1030
|
|
|
956
|
-
|
|
1031
|
+
|
|
1032
|
+
def encrypted(cipher="spritz", key=None, encoding="utf-8"):
|
|
957
1033
|
key = key or None
|
|
958
1034
|
|
|
959
1035
|
class _Encrypted(Encrypted):
|
|
960
|
-
|
|
961
1036
|
def __init__(self, value):
|
|
962
1037
|
cls = self.__class__
|
|
963
1038
|
util.verify(
|
|
964
|
-
isinstance(value, legacy.ALL_STRINGS) or
|
|
965
|
-
isinstance(value, Encrypted)
|
|
1039
|
+
isinstance(value, legacy.ALL_STRINGS) or isinstance(value, Encrypted)
|
|
966
1040
|
)
|
|
967
1041
|
self.key = key or common.base().APP.crypt_secret
|
|
968
1042
|
self.key = legacy.bytes(self.key)
|
|
969
|
-
if isinstance(value, Encrypted):
|
|
970
|
-
|
|
971
|
-
|
|
1043
|
+
if isinstance(value, Encrypted):
|
|
1044
|
+
self.build_i(value)
|
|
1045
|
+
elif value.endswith(cls.PADDING):
|
|
1046
|
+
self.build_e(value)
|
|
1047
|
+
else:
|
|
1048
|
+
self.build(value)
|
|
972
1049
|
|
|
973
1050
|
def __str__(self):
|
|
974
1051
|
return self.value
|
|
@@ -1001,28 +1078,31 @@ def encrypted(cipher = "spritz", key = None, encoding = "utf-8"):
|
|
|
1001
1078
|
def json_v(self, *args, **kwargs):
|
|
1002
1079
|
return self.encrypted
|
|
1003
1080
|
|
|
1004
|
-
def _encrypt(self, value, strict
|
|
1005
|
-
if not self.key and not strict:
|
|
1081
|
+
def _encrypt(self, value, strict=False):
|
|
1082
|
+
if not self.key and not strict:
|
|
1083
|
+
return value
|
|
1006
1084
|
cls = self.__class__
|
|
1007
|
-
value = legacy.bytes(value, encoding
|
|
1085
|
+
value = legacy.bytes(value, encoding=encoding)
|
|
1008
1086
|
cipher_i = crypt.Cipher.new(cipher, self.key)
|
|
1009
1087
|
encrypted = cipher_i.encrypt(value)
|
|
1010
1088
|
encrypted = base64.b64encode(encrypted)
|
|
1011
|
-
encrypted = legacy.str(encrypted, encoding
|
|
1089
|
+
encrypted = legacy.str(encrypted, encoding=encoding)
|
|
1012
1090
|
return encrypted + cls.PADDING
|
|
1013
1091
|
|
|
1014
|
-
def _decrypt(self, value, strict
|
|
1015
|
-
if not self.key and not strict:
|
|
1092
|
+
def _decrypt(self, value, strict=False):
|
|
1093
|
+
if not self.key and not strict:
|
|
1094
|
+
return value
|
|
1016
1095
|
cls = self.__class__
|
|
1017
1096
|
util.verify(value.endswith(cls.PADDING))
|
|
1018
|
-
value = value[
|
|
1097
|
+
value = value[: -len(cls.PADDING)]
|
|
1019
1098
|
value = legacy.bytes(value)
|
|
1020
1099
|
value = base64.b64decode(value)
|
|
1021
1100
|
cipher_i = crypt.Cipher.new(cipher, self.key)
|
|
1022
1101
|
decrypted = cipher_i.decrypt(value)
|
|
1023
|
-
decrypted = legacy.str(decrypted, encoding
|
|
1102
|
+
decrypted = legacy.str(decrypted, encoding=encoding)
|
|
1024
1103
|
return decrypted
|
|
1025
1104
|
|
|
1026
1105
|
return _Encrypted
|
|
1027
1106
|
|
|
1107
|
+
|
|
1028
1108
|
secure = encrypted()
|