class PortWithProfile(Node): """ Variant of :class:`Port` that is used by "card" records inside the "Ports" property. It differs from the normal port syntax by having different entries inside the last section. Availability is not listed here, only priority. Priority does not have a colon before the actual number. This port is followed by profile assignment. """ __fragments__ = { 'name': 'port-name', 'label': 'port-label', 'priority': 'port-priority', 'latency_offset': 'port-latency-offset', 'availability': 'port-availability', 'properties': lambda t: t['port-properties'].asList(), 'profile_list': lambda t: t['port-profile-list'].asList(), } __syntax__ = ( p.Word(p.alphanums + "-;").setResultsName('port-name') + p.Suppress(':') # This part was very tricky to write. The label is basically arbitrary # localized Unicode text. We want to grab all of it in one go but # without consuming the upcoming and latest '(' character or the space # that comes immediately before. # # The syntax here combines a sequence of words, as defined by anything # other than a space and '(', delimited by a single whitespace. + p.Combine( p.OneOrMore(~p.FollowedBy(p.Regex('\(.+?\)') + p.LineEnd()) + p.Regex('[^ \n]+') + p.White().suppress()), ' ').setResultsName('port-label') + p.Suppress('(') + p.Keyword('priority').suppress() + p.Optional(p.Suppress(':')) + p.Word(p.nums).setParseAction(lambda t: int(t[0])).setResultsName( 'port-priority') + p.Optional( p.MatchFirst([ p.Suppress(',') + p.Keyword('latency offset:').suppress() + p.Word(p.nums).setParseAction(lambda t: int(t[0])) + p.Literal("usec").suppress(), p.Empty().setParseAction(lambda t: '') ]).setResultsName('port-latency-offset')) + p.Optional( p.MatchFirst([ p.Suppress(',') + p.Literal('not available'), p.Suppress(',') + p.Literal('available'), p.Empty().setParseAction(lambda t: '') ]).setResultsName('port-availability')) + p.Suppress(')') + p.LineEnd().suppress() + p.Optional( p.MatchFirst([ p.LineStart().suppress() + p.NotAny(p.White(' ')) + p.White('\t').suppress() + p.Keyword('Properties:').suppress() + p.LineEnd().suppress() + PropertyAttributeValue, p.Empty().setParseAction(lambda t: []) ]).setResultsName('port-properties')) + p.White('\t', max=3).suppress() + p.Literal("Part of profile(s)").suppress() + p.Suppress(":") + p.delimitedList( p.Word(p.alphanums + "+-:"), ", ").setResultsName("port-profile-list")).setResultsName("port")
class GenericListAttribute(Node): __fragments__ = { 'name': 'attribute-name', 'value': lambda t: t['attribute-value'].asList() } __syntax__ = (p.LineStart().suppress() + p.NotAny(p.White(' ')) + p.Optional(p.White('\t')).suppress() + AttributeName + p.Literal(':').suppress() + p.LineEnd().suppress() + GenericListAttributeValue).setResultsName("attribute")
class Record(Node): """ Single standalone entry of `pactl list`. The record is composed of a name and a list of attributes. Pulseaudio exposes objects such as cards, sinks and sources as separate records. Each attribute may be of a different type. Some attributes are simple values while others have finer structure, including lits and even additional recursive attributes. """ __fragments__ = { 'name': 'record-name', 'attribute_list': lambda t: t['record-attributes'].asList(), 'attribute_map': lambda t: OrderedDict( (attr.name, attr) for attr in t['record-attributes'].asList()), } __syntax__ = ( p.LineStart() + p.NotAny(p.White(' \t')) + p.Regex("[A-Z][a-zA-Z ]+ #[0-9]+").setResultsName("record-name") + p.LineEnd().suppress() + p.OneOrMore( p.Or([ GenericListAttribute.Syntax, GenericSimpleAttribute.Syntax, ])).setResultsName("record-attributes")).setResultsName("record") def as_json(self): return { 'name': self.name, 'attribute_list': self.attribute_list, } def __repr__(self): # Custom __repr__ that skips attribute_map return "{}({})".format( type(self).__name__, ", ".join([ "{}={!r}".format(attr, getattr(self, attr)) for attr in ['name', 'attribute_list'] ]))
p.Suppress('(') + p.Keyword('priority').suppress() + p.Suppress(':') + p.Word(p.nums).setParseAction(lambda t: int(t[0])).setResultsName( 'port-priority') + p.MatchFirst([ p.Suppress(',') + p.Literal('not available'), p.Suppress(',') + p.Literal('available'), p.Empty().setParseAction(lambda t: '') ]).setResultsName('port-availability') + p.Suppress(')')).setResultsName("port") # ================= # Shared Attributes # ================= PropertyAttributeValue = (p.Group( p.OneOrMore(p.LineStart().suppress() + p.Optional(p.White('\t')).suppress() + p.Optional(Property.Syntax) + p.LineEnd().suppress())).setResultsName("attribute-value")) class PortWithProfile(Node): """ Variant of :class:`Port` that is used by "card" records inside the "Ports" property. It differs from the normal port syntax by having different entries inside the last section. Availability is not listed here, only priority. Priority does not have a colon before the actual number. This port is followed by profile assignment. """ __fragments__ = { 'name': 'port-name',