|
11 | 11 | from functools import lru_cache |
12 | 12 | from typing import Any, ClassVar, Optional, TypeVar, Union |
13 | 13 |
|
14 | | -from pydantic import GetCoreSchemaHandler, types, validate_call |
| 14 | +from pydantic import GetCoreSchemaHandler, validate_call |
15 | 15 | from pydantic_core import CoreSchema, core_schema |
16 | 16 | from typing_extensions import Literal |
17 | 17 |
|
18 | 18 | from dve.metadata_parser import exc |
| 19 | +from dve.metadata_parser.utilities import generate_alphanumeric_type_name |
19 | 20 |
|
20 | 21 | T = TypeVar("T") |
21 | 22 |
|
@@ -674,60 +675,65 @@ def reportingperiod( |
674 | 675 | return type("ReportingPeriod", (ReportingPeriod, *ReportingPeriod.__bases__), dict_) |
675 | 676 |
|
676 | 677 |
|
677 | | -# TODO - refactor this as it won't work in Pyndatic V2 |
| 678 | +class Alphanumeric(str): |
| 679 | + """ |
| 680 | + Alphanumeric type |
| 681 | + """ |
| 682 | + |
| 683 | + ID_GROUP_STR: Optional[str] = r"[A-Za-z0-9]" |
| 684 | + MIN_DIGITS: Optional[int] = None |
| 685 | + MAX_DIGITS: Optional[int] = 1 |
| 686 | + |
| 687 | + @classmethod |
| 688 | + def generate_pattern_and_type(cls) -> re.Pattern: |
| 689 | + """ |
| 690 | + Generates an alphanumeric regex pattern based on user defined min/max digits. |
| 691 | + """ |
| 692 | + if (cls.MAX_DIGITS == cls.MIN_DIGITS) or ( |
| 693 | + cls.MAX_DIGITS is not None and cls.MIN_DIGITS is None |
| 694 | + ): |
| 695 | + pattern_str = f"{cls.ID_GROUP_STR}{{{cls.MAX_DIGITS}}}" |
| 696 | + else: |
| 697 | + pattern_str = f"{cls.ID_GROUP_STR}{{{cls.MIN_DIGITS},{cls.MAX_DIGITS}}}" |
| 698 | + return re.compile(f"^{pattern_str}$") |
| 699 | + |
| 700 | + @classmethod |
| 701 | + def __get_pydantic_core_schema__( |
| 702 | + cls, source_type: Any, handler: GetCoreSchemaHandler |
| 703 | + ) -> CoreSchema: |
| 704 | + """Gets all validators""" |
| 705 | + return core_schema.str_schema(pattern=cls.generate_pattern_and_type()) |
| 706 | + |
| 707 | + |
678 | 708 | @lru_cache() |
679 | 709 | @validate_call |
680 | | -def alphanumeric( |
681 | | - min_digits: types.NonNegativeInt = 1, # pylint: disable=E1101 |
682 | | - max_digits: types.PositiveInt = 1, # pylint: disable=E1101 |
683 | | -) -> type[_SimpleRegexValidator]: |
684 | | - """Return a regex-validated class which will ensure that |
| 710 | +def alphanumeric(max_digits: int = 1, min_digits: Optional[int] = None) -> type[Alphanumeric]: |
| 711 | + """ |
| 712 | + Return a regex-validated class which will ensure that |
685 | 713 | passed numbers are alphanumeric. |
686 | | -
|
687 | 714 | """ |
688 | | - an_group_str = r"[A-Za-z0-9]" |
689 | | - if max_digits == min_digits: |
690 | | - type_name = f"AN{max_digits}" |
691 | | - pattern_str = f"{an_group_str}{{{max_digits}}}" |
692 | | - else: |
693 | | - type_name = f"AN{min_digits}_{max_digits}" |
694 | | - pattern_str = f"{an_group_str}{{{min_digits},{max_digits}}}" |
695 | | - |
696 | | - dict_ = _SimpleRegexValidator.__dict__.copy() |
697 | | - dict_["pattern"] = re.compile(f"^{pattern_str}$") |
698 | | - |
699 | | - return type( |
700 | | - type_name, |
701 | | - (_SimpleRegexValidator, *_SimpleRegexValidator.__bases__), |
702 | | - dict_, |
703 | | - ) |
| 715 | + dict_ = Alphanumeric.__dict__.copy() |
| 716 | + dict_["MAX_DIGITS"] = max_digits |
| 717 | + dict_["MIN_DIGITS"] = min_digits |
| 718 | + |
| 719 | + _type_name = generate_alphanumeric_type_name(max_digits, min_digits) |
| 720 | + |
| 721 | + return type(_type_name, (Alphanumeric, *Alphanumeric.__bases__), dict_) |
704 | 722 |
|
705 | 723 |
|
706 | | -# TODO - refactor this as it won't work in Pyndatic V2 |
707 | 724 | @lru_cache() |
708 | 725 | @validate_call |
709 | | -def identifier( |
710 | | - min_digits: types.NonNegativeInt = 1, # pylint: disable=E1101 |
711 | | - max_digits: types.PositiveInt = 1, # pylint: disable=E1101 |
712 | | -) -> type[_SimpleRegexValidator]: |
| 726 | +def identifier(max_digits: int = 1, min_digits: Optional[int] = None) -> type[Alphanumeric]: |
713 | 727 | """ |
714 | 728 | Return a regex-validated class which will ensure that |
715 | 729 | passed strings are alphanumeric or in a fixed set of |
716 | 730 | special characters for identifiers. |
717 | 731 | """ |
718 | | - id_group_str = r"[A-Za-z0-9_\-=\/\\#:; ().`*!,|+'\^\[\]]" |
719 | | - if max_digits == min_digits: |
720 | | - type_name = f"AN{max_digits}" |
721 | | - pattern_str = rf"{id_group_str}{{{max_digits}}}" |
722 | | - else: |
723 | | - type_name = f"AN{min_digits}_{max_digits}" |
724 | | - pattern_str = rf"{id_group_str}{{{min_digits},{max_digits}}}" |
725 | | - |
726 | | - dict_ = _SimpleRegexValidator.__dict__.copy() |
727 | | - dict_["pattern"] = re.compile(f"^{pattern_str}$") |
728 | | - |
729 | | - return type( |
730 | | - type_name, |
731 | | - (_SimpleRegexValidator, *_SimpleRegexValidator.__bases__), |
732 | | - dict_, |
733 | | - ) |
| 732 | + dict_ = Alphanumeric.__dict__.copy() |
| 733 | + dict_["MAX_DIGITS"] = max_digits |
| 734 | + dict_["MIN_DIGITS"] = min_digits |
| 735 | + dict_["ID_GROUP_STR"] = r"[A-Za-z0-9_\-=\/\\#:; ().`*!,|+'\^\[\]]" |
| 736 | + |
| 737 | + _type_name = generate_alphanumeric_type_name(max_digits, min_digits) |
| 738 | + |
| 739 | + return type(_type_name, (Alphanumeric, *Alphanumeric.__bases__), dict_) |
0 commit comments