/usr/lib/python2.7/dist-packages/parse_type/cardinality.py is in python-parse-type 0.3.4-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | # -*- coding: utf-8 -*-
"""
This module simplifies to build parse types and regular expressions
for a data type with the specified cardinality.
"""
# -- USE: enum34
from enum import Enum
# -----------------------------------------------------------------------------
# FUNCTIONS:
# -----------------------------------------------------------------------------
def pattern_group_count(pattern):
return pattern.replace(r"\(", "").count("(")
# -----------------------------------------------------------------------------
# CLASS: Cardinality (Enum Class)
# -----------------------------------------------------------------------------
class Cardinality(Enum):
"""
Cardinality enumeration class to simplify building regular expression
patterns for a data type with the specified cardinality.
"""
__order__ = "one, zero_or_one, zero_or_more, one_or_more"
one = (None, 0)
zero_or_one = (r"(%s)?", 1) # SCHEMA: pattern
zero_or_more = (r"(%s)?(\s*%s\s*(%s))*", 3) # SCHEMA: pattern sep pattern
one_or_more = (r"(%s)(\s*%s\s*(%s))*", 3) # SCHEMA: pattern sep pattern
# -- ALIASES:
optional = zero_or_one
many0 = zero_or_more
many = one_or_more
def __init__(self, schema, group_count=0):
self.schema = schema
self.group_count = group_count #< Number of match groups.
def is_many(self):
"""
Checks for a more general interpretation of "many".
:return: True, if Cardinality.zero_or_more or Cardinality.one_or_more.
"""
return ((self is Cardinality.zero_or_more) or
(self is Cardinality.one_or_more))
def make_pattern(self, pattern, listsep=','):
"""
Make pattern for a data type with the specified cardinality.
.. code-block:: python
yes_no_pattern = r"yes|no"
many_yes_no = Cardinality.one_or_more.make_pattern(yes_no_pattern)
:param pattern: Regular expression for type (as string).
:param listsep: List separator for multiple items (as string, optional)
:return: Regular expression pattern for type with cardinality.
"""
if self is Cardinality.one:
return pattern
elif self is Cardinality.zero_or_one:
return self.schema % pattern
else:
return self.schema % (pattern, listsep, pattern)
def compute_group_count(self, pattern):
"""
Compute the number of regexp match groups when the pattern is provided
to the :func:`Cardinality.make_pattern()` method.
:param pattern: Item regexp pattern (as string).
:return: Number of regexp match groups in the cardinality pattern.
"""
group_count = self.group_count
pattern_repeated = 1
if self.is_many():
pattern_repeated = 2
return group_count + pattern_repeated * pattern_group_count(pattern)
# -----------------------------------------------------------------------------
# CLASS: TypeBuilder
# -----------------------------------------------------------------------------
class TypeBuilder(object):
"""
Provides a utility class to build type-converters (parse_types) for parse.
It supports to build new type-converters for different cardinality
based on the type-converter for cardinality one.
"""
anything_pattern = r".+?"
default_pattern = anything_pattern
@classmethod
def with_cardinality(cls, cardinality, converter, pattern=None,
listsep=','):
"""
Creates a type converter for the specified cardinality
by using the type converter for T.
:param cardinality: Cardinality to use (0..1, 0..*, 1..*).
:param converter: Type converter (function) for data type T.
:param pattern: Regexp pattern for an item (=converter.pattern).
:return: type-converter for optional<T> (T or None).
"""
if cardinality is Cardinality.one:
return converter
# -- NORMAL-CASE
builder_func = getattr(cls, "with_%s" % cardinality.name)
if cardinality is Cardinality.zero_or_one:
return builder_func(converter, pattern)
else:
# -- MANY CASE: 0..*, 1..*
return builder_func(converter, pattern, listsep=listsep)
@classmethod
def with_zero_or_one(cls, converter, pattern=None):
"""
Creates a type converter for a T with 0..1 times
by using the type converter for one item of T.
:param converter: Type converter (function) for data type T.
:param pattern: Regexp pattern for an item (=converter.pattern).
:return: type-converter for optional<T> (T or None).
"""
cardinality = Cardinality.zero_or_one
if not pattern:
pattern = getattr(converter, "pattern", cls.default_pattern)
optional_pattern = cardinality.make_pattern(pattern)
group_count = cardinality.compute_group_count(pattern)
def convert_optional(text, m=None):
if text:
text = text.strip()
if not text:
return None
return converter(text)
convert_optional.pattern = optional_pattern
convert_optional.group_count = group_count
return convert_optional
@classmethod
def with_zero_or_more(cls, converter, pattern=None, listsep=","):
"""
Creates a type converter function for a list<T> with 0..N items
by using the type converter for one item of T.
:param converter: Type converter (function) for data type T.
:param pattern: Regexp pattern for an item (=converter.pattern).
:param listsep: Optional list separator between items (default: ',')
:return: type-converter for list<T>
"""
cardinality = Cardinality.zero_or_more
if not pattern:
pattern = getattr(converter, "pattern", cls.default_pattern)
many0_pattern = cardinality.make_pattern(pattern, listsep)
group_count = cardinality.compute_group_count(pattern)
def convert_list0(text, m=None):
if text:
text = text.strip()
if not text:
return []
return [converter(part.strip()) for part in text.split(listsep)]
convert_list0.pattern = many0_pattern
convert_list0.group_count = group_count
return convert_list0
@classmethod
def with_one_or_more(cls, converter, pattern=None, listsep=","):
"""
Creates a type converter function for a list<T> with 1..N items
by using the type converter for one item of T.
:param converter: Type converter (function) for data type T.
:param pattern: Regexp pattern for an item (=converter.pattern).
:param listsep: Optional list separator between items (default: ',')
:return: Type converter for list<T>
"""
cardinality = Cardinality.one_or_more
if not pattern:
pattern = getattr(converter, "pattern", cls.default_pattern)
many_pattern = cardinality.make_pattern(pattern, listsep)
group_count = cardinality.compute_group_count(pattern)
def convert_list(text, m=None):
return [converter(part.strip()) for part in text.split(listsep)]
convert_list.pattern = many_pattern
convert_list.group_count = group_count
return convert_list
# -- ALIAS METHODS:
@classmethod
def with_optional(cls, converter, pattern=None):
"""Alias for :py:meth:`with_zero_or_one()` method."""
return cls.with_zero_or_one(converter, pattern)
@classmethod
def with_many(cls, converter, pattern=None, listsep=','):
"""Alias for :py:meth:`with_one_or_more()` method."""
return cls.with_one_or_more(converter, pattern, listsep)
@classmethod
def with_many0(cls, converter, pattern=None, listsep=','):
"""Alias for :py:meth:`with_zero_or_more()` method."""
return cls.with_zero_or_more(converter, pattern, listsep)
|