@@ -74,15 +74,6 @@ def _listen_on_attribute(cls, attribute, coerce, parent_cls):
74
74
StoreManager .observe_attribute (attribute )
75
75
super ()._listen_on_attribute (attribute , coerce , parent_cls )
76
76
77
- @classmethod
78
- def _assert_type (cls , value ) -> None :
79
- """
80
- Checking attachment type, raising :exc:`TypeError` if the value is not derived from :class:`.Attachment`.
81
-
82
- """
83
- if not isinstance (value , cls ):
84
- raise TypeError ('Value type must be subclass of %s, but it\' s: %s' % (cls , type (value )))
85
-
86
77
@classmethod
87
78
def coerce (cls , key , value ) -> 'Attachment' :
88
79
"""
@@ -91,15 +82,19 @@ def coerce(cls, key, value) -> 'Attachment':
91
82
.. seealso:: :meth:`sqlalchemy.ext.mutable.MutableDict.coerce`
92
83
93
84
"""
94
- if value is not None and not isinstance (value , dict ):
95
- try :
96
- cls ._assert_type (value )
97
- except TypeError :
98
- if cls .__auto_coercion__ :
99
- return cls .create_from (value )
100
- raise
85
+ if value is None or isinstance (value , (cls , dict )):
86
+ return super ().coerce (key , value )
101
87
102
- return super ().coerce (key , value )
88
+ if cls .__auto_coercion__ :
89
+ if not isinstance (value , (tuple , list )):
90
+ value = (value , )
91
+
92
+ return cls .create_from (* value )
93
+
94
+ raise TypeError (
95
+ 'Value type must be subclass of %s or a tuple(file, mime, [filename]),'
96
+ 'but it\' s: %s' % (cls , type (value ))
97
+ )
103
98
104
99
@classmethod
105
100
def create_from (cls , * args , ** kwargs ):
@@ -168,7 +163,7 @@ def path(self) -> str:
168
163
def filename (self ) -> str :
169
164
"""
170
165
The filename used to store the attachment in the storage with this format::
171
-
166
+
172
167
'{self.__prefix__}-{self.key}{self.suffix}{if self.extension else ''}'
173
168
174
169
:type: str
@@ -250,14 +245,14 @@ def reproducible(self) -> bool:
250
245
def copy (self ) -> 'Attachment' :
251
246
"""
252
247
Copy this object using deepcopy.
253
-
248
+
254
249
"""
255
250
return self .__class__ (copy .deepcopy (self ))
256
251
257
252
def get_store (self ) -> Store :
258
253
"""
259
254
Returns the :class:`sqlalchemy_media.stores.Store` instance, which this file is stored on.
260
-
255
+
261
256
"""
262
257
store_manager = StoreManager .get_current_store_manager ()
263
258
return store_manager .get (self .store_id )
@@ -269,7 +264,7 @@ def delete(self) -> None:
269
264
.. warning:: This operation can not be roll-backed.So if you want to delete a file, just set it to
270
265
:const:`None` or set it by new :class:`.Attachment` instance, while passed ``delete_orphan=True``
271
266
in :class:`.StoreManager`.
272
-
267
+
273
268
"""
274
269
self .get_store ().delete (self .path )
275
270
@@ -319,7 +314,7 @@ def attach(self, attachable: Attachable, content_type: str = None, original_file
319
314
320
315
:param attachable: file-like object, filename or URL to attach.
321
316
:param content_type: If given, the content-detection is suppressed.
322
- :param original_filename: Original name of the file, if available, to append to the end of the the filename,
317
+ :param original_filename: Original name of the file, if available, to append to the end of the the filename,
323
318
useful for SEO, and readability.
324
319
:param extension: The file's extension, is available.else, tries to guess it by content_type
325
320
:param store_id: The store id to store this file on. Stores must be registered with appropriate id via
@@ -427,13 +422,13 @@ def get_objects_to_delete(self):
427
422
428
423
def get_orphaned_objects (self ):
429
424
"""
430
- this method will be always called by the store when adding the ``self`` to the orphaned list. so subclasses
431
- of the :class:`.Attachment` has a chance to add other related objects into the orphaned list and schedule it
432
- for delete. for example the :class:`.Image` class can schedule it's thumbnails for deletion also.
425
+ this method will be always called by the store when adding the ``self`` to the orphaned list. so subclasses
426
+ of the :class:`.Attachment` has a chance to add other related objects into the orphaned list and schedule it
427
+ for delete. for example the :class:`.Image` class can schedule it's thumbnails for deletion also.
433
428
:return: An iterable of :class:`.Attachment` to mark as orphan.
434
-
429
+
435
430
.. versionadded:: 0.11.0
436
-
431
+
437
432
"""
438
433
return iter ([])
439
434
@@ -477,18 +472,18 @@ class Person(BaseModel):
477
472
def observe_item (self , item ):
478
473
"""
479
474
A simple monkeypatch to instruct the children to notify the parent if contents are changed:
480
-
475
+
481
476
From `sqlalchemy mutable documentation:
482
477
<http://docs.sqlalchemy.org/en/latest/orm/extensions/mutable.html#sqlalchemy.ext.mutable.MutableList>`_
483
-
484
- Note that MutableList does not apply mutable tracking to the values themselves inside the list. Therefore
485
- it is not a sufficient solution for the use case of tracking deep changes to a recursive mutable structure,
486
- such as a JSON structure. To support this use case, build a subclass of MutableList that provides
487
- appropriate coercion to the values placed in the dictionary so that they too are “mutable”, and emit events
478
+
479
+ Note that MutableList does not apply mutable tracking to the values themselves inside the list. Therefore
480
+ it is not a sufficient solution for the use case of tracking deep changes to a recursive mutable structure,
481
+ such as a JSON structure. To support this use case, build a subclass of MutableList that provides
482
+ appropriate coercion to the values placed in the dictionary so that they too are “mutable”, and emit events
488
483
up to their parent structure.
489
-
484
+
490
485
:param item: The item to observe
491
- :return:
486
+ :return:
492
487
"""
493
488
item = self .__item_type__ .coerce (None , item )
494
489
item ._parents = self ._parents
@@ -574,7 +569,7 @@ class Person(BaseModel):
574
569
me = Person()
575
570
me.files = MyDict()
576
571
me.files['original'] = MyAttachment.create_from(any_file)
577
-
572
+
578
573
"""
579
574
580
575
@classmethod
@@ -627,7 +622,7 @@ def __setitem__(self, key, value):
627
622
class File (Attachment ):
628
623
"""
629
624
Representing an attached file. Normally if you want to store any file, this class is the best choice.
630
-
625
+
631
626
"""
632
627
633
628
__directory__ = 'files'
@@ -675,7 +670,7 @@ def attach(self, *args, dimension: Dimension=None, **kwargs):
675
670
:param kwargs: The same as the: :meth:`.Attachment.attach`.
676
671
677
672
:return: The same as the: :meth:`.Attachment.attach`.
678
-
673
+
679
674
"""
680
675
if dimension :
681
676
kwargs ['width' ], kwargs ['height' ] = dimension
@@ -854,9 +849,9 @@ def get_objects_to_delete(self):
854
849
855
850
def get_orphaned_objects (self ):
856
851
"""
857
- Mark thumbnails for deletion when the :class:`.Image` is being deleted.
852
+ Mark thumbnails for deletion when the :class:`.Image` is being deleted.
858
853
:return: An iterable of :class:`.Thumbnail` to mark as orphan.
859
-
854
+
860
855
.. versionadded:: 0.11.0
861
856
862
857
"""
@@ -870,7 +865,7 @@ def get_orphaned_objects(self):
870
865
class ImageList (AttachmentList ):
871
866
"""
872
867
Used to create a collection of :class:`.Image`es
873
-
868
+
874
869
.. versionadded:: 0.11.0
875
870
"""
876
871
0 commit comments