pycarlo 0.10.194__py3-none-any.whl → 0.11.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pycarlo
3
- Version: 0.10.194
3
+ Version: 0.11.15
4
4
  Summary: Monte Carlo's Python SDK
5
5
  Home-page: https://www.montecarlodata.com/
6
6
  Author: Monte Carlo Data, Inc
@@ -20,9 +20,12 @@ pycarlo/features/circuit_breakers/service.py,sha256=TljwMOhA5igBumkpJwM22iEJGyvt
20
20
  pycarlo/features/dbt/__init__.py,sha256=A2cFr8_aSY_kDw1m7jR6QkHfiBMC1cZ6O8WosF9XrRg,85
21
21
  pycarlo/features/dbt/dbt_importer.py,sha256=eJb9Jiu7tAEb_xsLO-ycDOjjVm-LLfTtbAzlzIRxT5I,7328
22
22
  pycarlo/features/dbt/queries.py,sha256=9o1HevRECYyGXQ0lG0LrN4iuuXCS-SWjz7NTgAAZIro,621
23
- pycarlo/features/metadata/__init__.py,sha256=lSfQ-3W6d4YCWpjWlbxBNm07KomrmPORweCGLvLbGuM,360
24
- pycarlo/features/metadata/allow_block_list.py,sha256=UWqGOzLELRRryHVRgNXqlfUfHFX9SeXuhKix_5B_7CY,5823
25
- pycarlo/features/metadata/metadata_filters_container.py,sha256=iHMd3S-JQLkTVgiKU5sgeJN9Wb6KWm-6YuulOCStGZ4,12670
23
+ pycarlo/features/metadata/__init__.py,sha256=0RDVHnwPvQcNXkeXEAxL4VJ8VWrl2P0fft_Kl2nlo7I,912
24
+ pycarlo/features/metadata/asset_allow_block_list.py,sha256=jXCS7HtUJhexEXZyRzyN4MT-BPSaMTKWCWiBT_l-Ijo,761
25
+ pycarlo/features/metadata/asset_filters_container.py,sha256=O15SC6u7HMGlViYnX7H8MRFttQrIXQd3a0oOrz7My5U,3411
26
+ pycarlo/features/metadata/base_allow_block_list.py,sha256=c8zd0BXkNSfQ3LkNC_A0KrO2AsYtIowc8FjbdyDyDu0,4738
27
+ pycarlo/features/metadata/metadata_allow_block_list.py,sha256=HzgXE0WhwDZoBHeV04e8dwe88rUSVVnOl8nFEPlb0jA,3496
28
+ pycarlo/features/metadata/metadata_filters_container.py,sha256=GCbk-t7Njq2IiQrre186aN3DT2ytN-8RTwBPnBmfgJA,12715
26
29
  pycarlo/features/pii/__init__.py,sha256=w5X-oD8HWaL6fP2jt40AhlXO-MNzlVAlhRaZ5kQqAZY,247
27
30
  pycarlo/features/pii/constants.py,sha256=XWeiikXk9AtljdWsGfl49b9zI6w8EzK8F__Euc0vQ3w,70
28
31
  pycarlo/features/pii/pii_filterer.py,sha256=k53b_V_mddY4A17-DJ5vQKszFDlUaiP3E650JFHAeJA,6209
@@ -35,10 +38,10 @@ pycarlo/features/user/queries.py,sha256=m97RvM0oiBlrU5xmOwe_JJ5N0G0NG5hIOeyQqN2O
35
38
  pycarlo/features/user/service.py,sha256=DHkhuonySaHro07NTd0YNe3cNkDk62CiRTY77dhVaMs,2890
36
39
  pycarlo/lib/README.md,sha256=QGNeUefPzLKGyZqn5aITpcFgkC9WQTNS292BGisRFHk,139
37
40
  pycarlo/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- pycarlo/lib/schema.json,sha256=UEjfprp10pXE6593WmYyj2kER6DuIxBIkc84HUTPBVM,6336286
39
- pycarlo/lib/schema.py,sha256=plDIF2K1mq-nUIksRS9WNxXZ1Pz25tIC4somKPrD4F4,2759178
40
- pycarlo-0.10.194.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
41
- pycarlo-0.10.194.dist-info/METADATA,sha256=4weWf_U3sSZg5WXxeS1bDNjbjMikBFDSoPSeoc0iv7k,8742
42
- pycarlo-0.10.194.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
43
- pycarlo-0.10.194.dist-info/top_level.txt,sha256=TIE04H4pgzGaFxAB-gvkmVAUOAoHxxFfhnEcpuQ5bF4,8
44
- pycarlo-0.10.194.dist-info/RECORD,,
41
+ pycarlo/lib/schema.json,sha256=QPrl1YZ0WF2HNxk4EJG3PuypjUEu6z9cT-zby0oXlqY,6521200
42
+ pycarlo/lib/schema.py,sha256=6MMMErpEG-oFTgOfGBoZmQw5tgo4li7XFKXA-JqGY3k,2832020
43
+ pycarlo-0.11.15.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
44
+ pycarlo-0.11.15.dist-info/METADATA,sha256=IiKzQSFemktwSfQa1MtnM2A2AeKeBxnbC_y4XwQaWx0,8741
45
+ pycarlo-0.11.15.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
46
+ pycarlo-0.11.15.dist-info/top_level.txt,sha256=TIE04H4pgzGaFxAB-gvkmVAUOAoHxxFfhnEcpuQ5bF4,8
47
+ pycarlo-0.11.15.dist-info/RECORD,,
@@ -1,159 +0,0 @@
1
- import enum
2
- import re
3
- from dataclasses import dataclass, field
4
- from typing import Any, Callable, List, Optional
5
-
6
- from dataclasses_json import config, dataclass_json
7
-
8
- from pycarlo.common import get_logger
9
-
10
- logger = get_logger(__name__)
11
-
12
- # For documentation and samples check the link below:
13
- # https://www.notion.so/montecarlodata/Catalog-Schema-Filtering-59edd6eff7f74c94ab6bfca75d2e3ff1
14
-
15
-
16
- def _exclude_none_values(value: Any) -> bool:
17
- return value is None
18
-
19
-
20
- class FilterEffectType(enum.Enum):
21
- BLOCK = "block"
22
- ALLOW = "allow"
23
-
24
-
25
- class FilterType(enum.Enum):
26
- EXACT_MATCH = "exact_match"
27
- PREFIX = "prefix"
28
- SUFFIX = "suffix"
29
- SUBSTRING = "substring"
30
- REGEXP = "regexp"
31
-
32
-
33
- @dataclass_json
34
- @dataclass
35
- class MetadataFilter:
36
- # we're using exclude=_exclude_none_values to prevent these properties to be serialized to json
37
- # when None, to keep the json doc simpler
38
- project: Optional[str] = field(metadata=config(exclude=_exclude_none_values), default=None)
39
- dataset: Optional[str] = field(metadata=config(exclude=_exclude_none_values), default=None)
40
- table_type: Optional[str] = field(metadata=config(exclude=_exclude_none_values), default=None)
41
- table_name: Optional[str] = field(metadata=config(exclude=_exclude_none_values), default=None)
42
- type: FilterType = FilterType.EXACT_MATCH
43
- effect: FilterEffectType = FilterEffectType.BLOCK
44
-
45
- def matches(self, force_regexp: bool = False, **kwargs: Any) -> bool:
46
- """
47
- Returns True if all properties specified in kwargs match the conditions specified in
48
- properties of the same name in this object.
49
- Supported keys in kwargs: 'project', 'dataset', 'table', 'table_type'
50
- For example kwargs={'project': 'prj_1'} will evaluate if 'prj_1' matches the condition in
51
- self.project. For kwargs={'project': 'prj_1', 'dataset': 'ds_1'} will evaluate if 'prj_1'
52
- matches the condition in self.project and if 'ds_1' matches the condition in self.dataset.
53
- If any of the conditions (for example self.project) is None, that condition will be matched.
54
- """
55
- if not kwargs:
56
- raise ValueError("At least one field needs to be specified for matching")
57
-
58
- # kwargs must match the field names in this class, if any of them do not,
59
- # invalidate the filter.
60
- try:
61
- is_match = all(
62
- self._safe_match(
63
- component=getattr(self, component),
64
- value=value,
65
- force_regexp=force_regexp,
66
- filter_type=self.type
67
- if self.filter_type_target_field() == component
68
- else FilterType.EXACT_MATCH,
69
- )
70
- for component, value in kwargs.items()
71
- )
72
- except AttributeError:
73
- is_match = False
74
-
75
- return is_match
76
-
77
- def filter_type_target_field(self) -> str:
78
- """
79
- The field that is evaluated using filter type. Other fields should be
80
- compared using exact match.
81
- """
82
- if self.table_name is not None:
83
- return "table_name"
84
- if self.dataset is not None:
85
- return "dataset"
86
- if self.project is not None:
87
- return "project"
88
-
89
- logger.exception("Invalid filter, missing target values")
90
- return ""
91
-
92
- @classmethod
93
- def _safe_match(
94
- cls,
95
- component: Optional[str],
96
- value: Optional[str],
97
- force_regexp: bool,
98
- filter_type: FilterType,
99
- ) -> bool:
100
- # Field not specified on this object, e.g. self.dataset=None, which matches everything
101
- if component is None:
102
- return True
103
- # The value in kwargs is empty, it does not match the condition.
104
- if value is None:
105
- return False
106
-
107
- # Convert it in lowercase. In the normalizer we are converting identifiers
108
- # (like project/dataset) to lowercase so the metadata filters may be defined with
109
- # lowercase on the UI, however on Snowflake the identifiers are usually in uppercase.
110
- # Therefore, we perform the evaluation case-insensitive.
111
- component = component.lower()
112
- value = value.lower()
113
-
114
- if force_regexp or filter_type == FilterType.REGEXP:
115
- regexp = f"^{component}$" # Anchor the regexp to be more strict about what to match.
116
- return re.match(regexp, value) is not None
117
- elif filter_type == FilterType.PREFIX:
118
- return value.startswith(component)
119
- elif filter_type == FilterType.SUFFIX:
120
- return value.endswith(component)
121
- elif filter_type == FilterType.SUBSTRING:
122
- return component in value
123
- else:
124
- return component == value
125
-
126
-
127
- @dataclass_json
128
- @dataclass
129
- class AllowBlockList:
130
- filters: List[MetadataFilter] = field(default_factory=list)
131
- default_effect: FilterEffectType = FilterEffectType.ALLOW
132
-
133
- @property
134
- def other_effect(self) -> FilterEffectType:
135
- return (
136
- FilterEffectType.ALLOW
137
- if self.default_effect == FilterEffectType.BLOCK
138
- else FilterEffectType.BLOCK
139
- )
140
-
141
- def get_default_effect_filters(
142
- self, condition: Optional[Callable[[MetadataFilter], bool]] = None
143
- ) -> List[MetadataFilter]:
144
- return list(
145
- filter(
146
- lambda f: f.effect == self.default_effect and (condition is None or condition(f)),
147
- self.filters,
148
- )
149
- )
150
-
151
- def get_other_effect_filters(
152
- self, condition: Optional[Callable[[MetadataFilter], bool]] = None
153
- ) -> List[MetadataFilter]:
154
- return list(
155
- filter(
156
- lambda f: f.effect != self.default_effect and (condition is None or condition(f)),
157
- self.filters,
158
- )
159
- )