/usr/lib/python3/dist-packages/parse_type/cardinality_field.py is in python3-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 | # -*- coding: utf-8 -*-
"""
Provides support for cardinality fields.
A cardinality field is a type suffix for parse format expression, ala:
"{person:Person?}" #< Cardinality: 0..1 = zero or one = optional
"{persons:Person*}" #< Cardinality: 0..* = zero or more = many0
"{persons:Person+}" #< Cardinality: 1..* = one or more = many
"""
from .cardinality import Cardinality, TypeBuilder
import six
class MissingTypeError(KeyError):
pass
# -----------------------------------------------------------------------------
# CLASS: Cardinality (Field Part)
# -----------------------------------------------------------------------------
class CardinalityField(object):
"""
Cardinality field for parse format expression, ala:
"{person:Person?}" #< Cardinality: 0..1 = zero or one = optional
"{persons:Person*}" #< Cardinality: 0..* = zero or more = many0
"{persons:Person+}" #< Cardinality: 1..* = one or more = many
STATUS: IDEA, currently not accepted in :mod:`parse` module.
"""
# -- MAPPING SUPPORT:
pattern_chars = "?*+"
from_char_map = {
'?': Cardinality.zero_or_one,
'*': Cardinality.zero_or_more,
'+': Cardinality.one_or_more,
}
to_char_map = dict([(value, key) for key, value in list(from_char_map.items())])
@classmethod
def matches_type(cls, type_name):
"""
Checks if a type name uses the CardinalityField naming scheme.
:param type_name: Type name to check (as string).
:return: True, if type name has CardinalityField name suffix.
"""
return type_name and type_name[-1] in CardinalityField.pattern_chars
@classmethod
def split_type(cls, type_name):
"""
Split type of a type name with CardinalityField suffix into its parts.
:param type_name: Type name (as string).
:return: Tuple (type_basename, cardinality)
"""
if cls.matches_type(type_name):
basename = type_name[:-1]
cardinality = cls.from_char_map[type_name[-1]]
else:
# -- ASSUME: Cardinality.one
cardinality = Cardinality.one
basename = type_name
return (basename, cardinality)
@classmethod
def make_type(cls, basename, cardinality):
"""
Build new type name according to CardinalityField naming scheme.
:param basename: Type basename of primary type (as string).
:param cardinality: Cardinality of the new type (as Cardinality item).
:return: Type name with CardinalityField suffix (if needed)
"""
if cardinality is Cardinality.one:
# -- POSTCONDITION: assert not cls.make_type(type_name)
return basename
# -- NORMAL CASE: type with CardinalityField suffix.
type_name = "%s%s" % (basename, cls.to_char_map[cardinality])
# -- POSTCONDITION: assert cls.make_type(type_name)
return type_name
# -----------------------------------------------------------------------------
# CLASS: CardinalityFieldTypeBuilder
# -----------------------------------------------------------------------------
class CardinalityFieldTypeBuilder(object):
"""
Utility class to create type converters based on:
* the CardinalityField naming scheme and
* type converter for cardinality=1
"""
listsep = ','
@classmethod
def create_type_variant(cls, type_name, type_converter):
"""
Create type variants for types with a cardinality field.
The new type converters are based on the type converter with
cardinality=1.
.. code-block:: python
import parse
@parse.with_pattern(r'\d+')
def parse_number(text):
return int(text)
new_type = CardinalityFieldTypeBuilder.create_type_variant(
"Number+", parse_number)
new_type = CardinalityFieldTypeBuilder.create_type_variant(
"Number+", dict(Number=parse_number))
:param type_name: Type name with cardinality field suffix.
:param type_converter: Type converter or type dictionary.
:return: Type converter variant (function).
:raises: ValueError, if type_name does not end with CardinalityField
:raises: MissingTypeError, if type_converter is missing in type_dict
"""
assert isinstance(type_name, six.string_types)
if not CardinalityField.matches_type(type_name):
message = "type_name='%s' has no CardinalityField" % type_name
raise ValueError(message)
primary_name, cardinality = CardinalityField.split_type(type_name)
if isinstance(type_converter, dict):
type_dict = type_converter
type_converter = type_dict.get(primary_name, None)
if not type_converter:
raise MissingTypeError(primary_name)
assert callable(type_converter)
type_variant = TypeBuilder.with_cardinality(cardinality,
type_converter, listsep=cls.listsep)
type_variant.name = type_name
return type_variant
@classmethod
def create_type_variants(cls, type_names, type_dict):
"""
Create type variants for types with a cardinality field.
The new type converters are based on the type converter with
cardinality=1.
.. code-block:: python
# -- USE: parse_number() type converter function.
new_types = CardinalityFieldTypeBuilder.create_type_variants(
["Number?", "Number+"], dict(Number=parse_number))
:param type_names: List of type names with cardinality field suffix.
:param type_dict: Type dictionary with named type converters.
:return: Type dictionary with type converter variants.
"""
type_variant_dict = {}
for type_name in type_names:
type_variant = cls.create_type_variant(type_name, type_dict)
type_variant_dict[type_name] = type_variant
return type_variant_dict
# XXX-JE-TODO: Check if really needed.
@classmethod
def create_missing_type_variants(cls, type_names, type_dict):
"""
Create missing type variants for types with a cardinality field.
:param type_names: List of type names with cardinality field suffix.
:param type_dict: Type dictionary with named type converters.
:return: Type dictionary with missing type converter variants.
"""
missing_type_names = [ name for name in type_names
if name not in type_dict ]
return cls.create_type_variants(missing_type_names, type_dict)
|