Source code for panoptes_client.subject
from __future__ import absolute_import, division, print_function
_OLD_STR_TYPES = (str,)
try:
_OLD_STR_TYPES = _OLD_STR_TYPES + (unicode,)
except NameError:
pass
from builtins import range, str
import requests
import time
try:
import magic
MEDIA_TYPE_DETECTION = 'magic'
except ImportError:
import imghdr
MEDIA_TYPE_DETECTION = 'imghdr'
from panoptes_client.panoptes import PanoptesObject, LinkResolver
UPLOAD_RETRY_LIMIT = 5
RETRY_BACKOFF_INTERVAL = 5
[docs]class Subject(PanoptesObject):
_api_slug = 'subjects'
_link_slug = 'subjects'
_edit_attributes = (
'locations',
'metadata',
{
'links': (
'project',
),
},
)
def __init__(self, raw={}, etag=None):
super(Subject, self).__init__(raw, etag)
if not self.locations:
self.locations = []
if not self.metadata:
self.metadata = {}
self._media_files = []
[docs] def save(self):
"""
Like :py:meth:`.PanoptesObject.save`, but also uploads any local files
which have previosly been added to the subject with
:py:meth:`add_location`. Automatically retries uploads on error.
"""
response = super(Subject, self).save()
for location, media_data in zip(
response['subjects'][0]['locations'],
self._media_files
):
if not media_data:
continue
for media_type, url in location.items():
for attempt in range(UPLOAD_RETRY_LIMIT):
try:
upload_response = requests.put(
url,
headers={
'Content-Type': media_type,
},
data=media_data,
)
upload_response.raise_for_status()
break
except requests.exceptions.RequestException:
if (attempt + 1) >= UPLOAD_RETRY_LIMIT:
raise
else:
time.sleep(attempt * RETRY_BACKOFF_INTERVAL)
[docs] def add_location(self, location):
"""
Add a media location to this subject.
- **location** can be an open :py:class:`file` object, a path to a
local file, or a :py:class:`dict` containing MIME types and URLs for
remote media.
Examples::
subject.add_location(my_file)
subject.add_location('/data/image.jpg')
subject.add_location({'image/png': 'https://example.com/image.png'})
"""
if type(location) is dict:
self.locations.append(location)
self._media_files.append(None)
return
elif type(location) in (str,) + _OLD_STR_TYPES:
f = open(location, 'rb')
else:
f = location
try:
media_data = f.read()
if MEDIA_TYPE_DETECTION == 'magic':
media_type = magic.from_buffer(media_data, mime=True)
else:
media_type = 'image/{}'.format(imghdr.what(None, media_data))
self.locations.append(media_type)
self._media_files.append(media_data)
finally:
f.close()
LinkResolver.register(Subject)
LinkResolver.register(Subject, 'subject')