1""" 2 3uritemplate.template 4==================== 5 6This module contains the essential inner workings of uritemplate. 7 8What treasures await you: 9 10- URITemplate class 11 12You see a treasure chest of knowledge in front of you. 13What do you do? 14> 15 16""" 17 18import re 19from uritemplate.orderedset import OrderedSet 20from uritemplate.variable import URIVariable 21 22template_re = re.compile('{([^}]+)}') 23 24 25def _merge(var_dict, overrides): 26 if var_dict: 27 opts = var_dict.copy() 28 opts.update(overrides) 29 return opts 30 return overrides 31 32 33class URITemplate(object): 34 35 """This parses the template and will be used to expand it. 36 37 This is the most important object as the center of the API. 38 39 Example:: 40 41 from uritemplate import URITemplate 42 import requests 43 44 45 t = URITemplate( 46 'https://api.github.com/users/sigmavirus24/gists{/gist_id}' 47 ) 48 uri = t.expand(gist_id=123456) 49 resp = requests.get(uri) 50 for gist in resp.json(): 51 print(gist['html_url']) 52 53 Please note:: 54 55 str(t) 56 # 'https://api.github.com/users/sigmavirus24/gists{/gistid}' 57 repr(t) # is equivalent to 58 # URITemplate(str(t)) 59 # Where str(t) is interpreted as the URI string. 60 61 Also, ``URITemplates`` are hashable so they can be used as keys in 62 dictionaries. 63 64 """ 65 66 def __init__(self, uri): 67 #: The original URI to be parsed. 68 self.uri = uri 69 #: A list of the variables in the URI. They are stored as 70 #: :class:`URIVariable`\ s 71 self.variables = [ 72 URIVariable(m.groups()[0]) for m in template_re.finditer(self.uri) 73 ] 74 #: A set of variable names in the URI. 75 self.variable_names = OrderedSet() 76 for variable in self.variables: 77 for name in variable.variable_names: 78 self.variable_names.add(name) 79 80 def __repr__(self): 81 return 'URITemplate("%s")' % self 82 83 def __str__(self): 84 return self.uri 85 86 def __eq__(self, other): 87 return self.uri == other.uri 88 89 def __hash__(self): 90 return hash(self.uri) 91 92 def _expand(self, var_dict, replace): 93 if not self.variables: 94 return self.uri 95 96 expansion = var_dict 97 expanded = {} 98 for v in self.variables: 99 expanded.update(v.expand(expansion)) 100 101 def replace_all(match): 102 return expanded.get(match.groups()[0], '') 103 104 def replace_partial(match): 105 match = match.groups()[0] 106 var = '{%s}' % match 107 return expanded.get(match) or var 108 109 replace = replace_partial if replace else replace_all 110 111 return template_re.sub(replace, self.uri) 112 113 def expand(self, var_dict=None, **kwargs): 114 """Expand the template with the given parameters. 115 116 :param dict var_dict: Optional dictionary with variables and values 117 :param kwargs: Alternative way to pass arguments 118 :returns: str 119 120 Example:: 121 122 t = URITemplate('https://api.github.com{/end}') 123 t.expand({'end': 'users'}) 124 t.expand(end='gists') 125 126 .. note:: Passing values by both parts, may override values in 127 ``var_dict``. For example:: 128 129 expand('https://{var}', {'var': 'val1'}, var='val2') 130 131 ``val2`` will be used instead of ``val1``. 132 133 """ 134 return self._expand(_merge(var_dict, kwargs), False) 135 136 def partial(self, var_dict=None, **kwargs): 137 """Partially expand the template with the given parameters. 138 139 If all of the parameters for the template are not given, return a 140 partially expanded template. 141 142 :param dict var_dict: Optional dictionary with variables and values 143 :param kwargs: Alternative way to pass arguments 144 :returns: :class:`URITemplate` 145 146 Example:: 147 148 t = URITemplate('https://api.github.com{/end}') 149 t.partial() # => URITemplate('https://api.github.com{/end}') 150 151 """ 152 return URITemplate(self._expand(_merge(var_dict, kwargs), True)) 153