def _gen_header(self, ctx, cls, name, parent): logger.debug("Generate header for %r", cls) with parent.element('thead'): with parent.element('tr'): th_attrs = {} if self.field_name_attr is not None: th_attrs[self.field_name_attr] = name if issubclass(cls, ComplexModelBase): fti = cls.get_flat_type_info(cls) if self.field_name_attr is None: for k, v in fti.items(): attr = get_cls_attrs(self, v) if attr.exc: continue header_name = self.trc(v, ctx.locale, k) parent.write(E.th(header_name, **th_attrs)) else: for k, v in fti.items(): attr = get_cls_attrs(self, v) if attr.exc: continue th_attrs[self.field_name_attr] = k header_name = self.trc(v, ctx.locale, k) parent.write(E.th(header_name, **th_attrs)) else: if self.field_name_attr is not None: th_attrs[self.field_name_attr] = name header_name = self.trc(cls, ctx.locale, name) parent.write(E.th(header_name, **th_attrs)) self.extend_header_row(ctx, cls, name, parent)
def _gen_header(self, ctx, cls, name, parent): logger.debug("Generate header for %r", cls) with parent.element('thead'): with parent.element('tr'): th_attrs = {} if self.field_name_attr is not None: th_attrs[self.field_name_attr] = name if issubclass(cls, ComplexModelBase): fti = cls.get_flat_type_info(cls) if self.field_name_attr is None: for k, v in fti.items(): attr = get_cls_attrs(self, v) if attr.exc: continue header_name = self.trc(v, ctx.locale, k) parent.write(E.th(header_name, **th_attrs)) else: for k, v in fti.items(): attr = get_cls_attrs(self, v) if attr.exc: continue th_attrs[self.field_name_attr] = k header_name = self.trc(v, ctx.locale, k) parent.write(E.th(header_name, **th_attrs)) else: if self.field_name_attr is not None: th_attrs[self.field_name_attr] = name header_name = self.trc(cls, ctx.locale, name) parent.write(E.th(header_name, **th_attrs)) self.extend_header_row(ctx, cls, parent, name)
def datetime_to_parent(self, ctx, cls, inst, parent, name, **kwargs): ctx.protocol.assets.extend([('jquery',), ('jquery-ui', 'datepicker'), ('jquery-timepicker',)]) cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, None, name, cls_attrs) elt.attrib['type'] = 'text' if cls_attrs.format is None: data_format = 'yy-mm-dd HH:MM:SS' else: data_format = cls_attrs.format.replace('%Y', 'yy') \ .replace('%m', 'mm') \ .replace('%d', 'dd') \ .replace('%H', 'HH') \ .replace('%M', 'MM') \ .replace('%S', 'SS') code = [ "$('#%(field_name)s').datetimepicker();", "$('#%(field_name)s').datetimepicker('option', 'DateTimeFormat', '%(format)s');", ] if inst is None: script = _format_js(code, field_name=elt.attrib['id'], format=data_format) else: value = self.to_string(cls, inst) code.append("$('#%(field_name)s').datetimepicker('setDate', '%(value)s');") script = _format_js(code, field_name=elt.attrib['id'], format=data_format, value=value) parent.write(_idiv(self._gen_label(ctx, cls, name, elt), elt, script))
def _pull_to_parent(self, ctx, cls, inst, parent, name, parent_inst=None, label_attrs=None, parent_key=None, no_label=False, **kwargs): key = self.selsafe(name) attr = get_cls_attrs(self, cls) if inst is None: inst = [] for i, subval in enumerate(inst): new_key = '%s[%09d]' % (key, i) with parent.element('div', {"class": key}): ret = self.to_parent(ctx, cls, subval, parent, new_key, parent_inst=parent_inst, no_label=True, from_arr=True, **kwargs) if not attr.no_write: parent.write(E.button('+', **{ "class": key + "_btn_add", 'type': 'button'})) parent.write(E.button('-', **{ "class": key + "_btn_del", 'type': 'button'})) if isgenerator(ret): try: while True: sv2 = (yield) ret.send(sv2) except Break as b: try: ret.throw(b) except StopIteration: pass if not attr.no_write: _gen_array_js(parent, key)
def _get_member_pairs(self, cls, inst): parent_cls = getattr(cls, '__extends__', None) if parent_cls is not None: for r in self._get_member_pairs(parent_cls, inst): yield r for k, v in cls._type_info.items(): attr = get_cls_attrs(self, v) if getattr(attr, 'exc', None): continue try: subinst = getattr(inst, k, None) # to guard against e.g. sqlalchemy throwing NoSuchColumnError except Exception as e: logger.error("Error getting %r: %r" %(k,e)) subinst = None if subinst is None: subinst = v.Attributes.default val = self._object_to_doc(v, subinst) min_o = v.Attributes.min_occurs if val is not None or min_o > 0 or self.complex_as is list: sub_name = v.Attributes.sub_name if sub_name is None: sub_name = k yield (sub_name, val)
def integer_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, inst, name, cls_attrs) elt.attrib['type'] = 'number' self._apply_number_constraints(cls_attrs, elt) parent.write(_idiv(self._gen_label(ctx, cls, name, elt), elt))
def _form_key(sort_key): k, v = sort_key attrs = get_cls_attrs(prot, v) return None if attrs.tab is None else \ (attrs.tab.index, attrs.tab.htmlid), \ None if attrs.fieldset is None else \ (attrs.fieldset.index, attrs.fieldset.htmlid), \ attrs.order, k
def boolean_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, inst, name, cls_attrs) elt.attrib.update({'type': 'checkbox', 'value': 'true'}) if bool(inst): elt.attrib['checked'] = '' parent.write(_idiv(elt, self._gen_label(ctx, cls, name, elt)))
def _write_members(self, ctx, cls, inst, parent): parent_cls = getattr(cls, '__extends__', None) if not (parent_cls is None): ret = self._write_members(ctx, parent_cls, inst, parent) if ret is not None: try: while True: sv2 = (yield) ret.send(sv2) except Break: try: ret.throw(Break()) except StopIteration: pass for k, v in cls._type_info.items(): attr = get_cls_attrs(self, v) if attr.exc: continue try: # e.g. SqlAlchemy could throw NoSuchColumnError subvalue = getattr(inst, k, None) except: subvalue = None # This is a tight loop, so enable this only when necessary. # logger.debug("get %r(%r) from %r: %r" % (k, v, inst, subvalue)) if issubclass(v, XmlData): if subvalue is not None: parent.write(self.to_unicode(k.type, subvalue)) continue sub_ns = v.Attributes.sub_ns if sub_ns is None: sub_ns = cls.get_namespace() sub_name = v.Attributes.sub_name if sub_name is None: sub_name = k name = "{%s}%s" % (sub_ns, sub_name) if subvalue is not None or v.Attributes.min_occurs > 0: ret = self.to_parent(ctx, v, subvalue, parent, name) if ret is not None: try: while True: sv2 = (yield) ret.send(sv2) except Break as b: try: ret.throw(b) except StopIteration: pass
def _gen_input_unicode(self, cls, inst, name, **_): cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, inst, name, cls_attrs) elt.attrib['type'] = 'text' if cls_attrs.max_len < Unicode.Attributes.max_len: elt.attrib['maxlength'] = str(int(cls_attrs.max_len)) if cls_attrs.min_len > Unicode.Attributes.min_len: elt.attrib['minlength'] = str(int(cls_attrs.min_len)) return cls_attrs, elt
def decimal_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, inst, name, cls_attrs) elt.attrib['type'] = 'number' if D(cls.Attributes.fraction_digits).is_infinite(): elt.attrib['step'] = 'any' else: elt.attrib['step'] = str(10**(-int(cls.Attributes.fraction_digits))) self._apply_number_constraints(cls_attrs, elt) parent.write(_idiv(self._gen_label(ctx, cls, name, elt), elt))
def spyne_to_argparse(cls): fti = cls.get_flat_type_info(cls) parser = ArgumentParser(description=cls.__doc__) parser.add_argument('-c', '--config-file', type=os.path.abspath, help="An alternative config file.") for k, v in sorted(fti.items(), key=lambda i: i[0]): attrs = get_cls_attrs(None, v) if attrs.no_cli: continue args = ['--%s' % k.replace('_', '-')] if attrs.short is not None: args.append('-%s' % attrs.short) assert not ('-c' in args or '--config-file' in args) kwargs = {} if attrs.help is not None: kwargs['help'] = attrs.help # types if _is_array_of_primitives(v): kwargs['nargs'] = "+" elif _is_array_of_complexes(v): continue elif issubclass(v, Boolean): kwargs['action'] = "store_const" kwargs['const'] = True elif issubclass(v, Unicode): if len(v.Attributes.values) > 0: kwargs['type'] = enum(v.Attributes.values) else: kwargs['type'] = six.text_type elif issubclass(v, tuple(ARGTYPE_MAP.keys())): kwargs['type'] = ARGTYPE_MAP[v] parser.add_argument(*args, **kwargs) return parser
def _gen_tab_headers(self, ctx, fti): retval = E.ul() tabs = {} for k, v in fti.items(): subattr = get_cls_attrs(self, v) tab = subattr.tab if tab is not None: tabs[id(tab)] = tab for i, tab in enumerate(sorted(tabs.values(), key=lambda t: (t.index, t.htmlid))): retval.append(E.li(E.a( self.trd(tab.legend, ctx.locale, "Tab %d" % i), href="#" + tab.htmlid ))) return retval
def _gen_row(self, ctx, cls, inst, parent, name, **kwargs): print("Generate row for", cls) with parent.element('tr'): for k, v in cls.get_flat_type_info(cls).items(): attr = get_cls_attrs(self, v) if attr.exc: print("\tExclude field %r type %r" % (k, v), "for", cls) continue if not attr.get('read', True): continue print("\tGenerate field %r type %r" % (k, v), "for", cls) try: sub_value = getattr(inst, k, None) except: # to guard against e.g. SQLAlchemy throwing NoSuchColumnError sub_value = None sub_name = attr.sub_name if sub_name is None: sub_name = k td_attrs = {} if self.field_name_attr is not None: td_attrs[self.field_name_attr] = sub_name with parent.element('td', td_attrs): ret = self.to_parent(ctx, v, sub_value, parent, sub_name, **kwargs) if isgenerator(ret): try: while True: sv2 = (yield) ret.send(sv2) except Break as b: try: ret.throw(b) except StopIteration: pass print("Generate row for %r done." % cls) self.extend_data_row(ctx, cls, inst, parent, name, **kwargs)
def _apply_custom_attributes(cls): fti = cls.get_flat_type_info(cls) for k, v in sorted(fti.items(), key=lambda i: i[0]): attrs = get_cls_attrs(None, v) if attrs.no_config == True: v.Attributes.prot_attrs = {YamlDocument: dict(exc=True)}
def complex_model_to_parent(self, ctx, cls, inst, parent, name, **kwargs): global SOME_COUNTER fti = cls.get_flat_type_info(cls) prev_fset = fset_ctx = None prev_tab = tab_ctx = tabview_ctx = None tabview_id = None # FIXME: hack! why do we have top-level object receiving name? if name == cls.get_type_name(): name = '' with parent.element('fieldset'): parent.write(E.legend(cls.get_type_name())) for k, v in sorted(fti.items(), key=_Tform_key(self)): subattr = get_cls_attrs(self, v) if subattr.exc: continue subinst = getattr(inst, k, None) tab = subattr.tab print("TAB", k, getattr(v.Attributes, 'tab', None), subattr.tab) if not (tab is prev_tab): if fset_ctx is not None: fset_ctx.__exit__(None, None, None) print("exiting fset tab ", prev_fset) fset_ctx = prev_fset = None if tab_ctx is not None: tab_ctx.__exit__(None, None, None) print("exiting tab", prev_tab) if prev_tab is None: print("entering tabview") tabview_id = 'tabview' + str(SOME_COUNTER) SOME_COUNTER += 1 tabview_ctx = parent.element('div', attrib={'id': tabview_id}) tabview_ctx.__enter__() parent.write(self._gen_tab_headers(ctx, fti)) print("entering tab", tab) attrib = {'id': tab.htmlid} attrib.update(tab.attrib) tab_ctx = parent.element('div', attrib) tab_ctx.__enter__() prev_tab = tab fset = subattr.fieldset if not (fset is prev_fset): if fset_ctx is not None: fset_ctx.__exit__(None, None, None) print("exiting fset norm", prev_fset) print("entering fset", fset) fset_ctx = parent.element(fset.tag, fset.attrib) fset_ctx.__enter__() parent.write(E.legend(self.trd(fset.legend, ctx.locale, k))) prev_fset = fset if name is not None and len(name) > 0: child_key = self.hier_delim.join((name, k)) else: child_key = k ret = self.to_parent(ctx, v, subinst, parent, child_key, **kwargs) if isgenerator(ret): try: while True: y = (yield) ret.send(y) except Break as b: try: ret.throw(b) except StopIteration: pass if fset_ctx is not None: fset_ctx.__exit__(None, None, None) print("exiting fset close", fset) if tab_ctx is not None: tab_ctx.__exit__(None, None, None) print("exiting tab close", fset) if tabview_ctx is not None: tabview_ctx.__exit__(None, None, None) parent.write(E.script( '$(function() { $( "#%s" ).tabs();});' % tabview_id, type="text/javascript" )) print("exiting tabview close", fset)
def duration_to_parent(self, ctx, cls, inst, parent, name, **kwargs): cls_attrs = get_cls_attrs(self, cls) elt = self._gen_input(cls, inst, name, cls_attrs) parent.write(_idiv(self._gen_label(ctx, cls, name, elt), elt))
def _gen_row(self, ctx, cls, inst, parent, name, from_arr=False, array_index=None, **kwargs): # because HtmlForm* protocols don't use the global null handler, it's # possible for null values to reach here. if inst is None: return print("Generate row for", cls) with parent.element('tr'): for k, v in cls.get_flat_type_info(cls).items(): attr = get_cls_attrs(self, v) if attr.exc: print("\tExclude table cell %r type %r" % (k, v), "for", cls) continue if not attr.get('read', True): continue print("\tGenerate table cell %r type %r" % (k, v), "for", cls) try: sub_value = getattr(inst, k, None) except: # e.g. SQLAlchemy could throw NoSuchColumnError sub_value = None sub_name = attr.sub_name if sub_name is None: sub_name = k if self.hier_delim is not None: if array_index is None: sub_name = "%s%s%s" % (name, self.hier_delim, sub_name) else: sub_name = "%s[%d]%s%s" % (name, array_index, self.hier_delim, sub_name) td_attrs = {} if self.field_name_attr is not None: td_attrs[self.field_name_attr] = attr.sub_name or k with parent.element('td', td_attrs): if attr.href is not None: try: attrib = {'href': attr.href % sub_value} except: attrib = {'href': attr.href} with parent.element('a', attrib=attrib): ret = self.to_parent(ctx, v, sub_value, parent, sub_name, from_arr=from_arr, array_index=array_index, **kwargs) else: ret = self.to_parent(ctx, v, sub_value, parent, sub_name, from_arr=from_arr, array_index=array_index, **kwargs) if isgenerator(ret): try: while True: sv2 = (yield) ret.send(sv2) except Break as b: try: ret.throw(b) except StopIteration: pass m = cls.Attributes.methods if m is not None and len(m) > 0: with parent.element('td'): first = True mrpc_delim = html.fromstring(" | ").text for mn, md in self._methods(cls, inst): if first: first = False else: parent.write(mrpc_delim) pd = {} for k, v in cls.get_flat_type_info(cls).items(): if getattr(v.Attributes, 'primary_key', None): r = self.to_unicode(v, getattr(inst, k, None)) if r is not None: pd[k] = r params = urlencode(pd) mdid2key = ctx.app.interface.method_descriptor_id_to_key href = mdid2key[id(md)].rsplit("}", 1)[-1] text = md.translate(ctx.locale, md.in_message.get_type_name()) parent.write(E.a(text, href="%s?%s" % (href, params))) print("Generate row for %r done." % cls) self.extend_data_row(ctx, cls, inst, parent, name, array_index=array_index, **kwargs)
def _doc_to_object(self, cls, doc, validator=None): if doc is None: return [] if issubclass(cls, Array): retval = [] (serializer, ) = cls._type_info.values() for i, child in enumerate(doc): retval.append( self._from_dict_value(i, serializer, child, validator)) return retval if not self.ignore_wrappers: if not isinstance(doc, dict): raise ValidationError("Wrapper documents must be dicts") if len(doc) == 0: return None if len(doc) > 1: raise ValidationError( doc, "There can be only one entry in a " "wrapper dict") subclasses = cls.get_subclasses() (class_name, doc), = doc.items() if cls.get_type_name() != class_name and subclasses is not None \ and len(subclasses) > 0: for subcls in subclasses: if subcls.get_type_name() == class_name: break if not self.issubclass(subcls, cls): raise ValidationError( class_name, "Class name %%r is not a subclass of %r" % cls.get_type_name()) cls = subcls inst = cls.get_deserialization_instance() # get all class attributes, including the ones coming from parent classes. flat_type_info = cls.get_flat_type_info(cls) # this is for validating cls.Attributes.{min,max}_occurs frequencies = defaultdict(int) try: items = doc.items() except AttributeError: # Input is not a dict, so we assume it's a sequence that we can pair # with the incoming sequence with field names. # TODO: cache this items = zip([ k for k, v in flat_type_info.items() if not get_cls_attrs(self, v).exc ], doc) # parse input to set incoming data to related attributes. for k, v in items: member = flat_type_info.get(k, None) if member is None: member, k = flat_type_info.alt.get(k, (None, k)) if member is None: continue attr = get_cls_attrs(self, member) mo = attr.max_occurs if mo > 1: subinst = getattr(inst, k, None) if subinst is None: subinst = [] for a in v: subinst.append( self._from_dict_value(k, member, a, validator)) else: subinst = self._from_dict_value(k, member, v, validator) inst._safe_set(k, subinst, member) frequencies[k] += 1 if validator is self.SOFT_VALIDATION and cls.Attributes.validate_freq: _check_freq_dict(cls, frequencies, flat_type_info) return inst