Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.mdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ Some useful direct links within this section are below:
* [Reference: Filter Syntax](https://github.com/shotgunsoftware/python-api/wiki/Reference%3A-Filter-Syntax)

## Changelog
**v3.0.6 - 2010 Jan 25**
**v3.0.7 - 2011 Apr 04**

+ fix: update() method should return a dict object not a list

**v3.0.6 - 2011 Jan 25**

+ optimization: don't request paging_info unless required (and server support is available)

Expand Down
66 changes: 41 additions & 25 deletions shotgun_api3.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
# https://support.shotgunsoftware.com/forums/48807-developer-api-info
# ---------------------------------------------------------------------------------------------

__version__ = "3.0.6"
__version__ = "3.0.7"

# ---------------------------------------------------------------------------------------------
# SUMMARY
Expand All @@ -51,14 +51,16 @@
- make file fields an http link to the file
- add logging functionality
- add scrubbing to text data sent to server to make sure it is all valid unicode
- support removing thumbnails / files (can only create or replace them now)
"""

# ---------------------------------------------------------------------------------------------
# CHANGELOG
# ---------------------------------------------------------------------------------------------
"""
+v3.0.6 - 2010 Jan 25
+v3.0.7 - 2011 Apr 04
+ fix: update() method should return a dict object not a list

+v3.0.6 - 2011 Jan 25
+ optimization: don't request paging_info unless required (and server support is available)

+v3.0.5 - 2010 Dec 20
Expand Down Expand Up @@ -240,7 +242,7 @@ def _inject_field_values(self, records):

for i,r in enumerate(records):
# skip results that aren't entity dictionaries
if type(r) is not dict:
if not hasattr(r, '__getitem__') or not hasattr(r, 'items'):
continue

# iterate over each item and check each field for possible injection
Expand All @@ -249,8 +251,9 @@ def _inject_field_values(self, records):
if k == 'image' and v:
records[i]['image'] = self._get_thumb_url(r['type'], r['id'])

if type(v) == dict and 'link_type' in v and v['link_type'] == 'local' \
and self.platform and self.local_path_string in r[k]:
if (hasattr(v, '__iter__') and hasattr(v, '__getitem__') and
'link_type' in v and v['link_type'] == 'local' and
self.platform and self.local_path_string in r[k]):
records[i][k]['local_path'] = r[k][self.local_path_string]
records[i][k]['url'] = "file://%s" % (r[k]['local_path'])

Expand Down Expand Up @@ -357,7 +360,7 @@ def find(self, entity_type, filters, fields=None, order=None, filter_operator=No
if order == None:
order = []

if type(filters) == type([]):
if hasattr(filters, '__iter__'):
new_filters = {}
if not filter_operator or filter_operator == "all":
new_filters["logical_operator"] = "and"
Expand All @@ -370,7 +373,7 @@ def find(self, entity_type, filters, fields=None, order=None, filter_operator=No

filters = new_filters
elif filter_operator:
raise ShotgunError("Deprecated: Use of filter_operator for find() is not valid any more. See the documention on find()")
raise ShotgunError("Deprecated: Use of filter_operator for find() is not valid in this context. See the documention on find()")

if retired_only:
return_only = 'retired'
Expand Down Expand Up @@ -398,7 +401,7 @@ def find(self, entity_type, filters, fields=None, order=None, filter_operator=No
sort['direction'] = 'asc'
req['sorts'].append({'field_name': sort['field_name'],'direction' : sort['direction']})

if type(limit) != int or limit < 0:
if not isinstance(limit, int) or limit < 0:
raise ValueError("find() 'limit' parameter must be a positive integer")
elif (limit and limit > 0 and limit <= self.records_per_page):
req["paging"]["entities_per_page"] = limit
Expand All @@ -411,12 +414,12 @@ def find(self, entity_type, filters, fields=None, order=None, filter_operator=No
records = []

# if page is specified, then only return the page of records requested
if type(page) != int or page < 0:
if not isinstance(page, int) or page < 0:
raise ValueError("find() 'page' parameter must be a positive integer")
elif page != 0:
# No paging_info needed, so optimize it out.
if self.supports_paging_info:
req["return_paging_info"] = False
req["return_paging_info"] = False

req["paging"]["current_page"] = page
resp = self._api3.read(req)
Expand Down Expand Up @@ -459,8 +462,8 @@ def _required_keys(self, message, required_keys, data):
raise ShotgunError("%s missing required key: %s. Value was: %s." % (message, ", ".join(missing), data))

def batch(self, requests):
if type(requests) != type([]):
raise ShotgunError("batch() expects a list. Instead was sent a %s"%type(requests))
if not hasattr(requests, '__iter__'):
raise ShotgunError("batch() expects an iterable. A %s is not iterable." % type(requests))

reqs = []

Expand Down Expand Up @@ -549,8 +552,8 @@ def update(self, entity_type, entity_id, data):
args["fields"].append( {"field_name":f,"value":v} )

resp = self._api3.update(args)
records = self._inject_field_values([resp["results"]])
return records
record = self._inject_field_values([resp["results"]])[0]
return record

def delete(self, entity_type, entity_id):
"""
Expand Down Expand Up @@ -1488,13 +1491,21 @@ def dumps(self, values):
return result

def __dump(self, value, write):
try:
f = self.dispatch[type(value)]
except KeyError:
raise TypeError, "cannot marshal %s objects" % type(value)
else:
f(self, value, write)

# Try to get the dispatch function directly by looking at the type
dispatchFunction = self.dispatch.get(type(value))

# If the exact type isn't in the dispatch table, identify subtypes
if dispatchFunction is None:
for dispatchType, dispatchFunction in self.dispatch.items():
if isinstance(value, dispatchType):
break
else:
# The value isn't an instance of any registered types
raise TypeError, "cannot marshal %s objects" % type(value)

# We found a function through type lookup or subtype search
dispatchFunction(self, value, write)

def dump_nil (self, value, write):
if not self.allow_none:
raise TypeError, "cannot marshal None unless allow_none is enabled"
Expand Down Expand Up @@ -1568,8 +1579,8 @@ def dump_struct(self, value, write, escape=escape):
write("<value><struct>\n")
for k, v in value.items():
write("<member>\n")
if type(k) is not StringType:
if unicode and type(k) is UnicodeType:
if not isinstance(k, StringType):
if unicode and isinstance(k, UnicodeType):
k = k.encode(self.encoding)
else:
raise TypeError, "dictionary key must be string"
Expand Down Expand Up @@ -2053,7 +2064,12 @@ def request(self, host, handler, request_body, verbose=0):
try:
return self.single_request(host, handler, request_body, verbose)
except socket.error, e:
if i >= 10 or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
# not all socket errors have errno attributes. Specifically, if the socket times out
# the resulting error is a socket.sslerror which does not.
if hasattr(e, 'errno'):
if i >= 10 or e.errno not in (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE):
raise
else:
raise
except httplib.BadStatusLine: #close after we sent request
if i >= 10:
Expand Down