mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-21 03:18:23 +00:00
Added rest framework
This commit is contained in:
100
thirdpart/rest_framework/utils/__init__.py
Normal file
100
thirdpart/rest_framework/utils/__init__.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from django.utils.encoding import smart_unicode
|
||||
from django.utils.xmlutils import SimplerXMLGenerator
|
||||
from rest_framework.compat import StringIO
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
# From xml2dict
|
||||
class XML2Dict(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def _parse_node(self, node):
|
||||
node_tree = {}
|
||||
# Save attrs and text, hope there will not be a child with same name
|
||||
if node.text:
|
||||
node_tree = node.text
|
||||
for (k, v) in node.attrib.items():
|
||||
k, v = self._namespace_split(k, v)
|
||||
node_tree[k] = v
|
||||
#Save childrens
|
||||
for child in node.getchildren():
|
||||
tag, tree = self._namespace_split(child.tag, self._parse_node(child))
|
||||
if tag not in node_tree: # the first time, so store it in dict
|
||||
node_tree[tag] = tree
|
||||
continue
|
||||
old = node_tree[tag]
|
||||
if not isinstance(old, list):
|
||||
node_tree.pop(tag)
|
||||
node_tree[tag] = [old] # multi times, so change old dict to a list
|
||||
node_tree[tag].append(tree) # add the new one
|
||||
|
||||
return node_tree
|
||||
|
||||
def _namespace_split(self, tag, value):
|
||||
"""
|
||||
Split the tag '{http://cs.sfsu.edu/csc867/myscheduler}patients'
|
||||
ns = http://cs.sfsu.edu/csc867/myscheduler
|
||||
name = patients
|
||||
"""
|
||||
result = re.compile("\{(.*)\}(.*)").search(tag)
|
||||
if result:
|
||||
value.namespace, tag = result.groups()
|
||||
return (tag, value)
|
||||
|
||||
def parse(self, file):
|
||||
"""parse a xml file to a dict"""
|
||||
f = open(file, 'r')
|
||||
return self.fromstring(f.read())
|
||||
|
||||
def fromstring(self, s):
|
||||
"""parse a string"""
|
||||
t = ET.fromstring(s)
|
||||
unused_root_tag, root_tree = self._namespace_split(t.tag, self._parse_node(t))
|
||||
return root_tree
|
||||
|
||||
|
||||
def xml2dict(input):
|
||||
return XML2Dict().fromstring(input)
|
||||
|
||||
|
||||
# Piston:
|
||||
class XMLRenderer():
|
||||
def _to_xml(self, xml, data):
|
||||
if isinstance(data, (list, tuple)):
|
||||
for item in data:
|
||||
xml.startElement("list-item", {})
|
||||
self._to_xml(xml, item)
|
||||
xml.endElement("list-item")
|
||||
|
||||
elif isinstance(data, dict):
|
||||
for key, value in data.iteritems():
|
||||
xml.startElement(key, {})
|
||||
self._to_xml(xml, value)
|
||||
xml.endElement(key)
|
||||
|
||||
elif data is None:
|
||||
# Don't output any value
|
||||
pass
|
||||
|
||||
else:
|
||||
xml.characters(smart_unicode(data))
|
||||
|
||||
def dict2xml(self, data):
|
||||
stream = StringIO.StringIO()
|
||||
|
||||
xml = SimplerXMLGenerator(stream, "utf-8")
|
||||
xml.startDocument()
|
||||
xml.startElement("root", {})
|
||||
|
||||
self._to_xml(xml, data)
|
||||
|
||||
xml.endElement("root")
|
||||
xml.endDocument()
|
||||
return stream.getvalue()
|
||||
|
||||
|
||||
def dict2xml(input):
|
||||
return XMLRenderer().dict2xml(input)
|
38
thirdpart/rest_framework/utils/breadcrumbs.py
Normal file
38
thirdpart/rest_framework/utils/breadcrumbs.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from django.core.urlresolvers import resolve, get_script_prefix
|
||||
|
||||
|
||||
def get_breadcrumbs(url):
|
||||
"""Given a url returns a list of breadcrumbs, which are each a tuple of (name, url)."""
|
||||
|
||||
from rest_framework.views import APIView
|
||||
|
||||
def breadcrumbs_recursive(url, breadcrumbs_list, prefix, seen):
|
||||
"""Add tuples of (name, url) to the breadcrumbs list, progressively chomping off parts of the url."""
|
||||
|
||||
try:
|
||||
(view, unused_args, unused_kwargs) = resolve(url)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
# Check if this is a REST framework view, and if so add it to the breadcrumbs
|
||||
if isinstance(getattr(view, 'cls_instance', None), APIView):
|
||||
# Don't list the same view twice in a row.
|
||||
# Probably an optional trailing slash.
|
||||
if not seen or seen[-1] != view:
|
||||
breadcrumbs_list.insert(0, (view.cls_instance.get_name(), prefix + url))
|
||||
seen.append(view)
|
||||
|
||||
if url == '':
|
||||
# All done
|
||||
return breadcrumbs_list
|
||||
|
||||
elif url.endswith('/'):
|
||||
# Drop trailing slash off the end and continue to try to resolve more breadcrumbs
|
||||
return breadcrumbs_recursive(url.rstrip('/'), breadcrumbs_list, prefix, seen)
|
||||
|
||||
# Drop trailing non-slash off the end and continue to try to resolve more breadcrumbs
|
||||
return breadcrumbs_recursive(url[:url.rfind('/') + 1], breadcrumbs_list, prefix, seen)
|
||||
|
||||
prefix = get_script_prefix().rstrip('/')
|
||||
url = url[len(prefix):]
|
||||
return breadcrumbs_recursive(url, [], prefix, [])
|
91
thirdpart/rest_framework/utils/encoders.py
Normal file
91
thirdpart/rest_framework/utils/encoders.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
Helper classes for parsers.
|
||||
"""
|
||||
import datetime
|
||||
import decimal
|
||||
import types
|
||||
from django.utils import simplejson as json
|
||||
from django.utils.datastructures import SortedDict
|
||||
from rest_framework.compat import timezone
|
||||
from rest_framework.serializers import DictWithMetadata, SortedDictWithMetadata
|
||||
|
||||
|
||||
class JSONEncoder(json.JSONEncoder):
|
||||
"""
|
||||
JSONEncoder subclass that knows how to encode date/time,
|
||||
decimal types, and generators.
|
||||
"""
|
||||
def default(self, o):
|
||||
# For Date Time string spec, see ECMA 262
|
||||
# http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
|
||||
if isinstance(o, datetime.datetime):
|
||||
r = o.isoformat()
|
||||
if o.microsecond:
|
||||
r = r[:23] + r[26:]
|
||||
if r.endswith('+00:00'):
|
||||
r = r[:-6] + 'Z'
|
||||
return r
|
||||
elif isinstance(o, datetime.date):
|
||||
return o.isoformat()
|
||||
elif isinstance(o, datetime.time):
|
||||
if timezone and timezone.is_aware(o):
|
||||
raise ValueError("JSON can't represent timezone-aware times.")
|
||||
r = o.isoformat()
|
||||
if o.microsecond:
|
||||
r = r[:12]
|
||||
return r
|
||||
elif isinstance(o, decimal.Decimal):
|
||||
return str(o)
|
||||
elif hasattr(o, '__iter__'):
|
||||
return [i for i in o]
|
||||
return super(JSONEncoder, self).default(o)
|
||||
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
SafeDumper = None
|
||||
else:
|
||||
# Adapted from http://pyyaml.org/attachment/ticket/161/use_ordered_dict.py
|
||||
class SafeDumper(yaml.SafeDumper):
|
||||
"""
|
||||
Handles decimals as strings.
|
||||
Handles SortedDicts as usual dicts, but preserves field order, rather
|
||||
than the usual behaviour of sorting the keys.
|
||||
"""
|
||||
def represent_decimal(self, data):
|
||||
return self.represent_scalar('tag:yaml.org,2002:str', str(data))
|
||||
|
||||
def represent_mapping(self, tag, mapping, flow_style=None):
|
||||
value = []
|
||||
node = yaml.MappingNode(tag, value, flow_style=flow_style)
|
||||
if self.alias_key is not None:
|
||||
self.represented_objects[self.alias_key] = node
|
||||
best_style = True
|
||||
if hasattr(mapping, 'items'):
|
||||
mapping = list(mapping.items())
|
||||
if not isinstance(mapping, SortedDict):
|
||||
mapping.sort()
|
||||
for item_key, item_value in mapping:
|
||||
node_key = self.represent_data(item_key)
|
||||
node_value = self.represent_data(item_value)
|
||||
if not (isinstance(node_key, yaml.ScalarNode) and not node_key.style):
|
||||
best_style = False
|
||||
if not (isinstance(node_value, yaml.ScalarNode) and not node_value.style):
|
||||
best_style = False
|
||||
value.append((node_key, node_value))
|
||||
if flow_style is None:
|
||||
if self.default_flow_style is not None:
|
||||
node.flow_style = self.default_flow_style
|
||||
else:
|
||||
node.flow_style = best_style
|
||||
return node
|
||||
|
||||
SafeDumper.add_representer(SortedDict,
|
||||
yaml.representer.SafeRepresenter.represent_dict)
|
||||
SafeDumper.add_representer(DictWithMetadata,
|
||||
yaml.representer.SafeRepresenter.represent_dict)
|
||||
SafeDumper.add_representer(SortedDictWithMetadata,
|
||||
yaml.representer.SafeRepresenter.represent_dict)
|
||||
SafeDumper.add_representer(types.GeneratorType,
|
||||
yaml.representer.SafeRepresenter.represent_list)
|
87
thirdpart/rest_framework/utils/mediatypes.py
Normal file
87
thirdpart/rest_framework/utils/mediatypes.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""
|
||||
Handling of media types, as found in HTTP Content-Type and Accept headers.
|
||||
|
||||
See http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
|
||||
"""
|
||||
|
||||
from django.http.multipartparser import parse_header
|
||||
|
||||
|
||||
def media_type_matches(lhs, rhs):
|
||||
"""
|
||||
Returns ``True`` if the media type in the first argument <= the
|
||||
media type in the second argument. The media types are strings
|
||||
as described by the HTTP spec.
|
||||
|
||||
Valid media type strings include:
|
||||
|
||||
'application/json; indent=4'
|
||||
'application/json'
|
||||
'text/*'
|
||||
'*/*'
|
||||
"""
|
||||
lhs = _MediaType(lhs)
|
||||
rhs = _MediaType(rhs)
|
||||
return lhs.match(rhs)
|
||||
|
||||
|
||||
def order_by_precedence(media_type_lst):
|
||||
"""
|
||||
Returns a list of sets of media type strings, ordered by precedence.
|
||||
Precedence is determined by how specific a media type is:
|
||||
|
||||
3. 'type/subtype; param=val'
|
||||
2. 'type/subtype'
|
||||
1. 'type/*'
|
||||
0. '*/*'
|
||||
"""
|
||||
ret = [set(), set(), set(), set()]
|
||||
for media_type in media_type_lst:
|
||||
precedence = _MediaType(media_type).precedence
|
||||
ret[3 - precedence].add(media_type)
|
||||
return [media_types for media_types in ret if media_types]
|
||||
|
||||
|
||||
class _MediaType(object):
|
||||
def __init__(self, media_type_str):
|
||||
if media_type_str is None:
|
||||
media_type_str = ''
|
||||
self.orig = media_type_str
|
||||
self.full_type, self.params = parse_header(media_type_str)
|
||||
self.main_type, sep, self.sub_type = self.full_type.partition('/')
|
||||
|
||||
def match(self, other):
|
||||
"""Return true if this MediaType satisfies the given MediaType."""
|
||||
for key in self.params.keys():
|
||||
if key != 'q' and other.params.get(key, None) != self.params.get(key, None):
|
||||
return False
|
||||
|
||||
if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type:
|
||||
return False
|
||||
|
||||
if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def precedence(self):
|
||||
"""
|
||||
Return a precedence level from 0-3 for the media type given how specific it is.
|
||||
"""
|
||||
if self.main_type == '*':
|
||||
return 0
|
||||
elif self.sub_type == '*':
|
||||
return 1
|
||||
elif not self.params or self.params.keys() == ['q']:
|
||||
return 2
|
||||
return 3
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
ret = "%s/%s" % (self.main_type, self.sub_type)
|
||||
for key, val in self.params.items():
|
||||
ret += "; %s=%s" % (key, val)
|
||||
return ret
|
Reference in New Issue
Block a user