utils.py (11554B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\lib\werkzeug\utils.py 2 import re 3 import os 4 from time import time 5 from datetime import datetime, timedelta 6 from werkzeug._internal import _decode_unicode, _iter_modules, _ExtendedCookie, _ExtendedMorsel, _DictAccessorProperty, _dump_date, _parse_signature, _missing 7 _format_re = re.compile('\\$(?:(%s)|\\{(%s)\\})' % ('[a-zA-Z_][a-zA-Z0-9_]*', '[a-zA-Z_][a-zA-Z0-9_]*')) 8 _entity_re = re.compile('&([^;]+);') 9 _filename_ascii_strip_re = re.compile('[^A-Za-z0-9_.-]') 10 _windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1', 'LPT2', 'LPT3', 'PRN', 'NUL') 11 12 class cached_property(object): 13 14 def __init__(self, func, name = None, doc = None, writeable = False): 15 if writeable: 16 from warnings import warn 17 warn(DeprecationWarning('the writeable argument to the cached property is a noop since 0.6 because the property is writeable by default for performance reasons')) 18 self.__name__ = name or func.__name__ 19 self.__module__ = func.__module__ 20 self.__doc__ = doc or func.__doc__ 21 self.func = func 22 23 def __get__(self, obj, type = None): 24 if obj is None: 25 return self 26 value = obj.__dict__.get(self.__name__, _missing) 27 if value is _missing: 28 value = self.func(obj) 29 obj.__dict__[self.__name__] = value 30 return value 31 32 33 class environ_property(_DictAccessorProperty): 34 read_only = True 35 36 def lookup(self, obj): 37 return obj.environ 38 39 40 class header_property(_DictAccessorProperty): 41 42 def lookup(self, obj): 43 return obj.headers 44 45 46 class HTMLBuilder(object): 47 from htmlentitydefs import name2codepoint 48 _entity_re = re.compile('&([^;]+);') 49 _entities = name2codepoint.copy() 50 _entities['apos'] = 39 51 _empty_elements = set(['area', 52 'base', 53 'basefont', 54 'br', 55 'col', 56 'frame', 57 'hr', 58 'img', 59 'input', 60 'isindex', 61 'link', 62 'meta', 63 'param']) 64 _boolean_attributes = set(['selected', 65 'checked', 66 'compact', 67 'declare', 68 'defer', 69 'disabled', 70 'ismap', 71 'multiple', 72 'nohref', 73 'noresize', 74 'noshade', 75 'nowrap']) 76 _plaintext_elements = set(['textarea']) 77 _c_like_cdata = set(['script', 'style']) 78 del name2codepoint 79 80 def __init__(self, dialect): 81 self._dialect = dialect 82 83 def __call__(self, s): 84 return escape(s) 85 86 def __getattr__(self, tag): 87 if tag[:2] == '__': 88 raise AttributeError(tag) 89 90 def proxy(*children, **arguments): 91 buffer = ['<' + tag] 92 write = buffer.append 93 for key, value in arguments.iteritems(): 94 if value is None: 95 continue 96 if key.endswith('_'): 97 key = key[:-1] 98 if key in self._boolean_attributes: 99 if not value: 100 continue 101 value = self._dialect == 'xhtml' and '="%s"' % key or '' 102 else: 103 value = '="%s"' % escape(value, True) 104 write(' ' + key + value) 105 106 if not children and tag in self._empty_elements: 107 write(self._dialect == 'xhtml' and ' />' or '>') 108 return ''.join(buffer) 109 write('>') 110 children_as_string = ''.join((unicode(x) for x in children if x is not None)) 111 if children_as_string: 112 if tag in self._plaintext_elements: 113 children_as_string = escape(children_as_string) 114 elif tag in self._c_like_cdata and self._dialect == 'xhtml': 115 children_as_string = '/*<![CDATA[*/%s/*]]>*/' % children_as_string 116 buffer.extend((children_as_string, '</%s>' % tag)) 117 return ''.join(buffer) 118 119 return proxy 120 121 def __repr__(self): 122 return '<%s for %r>' % (self.__class__.__name__, self._dialect) 123 124 125 html = HTMLBuilder('html') 126 xhtml = HTMLBuilder('xhtml') 127 128 def get_content_type(mimetype, charset): 129 if mimetype.startswith('text/') or mimetype == 'application/xml' or mimetype.startswith('application/') and mimetype.endswith('+xml'): 130 mimetype += '; charset=' + charset 131 return mimetype 132 133 134 def format_string(string, context): 135 136 def lookup_arg(match): 137 x = context[match.group(1) or match.group(2)] 138 if not isinstance(x, basestring): 139 x = type(string)(x) 140 return x 141 142 return _format_re.sub(lookup_arg, string) 143 144 145 def secure_filename(filename): 146 if isinstance(filename, unicode): 147 from unicodedata import normalize 148 filename = normalize('NFKD', filename).encode('ascii', 'ignore') 149 for sep in (os.path.sep, os.path.altsep): 150 if sep: 151 filename = filename.replace(sep, ' ') 152 153 filename = str(_filename_ascii_strip_re.sub('', '_'.join(filename.split()))).strip('._') 154 if os.name == 'nt' and filename and filename.split('.')[0].upper() in _windows_device_files: 155 filename = '_' + filename 156 return filename 157 158 159 def escape(s, quote = False): 160 if s is None: 161 return '' 162 if hasattr(s, '__html__'): 163 return s.__html__() 164 if not isinstance(s, basestring): 165 s = unicode(s) 166 s = s.replace('&', '&').replace('<', '<').replace('>', '>') 167 if quote: 168 s = s.replace('"', '"') 169 return s 170 171 172 def unescape(s): 173 174 def handle_match(m): 175 name = m.group(1) 176 if name in HTMLBuilder._entities: 177 return unichr(HTMLBuilder._entities[name]) 178 try: 179 if name[:2] in ('#x', '#X'): 180 return unichr(int(name[2:], 16)) 181 if name.startswith('#'): 182 return unichr(int(name[1:])) 183 except ValueError: 184 pass 185 186 return u'' 187 188 return _entity_re.sub(handle_match, s) 189 190 191 def cookie_date(expires = None): 192 return _dump_date(expires, '-') 193 194 195 def parse_cookie(header, charset = 'utf-8', errors = 'ignore', cls = None): 196 if isinstance(header, dict): 197 header = header.get('HTTP_COOKIE', '') 198 if cls is None: 199 cls = TypeConversionDict 200 cookie = _ExtendedCookie() 201 cookie.load(header) 202 result = {} 203 for key, value in cookie.iteritems(): 204 if value.value is not None: 205 result[key] = _decode_unicode(unquote_header_value(value.value), charset, errors) 206 207 return cls(result) 208 209 210 def dump_cookie(key, value = '', max_age = None, expires = None, path = '/', domain = None, secure = None, httponly = False, charset = 'utf-8', sync_expires = True): 211 try: 212 key = str(key) 213 except UnicodeError: 214 raise TypeError('invalid key %r' % key) 215 216 if isinstance(value, unicode): 217 value = value.encode(charset) 218 value = quote_header_value(value) 219 morsel = _ExtendedMorsel(key, value) 220 if isinstance(max_age, timedelta): 221 max_age = max_age.days * 60 * 60 * 24 + max_age.seconds 222 if expires is not None: 223 if not isinstance(expires, basestring): 224 expires = cookie_date(expires) 225 morsel['expires'] = expires 226 elif max_age is not None and sync_expires: 227 morsel['expires'] = cookie_date(time() + max_age) 228 for k, v in (('path', path), 229 ('domain', domain), 230 ('secure', secure), 231 ('max-age', max_age), 232 ('httponly', httponly)): 233 if v is not None and v is not False: 234 morsel[k] = str(v) 235 236 return morsel.output(header='').lstrip() 237 238 239 def http_date(timestamp = None): 240 return _dump_date(timestamp, ' ') 241 242 243 def redirect(location, code = 302): 244 from werkzeug.wrappers import BaseResponse 245 display_location = location 246 if isinstance(location, unicode): 247 from werkzeug.urls import iri_to_uri 248 location = iri_to_uri(location) 249 response = BaseResponse('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You should be redirected automatically to target URL: <a href="%s">%s</a>. If not click the link.' % (location, display_location), code, mimetype='text/html') 250 response.headers['Location'] = location 251 return response 252 253 254 def append_slash_redirect(environ, code = 301): 255 new_path = environ['PATH_INFO'].strip('/') + '/' 256 query_string = environ.get('QUERY_STRING') 257 if query_string: 258 new_path += '?' + query_string 259 return redirect(new_path, code) 260 261 262 def import_string(import_name, silent = False): 263 if isinstance(import_name, unicode): 264 import_name = str(import_name) 265 try: 266 if ':' in import_name: 267 module, obj = import_name.split(':', 1) 268 elif '.' in import_name: 269 module, obj = import_name.rsplit('.', 1) 270 else: 271 return __import__(import_name) 272 if isinstance(obj, unicode): 273 obj = obj.encode('utf-8') 274 return getattr(__import__(module, None, None, [obj]), obj) 275 except (ImportError, AttributeError): 276 if not silent: 277 raise 278 279 280 def find_modules(import_path, include_packages = False, recursive = False): 281 module = import_string(import_path) 282 path = getattr(module, '__path__', None) 283 if path is None: 284 raise ValueError('%r is not a package' % import_path) 285 basename = module.__name__ + '.' 286 for modname, ispkg in _iter_modules(path): 287 modname = basename + modname 288 if ispkg: 289 if include_packages: 290 yield modname 291 if recursive: 292 for item in find_modules(modname, include_packages, True): 293 yield item 294 295 else: 296 yield modname 297 298 299 def validate_arguments(func, args, kwargs, drop_extra = True): 300 parser = _parse_signature(func) 301 args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5] 302 if missing: 303 raise ArgumentValidationError(tuple(missing)) 304 elif (extra or extra_positional) and not drop_extra: 305 raise ArgumentValidationError(None, extra, extra_positional) 306 return (tuple(args), kwargs) 307 308 309 def bind_arguments(func, args, kwargs): 310 args, kwargs, missing, extra, extra_positional, arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs) 311 values = {} 312 for (name, has_default, default), value in zip(arg_spec, args): 313 values[name] = value 314 315 if vararg_var is not None: 316 values[vararg_var] = tuple(extra_positional) 317 elif extra_positional: 318 raise TypeError('too many positional arguments') 319 if kwarg_var is not None: 320 multikw = set(extra) & set([ x[0] for x in arg_spec ]) 321 if multikw: 322 raise TypeError('got multiple values for keyword argument ' + repr(iter(multikw).next())) 323 values[kwarg_var] = extra 324 elif extra: 325 raise TypeError('got unexpected keyword argument ' + repr(iter(extra).next())) 326 return values 327 328 329 class ArgumentValidationError(ValueError): 330 331 def __init__(self, missing = None, extra = None, extra_positional = None): 332 self.missing = set(missing or ()) 333 self.extra = extra or {} 334 self.extra_positional = extra_positional or [] 335 ValueError.__init__(self, 'function arguments invalid. (%d missing, %d additional)' % (len(self.missing), len(self.extra) + len(self.extra_positional))) 336 337 338 from werkzeug.http import quote_header_value, unquote_header_value 339 from werkzeug.exceptions import BadRequest 340 from werkzeug.datastructures import TypeConversionDict 341 from werkzeug.datastructures import MultiDict, CombinedMultiDict, Headers, EnvironHeaders