class MacDef(structure.Structure): """A macro definition within an RD. The macro defined is available on the parent. """ name_ = "macDef" _name = attrdef.UnicodeAttribute("name", description="Name the macro" " will be available as", copyable=True, default=utils.Undefined) _content = structure.DataContent(description="Replacement text of the" " macro") def validate(self): self._validateNext(MacDef) if len(self.name) < 2: raise common.LiteralParseError( "name", self.name, hint="Macro names must have at least two characters.") def onElementComplete(self): self._onElementCompleteNext(MacDef) def mac(): return self.content_ setattr(self.parent, "macro_" + self.name, mac)
def getAttribute(self, name): try: return DelayedReplayBase.getAttribute(self, name) except common.StructureError: # no "real" attribute, it's a macro def def m(): return getattr(self, name) setattr(self, "macro_" + name.strip(), m) self.managedAttrs[name] = attrdef.UnicodeAttribute(name) return self.managedAttrs[name]
def __init__(self, name, default=[], itemAttD=attrdef.UnicodeAttribute("listItem"), **kwargs): attrdef.AttributeDef.__init__(self, name, default=attrdef.Computed, **kwargs) self.xmlName_ = itemAttD.name_ self.itemAttD = itemAttD self.realDefault = default
def __init__(self, name, description="Undocumented", itemAttD=attrdef.UnicodeAttribute("value"), keyName="key", inverted=False, **kwargs): attrdef.AttributeDef.__init__(self, name, attrdef.Computed, description, **kwargs) self.xmlName_ = itemAttD.name_ self.itemAttD = itemAttD self.keyName = keyName self.inverted = inverted
class DBProfile(structure.Structure): """is a profile for DB access. """ name_ = "dbProfile" profileName = "anonymous" _name = attrdef.UnicodeAttribute("name", default=attrdef.Undefined, description="An identifier for this profile") _host = attrdef.UnicodeAttribute("host", default="", description="Host" " the database runs on") _port = attrdef.IntAttribute("port", default=None, description= "Port the DB server listens on") _database = attrdef.UnicodeAttribute("database", default=attrdef.Undefined, description="Name of the database to connect to") _user = attrdef.UnicodeAttribute("user", default="", description= "User to log into DB as") _pw = attrdef.UnicodeAttribute("password", default="", description= "Password for user") _sslmode = attrdef.UnicodeAttribute("sslmode", default="allow", description= "SSL negotiation mode (disable, allow, prefer, require, verify-*)") def getDsn(self): parts = [] for key, part in [("host", "host"), ("port", "port"), ("sslmode", "sslmode"), ("database", "dbname"), ("user", "user"), ("password", "password")]: if getattr(self, part): parts.append("%s=%s"%(key, getattr(self, part))) return " ".join(parts) def getArgs(self): """returns a dictionary suitable as keyword arguments to psycopg2's connect. """ res = {} for key in ["database", "user", "password", "host", "port", "sslmode"]: if getattr(self, key): res[key] = getattr(self, key) if res.keys()==["sslmode"]: raise utils.logOldExc(utils.StructureError("Insufficient information" " to connect to the database in profile '%s'."%( self.profileName))) return res @property def roleName(self): """returns the database role used by this profile. This normally is user, but in the special case of the empty user, we return the logged users' name. """ if self.user: return self.user else: return os.getlogin()
class Edit(EmbeddedStream): """an event stream targeted at editing other structures. """ name_ = "EDIT" _ref = attrdef.UnicodeAttribute( "ref", description="Destination of" " the edits, in the form elementName[<name or id>]", default=utils.Undefined) refPat = re.compile( r"([A-Za-z_][A-Za-z0-9_]*)\[([A-Za-z_][A-Za-z0-9_]*)\]") def onElementComplete(self): mat = self.refPat.match(self.ref) if not mat: raise common.LiteralParseError( "ref", self.ref, hint="edit references have the form <element name>[<value of" " name or id attribute>]") self.triggerEl, self.triggerId = mat.groups()
class Loop(ReplayedEventsWithFreeAttributesBase): """An active tag that replays a feed several times, each time with different values. """ name_ = "LOOP" _csvItems = attrdef.UnicodeAttribute( "csvItems", default=None, description="The items to loop over, in CSV-with-labels format.", strip=True) _listItems = attrdef.UnicodeAttribute( "listItems", default=None, description="The items to loop over, as space-separated single" " items. Each item will show up once, as 'item' macro.", strip=True) _codeItems = GeneratorAttribute( "codeItems", default=None, description="A python generator body that yields dictionaries" " that are then used as loop items. You can access the parse context" " as the context variable in these code snippets.", strip=False) def maybeExpand(self, val): if "\\" in val: el = self.parent while el: if hasattr(el, "expand"): return el.expand(val) el = el.parent return val def _makeRowIteratorFromListItems(self): if self.listItems is None: return None def rowIterator(): for item in self.maybeExpand(self.listItems).split(): yield {"item": item} return rowIterator() def _makeRowIteratorFromCSV(self): if self.csvItems is None: return None # I'd rather not do the encode below, but 2.7 csv can't handle # unicode. We'll need to decode stuff again. src = self.maybeExpand(self.csvItems).strip().encode("utf-8") def encodeValues(row): return dict((key, str(val).decode("utf-8")) for key, val in row.iteritems()) return ( encodeValues(row) for row in csv.DictReader(StringIO(src), skipinitialspace=True)) def _makeRowIteratorFromCode(self): if self.codeItems is None: return None return self.iterRowsFromCode() def _getRowIterator(self): rowIterators = [ ri for ri in [ self._makeRowIteratorFromListItems(), self._makeRowIteratorFromCSV(), self._makeRowIteratorFromCode() ] if ri ] if len(rowIterators) != 1: raise common.StructureError("Must give exactly one data source in" " LOOP") return rowIterators[0] def completeElement(self, ctx): self._completeElementNext(Loop, ctx) for row in self._getRowIterator(): for name, value in row.iteritems(): if value: value = value.strip() if name is None: raise utils.StructureError( "Too many CSV items (extra data: %s)" % value) setattr(self, "macro_" + name.strip(), lambda v=value: v) self._replayer()
class RecordingBase(structure.Structure): """An "abstract base" for active tags doing event recording. The recorded events are available in the events attribute. """ name_ = None _doc = attrdef.UnicodeAttribute( "doc", description="A description of" " this stream (should be restructured text).", strip=False) _defaults = complexattrs.StructAttribute( "DEFAULTS", childFactory=Defaults, description="A mapping giving" " defaults for macros expanded in this stream. Macros" " not defaulted will fail when not given in a FEED's attributes.", default=None) def __init__(self, *args, **kwargs): self.events_ = [] self.tagStack_ = [] structure.Structure.__init__(self, *args, **kwargs) def feedEvent(self, ctx, type, name, value): # keep _EXPANDED_VALUE rather than feed the value to protect it from # further expansion by subordinate structures (except if we, the # active tag, is the final recipient, in which case we gobble the thing # ourselves). if (type is _EXPANDED_VALUE and name not in self.managedAttrs): self.events_.append((_EXPANDED_VALUE, name, value, ctx.pos)) return self else: return structure.Structure.feedEvent(self, ctx, type, name, value) def start_(self, ctx, name, value): if name in self.managedAttrs and not self.tagStack_: res = structure.Structure.start_(self, ctx, name, value) else: self.events_.append(("start", name, value, ctx.pos)) res = self self.tagStack_.append(name) return res def end_(self, ctx, name, value): if name in self.managedAttrs and not self.tagStack_: structure.Structure.end_(self, ctx, name, value) else: self.events_.append(("end", name, value, ctx.pos)) self.tagStack_.pop() return self def value_(self, ctx, name, value): if name in self.managedAttrs and not self.tagStack_: # our attribute structure.Structure.value_(self, ctx, name, value) else: self.events_.append(("value", name, value, ctx.pos)) return self def getEventSource(self): """returns an object suitable as event source in xmlstruct. """ return _PreparedEventSource(self.events_) def unexpandMacros(self): """undoes the marking of expanded values as expanded. This is when, as with mixins, duplicate expansion of macros during replay is desired. """ for ind, ev in enumerate(self.events_): if ev[0] == _EXPANDED_VALUE: self.events_[ind] = ("value", ) + ev[1:] # This lets us feedFrom these iterEvents = getEventSource