diff options
Diffstat (limited to 'parse_type/cfparse.py')
-rw-r--r-- | parse_type/cfparse.py | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/parse_type/cfparse.py b/parse_type/cfparse.py new file mode 100644 index 0000000..1032a87 --- /dev/null +++ b/parse_type/cfparse.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +""" +Provides an extended :class:`parse.Parser` class that supports the +cardinality fields in (user-defined) types. +""" + +from __future__ import absolute_import +import logging +import parse +from .cardinality_field import CardinalityField, CardinalityFieldTypeBuilder +from .parse_util import FieldParser + + +log = logging.getLogger(__name__) # pylint: disable=invalid-name + + +class Parser(parse.Parser): + """Provides an extended :class:`parse.Parser` with cardinality field support. + A cardinality field is a type suffix for parse format expression, ala: + + "... {person:Person?} ..." -- OPTIONAL: Cardinality zero or one, 0..1 + "... {persons:Person*} ..." -- MANY0: Cardinality zero or more, 0.. + "... {persons:Person+} ..." -- MANY: Cardinality one or more, 1.. + + When the primary type converter for cardinality=1 is provided, + the type variants for the other cardinality cases can be derived from it. + + This parser class automatically creates missing type variants for types + with a cardinality field and passes the extended type dictionary + to its base class. + """ + # -- TYPE-BUILDER: For missing types in Fields with CardinalityField part. + type_builder = CardinalityFieldTypeBuilder + + def __init__(self, schema, extra_types=None, case_sensitive=False, + type_builder=None): + """Creates a parser with CardinalityField part support. + + :param schema: Parse schema (or format) for parser (as string). + :param extra_types: Type dictionary with type converters (or None). + :param case_sensitive: Indicates if case-sensitive regexp are used. + :param type_builder: Type builder to use for missing types. + """ + if extra_types is None: + extra_types = {} + missing = self.create_missing_types(schema, extra_types, type_builder) + if missing: + # pylint: disable=logging-not-lazy + log.debug("MISSING TYPES: %s" % ",".join(missing.keys())) + extra_types.update(missing) + + # -- FINALLY: Delegate to base class. + super(Parser, self).__init__(schema, extra_types, + case_sensitive=case_sensitive) + + @classmethod + def create_missing_types(cls, schema, type_dict, type_builder=None): + """Creates missing types for fields with a CardinalityField part. + It is assumed that the primary type converter for cardinality=1 + is registered in the type dictionary. + + :param schema: Parse schema (or format) for parser (as string). + :param type_dict: Type dictionary with type converters. + :param type_builder: Type builder to use for missing types. + :return: Type dictionary with missing types. Empty, if none. + :raises: MissingTypeError, + if a primary type converter with cardinality=1 is missing. + """ + if not type_builder: + type_builder = cls.type_builder + + missing = cls.extract_missing_special_type_names(schema, type_dict) + return type_builder.create_type_variants(missing, type_dict) + + @staticmethod + def extract_missing_special_type_names(schema, type_dict): + # pylint: disable=invalid-name + """Extract the type names for fields with CardinalityField part. + Selects only the missing type names that are not in the type dictionary. + + :param schema: Parse schema to use (as string). + :param type_dict: Type dictionary with type converters. + :return: Generator with missing type names (as string). + """ + for name in FieldParser.extract_types(schema): + if CardinalityField.matches_type(name) and (name not in type_dict): + yield name |