def __init__(self, pattern, destination_path, regexp_flags=re.I, match_on_full_url=False, methods=None, params={}): '''Create a new regular expressions-based filter. :param pattern: Pattern :type pattern: string or re.Regex :param destination_path: Path to leaf, expressed in internal canonical form. i.e. "/controller/leaf". :type destination_path: string :param regexp_flags: Defaults to ``re.I`` (case-insensitive) :type regexp_flags: int :param match_on_full_url: Where there or not to perform matches on complete URL (i.e. "https://foo.tld/bar?question=2"). Defauts to False (i.e.matches on path only. "/bar") :type match_on_full_url: bool :param params: Parameters are saved and later included in every call to leafs taking this route. :type params: dict ''' if not isinstance(regexp_flags, int): regexp_flags = 0 if isinstance(pattern, RegexType): self.pattern = pattern elif not isinstance(pattern, basestring): raise ValueError('first argument "pattern" must be a Regex object or a string, not %s'\ % type(pattern).__name__) else: self.pattern = re.compile(pattern, regexp_flags) if not isinstance(destination_path, (basestring, URL)): raise ValueError('second argument "destination_path" must be a string or URL, not %s'\ % type(destination_path).__name__) self.destination_path = _prep_path(destination_path) self.match_on_full_url = match_on_full_url self.params = params if isinstance(methods, (list, tuple)): self.methods = methods elif methods is not None: if not isinstance(methods, basestring): raise TypeError('methods must be a tuple or list of strings, '\ 'alternatively a string, not a %s.' % type(methods)) self.methods = (methods,) else: self.methods = None
def format_members(cls, o, colorize=False): s = [] items = [] longest_k = 0 types = {} type_i = 0 color = 0 for k in dir(o): v = getattr(o,k) if len(k) > longest_k: longest_k = len(k) if colorize: t = str(type(v)) if t not in types: types[t] = type_i type_i += 1 color = 31 + (types[t] % 5) items.append((k,v,color)) if colorize: pat = '\033[1;%%dm%%-%ds\033[m = \033[1;%%dm%%s\033[m' % longest_k else: pat = '%%-%ds = %%s' % longest_k for k,v,color in items: v = cls._repr.repr(v) if colorize: s.append(pat % (color, k, color, v)) else: s.append(pat % (k, v)) return '\n'.join(s)
def send_response(self, rsp): '''Send the response to the current client, finalizing the current HTTP transaction. ''' # Empty rsp if rsp is None: # The leaf might have sent content using low-level functions, # so we need to confirm the response has not yet started and # a custom content length header has not been set. if not self.response.has_begun: self.response.adjust_status(False) return # Add headers if the response has not yet begun if not self.response.has_begun: # Add Content-Length header if self.response.find_header('Content-Length:') == -1: self.response.headers.append('Content-Length: %d' % len(rsp)) # Add Content-Type header self.response.serializer.add_content_type_header(self.response, self.response.charset) # Has content or not? if len(rsp) > 0: # Make sure appropriate status is set, if needed self.response.adjust_status(True) # Add ETag if enabled etag = config.get('smisk.mvc.etag') if etag is not None and self.response.find_header('ETag:') == -1: h = etag(''.join(self.response.headers)) h.update(rsp) self.response.headers.append('ETag: "%s"' % h.hexdigest()) else: # Make sure appropriate status is set, if needed self.response.adjust_status(False) # Debug print if log.level <= logging.DEBUG: self._log_debug_sending_rsp(rsp) # Send headers self.response.begin() # Head does not contain a payload, but all the headers should be exactly # like they would with a GET. (Including Content-Length) if self.request.method != 'HEAD': # Send body if __debug__: assert isinstance(rsp, str), 'type(rsp) == %s' % type(rsp) self.response.write(rsp)
def _resolve(self, raw_path): # Tokenize path path = tokenize_path(raw_path) node = control.root_controller() cls = node log.debug('resolving %s (%r) on tree %r', raw_path, path, node) # Check root if node is None: return wrap_exc_in_callable(http.ControllerNotFound('No root controller exists')) # Special case: empty path == root.__call__ if not path: try: node = node().__call__ log.debug('found leaf: %s', node) return node except AttributeError: return wrap_exc_in_callable(http.MethodNotFound('/')) # Traverse tree for part in path: log.debug('looking at part %r', part) found = None # 1. Search subclasses first log.debug('matching %r to subclasses of %r', part, node) try: subclasses = node.__subclasses__() except AttributeError: log.debug('node %r does not have subclasses -- returning MethodNotFound') return wrap_exc_in_callable(http.MethodNotFound(raw_path)) for subclass in node.__subclasses__(): if _node_name(subclass, subclass.controller_name()) == part: if getattr(subclass, 'hidden', False): continue found = subclass break if found is not None: node = found cls = node continue # 2. Search methods log.debug('matching %r to methods of %r', part, node) # Aquire instance if type(node) is type: node = node() for k,v in node.__dict__.items(): if _node_name(v, k.lower()) == part: # If the leaf is hidden, we skip it if getattr(v, 'hidden', False): continue # If the leaf is not defined directly on parent node node, and # node.delegate evaluates to False, we bail out if not control.leaf_is_visible(v, cls): node = None else: found = v break # Check found node if found is not None: node = found node_type = type(node) # The following two lines enables accepting prefix routes: #if node_type is MethodType or node_type is FunctionType: # break else: # Not found return wrap_exc_in_callable(http.MethodNotFound(raw_path)) # Did we hit a class/type at the end? If so, get its instance. if type(node) is type: try: cls = node node = cls().__call__ if not control.leaf_is_visible(node, cls): node = None except AttributeError: # Uncallable leaf node = None # Not callable? if node is None or not callable(node): return wrap_exc_in_callable(http.MethodNotFound(raw_path)) log.debug('found leaf: %s', node) return node