aboutsummaryrefslogtreecommitdiff
path: root/parse_type/cfparse.py
diff options
context:
space:
mode:
Diffstat (limited to 'parse_type/cfparse.py')
-rw-r--r--parse_type/cfparse.py87
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