class Css(CssBase): '''A :class:`css` element in python. .. attribute:: attributes List of css attributes for the css element. .. attribute:: children An ordered dictionary of children for this :class:`css` element. Children are either other :class:`css` elements or :class:`Mixin`. .. attribute:: parent The :class:`css` ancestor for this :class:`css` element. ''' rendered = False _app = None _css_libs = None def __init__(self, tag=None, vars=None, app=None, known_libraries=None): self._tag = tag self._http = None self._parent = None self._children = OrderedDict() self._attributes = [] if app: assert tag is None, 'app should be passed to the root element only' self._app = app if self._tag is None: known_libraries = known_libraries or lux.media_libraries self._css_libs = wsgi.Css(self.config('MEDIA_URL', '/media/'), known_libraries=known_libraries) self.variables = Variables() if vars is None else vars self.classes = Variables() self.classes.hover = 'hover' self.classes.active = 'active' elif not tag: raise ValueError('A tag must be defined') def clone(self): c = copy(self) c._parent = None c._children = OrderedDict(((name, [c.clone() for c in children]) for name, children in self._children.items())) c._attributes = copy(self._attributes) return c @property def tag(self): '''The tag for this :class:`Css` element. Always defined unless this is the root instance. ''' return self._full_tag(self._tag) @property def code(self): '''The code for this css tag.''' return self._tag or 'ROOT' @property def attributes(self): '''Css attributes for this element.''' return self._attributes @property def children(self): ''':class:`Css` children of this element.''' return self._children @property def parent(self): return self._parent @property def root(self): if self._parent: return self._parent.root else: return self @property def app(self): return self.root._app @property def http(self): if self._parent: return self._parent.http else: if self._http is None: self._http = HttpClient(loop=asyncio.new_event_loop()) return self._http def __setitem__(self, name, value): if value is None or isinstance(value, Variables): return if isinstance(value, Mixin): raise TypeError('Cannot assign a Mixin to {0}. Use add instead.' .format(name)) name = name.replace('_', '-') self._attributes.append((name, value)) def __getitem__(self, name): raise NotImplementedError('cannot get item') def config(self, name, default=None): return self.app.config.get(name, default) if self.app else default def css(self, tag, *components, **attributes): '''A child :class:`Css` elements.''' if tag: elems = [Css(t) for t in alltags(tag)] else: elems = [Css(tag)] for clone, css in enumerate(elems): for name, value in iteritems(attributes): css[name] = value css.set_parent(self) # Loop over components to add them to self for cl in components: if not isinstance(cl, list): cl = (cl,) for c in cl: css.add(c.clone() if clone else c) return elems[0] if len(elems) == 1 else elems def get_media_url(self, path): '''Build the url for a media path. ''' libs = self.root._css_libs if libs: path = libs.absolute_path(path) if not path.startswith('http'): path = 'http:%s' % path return path else: raise RuntimeError('No css libs configured') def update(self, iterable): for name, value in mapping_iterator(iterable): self[name] = value def add(self, c): '''Add a child :class:`css` or a class:`Mixin`.''' if isinstance(c, CssBase): c.set_parent(self) def add_child(self, child): clist = self._children.get(child.code) if isinstance(clist, list) and child not in clist: clist.append(child) else: self._children[child.code] = [child] def add_stream(self, stream): '''Add css text to the element.''' self._children[stream] = stream def set_parent(self, parent): # Get the element if available if getattr(self, 'tag', False) is None: if parent: raise ValueError('Body cannot have parent') return self assert parent is not self, 'cannot set self as parent' # When switching parents, remove itself from current parent children if self._parent and self._parent is not parent: self._parent.remove(self) self._parent = parent self._parent.add_child(self) def destroy(self): '''Safely this :class:`css` from the body tree.''' parent = self.parent if parent: parent.remove(self) def remove(self, child): '''Safely remove *child* form this :class:`css` element.''' clist = self._children.get(child.code) if clist: try: clist.remove(child) except ValueError: pass if not clist: self._children.pop(child.code) def extend(self, elem): '''Extend by adding *elem* attributes and children.''' self._attributes.extend(elem._attributes) for child_list in itervalues(elem._children): for child in child_list: child.set_parent(self) def stream(self, whitespace=''): '''This function convert the :class:`css` element into a string.''' # First we execute mixins if self.rendered: raise RuntimeError('%s already rendered' % self) self.rendered = True children = self._children self._children = OrderedDict() for tag, clist in iteritems(children): for c in clist: c._parent = None s = c.set_parent(self) if s: # the child (mixin) has return a string, added it. yield (None, s) data = [] for k, v in self._attributes: v = as_value(v) if v is not None: data.append('%s %s: %s;' % (whitespace, k, v)) if data: yield (self.tag, '\n'.join(data)) # yield Mixins and children for child_list in itervalues(self._children): if isinstance(child_list, list): child = child_list[0] for c in child_list[1:]: child.extend(c) for s in child.stream(whitespace): yield s else: yield None, child_list def render(self, whitespace=''): '''Render the :class:`css` component and all its children''' od = OrderedDict() for tag, data in self.stream(whitespace): if data not in od: od[data] = [] if tag: od[data].append(tag) def _(): for data, tags in iteritems(od): if tags: yield ',\n'.join(('%s%s' % (whitespace, t) for t in tags) ) + ' {' yield data yield whitespace + '}\n' else: yield data return '\n'.join(_()) def render_all(self, media_url=None, charset='utf-8'): root = self.root if media_url: root.variables.MEDIAURL = media_url start = time.time() body = root.render() created = datetime.fromtimestamp(int(start)) nice_dt = round(time.time() - start, 2) intro = '''\ /* ------------------------------------------------------------------ ------------------------------------------------------------------ Created by lux {0} in {1} seconds. ------------------------------------------------------------------ ------------------------------------------------------------------ */ '''.format(created.isoformat(' '), nice_dt) return intro + body def dump(self, theme=None, dump_variables=False): root = self.root app = root.app if app: module = None # Import applications styles if available for extension in app.config['EXTENSIONS']: try: module = import_module(extension) if hasattr(module, 'add_css'): module.add_css(root) app.write('Imported style from "%s".' % extension) except ImportError as e: app.write_err('Cannot import style %s: "%s".' % (extension, e)) if dump_variables: data = root.variables.tojson() return json.dumps(data, indent=4) else: return root.render_all() ######################################################################## ## PRIVATE METHODS ######################################################################## def _full_tag(self, tag): if self._parent and self._parent.tag: tag = '%s%s' % (self._parent.tag, tag) if tag: return tag[1:] if tag.startswith(' ') else tag
def create_datagram_endpoint(event_loop, protocol_factory, local_addr, remote_addr, family, proto, flags): if not (local_addr or remote_addr): if family == socket.AF_UNSPEC: raise ValueError('unexpected address family') addr_pairs_info = (((family, proto), (None, None)),) else: # join address by (family, protocol) addr_infos = OrderedDict() for idx, addr in enumerate((local_addr, remote_addr)): if addr is not None: assert isinstance(addr, tuple) and len(addr) == 2, ( '2-tuple is expected') infos = yield event_loop.getaddrinfo( *addr, family=family, type=socket.SOCK_DGRAM, proto=proto, flags=flags) if not infos: raise OSError('getaddrinfo() returned empty list') for fam, _, pro, _, address in infos: key = (fam, pro) if key not in addr_infos: addr_infos[key] = [None, None] addr_infos[key][idx] = address # each addr has to have info for each (family, proto) pair addr_pairs_info = [ (key, addr_pair) for key, addr_pair in addr_infos.items() if not ((local_addr and addr_pair[0] is None) or (remote_addr and addr_pair[1] is None))] if not addr_pairs_info: raise ValueError('can not get address information') exceptions = [] for ((family, proto), (local_address, remote_address)) in addr_pairs_info: sock = None l_addr = None r_addr = None try: sock = socket.socket( family=family, type=socket.SOCK_DGRAM, proto=proto) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(False) if local_addr: sock.bind(local_address) l_addr = sock.getsockname() if remote_addr: yield event_loop.sock_connect(sock, remote_address) r_addr = remote_address except OSError as exc: if sock is not None: sock.close() exceptions.append(exc) else: break else: raise exceptions[0] protocol = protocol_factory() transport = SocketDatagramTransport(event_loop, sock, protocol, r_addr, extra={'addr': l_addr}) yield transport, protocol
class Css(CssBase): '''A :class:`css` element in python. .. attribute:: attributes List of css attributes for the css element. .. attribute:: children An ordered dictionary of children for this :class:`css` element. Children are either other :class:`css` elements or :class:`Mixin`. .. attribute:: parent The :class:`css` ancestor for this :class:`css` element. ''' rendered = False theme = None _app = None _css_libs = None def __init__(self, tag=None, vars=None, app=None): self._tag = tag self._http = None self._parent = None self._children = OrderedDict() self._attributes = [] if app: assert tag is None, 'app should be passed to the root element only' self._app = app if self._tag is None: self._css_libs = wsgi.Links(self.config('MEDIA_URL', '/media/')) self.variables = Variables() if vars is None else vars self.classes = Variables() self.classes.hover = 'hover' self.classes.active = 'active' elif not tag: raise ValueError('A tag must be defined') def clone(self): c = copy(self) c._parent = None c._children = OrderedDict(((name, [c.clone() for c in children]) for name, children in self._children.items())) c._attributes = copy(self._attributes) return c @property def tag(self): '''The tag for this :class:`Css` element. Always defined unless this is the root instance. ''' tag = self._tag if self._parent: ptag = self._parent.tag if ptag: tag = '%s%s' % (ptag, tag) if tag: return tag[1:] if tag.startswith(' ') else tag @property def code(self): '''The code for this css tag.''' return self._tag or 'ROOT' @property def attributes(self): '''Css attributes for this element.''' return self._attributes @property def children(self): ''':class:`Css` children of this element.''' return self._children @property def parent(self): return self._parent @property def root(self): if self._parent: return self._parent.root else: return self @property def app(self): return self.root._app @property def http(self): if self._parent: return self._parent.http else: if self._http is None: self._http = HttpClient(loop=asyncio.new_event_loop()) return self._http def __setitem__(self, name, value): if value is None or isinstance(value, Variables): return if isinstance(value, Mixin): raise TypeError('Cannot assign a Mixin to {0}. Use add instead.' .format(name)) name = name.replace('_', '-') self._attributes.append((name, value)) def __getitem__(self, name): raise NotImplementedError('cannot get item') def config(self, name, default=None): return self.app.config.get(name, default) if self.app else default def css(self, tag, *components, **attributes): '''A child :class:`Css` elements.''' if tag: elems = [Css(t) for t in alltags(tag)] else: elems = [Css(tag)] for clone, css in enumerate(elems): for name, value in attributes.items(): css[name] = value css.set_parent(self) # Loop over components to add them to self for cl in components: if not isinstance(cl, list): cl = (cl,) for c in cl: css.add(c.clone() if clone else c) return elems[0] if len(elems) == 1 else elems def media(self, *type, **query): assert len(type) <= 1 media = Media(type[0] if type else 'all', query) self.add(media) return media def get_media_url(self, path): '''Build the url for a media path. ''' libs = self.root._css_libs if libs: path = libs.absolute_path(path) if not path.startswith('http'): path = 'http:%s' % path return path else: raise RuntimeError('No css libs configured') def update(self, iterable): for name, value in mapping_iterator(iterable): self[name] = value def add(self, c): '''Add a child :class:`css` or a class:`Mixin`.''' if isinstance(c, CssBase): c.set_parent(self) def add_child(self, child): clist = self._children.get(child.code) if isinstance(clist, list) and child not in clist: clist.append(child) else: self._children[child.code] = [child] def add_stream(self, stream): '''Add css text to the element.''' self._children[stream] = stream def set_parent(self, parent): # Get the element if available if getattr(self, 'tag', False) is None: if parent: raise ValueError('Body cannot have parent') return self assert parent is not self, 'cannot set self as parent' # When switching parents, remove itself from current parent children if self._parent and self._parent is not parent: self._parent.remove(self) self._parent = parent self._parent.add_child(self) def destroy(self): '''Safely this :class:`css` from the body tree.''' parent = self.parent if parent: parent.remove(self) def remove(self, child): '''Safely remove *child* form this :class:`css` element.''' clist = self._children.get(child.code) if clist: try: clist.remove(child) except ValueError: pass if not clist: self._children.pop(child.code) def extend(self, elem): '''Extend by adding *elem* attributes and children.''' self._attributes.extend(elem._attributes) for child_list in tuple(elem._children.values()): for child in child_list: child.set_parent(self) def stream(self, whitespace=''): '''This function convert the :class:`css` element into a string.''' # First we execute mixins if self.rendered: raise RuntimeError('%s already rendered' % self) self.rendered = True children = self._children self._children = OrderedDict() for tag, clist in children.items(): for c in clist: c._parent = None s = c.set_parent(self) if s: # the child (mixin) has return a string, added it. yield (None, s) data = [] for k, v in self._attributes: v = as_value(v) if v is not None: data.append('%s %s: %s;' % (whitespace, k, v)) if data: yield (self.tag, '\n'.join(data)) # Mixins and children for child_list in self._children.values(): if isinstance(child_list, list): child = child_list[0] for c in child_list[1:]: child.extend(c) for s in child.stream(whitespace): yield s else: yield None, child_list def render(self, whitespace=''): '''Render the :class:`css` component and all its children''' od = OrderedDict() for tag, data in self.stream(whitespace): if data not in od: od[data] = [] if tag: od[data].append(tag) def _(): for data, tags in od.items(): if tags: yield ',\n'.join(('%s%s' % (whitespace, t) for t in tags) ) + ' {' yield data yield whitespace + '}\n' else: yield data return '\n'.join(_()) def render_all(self, media_url=None, charset='utf-8'): root = self.root if media_url: root.variables.MEDIAURL = media_url start = time.time() body = root.render() created = datetime.fromtimestamp(int(start)) nice_dt = round(time.time() - start, 2) intro = '''@charset "UTF-8"; /* ------------------------------------------------------------------ Created by lux in {1} seconds Date: {0} http://quantmind.github.io/lux/ ------------------------------------------------------------------ */ '''.format(created.isoformat(' '), nice_dt) return intro + body def dump(self, theme=None, dump_variables=False): root = self.root root.theme = theme app = root.app if app: module = None # Import applications styles if available exclude = app.config['EXCLUDE_EXTENSIONS_CSS'] or () for extension in app.config['EXTENSIONS']: if extension in exclude: continue try: module = import_module(extension) if hasattr(module, 'add_css'): module.add_css(root) app.write('Imported style from "%s".' % extension) except ImportError as e: app.write_err('Cannot import style %s: "%s".' % (extension, e)) if dump_variables: data = root.variables.tojson() return json.dumps(data, indent=4) else: return root.render_all()
class Css(CssBase): """A :class:`css` element in python. .. attribute:: attributes List of css attributes for the css element. .. attribute:: children An ordered dictionary of children for this :class:`css` element. Children are either other :class:`css` elements or :class:`Mixin`. .. attribute:: parent The :class:`css` ancestor for this :class:`css` element. """ rendered = False theme = None _app = None _css_libs = None def __init__(self, tag=None, vars=None, app=None): self._tag = tag self._http = None self._parent = None self._children = OrderedDict() self._attributes = [] if app: assert tag is None, "app should be passed to the root element only" self._app = app if self._tag is None: self._css_libs = wsgi.Links(self.config("MEDIA_URL", "/media/")) self.variables = Variables() if vars is None else vars self.classes = Variables() self.classes.hover = "hover" self.classes.active = "active" elif not tag: raise ValueError("A tag must be defined") def clone(self): c = copy(self) c._parent = None c._children = OrderedDict(((name, [c.clone() for c in children]) for name, children in self._children.items())) c._attributes = copy(self._attributes) return c @property def tag(self): """The tag for this :class:`Css` element. Always defined unless this is the root instance. """ tag = self._tag if self._parent: ptag = self._parent.tag if ptag: tag = "%s%s" % (ptag, tag) if tag: return tag[1:] if tag.startswith(" ") else tag @property def code(self): """The code for this css tag.""" return self._tag or "ROOT" @property def attributes(self): """Css attributes for this element.""" return self._attributes @property def children(self): """:class:`Css` children of this element.""" return self._children @property def parent(self): return self._parent @property def root(self): if self._parent: return self._parent.root else: return self @property def app(self): return self.root._app @property def http(self): if self._parent: return self._parent.http else: if self._http is None: self._http = HttpClient(loop=asyncio.new_event_loop()) return self._http def __setitem__(self, name, value): if value is None or isinstance(value, Variables): return if isinstance(value, Mixin): raise TypeError("Cannot assign a Mixin to {0}. Use add instead.".format(name)) name = name.replace("_", "-") self._attributes.append((name, value)) def __getitem__(self, name): raise NotImplementedError("cannot get item") def config(self, name, default=None): return self.app.config.get(name, default) if self.app else default def css(self, tag, *components, **attributes): """A child :class:`Css` elements.""" if tag: elems = [Css(t) for t in alltags(tag)] else: elems = [Css(tag)] for clone, css in enumerate(elems): for name, value in attributes.items(): css[name] = value css.set_parent(self) # Loop over components to add them to self for cl in components: if not isinstance(cl, list): cl = (cl,) for c in cl: css.add(c.clone() if clone else c) return elems[0] if len(elems) == 1 else elems def media(self, *type, **query): assert len(type) <= 1 media = Media(type[0] if type else "all", query) self.add(media) return media def get_media_url(self, path): """Build the url for a media path. """ libs = self.root._css_libs if libs: path = libs.absolute_path(path) if not path.startswith("http"): path = "http:%s" % path return path else: raise RuntimeError("No css libs configured") def update(self, iterable): for name, value in mapping_iterator(iterable): self[name] = value def add(self, c): """Add a child :class:`css` or a class:`Mixin`.""" if isinstance(c, CssBase): c.set_parent(self) def add_child(self, child): clist = self._children.get(child.code) if isinstance(clist, list) and child not in clist: clist.append(child) else: self._children[child.code] = [child] def add_stream(self, stream): """Add css text to the element.""" self._children[stream] = stream def set_parent(self, parent): # Get the element if available if getattr(self, "tag", False) is None: if parent: raise ValueError("Body cannot have parent") return self assert parent is not self, "cannot set self as parent" # When switching parents, remove itself from current parent children if self._parent and self._parent is not parent: self._parent.remove(self) self._parent = parent self._parent.add_child(self) def destroy(self): """Safely this :class:`css` from the body tree.""" parent = self.parent if parent: parent.remove(self) def remove(self, child): """Safely remove *child* form this :class:`css` element.""" clist = self._children.get(child.code) if clist: try: clist.remove(child) except ValueError: pass if not clist: self._children.pop(child.code) def extend(self, elem): """Extend by adding *elem* attributes and children.""" self._attributes.extend(elem._attributes) for child_list in tuple(elem._children.values()): for child in child_list: child.set_parent(self) def stream(self, whitespace=""): """This function convert the :class:`css` element into a string.""" # First we execute mixins if self.rendered: raise RuntimeError("%s already rendered" % self) self.rendered = True children = self._children self._children = OrderedDict() for tag, clist in children.items(): for c in clist: c._parent = None s = c.set_parent(self) if s: # the child (mixin) has return a string, added it. yield (None, s) data = [] for k, v in self._attributes: v = as_value(v) if v is not None: data.append("%s %s: %s;" % (whitespace, k, v)) if data: yield (self.tag, "\n".join(data)) # Mixins and children for child_list in self._children.values(): if isinstance(child_list, list): child = child_list[0] for c in child_list[1:]: child.extend(c) for s in child.stream(whitespace): yield s else: yield None, child_list def render(self, whitespace=""): """Render the :class:`css` component and all its children""" od = OrderedDict() for tag, data in self.stream(whitespace): if data not in od: od[data] = [] if tag: od[data].append(tag) def _(): for data, tags in od.items(): if tags: yield ",\n".join(("%s%s" % (whitespace, t) for t in tags)) + " {" yield data yield whitespace + "}\n" else: yield data return "\n".join(_()) def render_all(self, media_url=None, charset="utf-8"): root = self.root if media_url: root.variables.MEDIAURL = media_url start = time.time() body = root.render() created = datetime.fromtimestamp(int(start)) nice_dt = round(time.time() - start, 2) intro = """@charset "UTF-8"; /* ------------------------------------------------------------------ Created by lux in {1} seconds Date: {0} http://quantmind.github.io/lux/ ------------------------------------------------------------------ */ """.format( created.isoformat(" "), nice_dt ) return intro + body def dump(self, theme=None, dump_variables=False): root = self.root root.theme = theme app = root.app if app: module = None # Import applications styles if available exclude = app.config["EXCLUDE_EXTENSIONS_CSS"] or () for extension in app.config["EXTENSIONS"]: if extension in exclude: continue try: module = import_module(extension) if hasattr(module, "add_css"): module.add_css(root) app.write('Imported style from "%s".' % extension) except ImportError as e: app.write_err('Cannot import style %s: "%s".' % (extension, e)) if dump_variables: data = root.variables.tojson() return json.dumps(data, indent=4) else: return root.render_all()