Added delete option to database storage.

This commit is contained in:
Batuhan Berk Başoğlu 2020-10-12 12:10:01 -04:00
parent 308604a33c
commit 963b5bc68b
1868 changed files with 192402 additions and 13278 deletions

View file

@ -0,0 +1,26 @@
"""
uritemplate
===========
The URI templating library for humans.
See http://uritemplate.rtfd.org/ for documentation
:copyright: (c) 2013-2015 Ian Cordasco
:license: Modified BSD, see LICENSE for more details
"""
__title__ = 'uritemplate'
__author__ = 'Ian Cordasco'
__license__ = 'Modified BSD or Apache License, Version 2.0'
__copyright__ = 'Copyright 2013 Ian Cordasco'
__version__ = '3.0.1'
__version_info__ = tuple(int(i) for i in __version__.split('.') if i.isdigit())
from uritemplate.api import (
URITemplate, expand, partial, variables # noqa: E402
)
__all__ = ('URITemplate', 'expand', 'partial', 'variables')

View file

@ -0,0 +1,73 @@
"""
uritemplate.api
===============
This module contains the very simple API provided by uritemplate.
"""
from uritemplate.orderedset import OrderedSet
from uritemplate.template import URITemplate
def expand(uri, var_dict=None, **kwargs):
"""Expand the template with the given parameters.
:param str uri: The templated URI to expand
:param dict var_dict: Optional dictionary with variables and values
:param kwargs: Alternative way to pass arguments
:returns: str
Example::
expand('https://api.github.com{/end}', {'end': 'users'})
expand('https://api.github.com{/end}', end='gists')
.. note:: Passing values by both parts, may override values in
``var_dict``. For example::
expand('https://{var}', {'var': 'val1'}, var='val2')
``val2`` will be used instead of ``val1``.
"""
return URITemplate(uri).expand(var_dict, **kwargs)
def partial(uri, var_dict=None, **kwargs):
"""Partially expand the template with the given parameters.
If all of the parameters for the template are not given, return a
partially expanded template.
:param dict var_dict: Optional dictionary with variables and values
:param kwargs: Alternative way to pass arguments
:returns: :class:`URITemplate`
Example::
t = URITemplate('https://api.github.com{/end}')
t.partial() # => URITemplate('https://api.github.com{/end}')
"""
return URITemplate(uri).partial(var_dict, **kwargs)
def variables(uri):
"""Parse the variables of the template.
This returns all of the variable names in the URI Template.
:returns: Set of variable names
:rtype: set
Example::
variables('https://api.github.com{/end})
# => {'end'}
variables('https://api.github.com/repos{/username}{/repository}')
# => {'username', 'repository'}
"""
return OrderedSet(URITemplate(uri).variable_names)

View file

@ -0,0 +1,90 @@
# From: https://github.com/ActiveState/code/blob/master/recipes/Python/576696_OrderedSet_with_Weakrefs/ # noqa
from weakref import proxy
try:
import collections.abc as collections_abc
except ImportError:
import collections as collections_abc
class Link(object):
__slots__ = 'prev', 'next', 'key', '__weakref__'
class OrderedSet(collections_abc.MutableSet):
'Set the remembers the order elements were added'
# Big-O running times for all methods are the same as for regular sets.
# The internal self.__map dictionary maps keys to links in a doubly linked
# list. The circular doubly linked list starts and ends with a sentinel
# element. The sentinel element never gets deleted (this simplifies the
# algorithm). The prev/next links are weakref proxies (to prevent circular
# references). Individual links are kept alive by the hard reference in
# self.__map. Those hard references disappear when a key is deleted from
# an OrderedSet.
def __init__(self, iterable=None):
self.__root = root = Link() # sentinel node for doubly linked list
root.prev = root.next = root
self.__map = {} # key --> link
if iterable is not None:
self |= iterable
def __len__(self):
return len(self.__map)
def __contains__(self, key):
return key in self.__map
def add(self, key):
# Store new key in a new link at the end of the linked list
if key not in self.__map:
self.__map[key] = link = Link()
root = self.__root
last = root.prev
link.prev, link.next, link.key = last, root, key
last.next = root.prev = proxy(link)
def discard(self, key):
# Remove an existing item using self.__map to find the link which is
# then removed by updating the links in the predecessor and successors.
if key in self.__map:
link = self.__map.pop(key)
link.prev.next = link.next
link.next.prev = link.prev
def __iter__(self):
# Traverse the linked list in order.
root = self.__root
curr = root.next
while curr is not root:
yield curr.key
curr = curr.next
def __reversed__(self):
# Traverse the linked list in reverse order.
root = self.__root
curr = root.prev
while curr is not root:
yield curr.key
curr = curr.prev
def pop(self, last=True):
if not self:
raise KeyError('set is empty')
key = next(reversed(self)) if last else next(iter(self))
self.discard(key)
return key
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, list(self))
def __str__(self):
return self.__repr__()
def __eq__(self, other):
if isinstance(other, OrderedSet):
return len(self) == len(other) and list(self) == list(other)
return not self.isdisjoint(other)

View file

@ -0,0 +1,152 @@
"""
uritemplate.template
====================
This module contains the essential inner workings of uritemplate.
What treasures await you:
- URITemplate class
You see a treasure chest of knowledge in front of you.
What do you do?
>
"""
import re
from uritemplate.orderedset import OrderedSet
from uritemplate.variable import URIVariable
template_re = re.compile('{([^}]+)}')
def _merge(var_dict, overrides):
if var_dict:
opts = var_dict.copy()
opts.update(overrides)
return opts
return overrides
class URITemplate(object):
"""This parses the template and will be used to expand it.
This is the most important object as the center of the API.
Example::
from uritemplate import URITemplate
import requests
t = URITemplate(
'https://api.github.com/users/sigmavirus24/gists{/gist_id}'
)
uri = t.expand(gist_id=123456)
resp = requests.get(uri)
for gist in resp.json():
print(gist['html_url'])
Please note::
str(t)
# 'https://api.github.com/users/sigmavirus24/gists{/gistid}'
repr(t) # is equivalent to
# URITemplate(str(t))
# Where str(t) is interpreted as the URI string.
Also, ``URITemplates`` are hashable so they can be used as keys in
dictionaries.
"""
def __init__(self, uri):
#: The original URI to be parsed.
self.uri = uri
#: A list of the variables in the URI. They are stored as
#: :class:`URIVariable`\ s
self.variables = [
URIVariable(m.groups()[0]) for m in template_re.finditer(self.uri)
]
#: A set of variable names in the URI.
self.variable_names = OrderedSet()
for variable in self.variables:
for name in variable.variable_names:
self.variable_names.add(name)
def __repr__(self):
return 'URITemplate("%s")' % self
def __str__(self):
return self.uri
def __eq__(self, other):
return self.uri == other.uri
def __hash__(self):
return hash(self.uri)
def _expand(self, var_dict, replace):
if not self.variables:
return self.uri
expansion = var_dict
expanded = {}
for v in self.variables:
expanded.update(v.expand(expansion))
def replace_all(match):
return expanded.get(match.groups()[0], '')
def replace_partial(match):
match = match.groups()[0]
var = '{%s}' % match
return expanded.get(match) or var
replace = replace_partial if replace else replace_all
return template_re.sub(replace, self.uri)
def expand(self, var_dict=None, **kwargs):
"""Expand the template with the given parameters.
:param dict var_dict: Optional dictionary with variables and values
:param kwargs: Alternative way to pass arguments
:returns: str
Example::
t = URITemplate('https://api.github.com{/end}')
t.expand({'end': 'users'})
t.expand(end='gists')
.. note:: Passing values by both parts, may override values in
``var_dict``. For example::
expand('https://{var}', {'var': 'val1'}, var='val2')
``val2`` will be used instead of ``val1``.
"""
return self._expand(_merge(var_dict, kwargs), False)
def partial(self, var_dict=None, **kwargs):
"""Partially expand the template with the given parameters.
If all of the parameters for the template are not given, return a
partially expanded template.
:param dict var_dict: Optional dictionary with variables and values
:param kwargs: Alternative way to pass arguments
:returns: :class:`URITemplate`
Example::
t = URITemplate('https://api.github.com{/end}')
t.partial() # => URITemplate('https://api.github.com{/end}')
"""
return URITemplate(self._expand(_merge(var_dict, kwargs), True))

View file

@ -0,0 +1,386 @@
"""
uritemplate.variable
====================
This module contains the URIVariable class which powers the URITemplate class.
What treasures await you:
- URIVariable class
You see a hammer in front of you.
What do you do?
>
"""
import sys
try:
import collections.abc as collections_abc
except ImportError:
import collections as collections_abc
if sys.version_info.major == 2:
import urllib
elif sys.version_info.major == 3:
import urllib.parse as urllib
class URIVariable(object):
"""This object validates everything inside the URITemplate object.
It validates template expansions and will truncate length as decided by
the template.
Please note that just like the :class:`URITemplate <URITemplate>`, this
object's ``__str__`` and ``__repr__`` methods do not return the same
information. Calling ``str(var)`` will return the original variable.
This object does the majority of the heavy lifting. The ``URITemplate``
object finds the variables in the URI and then creates ``URIVariable``
objects. Expansions of the URI are handled by each ``URIVariable``
object. ``URIVariable.expand()`` returns a dictionary of the original
variable and the expanded value. Check that method's documentation for
more information.
"""
operators = ('+', '#', '.', '/', ';', '?', '&', '|', '!', '@')
reserved = ":/?#[]@!$&'()*+,;="
def __init__(self, var):
#: The original string that comes through with the variable
self.original = var
#: The operator for the variable
self.operator = ''
#: List of safe characters when quoting the string
self.safe = ''
#: List of variables in this variable
self.variables = []
#: List of variable names
self.variable_names = []
#: List of defaults passed in
self.defaults = {}
# Parse the variable itself.
self.parse()
self.post_parse()
def __repr__(self):
return 'URIVariable(%s)' % self
def __str__(self):
return self.original
def parse(self):
"""Parse the variable.
This finds the:
- operator,
- set of safe characters,
- variables, and
- defaults.
"""
var_list = self.original
if self.original[0] in URIVariable.operators:
self.operator = self.original[0]
var_list = self.original[1:]
if self.operator in URIVariable.operators[:2]:
self.safe = URIVariable.reserved
var_list = var_list.split(',')
for var in var_list:
default_val = None
name = var
if '=' in var:
name, default_val = tuple(var.split('=', 1))
explode = False
if name.endswith('*'):
explode = True
name = name[:-1]
prefix = None
if ':' in name:
name, prefix = tuple(name.split(':', 1))
prefix = int(prefix)
if default_val:
self.defaults[name] = default_val
self.variables.append(
(name, {'explode': explode, 'prefix': prefix})
)
self.variable_names = [varname for (varname, _) in self.variables]
def post_parse(self):
"""Set ``start``, ``join_str`` and ``safe`` attributes.
After parsing the variable, we need to set up these attributes and it
only makes sense to do it in a more easily testable way.
"""
self.safe = ''
self.start = self.join_str = self.operator
if self.operator == '+':
self.start = ''
if self.operator in ('+', '#', ''):
self.join_str = ','
if self.operator == '#':
self.start = '#'
if self.operator == '?':
self.start = '?'
self.join_str = '&'
if self.operator in ('+', '#'):
self.safe = URIVariable.reserved
def _query_expansion(self, name, value, explode, prefix):
"""Expansion method for the '?' and '&' operators."""
if value is None:
return None
tuples, items = is_list_of_tuples(value)
safe = self.safe
if list_test(value) and not tuples:
if not value:
return None
if explode:
return self.join_str.join(
'{}={}'.format(name, quote(v, safe)) for v in value
)
else:
value = ','.join(quote(v, safe) for v in value)
return '{}={}'.format(name, value)
if dict_test(value) or tuples:
if not value:
return None
items = items or sorted(value.items())
if explode:
return self.join_str.join(
'{}={}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items
)
else:
value = ','.join(
'{},{}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items
)
return '{}={}'.format(name, value)
if value:
value = value[:prefix] if prefix else value
return '{}={}'.format(name, quote(value, safe))
return name + '='
def _label_path_expansion(self, name, value, explode, prefix):
"""Label and path expansion method.
Expands for operators: '/', '.'
"""
join_str = self.join_str
safe = self.safe
if value is None or (len(value) == 0 and value != ''):
return None
tuples, items = is_list_of_tuples(value)
if list_test(value) and not tuples:
if not explode:
join_str = ','
fragments = [quote(v, safe) for v in value if v is not None]
return join_str.join(fragments) if fragments else None
if dict_test(value) or tuples:
items = items or sorted(value.items())
format_str = '%s=%s'
if not explode:
format_str = '%s,%s'
join_str = ','
expanded = join_str.join(
format_str % (
quote(k, safe), quote(v, safe)
) for k, v in items if v is not None
)
return expanded if expanded else None
value = value[:prefix] if prefix else value
return quote(value, safe)
def _semi_path_expansion(self, name, value, explode, prefix):
"""Expansion method for ';' operator."""
join_str = self.join_str
safe = self.safe
if value is None:
return None
if self.operator == '?':
join_str = '&'
tuples, items = is_list_of_tuples(value)
if list_test(value) and not tuples:
if explode:
expanded = join_str.join(
'{}={}'.format(
name, quote(v, safe)
) for v in value if v is not None
)
return expanded if expanded else None
else:
value = ','.join(quote(v, safe) for v in value)
return '{}={}'.format(name, value)
if dict_test(value) or tuples:
items = items or sorted(value.items())
if explode:
return join_str.join(
'{}={}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items if v is not None
)
else:
expanded = ','.join(
'{},{}'.format(
quote(k, safe), quote(v, safe)
) for k, v in items if v is not None
)
return '{}={}'.format(name, expanded)
value = value[:prefix] if prefix else value
if value:
return '{}={}'.format(name, quote(value, safe))
return name
def _string_expansion(self, name, value, explode, prefix):
if value is None:
return None
tuples, items = is_list_of_tuples(value)
if list_test(value) and not tuples:
return ','.join(quote(v, self.safe) for v in value)
if dict_test(value) or tuples:
items = items or sorted(value.items())
format_str = '%s=%s' if explode else '%s,%s'
return ','.join(
format_str % (
quote(k, self.safe), quote(v, self.safe)
) for k, v in items
)
value = value[:prefix] if prefix else value
return quote(value, self.safe)
def expand(self, var_dict=None):
"""Expand the variable in question.
Using ``var_dict`` and the previously parsed defaults, expand this
variable and subvariables.
:param dict var_dict: dictionary of key-value pairs to be used during
expansion
:returns: dict(variable=value)
Examples::
# (1)
v = URIVariable('/var')
expansion = v.expand({'var': 'value'})
print(expansion)
# => {'/var': '/value'}
# (2)
v = URIVariable('?var,hello,x,y')
expansion = v.expand({'var': 'value', 'hello': 'Hello World!',
'x': '1024', 'y': '768'})
print(expansion)
# => {'?var,hello,x,y':
# '?var=value&hello=Hello%20World%21&x=1024&y=768'}
"""
return_values = []
for name, opts in self.variables:
value = var_dict.get(name, None)
if not value and value != '' and name in self.defaults:
value = self.defaults[name]
if value is None:
continue
expanded = None
if self.operator in ('/', '.'):
expansion = self._label_path_expansion
elif self.operator in ('?', '&'):
expansion = self._query_expansion
elif self.operator == ';':
expansion = self._semi_path_expansion
else:
expansion = self._string_expansion
expanded = expansion(name, value, opts['explode'], opts['prefix'])
if expanded is not None:
return_values.append(expanded)
value = ''
if return_values:
value = self.start + self.join_str.join(return_values)
return {self.original: value}
def is_list_of_tuples(value):
if (not value or
not isinstance(value, (list, tuple)) or
not all(isinstance(t, tuple) and len(t) == 2 for t in value)):
return False, None
return True, value
def list_test(value):
return isinstance(value, (list, tuple))
def dict_test(value):
return isinstance(value, (dict, collections_abc.MutableMapping))
try:
texttype = unicode
except NameError: # Python 3
texttype = str
stringlikes = (texttype, bytes)
def _encode(value, encoding='utf-8'):
if (isinstance(value, texttype) and
getattr(value, 'encode', None) is not None):
return value.encode(encoding)
return value
def quote(value, safe):
if not isinstance(value, stringlikes):
value = str(value)
return urllib.quote(_encode(value), safe)