PyFunceble-dev 4.3.0a13__py3-none-any.whl → 4.3.0a14__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.
@@ -64,6 +64,7 @@ import PyFunceble.storage
64
64
  from PyFunceble.checker.availability.extras.base import ExtraRuleHandlerBase
65
65
  from PyFunceble.checker.availability.extras.dns import DNSRulesHandler
66
66
  from PyFunceble.checker.availability.extras.etoxic import EToxicHandler
67
+ from PyFunceble.checker.availability.extras.external import ExternalRulesHandler
67
68
  from PyFunceble.checker.availability.extras.rules import ExtraRulesHandler
68
69
  from PyFunceble.checker.availability.extras.subject_switch import (
69
70
  SubjectSwitchRulesHandler,
@@ -174,6 +175,7 @@ class AvailabilityCheckerBase(CheckerBase):
174
175
  DNSRulesHandler(),
175
176
  EToxicHandler(),
176
177
  ExtraRulesHandler(),
178
+ ExternalRulesHandler(rulesets=PyFunceble.storage.SPECIAL_RULES),
177
179
  ]
178
180
  self.db_session = db_session
179
181
 
@@ -328,7 +328,7 @@ class ExtraRuleHandlerBase:
328
328
  def handle_regex_match_mode(_req: requests.Response):
329
329
  matches2search_result = {}
330
330
 
331
- for header, loc_matches in matches:
331
+ for header, loc_matches in matches.items():
332
332
  matches2search_result[header] = False
333
333
 
334
334
  if header not in _req.headers:
@@ -0,0 +1,341 @@
1
+ """
2
+ The tool to check the availability or syntax of domain, IP or URL.
3
+
4
+ ::
5
+
6
+
7
+ ██████╗ ██╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗███████╗██████╗ ██╗ ███████╗
8
+ ██╔══██╗╚██╗ ██╔╝██╔════╝██║ ██║████╗ ██║██╔════╝██╔════╝██╔══██╗██║ ██╔════╝
9
+ ██████╔╝ ╚████╔╝ █████╗ ██║ ██║██╔██╗ ██║██║ █████╗ ██████╔╝██║ █████╗
10
+ ██╔═══╝ ╚██╔╝ ██╔══╝ ██║ ██║██║╚██╗██║██║ ██╔══╝ ██╔══██╗██║ ██╔══╝
11
+ ██║ ██║ ██║ ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
12
+ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝
13
+
14
+ Provides the extra rules handler based on some DNS records.
15
+
16
+ Author:
17
+ Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom
18
+
19
+ Special thanks:
20
+ https://pyfunceble.github.io/#/special-thanks
21
+
22
+ Contributors:
23
+ https://pyfunceble.github.io/#/contributors
24
+
25
+ Project link:
26
+ https://github.com/funilrys/PyFunceble
27
+
28
+ Project documentation:
29
+ https://docs.pyfunceble.com
30
+
31
+ Project homepage:
32
+ https://pyfunceble.github.io/
33
+
34
+ License:
35
+ ::
36
+
37
+
38
+ Copyright 2017, 2018, 2019, 2020, 2022, 2023, 2024 Nissar Chababy
39
+
40
+ Licensed under the Apache License, Version 2.0 (the "License");
41
+ you may not use this file except in compliance with the License.
42
+ You may obtain a copy of the License at
43
+
44
+ https://www.apache.org/licenses/LICENSE-2.0
45
+
46
+ Unless required by applicable law or agreed to in writing, software
47
+ distributed under the License is distributed on an "AS IS" BASIS,
48
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49
+ See the License for the specific language governing permissions and
50
+ limitations under the License.
51
+ """
52
+
53
+ # pylint: disable=line-too-long
54
+
55
+ from typing import Optional
56
+
57
+ from PyFunceble.checker.availability.extras.base import ExtraRuleHandlerBase
58
+ from PyFunceble.checker.availability.status import AvailabilityCheckerStatus
59
+
60
+
61
+ class ExternalRulesHandler(ExtraRuleHandlerBase):
62
+ """
63
+ Provides the external rules handler that is used to handle the external
64
+ provided rules.
65
+
66
+ Through this handler, end-user can provide their own rules to handle
67
+ the availability status of a subject.
68
+
69
+ :param status:
70
+ The previously gathered status.
71
+ :type status:
72
+ :class:`~PyFunceble.checker.availability.status.AvailabilityCheckerStatus`
73
+ """
74
+
75
+ rulesets: list = []
76
+ """
77
+ The rulesets to process.
78
+
79
+ If you want to switch from the status code, you should provide a dict
80
+ with the following structure:
81
+
82
+ {
83
+ "subject_pattern": ".*", // The pattern the subject should match.
84
+ "validation_type": "status_code", // Type of validation (status_code, headers, body, etc.)
85
+ "state_transition": "up", // "up" -> ACTIVE, "down" -> INACTIVE
86
+ "required_status_code": [404], // Status code to match.
87
+ }
88
+
89
+ If you want to switch from the headers, you should provide a dict
90
+
91
+ {
92
+ "subject_pattern": ".*", // The pattern the subject should match.
93
+ "validation_type": "headers", // Type of validation (status_code, headers, body, etc.)
94
+ "state_transition": "up", // "up" -> ACTIVE, "down" -> INACTIVE
95
+ "required_headers_patterns": { // Required, the headers to match.
96
+ "header_name": ["possible", "values"]
97
+ },
98
+ }
99
+
100
+ If you want to switch from the body, you should provide a dict
101
+
102
+ {
103
+ "subject_pattern": ".*", // The pattern the subject should match.
104
+ "validation_type": "body", // Type of validation (status_code, headers, body, etc.)
105
+ "state_transition": "up", // "up" -> ACTIVE, "down" -> INACTIVE
106
+ "required_body_patterns": ["regex1", "regex2"] // Required, the body patterns to match.
107
+ }
108
+
109
+ If you want to switch from a combination of headers and body, you should provide a dict
110
+
111
+ {
112
+ "subject_pattern": ".*", // The pattern the subject should match.
113
+ "validation_type": "headers+body", // Type of validation (status_code, headers, body, etc.)
114
+ "state_transition": "up", // "up" -> ACTIVE, "down" -> INACTIVE
115
+ "required_headers_patterns": { // Required, the headers to match.
116
+ "header_name": ["possible", "values"]
117
+ },
118
+ "required_body_patterns": ["regex1", "regex2"] // Required, the body patterns to match.
119
+ }
120
+
121
+ If you want to switch from a combination of all, you should provide a dict
122
+
123
+ {
124
+ "subject_pattern": ".*", // The pattern the subject should match.
125
+ "validation_type": "all", // Type of validation (status_code, headers, body, etc.)
126
+ "state_transition": "up", // "up" -> ACTIVE, "down" -> INACTIVE
127
+ "required_status_code": [404], // Optional, Status code to match.
128
+ "required_headers_patterns": { // Optional, the headers to match.
129
+ "header_name": ["possible", "values"]
130
+ },
131
+ "required_body_patterns": ["regex1", "regex2"] // Optional, the body patterns to match.
132
+ }
133
+
134
+ """
135
+
136
+ def __init__(
137
+ self,
138
+ status: Optional[AvailabilityCheckerStatus] = None,
139
+ *,
140
+ rulesets: list = None
141
+ ) -> None:
142
+ if rulesets is not None:
143
+ self.rulesets = rulesets
144
+
145
+ super().__init__(status)
146
+
147
+ def switch_from_status_code_rule(self, rule: dict) -> "ExternalRulesHandler":
148
+ """
149
+ Switch from the status code rule.
150
+
151
+ :param rule:
152
+ The rule to switch from.
153
+ :type rule: dict
154
+ """
155
+
156
+ required_keys = ["validation_type", "required_status_code"]
157
+
158
+ if any(x not in rule for x in required_keys):
159
+ return self
160
+
161
+ if rule["validation_type"] != "status_code":
162
+ return self
163
+
164
+ if all(
165
+ self.status.http_status_code != int(x) for x in rule["required_status_code"]
166
+ ):
167
+ return self
168
+
169
+ if rule["state_transition"] == "up":
170
+ return self.switch_to_up()
171
+
172
+ if rule["state_transition"] == "down":
173
+ return self.switch_to_down()
174
+
175
+ return self
176
+
177
+ def switch_from_headers_rule(self, rule: dict) -> "ExternalRulesHandler":
178
+ """
179
+ Switch from the headers rule.
180
+
181
+ :param rule:
182
+ The rule to switch from.
183
+ :type rule: dict
184
+ """
185
+
186
+ required_keys = ["validation_type", "required_headers_patterns"]
187
+
188
+ if any(x not in rule for x in required_keys):
189
+ return self
190
+
191
+ if rule["validation_type"] != "headers":
192
+ return self
193
+
194
+ if rule["state_transition"] == "up":
195
+ switch_method = self.switch_to_up
196
+
197
+ if rule["state_transition"] == "down":
198
+ switch_method = self.switch_to_down
199
+
200
+ if "required_headers_patterns" in rule and rule["required_headers_patterns"]:
201
+ # pylint: disable=possibly-used-before-assignment
202
+ self.do_on_header_match(
203
+ self.req_url,
204
+ rule["required_headers_patterns"],
205
+ method=switch_method,
206
+ strict=False,
207
+ allow_redirects=False,
208
+ )
209
+
210
+ return self
211
+
212
+ def switch_from_body_rule(self, rule: dict) -> "ExternalRulesHandler":
213
+ """
214
+ Switch from the body rule.
215
+
216
+ :param rule:
217
+ The rule to switch from.
218
+ :type rule: dict
219
+ """
220
+
221
+ required_keys = ["validation_type", "required_body_patterns"]
222
+
223
+ if any(x not in rule for x in required_keys):
224
+ return self
225
+
226
+ if rule["validation_type"] != "body":
227
+ return self
228
+
229
+ if rule["state_transition"] == "up":
230
+ switch_method = self.switch_to_up
231
+
232
+ if rule["state_transition"] == "down":
233
+ switch_method = self.switch_to_down
234
+
235
+ if "required_body_patterns" in rule and rule["required_body_patterns"]:
236
+ # pylint: disable=possibly-used-before-assignment
237
+ self.do_on_body_match(
238
+ self.req_url,
239
+ rule["required_body_patterns"],
240
+ method=switch_method,
241
+ strict=False,
242
+ allow_redirects=False,
243
+ )
244
+
245
+ return self
246
+
247
+ def switch_from_all_rule(self, rule: dict) -> "ExternalRulesHandler":
248
+ """
249
+ Switch from the all rule.
250
+
251
+ :param rule:
252
+ The rule to switch from.
253
+ :type rule: dict
254
+ """
255
+
256
+ required_keys = [
257
+ "validation_type",
258
+ ]
259
+
260
+ if any(x not in rule for x in required_keys):
261
+ return self
262
+
263
+ if rule["validation_type"] != "all":
264
+ return self
265
+
266
+ if rule["state_transition"] == "up":
267
+ switch_method = self.switch_to_up
268
+
269
+ if rule["state_transition"] == "down":
270
+ switch_method = self.switch_to_down
271
+
272
+ if (
273
+ "required_status_code" in rule
274
+ and rule["required_status_code"]
275
+ and any(
276
+ self.status.http_status_code == int(x)
277
+ for x in rule["required_status_code"]
278
+ )
279
+ ):
280
+ # pylint: disable=possibly-used-before-assignment
281
+ switch_method()
282
+
283
+ if "required_headers_patterns" in rule and rule["required_headers_patterns"]:
284
+ self.do_on_header_match(
285
+ self.req_url,
286
+ rule["required_headers_patterns"],
287
+ method=switch_method,
288
+ strict=False,
289
+ allow_redirects=False,
290
+ )
291
+
292
+ if "required_body_patterns" in rule and rule["required_body_patterns"]:
293
+ self.do_on_body_match(
294
+ self.req_url,
295
+ rule["required_body_patterns"],
296
+ method=switch_method,
297
+ strict=False,
298
+ allow_redirects=False,
299
+ )
300
+
301
+ return self
302
+
303
+ @ExtraRuleHandlerBase.ensure_status_is_given
304
+ @ExtraRuleHandlerBase.setup_status_before
305
+ @ExtraRuleHandlerBase.setup_status_after
306
+ def start(self) -> "ExternalRulesHandler":
307
+ """
308
+ Process the check and handling of the external rules for the given subject.
309
+ """
310
+
311
+ required_keys = ["subject_pattern", "validation_type", "state_transition"]
312
+
313
+ for rule in self.rulesets:
314
+ if any(x not in rule for x in required_keys):
315
+ continue
316
+
317
+ if not self.regex_helper.set_regex(rule["subject_pattern"]).match(
318
+ self.status.netloc, return_match=False
319
+ ):
320
+ continue
321
+
322
+ if rule["state_transition"] not in ["up", "down"]:
323
+ continue
324
+
325
+ if self.status.status_after_extra_rules:
326
+ # We already switched the status.
327
+ break
328
+
329
+ if rule["validation_type"] == "status_code":
330
+ self.switch_from_status_code_rule(rule)
331
+ elif rule["validation_type"] == "headers":
332
+ self.switch_from_headers_rule(rule)
333
+ elif rule["validation_type"] == "body":
334
+ self.switch_from_body_rule(rule)
335
+ elif rule["validation_type"] == "headers+body":
336
+ self.switch_from_headers_rule(rule)
337
+ self.switch_from_body_rule(rule)
338
+ elif rule["validation_type"] == "all":
339
+ self.switch_from_all_rule(rule)
340
+
341
+ return self
@@ -651,6 +651,9 @@ class ConfigLoader:
651
651
  if "proxy" in config and config["proxy"]:
652
652
  PyFunceble.storage.PROXY = Box(config["proxy"])
653
653
 
654
+ if "special_rules" in config and config["special_rules"]:
655
+ PyFunceble.storage.SPECIAL_RULES = config["special_rules"]
656
+
654
657
  # Early load user agents to allow usage of defined user agents.
655
658
  UserAgentDataset().get_latest()
656
659
 
@@ -676,6 +679,7 @@ class ConfigLoader:
676
679
  PyFunceble.storage.PLATFORM = Box({})
677
680
  PyFunceble.storage.LINKS = Box({})
678
681
  PyFunceble.storage.PROXY = Box({})
682
+ PyFunceble.storage.SPECIAL_RULES = Box({})
679
683
  except (AttributeError, TypeError): # pragma: no cover ## Safety.
680
684
  pass
681
685
 
@@ -852,3 +852,86 @@ platform:
852
852
  # CLI Argument: none
853
853
  checker_exclude:
854
854
  - none
855
+
856
+ special_rules:
857
+ # Let end-user define or integrate their own special rules.
858
+ #
859
+ # The idea: We want to give the end-user the possibility to define their own
860
+ # rules. This is useful when they want to switch the status of a subject based
861
+ # on a specific pattern, header, body, or status code.
862
+ #
863
+ # The structure:
864
+ # subject_pattern:
865
+ # -> The pattern to match against the subject.
866
+ # validation_type:
867
+ # -> The type of validation to perform. It can be one of the following:
868
+ # - all: A combination of everything (first match wins).
869
+ # - status_code: Only the status code.
870
+ # - headers: Only the headers.
871
+ # - body: Only the body.
872
+ # - headers+body: Match against the headers and the body.
873
+ # state_transition:
874
+ # -> The state to switch to when the validation is successful.
875
+ # When set to `down`, the status will be switched to INACTIVE. When set
876
+ # to `up`, the status will be switched to ACTIVE.
877
+ # required_status_code:
878
+ # -> A list of status code to match against.
879
+ # required_headers_patterns:
880
+ # -> A dictionary of headers to match against. The key is the header name
881
+ # and the value is a list of patterns to match against.
882
+ # required_body_patterns:
883
+ # -> A list of patterns to match against the body.
884
+ #
885
+ # Examples:
886
+ # When testing httpbin.org, we want to switch the status to down when the
887
+ # status code is 403 and the server header contains "gunicorn".
888
+ #
889
+ # - subject_pattern: "^httpbin\\.org$"
890
+ # validation_type: all
891
+ # state_transition: down
892
+ # required_status_code:
893
+ # - 403
894
+ # required_headers_patterns:
895
+ # server:
896
+ # - gunicorn
897
+ #
898
+ # When testing example.org, we want to switch the status to down when the
899
+ # status code is 404.
900
+ #
901
+ # - subject_pattern: "^example\\.org$"
902
+ # validation_type: status_code
903
+ # state_transition: down
904
+ # required_status_code:
905
+ # - 404
906
+ #
907
+ # When testing example.com, we want to switch The body and headers.the status to down when the
908
+ # header `server` contains `nginx`.
909
+ #
910
+ # - subject_pattern: "^example\\.com$"
911
+ # validation_type: headers
912
+ # state_transition: down
913
+ # required_headers_patterns:
914
+ # server:
915
+ # - nginx
916
+ #
917
+ # When testing example.net, we want to switch the status to down when the
918
+ # body contains "Hello, World!".
919
+ #
920
+ # - subject_pattern: "^example\\.net$"
921
+ # validation_type: body
922
+ # state_transition: down
923
+ # required_body_patterns:
924
+ # - Hello, World!
925
+ #
926
+ # When testing example.dev, we want to switch the status to down when the
927
+ # headers server contains `nginx` or the body contains "Hello, World!".
928
+ #
929
+ # - subject_pattern: "^example\\.dev$"
930
+ # validation_type: headers+body
931
+ # state_transition: down
932
+ # required_headers_patterns:
933
+ # server:
934
+ # - nginx
935
+ # required_body_patterns:
936
+ # - Hello, World!
937
+ []
PyFunceble/storage.py CHANGED
@@ -52,7 +52,7 @@ License:
52
52
  """
53
53
 
54
54
  import os
55
- from typing import Optional
55
+ from typing import List, Optional
56
56
 
57
57
  from box import Box
58
58
  from dotenv import load_dotenv
@@ -60,7 +60,7 @@ from dotenv import load_dotenv
60
60
  from PyFunceble.storage_facility import get_config_directory
61
61
 
62
62
  PROJECT_NAME: str = "PyFunceble"
63
- PROJECT_VERSION: str = "4.3.0a13.dev (Blue Duckling: Tulip)"
63
+ PROJECT_VERSION: str = "4.3.0a14.dev (Blue Duckling: Tulip)"
64
64
 
65
65
  DISTRIBUTED_CONFIGURATION_FILENAME: str = ".PyFunceble_production.yaml"
66
66
 
@@ -107,6 +107,7 @@ STATUS: Optional[Box] = Box(
107
107
  )
108
108
  HTTP_CODES: Optional[Box] = Box({})
109
109
  PLATFORM: Optional[Box] = Box({})
110
+ SPECIAL_RULES: Optional[List[dict]] = []
110
111
  LINKS: Optional[Box] = Box({})
111
112
  PROXY: Optional[Box] = Box({})
112
113
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyFunceble-dev
3
- Version: 4.3.0a13
3
+ Version: 4.3.0a14
4
4
  Summary: The tool to check the availability or syntax of domain, IP or URL.
5
5
  Home-page: https://github.com/funilrys/PyFunceble
6
6
  Author: funilrys
@@ -22,169 +22,169 @@ Classifier: License :: OSI Approved
22
22
  Requires-Python: >=3.9, <4
23
23
  Description-Content-Type: text/markdown
24
24
  License-File: LICENSE
25
+ Requires-Dist: colorama
26
+ Requires-Dist: PyMySQL
27
+ Requires-Dist: python-box[all]~=6.0.0
25
28
  Requires-Dist: requests[socks]<3
29
+ Requires-Dist: packaging
30
+ Requires-Dist: inflection
31
+ Requires-Dist: shtab
26
32
  Requires-Dist: domain2idna~=1.12.0
27
33
  Requires-Dist: setuptools>=65.5.1
34
+ Requires-Dist: dnspython[DOH]~=2.6.0
35
+ Requires-Dist: SQLAlchemy~=2.0
28
36
  Requires-Dist: python-dotenv
29
- Requires-Dist: shtab
30
37
  Requires-Dist: PyYAML
31
- Requires-Dist: packaging
32
- Requires-Dist: inflection
33
- Requires-Dist: python-box[all]~=6.0.0
34
- Requires-Dist: PyMySQL
35
- Requires-Dist: dnspython[DOH]~=2.6.0
36
38
  Requires-Dist: alembic
37
- Requires-Dist: SQLAlchemy~=2.0
38
- Requires-Dist: colorama
39
39
  Provides-Extra: docs
40
- Requires-Dist: mkdocs-literate-nav~=0.6; extra == "docs"
41
- Requires-Dist: mkdocs-gen-files~=0.5; extra == "docs"
42
- Requires-Dist: mkdocstrings[python]~=0.26; extra == "docs"
43
- Requires-Dist: zipp>=3.19.1; extra == "docs"
40
+ Requires-Dist: mkdocs-material~=9.5; extra == "docs"
41
+ Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "docs"
44
42
  Requires-Dist: mkdocs-git-authors-plugin~=0.9; extra == "docs"
45
43
  Requires-Dist: pymdown-extensions~=10.9; extra == "docs"
46
- Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "docs"
47
- Requires-Dist: mkdocs-macros-plugin~=1.2; extra == "docs"
44
+ Requires-Dist: mkdocs-gen-files~=0.5; extra == "docs"
48
45
  Requires-Dist: mkdocs~=1.5; extra == "docs"
46
+ Requires-Dist: mkdocstrings[python]~=0.26; extra == "docs"
47
+ Requires-Dist: mkdocs-literate-nav~=0.6; extra == "docs"
49
48
  Requires-Dist: mkdocs-section-index~=0.3; extra == "docs"
50
- Requires-Dist: mkdocs-material~=9.5; extra == "docs"
49
+ Requires-Dist: zipp>=3.19.1; extra == "docs"
50
+ Requires-Dist: mkdocs-macros-plugin~=1.2; extra == "docs"
51
51
  Provides-Extra: dev
52
52
  Requires-Dist: isort; extra == "dev"
53
- Requires-Dist: black; extra == "dev"
54
53
  Requires-Dist: flake8; extra == "dev"
55
54
  Requires-Dist: pylint; extra == "dev"
55
+ Requires-Dist: black; extra == "dev"
56
56
  Provides-Extra: test
57
57
  Requires-Dist: coverage; extra == "test"
58
58
  Requires-Dist: tox; extra == "test"
59
59
  Provides-Extra: psql
60
+ Requires-Dist: colorama; extra == "psql"
61
+ Requires-Dist: PyMySQL; extra == "psql"
62
+ Requires-Dist: python-box[all]~=6.0.0; extra == "psql"
60
63
  Requires-Dist: requests[socks]<3; extra == "psql"
64
+ Requires-Dist: packaging; extra == "psql"
65
+ Requires-Dist: inflection; extra == "psql"
66
+ Requires-Dist: shtab; extra == "psql"
61
67
  Requires-Dist: domain2idna~=1.12.0; extra == "psql"
62
68
  Requires-Dist: setuptools>=65.5.1; extra == "psql"
69
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "psql"
70
+ Requires-Dist: SQLAlchemy~=2.0; extra == "psql"
71
+ Requires-Dist: psycopg2; extra == "psql"
63
72
  Requires-Dist: python-dotenv; extra == "psql"
64
- Requires-Dist: shtab; extra == "psql"
65
73
  Requires-Dist: PyYAML; extra == "psql"
66
- Requires-Dist: packaging; extra == "psql"
67
- Requires-Dist: psycopg2; extra == "psql"
68
- Requires-Dist: inflection; extra == "psql"
69
- Requires-Dist: python-box[all]~=6.0.0; extra == "psql"
70
- Requires-Dist: PyMySQL; extra == "psql"
71
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "psql"
72
74
  Requires-Dist: alembic; extra == "psql"
73
- Requires-Dist: SQLAlchemy~=2.0; extra == "psql"
74
- Requires-Dist: colorama; extra == "psql"
75
75
  Provides-Extra: psql-binary
76
- Requires-Dist: psycopg2-binary; extra == "psql-binary"
76
+ Requires-Dist: colorama; extra == "psql-binary"
77
+ Requires-Dist: PyMySQL; extra == "psql-binary"
78
+ Requires-Dist: python-box[all]~=6.0.0; extra == "psql-binary"
77
79
  Requires-Dist: requests[socks]<3; extra == "psql-binary"
80
+ Requires-Dist: packaging; extra == "psql-binary"
81
+ Requires-Dist: inflection; extra == "psql-binary"
82
+ Requires-Dist: shtab; extra == "psql-binary"
83
+ Requires-Dist: psycopg2-binary; extra == "psql-binary"
78
84
  Requires-Dist: domain2idna~=1.12.0; extra == "psql-binary"
79
85
  Requires-Dist: setuptools>=65.5.1; extra == "psql-binary"
86
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "psql-binary"
87
+ Requires-Dist: SQLAlchemy~=2.0; extra == "psql-binary"
80
88
  Requires-Dist: python-dotenv; extra == "psql-binary"
81
- Requires-Dist: shtab; extra == "psql-binary"
82
89
  Requires-Dist: PyYAML; extra == "psql-binary"
83
- Requires-Dist: packaging; extra == "psql-binary"
84
- Requires-Dist: inflection; extra == "psql-binary"
85
- Requires-Dist: python-box[all]~=6.0.0; extra == "psql-binary"
86
- Requires-Dist: PyMySQL; extra == "psql-binary"
87
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "psql-binary"
88
90
  Requires-Dist: alembic; extra == "psql-binary"
89
- Requires-Dist: SQLAlchemy~=2.0; extra == "psql-binary"
90
- Requires-Dist: colorama; extra == "psql-binary"
91
91
  Provides-Extra: postgresql
92
+ Requires-Dist: colorama; extra == "postgresql"
93
+ Requires-Dist: PyMySQL; extra == "postgresql"
94
+ Requires-Dist: python-box[all]~=6.0.0; extra == "postgresql"
92
95
  Requires-Dist: requests[socks]<3; extra == "postgresql"
96
+ Requires-Dist: packaging; extra == "postgresql"
97
+ Requires-Dist: inflection; extra == "postgresql"
98
+ Requires-Dist: shtab; extra == "postgresql"
93
99
  Requires-Dist: domain2idna~=1.12.0; extra == "postgresql"
94
100
  Requires-Dist: setuptools>=65.5.1; extra == "postgresql"
101
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "postgresql"
102
+ Requires-Dist: SQLAlchemy~=2.0; extra == "postgresql"
103
+ Requires-Dist: psycopg2; extra == "postgresql"
95
104
  Requires-Dist: python-dotenv; extra == "postgresql"
96
- Requires-Dist: shtab; extra == "postgresql"
97
105
  Requires-Dist: PyYAML; extra == "postgresql"
98
- Requires-Dist: packaging; extra == "postgresql"
99
- Requires-Dist: psycopg2; extra == "postgresql"
100
- Requires-Dist: inflection; extra == "postgresql"
101
- Requires-Dist: python-box[all]~=6.0.0; extra == "postgresql"
102
- Requires-Dist: PyMySQL; extra == "postgresql"
103
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "postgresql"
104
106
  Requires-Dist: alembic; extra == "postgresql"
105
- Requires-Dist: SQLAlchemy~=2.0; extra == "postgresql"
106
- Requires-Dist: colorama; extra == "postgresql"
107
107
  Provides-Extra: postgresql-binary
108
- Requires-Dist: psycopg2-binary; extra == "postgresql-binary"
108
+ Requires-Dist: colorama; extra == "postgresql-binary"
109
+ Requires-Dist: PyMySQL; extra == "postgresql-binary"
110
+ Requires-Dist: python-box[all]~=6.0.0; extra == "postgresql-binary"
109
111
  Requires-Dist: requests[socks]<3; extra == "postgresql-binary"
112
+ Requires-Dist: packaging; extra == "postgresql-binary"
113
+ Requires-Dist: inflection; extra == "postgresql-binary"
114
+ Requires-Dist: shtab; extra == "postgresql-binary"
115
+ Requires-Dist: psycopg2-binary; extra == "postgresql-binary"
110
116
  Requires-Dist: domain2idna~=1.12.0; extra == "postgresql-binary"
111
117
  Requires-Dist: setuptools>=65.5.1; extra == "postgresql-binary"
118
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "postgresql-binary"
119
+ Requires-Dist: SQLAlchemy~=2.0; extra == "postgresql-binary"
112
120
  Requires-Dist: python-dotenv; extra == "postgresql-binary"
113
- Requires-Dist: shtab; extra == "postgresql-binary"
114
121
  Requires-Dist: PyYAML; extra == "postgresql-binary"
115
- Requires-Dist: packaging; extra == "postgresql-binary"
116
- Requires-Dist: inflection; extra == "postgresql-binary"
117
- Requires-Dist: python-box[all]~=6.0.0; extra == "postgresql-binary"
118
- Requires-Dist: PyMySQL; extra == "postgresql-binary"
119
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "postgresql-binary"
120
122
  Requires-Dist: alembic; extra == "postgresql-binary"
121
- Requires-Dist: SQLAlchemy~=2.0; extra == "postgresql-binary"
122
- Requires-Dist: colorama; extra == "postgresql-binary"
123
123
  Provides-Extra: full
124
- Requires-Dist: requests[socks]<3; extra == "full"
125
- Requires-Dist: python-dotenv; extra == "full"
126
- Requires-Dist: pymdown-extensions~=10.9; extra == "full"
127
- Requires-Dist: PyYAML; extra == "full"
128
- Requires-Dist: tox; extra == "full"
129
- Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "full"
130
- Requires-Dist: mkdocs~=1.5; extra == "full"
131
124
  Requires-Dist: python-box[all]~=6.0.0; extra == "full"
132
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "full"
133
- Requires-Dist: mkdocs-literate-nav~=0.6; extra == "full"
134
- Requires-Dist: zipp>=3.19.1; extra == "full"
135
- Requires-Dist: flake8; extra == "full"
136
- Requires-Dist: mkdocstrings[python]~=0.26; extra == "full"
137
- Requires-Dist: setuptools>=65.5.1; extra == "full"
138
- Requires-Dist: black; extra == "full"
125
+ Requires-Dist: mkdocs-material~=9.5; extra == "full"
139
126
  Requires-Dist: packaging; extra == "full"
140
- Requires-Dist: coverage; extra == "full"
141
- Requires-Dist: alembic; extra == "full"
142
- Requires-Dist: SQLAlchemy~=2.0; extra == "full"
127
+ Requires-Dist: inflection; extra == "full"
128
+ Requires-Dist: black; extra == "full"
143
129
  Requires-Dist: domain2idna~=1.12.0; extra == "full"
144
- Requires-Dist: mkdocs-git-authors-plugin~=0.9; extra == "full"
130
+ Requires-Dist: setuptools>=65.5.1; extra == "full"
131
+ Requires-Dist: SQLAlchemy~=2.0; extra == "full"
132
+ Requires-Dist: mkdocstrings[python]~=0.26; extra == "full"
133
+ Requires-Dist: PyYAML; extra == "full"
134
+ Requires-Dist: alembic; extra == "full"
145
135
  Requires-Dist: mkdocs-macros-plugin~=1.2; extra == "full"
146
- Requires-Dist: PyMySQL; extra == "full"
147
- Requires-Dist: colorama; extra == "full"
148
- Requires-Dist: mkdocs-gen-files~=0.5; extra == "full"
136
+ Requires-Dist: coverage; extra == "full"
137
+ Requires-Dist: mkdocs-git-authors-plugin~=0.9; extra == "full"
149
138
  Requires-Dist: shtab; extra == "full"
150
- Requires-Dist: inflection; extra == "full"
139
+ Requires-Dist: mkdocs-gen-files~=0.5; extra == "full"
140
+ Requires-Dist: tox; extra == "full"
151
141
  Requires-Dist: isort; extra == "full"
152
- Requires-Dist: mkdocs-section-index~=0.3; extra == "full"
153
- Requires-Dist: mkdocs-material~=9.5; extra == "full"
142
+ Requires-Dist: colorama; extra == "full"
143
+ Requires-Dist: PyMySQL; extra == "full"
144
+ Requires-Dist: pymdown-extensions~=10.9; extra == "full"
145
+ Requires-Dist: mkdocs~=1.5; extra == "full"
154
146
  Requires-Dist: pylint; extra == "full"
147
+ Requires-Dist: mkdocs-literate-nav~=0.6; extra == "full"
148
+ Requires-Dist: python-dotenv; extra == "full"
149
+ Requires-Dist: mkdocs-section-index~=0.3; extra == "full"
150
+ Requires-Dist: requests[socks]<3; extra == "full"
151
+ Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "full"
152
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "full"
153
+ Requires-Dist: zipp>=3.19.1; extra == "full"
154
+ Requires-Dist: flake8; extra == "full"
155
155
  Provides-Extra: all
156
- Requires-Dist: requests[socks]<3; extra == "all"
157
- Requires-Dist: python-dotenv; extra == "all"
158
- Requires-Dist: pymdown-extensions~=10.9; extra == "all"
159
- Requires-Dist: PyYAML; extra == "all"
160
- Requires-Dist: tox; extra == "all"
161
- Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "all"
162
- Requires-Dist: mkdocs~=1.5; extra == "all"
163
156
  Requires-Dist: python-box[all]~=6.0.0; extra == "all"
164
- Requires-Dist: dnspython[DOH]~=2.6.0; extra == "all"
165
- Requires-Dist: psycopg2-binary; extra == "all"
166
- Requires-Dist: mkdocs-literate-nav~=0.6; extra == "all"
167
- Requires-Dist: zipp>=3.19.1; extra == "all"
168
- Requires-Dist: flake8; extra == "all"
169
- Requires-Dist: mkdocstrings[python]~=0.26; extra == "all"
170
- Requires-Dist: setuptools>=65.5.1; extra == "all"
171
- Requires-Dist: black; extra == "all"
157
+ Requires-Dist: mkdocs-material~=9.5; extra == "all"
172
158
  Requires-Dist: packaging; extra == "all"
173
- Requires-Dist: coverage; extra == "all"
174
- Requires-Dist: alembic; extra == "all"
175
- Requires-Dist: SQLAlchemy~=2.0; extra == "all"
159
+ Requires-Dist: inflection; extra == "all"
160
+ Requires-Dist: black; extra == "all"
176
161
  Requires-Dist: domain2idna~=1.12.0; extra == "all"
177
- Requires-Dist: mkdocs-git-authors-plugin~=0.9; extra == "all"
162
+ Requires-Dist: setuptools>=65.5.1; extra == "all"
163
+ Requires-Dist: SQLAlchemy~=2.0; extra == "all"
164
+ Requires-Dist: mkdocstrings[python]~=0.26; extra == "all"
165
+ Requires-Dist: PyYAML; extra == "all"
166
+ Requires-Dist: alembic; extra == "all"
178
167
  Requires-Dist: mkdocs-macros-plugin~=1.2; extra == "all"
179
- Requires-Dist: PyMySQL; extra == "all"
180
- Requires-Dist: colorama; extra == "all"
181
- Requires-Dist: mkdocs-gen-files~=0.5; extra == "all"
168
+ Requires-Dist: coverage; extra == "all"
169
+ Requires-Dist: mkdocs-git-authors-plugin~=0.9; extra == "all"
182
170
  Requires-Dist: shtab; extra == "all"
183
- Requires-Dist: inflection; extra == "all"
171
+ Requires-Dist: mkdocs-gen-files~=0.5; extra == "all"
172
+ Requires-Dist: tox; extra == "all"
173
+ Requires-Dist: psycopg2-binary; extra == "all"
184
174
  Requires-Dist: isort; extra == "all"
185
- Requires-Dist: mkdocs-section-index~=0.3; extra == "all"
186
- Requires-Dist: mkdocs-material~=9.5; extra == "all"
175
+ Requires-Dist: colorama; extra == "all"
176
+ Requires-Dist: PyMySQL; extra == "all"
177
+ Requires-Dist: pymdown-extensions~=10.9; extra == "all"
178
+ Requires-Dist: mkdocs~=1.5; extra == "all"
187
179
  Requires-Dist: pylint; extra == "all"
180
+ Requires-Dist: mkdocs-literate-nav~=0.6; extra == "all"
181
+ Requires-Dist: python-dotenv; extra == "all"
182
+ Requires-Dist: mkdocs-section-index~=0.3; extra == "all"
183
+ Requires-Dist: requests[socks]<3; extra == "all"
184
+ Requires-Dist: mkdocs-git-revision-date-localized-plugin~=1.2; extra == "all"
185
+ Requires-Dist: dnspython[DOH]~=2.6.0; extra == "all"
186
+ Requires-Dist: zipp>=3.19.1; extra == "all"
187
+ Requires-Dist: flake8; extra == "all"
188
188
 
189
189
  ![image](https://raw.githubusercontent.com/PyFunceble/logo/dev/Green/HD/RM.png)
190
190
 
@@ -4,7 +4,7 @@ PyFunceble/facility.py,sha256=hyEzCCTOgtAS0x88uEtv9xNwIXnDCDvgq5RHcPNDE-A,2626
4
4
  PyFunceble/factory.py,sha256=ETvTe1Ss3VaIhSBOj-ro80XFAYiknsGG9B5oKpubr2s,2576
5
5
  PyFunceble/logger.py,sha256=pmValhdu0XB34FrK1rSgOAhr4spQ8a3QbqQ26jpJHa0,16815
6
6
  PyFunceble/sessions.py,sha256=juHBKHSuVd-tAEIMRj3RXyGyUhZQLEBmeMssd_5qo1U,2568
7
- PyFunceble/storage.py,sha256=zlXjBisXljB0u--UPFKoTHhyjO2S4dYCfjOLpvMe9y4,5349
7
+ PyFunceble/storage.py,sha256=nqG7u6kLO80Y141dKR_H_yJS0a-gwbuD3ScqybfdMI8,5396
8
8
  PyFunceble/storage_facility.py,sha256=uvW91dOTxF7-2nXxIp2xGI5sDRABBoGMA7D9xfemfGk,4819
9
9
  PyFunceble/checker/__init__.py,sha256=jSCfY25VNBrxLECSgNwU6kTGSl0bM1_JLl_UKvtKP6w,2430
10
10
  PyFunceble/checker/base.py,sha256=WP9Rjl6rvsq69oCaG4a5WDhoWofMpyxfa4K-WY27Gxw,13615
@@ -12,7 +12,7 @@ PyFunceble/checker/complex_json_encoder.py,sha256=oYVqzOV7qICTsN3f2mHtIJU1WdT-41
12
12
  PyFunceble/checker/params_base.py,sha256=eUqfukjplc68QYGbaMsyAv925axxNr3S4Vd2ZvHZfBw,3281
13
13
  PyFunceble/checker/status_base.py,sha256=Rlz9oNMLjCwDeTwH1rYfothY8UDsmpdj4Ll3Qds6fno,3584
14
14
  PyFunceble/checker/availability/__init__.py,sha256=Ir6tRpMV9qLmED3LOsDQYyVx1YgGvzePLYejd9OAk3w,2475
15
- PyFunceble/checker/availability/base.py,sha256=938MMkIYe8zXjFL6x-MfbCb91KGV-PsSn9oTDctXOqU,39250
15
+ PyFunceble/checker/availability/base.py,sha256=hx_4eAGfykN62si91KkzB_6o7QzENS_t2ZaStMo7SKc,39408
16
16
  PyFunceble/checker/availability/domain.py,sha256=DMb2fxh9JYuNBLCzy_kahca6rFCekZl5s57VOGFHAhE,7430
17
17
  PyFunceble/checker/availability/domain_and_ip.py,sha256=gClAt_qmggNE4VpPH4XJ-1sHdVOzOOqWV_fuFC6bD3M,6577
18
18
  PyFunceble/checker/availability/ip.py,sha256=x41TEko2ajBWzPyfgCT6KXtVxcd8HHPuKVIeNHeWQIc,7025
@@ -20,9 +20,10 @@ PyFunceble/checker/availability/params.py,sha256=Z5kpiFWA-txTSE4Yp-SJM7gJd7jvicT
20
20
  PyFunceble/checker/availability/status.py,sha256=l30efESj8LWvyXr-QRnRicmIQN_b9P74qJ5veNpwknU,5228
21
21
  PyFunceble/checker/availability/url.py,sha256=1Xz_lTQjflNIFgNegpUOXjZfXP-clCmXCfdxEQ_hthg,11310
22
22
  PyFunceble/checker/availability/extras/__init__.py,sha256=x2tAu7KXzzrf1b0rB42tfBlZwQZC2F3jKMAtzXKpl9U,2477
23
- PyFunceble/checker/availability/extras/base.py,sha256=N7kyhvHiqT8n3l2eNzVFZTw--dmBe2juubSawqyCBsU,15426
23
+ PyFunceble/checker/availability/extras/base.py,sha256=aUzG-K8gvjDURC_ipv7J46FhvqfpVe473m1NUng84dg,15434
24
24
  PyFunceble/checker/availability/extras/dns.py,sha256=Dgaw1PaQJytPpH-WAtVokE_baFKX_bWTsOn4IyO2a4k,6830
25
25
  PyFunceble/checker/availability/extras/etoxic.py,sha256=p-DfvrBhVx71-MUliVW1i7lyrz_4TTnBb5rqmJ7b1pI,10056
26
+ PyFunceble/checker/availability/extras/external.py,sha256=RcYpYw4jGgT-0pxBNn8P0PM2i_pPOOT4N01LsGn9xZw,12122
26
27
  PyFunceble/checker/availability/extras/parked.py,sha256=1wFHVUgEpe0kZcDw8D2gmOzZ8TNVKvo29g-AseihZfI,5258
27
28
  PyFunceble/checker/availability/extras/rules.py,sha256=Sf9R58W3XmKNtov0HeGMUptNWqlHss2utO1j_DuOXJo,11731
28
29
  PyFunceble/checker/availability/extras/subject_switch.py,sha256=lKWGuK98nu7LKceHbjpBKMtxRoWlTdUvhfr8yjHAA-g,5863
@@ -147,7 +148,7 @@ PyFunceble/cli/utils/testing.py,sha256=yobBqTpA-MT8_sPRMohCuP4ujeCfjUMg7DhOVHfD9
147
148
  PyFunceble/cli/utils/version.py,sha256=G-yLUVolaQouGz1qnQigT33VgH6EEUu8-Qm_QkkXfUo,13892
148
149
  PyFunceble/config/__init__.py,sha256=5t7ypzV6rpSz5IC0QwQMEbmWb0H_w3J917L6DC9NaWw,2454
149
150
  PyFunceble/config/compare.py,sha256=GLmrcAdCXX2SmWQph8kMG0hdDeKgr-LxMSzFGhkxb5E,13631
150
- PyFunceble/config/loader.py,sha256=A4qhaVqoCFcBKiLAZ7O-5RXGywquxwJEGqXIX6FYEIE,22631
151
+ PyFunceble/config/loader.py,sha256=syRD0jmR5Y9TU-aIGJJ_7zxKJSfYcAOG1jNv-YML3cY,22824
151
152
  PyFunceble/converter/__init__.py,sha256=xV1NBUxxzsArjJfhSj0c3HLXs0QPHrX196YsbVPvrbw,2436
152
153
  PyFunceble/converter/adblock_input_line2subject.py,sha256=88zGa0BJacMVIV4LkRXX0EqT9Fez8BTUw8pzas0AwPI,12925
153
154
  PyFunceble/converter/base.py,sha256=bhljvSmbqTiEHXkZ01WyD7XYXXxYG9VmW3RNRtcZlB0,4915
@@ -184,7 +185,7 @@ PyFunceble/data/alembic/postgresql/env.py,sha256=UfJff9bY99TTC0z9bQgsm17NqsGnLmz
184
185
  PyFunceble/data/alembic/postgresql/script.py.mako,sha256=8_xgA-gm_OhehnO7CiIijWgnm00ZlszEHtIHrAYFJl0,494
185
186
  PyFunceble/data/alembic/postgresql/versions/__init__.py,sha256=5E57ZZeUcnx4sgc3LJh6e6bjgeaQhS4W-f2UVuUYsrs,2452
186
187
  PyFunceble/data/alembic/postgresql/versions/a32ac5d66eee_initial_version.py,sha256=xJdnoCnHAG1vmt-nBeomuIEDRwUK1Upv1mtkUt1txQM,2487
187
- PyFunceble/data/infrastructure/.PyFunceble_production.yaml,sha256=Mpz5HKewJvZNhyOV0W4WLURgoOVtPC7bQJ2-yh3StE4,25411
188
+ PyFunceble/data/infrastructure/.PyFunceble_production.yaml,sha256=iGHEYd4R9zg37vocZKKpDyCnaOlBKBiUv01u8AykpWk,28488
188
189
  PyFunceble/data/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
189
190
  PyFunceble/data/infrastructure/dir_structure_production.json,sha256=XpWin49SkoWu3pvnsoNlbNh6j9MlTGVKkvTmX99jZkM,5722
190
191
  PyFunceble/database/__init__.py,sha256=r8zmExtTZguf07GzlaYW5hz11DCC1C6qeU3XvkSQXSU,2492
@@ -275,9 +276,9 @@ PyFunceble/utils/__init__.py,sha256=Vnhd0wNrWJulWwUUK-vlv5VWBiKfSnXtI2XH_FyYkBA,
275
276
  PyFunceble/utils/platform.py,sha256=JA6rc6Uyx6czNWR9917HGB-EZyMjMK17kUVagMtEEjs,3906
276
277
  PyFunceble/utils/profile.py,sha256=f9FsKuiN3ScftqqrZ3yGpcIFqGSf616dPT_QvBduqxw,4552
277
278
  PyFunceble/utils/version.py,sha256=LvSiIrQWztuQ1qT7ekiDvh5TateyVRGMFRui73O4wFQ,8371
278
- PyFunceble_dev-4.3.0a13.dist-info/LICENSE,sha256=JBG6UfPnf3940AtwZB6vwAK6YH82Eo6nzMVnjGqopF0,10796
279
- PyFunceble_dev-4.3.0a13.dist-info/METADATA,sha256=Bo8sFXk056mAtQG4mxPokO3Y6ZClCqz8W4Ingr0b-4o,46666
280
- PyFunceble_dev-4.3.0a13.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
281
- PyFunceble_dev-4.3.0a13.dist-info/entry_points.txt,sha256=Ic1suwopOi_XTgiQi2ErtpY5xT3R8EFMI6B_ONDuR9E,201
282
- PyFunceble_dev-4.3.0a13.dist-info/top_level.txt,sha256=J7GBKIiNYv93m1AxLy8_gr6ExXyZbMmCVXHMQBTUq2Y,11
283
- PyFunceble_dev-4.3.0a13.dist-info/RECORD,,
279
+ PyFunceble_dev-4.3.0a14.dist-info/LICENSE,sha256=JBG6UfPnf3940AtwZB6vwAK6YH82Eo6nzMVnjGqopF0,10796
280
+ PyFunceble_dev-4.3.0a14.dist-info/METADATA,sha256=4AVyFnooal83gmSj5mJKaXnQty_XV_RXWVJC5SZjUnk,46666
281
+ PyFunceble_dev-4.3.0a14.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
282
+ PyFunceble_dev-4.3.0a14.dist-info/entry_points.txt,sha256=Ic1suwopOi_XTgiQi2ErtpY5xT3R8EFMI6B_ONDuR9E,201
283
+ PyFunceble_dev-4.3.0a14.dist-info/top_level.txt,sha256=J7GBKIiNYv93m1AxLy8_gr6ExXyZbMmCVXHMQBTUq2Y,11
284
+ PyFunceble_dev-4.3.0a14.dist-info/RECORD,,