PyFunceble-dev 4.0.0b34__py3-none-any.whl → 4.0.0b36__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.
@@ -841,6 +841,8 @@ class AvailabilityCheckerBase(CheckerBase):
841
841
  lookup_result = self.addressinfo_query_tool.get_info()
842
842
  elif self.status.ip_syntax:
843
843
  lookup_result = self.hostbyaddr_query_tool.get_info()
844
+ elif self.status.idna_subject.isdigit():
845
+ lookup_result = None
844
846
  else:
845
847
  lookup_result = self.addressinfo_query_tool.get_info()
846
848
 
@@ -122,5 +122,7 @@ class SyntaxCheckerBase(CheckerBase):
122
122
  raise NotImplementedError()
123
123
 
124
124
  # pylint: disable=useless-super-delegation
125
- def get_status(self) -> Optional[SyntaxCheckerStatus]:
125
+ def get_status(
126
+ self,
127
+ ) -> Optional[SyntaxCheckerStatus]: # pragma: no cover ## Safety.
126
128
  return super().get_status()
@@ -219,6 +219,15 @@ def get_filtering_group_data() -> List[Tuple[List[str], dict]]:
219
219
  "help": argparse.SUPPRESS,
220
220
  },
221
221
  ),
222
+ (
223
+ ["--cidr"],
224
+ {
225
+ "dest": "cli_testing.cidr_expand",
226
+ "action": "store_true",
227
+ "help": "Activates or disables the expansion of CIDR formatted\n"
228
+ "addresses. %s" % get_configured_value("cli_testing.cidr_expand"),
229
+ },
230
+ ),
222
231
  (
223
232
  [
224
233
  "--complements",
@@ -66,6 +66,7 @@ from PyFunceble.cli.processes.workers.tester import TesterWorker
66
66
  from PyFunceble.cli.utils.stdout import print_single_line
67
67
  from PyFunceble.cli.utils.testing import get_subjects_from_line
68
68
  from PyFunceble.converter.adblock_input_line2subject import AdblockInputLine2Subject
69
+ from PyFunceble.converter.cidr2subject import CIDR2Subject
69
70
  from PyFunceble.converter.input_line2subject import InputLine2Subject
70
71
  from PyFunceble.converter.rpz_input_line2subject import RPZInputLine2Subject
71
72
  from PyFunceble.converter.rpz_policy2subject import RPZPolicy2Subject
@@ -122,6 +123,7 @@ class FilePreloader:
122
123
  rpz_policy2subject: Optional[RPZPolicy2Subject] = None
123
124
  rpz_inputline2subject: Optional[RPZInputLine2Subject] = None
124
125
  url2netloc: Optional[Url2Netloc] = None
126
+ cidr2subject: Optional[CIDR2Subject] = None
125
127
 
126
128
  def __init__(
127
129
  self,
@@ -139,6 +141,7 @@ class FilePreloader:
139
141
  url2netloc: Optional[Url2Netloc] = None,
140
142
  continue_dataset: Optional[ContinueDatasetBase] = None,
141
143
  inactive_dataset: Optional[InactiveDatasetBase] = None,
144
+ cidr2subject: Optional[CIDR2Subject] = None,
142
145
  ) -> None:
143
146
  if authorized is not None:
144
147
  self.authorized = authorized
@@ -160,6 +163,7 @@ class FilePreloader:
160
163
  self.url2netloc = url2netloc
161
164
  self.continue_dataset = continue_dataset
162
165
  self.inactive_dataset = inactive_dataset
166
+ self.cidr2subject = cidr2subject
163
167
 
164
168
  def execute_if_authorized(default: Any = None): # pylint: disable=no-self-argument
165
169
  """
@@ -394,6 +398,7 @@ class FilePreloader:
394
398
  inputline2subject=self.inputline2subject,
395
399
  subject2complements=self.subject2complements,
396
400
  url2netloc=self.url2netloc,
401
+ cidr2subject=self.cidr2subject,
397
402
  ):
398
403
 
399
404
  to_send = copy.deepcopy(self.protocol)
@@ -183,6 +183,21 @@ class ProcessesManagerBase:
183
183
 
184
184
  return wrapper
185
185
 
186
+ def ignore_if_running(func): # pylint: disable=no-self-argument
187
+ """
188
+ Ignore the launching of the decorated method if the workers are
189
+ running.
190
+ """
191
+
192
+ @functools.wraps(func)
193
+ def wrapper(self, *args, **kwargs):
194
+ if not self.is_running():
195
+ return func(self, *args, **kwargs) # pylint: disable=not-callable
196
+
197
+ return self
198
+
199
+ return wrapper
200
+
186
201
  @property
187
202
  def max_worker(self) -> Optional[int]:
188
203
  """
@@ -434,6 +449,7 @@ class ProcessesManagerBase:
434
449
 
435
450
  @ensure_worker_obj_is_given
436
451
  @create_workers_if_missing
452
+ # @ignore_if_running
437
453
  def start(self) -> "ProcessesManagerBase":
438
454
  """
439
455
  Starts a defined number of worker.
@@ -101,6 +101,7 @@ from PyFunceble.cli.utils.testing import (
101
101
  )
102
102
  from PyFunceble.cli.utils.version import print_central_messages
103
103
  from PyFunceble.converter.adblock_input_line2subject import AdblockInputLine2Subject
104
+ from PyFunceble.converter.cidr2subject import CIDR2Subject
104
105
  from PyFunceble.converter.input_line2subject import InputLine2Subject
105
106
  from PyFunceble.converter.rpz_input_line2subject import RPZInputLine2Subject
106
107
  from PyFunceble.converter.rpz_policy2subject import RPZPolicy2Subject
@@ -133,6 +134,7 @@ class SystemLauncher(SystemBase):
133
134
  rpz_policy2subject: RPZPolicy2Subject = RPZPolicy2Subject()
134
135
  rpz_inputline2subject: RPZInputLine2Subject = RPZInputLine2Subject()
135
136
  url2netloc: Url2Netloc = Url2Netloc()
137
+ cidr2subject: CIDR2Subject = CIDR2Subject()
136
138
 
137
139
  stdout_printer: StdoutPrinter = StdoutPrinter()
138
140
  file_printer: FilePrinter = FilePrinter()
@@ -528,6 +530,7 @@ class SystemLauncher(SystemBase):
528
530
  inputline2subject=self.inputline2subject,
529
531
  subject2complements=self.subject2complements,
530
532
  url2netloc=self.url2netloc,
533
+ cidr2subject=self.cidr2subject,
531
534
  ):
532
535
  to_send = copy.deepcopy(protocol)
533
536
  to_send["subject"] = subject
@@ -575,6 +578,7 @@ class SystemLauncher(SystemBase):
575
578
  inputline2subject=self.inputline2subject,
576
579
  subject2complements=self.subject2complements,
577
580
  url2netloc=self.url2netloc,
581
+ cidr2subject=self.cidr2subject,
578
582
  ):
579
583
  to_send = copy.deepcopy(protocol)
580
584
  to_send["subject"], to_send["idna_subject"] = (
@@ -57,6 +57,7 @@ from sqlalchemy.orm import Session
57
57
 
58
58
  import PyFunceble.storage
59
59
  from PyFunceble.converter.adblock_input_line2subject import AdblockInputLine2Subject
60
+ from PyFunceble.converter.cidr2subject import CIDR2Subject
60
61
  from PyFunceble.converter.input_line2subject import InputLine2Subject
61
62
  from PyFunceble.converter.rpz_input_line2subject import RPZInputLine2Subject
62
63
  from PyFunceble.converter.rpz_policy2subject import RPZPolicy2Subject
@@ -186,6 +187,7 @@ def get_subjects_from_line(
186
187
  inputline2subject: Optional[InputLine2Subject] = None,
187
188
  subject2complements: Optional[Subject2Complements] = None,
188
189
  url2netloc: Optional[Url2Netloc] = None,
190
+ cidr2subject: Optional[CIDR2Subject] = None,
189
191
  ) -> List[str]:
190
192
  """
191
193
  Provides the list of subject to test.
@@ -214,6 +216,9 @@ def get_subjects_from_line(
214
216
  if url2netloc is None:
215
217
  url2netloc = Url2Netloc()
216
218
 
219
+ if cidr2subject is None:
220
+ cidr2subject = CIDR2Subject()
221
+
217
222
  if PyFunceble.storage.CONFIGURATION.cli_decoding.adblock:
218
223
  result.extend(
219
224
  # pylint: disable=line-too-long
@@ -244,6 +249,13 @@ def get_subjects_from_line(
244
249
  ]
245
250
  )
246
251
 
252
+ if PyFunceble.storage.CONFIGURATION.cli_testing.cidr_expand:
253
+ result = [
254
+ y
255
+ for x in result
256
+ for y in cidr2subject.set_data_to_convert(x).get_converted()
257
+ ]
258
+
247
259
  if checker_type.lower() != "syntax":
248
260
  for index, subject in enumerate(result):
249
261
  if not subject:
@@ -51,10 +51,8 @@ License:
51
51
  limitations under the License.
52
52
  """
53
53
 
54
- from typing import Any, List, Optional, Union
54
+ from typing import Any, List, Optional, Set, Union
55
55
 
56
- from PyFunceble.checker.syntax.domain import DomainSyntaxChecker
57
- from PyFunceble.checker.syntax.ip import IPSyntaxChecker
58
56
  from PyFunceble.converter.base import ConverterBase
59
57
  from PyFunceble.converter.url2netloc import Url2Netloc
60
58
  from PyFunceble.helpers.list import ListHelper
@@ -63,24 +61,23 @@ from PyFunceble.helpers.regex import RegexHelper
63
61
 
64
62
  class AdblockInputLine2Subject(ConverterBase):
65
63
  """
66
- Converts/Extract the subjects to test from an inputed AdBlock line.
67
-
68
- In order to decode the given line, this class and its conversion method
69
- will go though a brunch of decoding method.
64
+ Provides an interface for the conversion or extraction of valuable subjects
65
+ from an inputted AdBlock line.
70
66
  """
71
67
 
72
- OPTION_SEPARATOR: str = ","
73
- OPTIONS_SEPARATOR: str = "$"
74
-
75
68
  _aggressive: bool = False
76
69
 
70
+ __regex_helper: Optional[RegexHelper] = None
71
+
77
72
  def __init__(
78
73
  self, data_to_convert: Optional[Any] = None, aggressive: bool = False
79
74
  ) -> None:
80
75
  if aggressive is not None:
81
76
  self.aggressive = aggressive
82
77
 
83
- super().__init__(data_to_convert)
78
+ self.__regex_helper = RegexHelper()
79
+
80
+ super().__init__(data_to_convert=data_to_convert)
84
81
 
85
82
  @ConverterBase.data_to_convert.setter
86
83
  def data_to_convert(self, value: Any) -> None:
@@ -136,219 +133,302 @@ class AdblockInputLine2Subject(ConverterBase):
136
133
  Checks if we should ignore the given line.
137
134
  """
138
135
 
139
- to_ignore = r"(^!|^@@|^\/|^\[|^\.|^-|^_|^\?|^&)"
136
+ starting_chars = ["!", "@@", "/", "[", ".", "-", "_", "?", "&"]
140
137
 
141
- return RegexHelper(to_ignore).match(line.strip(), return_match=False)
138
+ return any(line.startswith(x) for x in starting_chars)
142
139
 
143
- @classmethod
144
- def extract_base(cls, subject: Union[str, list]) -> str:
140
+ @staticmethod
141
+ def extract_base(subject: Union[str, List[str]]) -> Union[str, List[str]]:
145
142
  """
146
- Extracts the base of the given element (supposed URL).
143
+ Extracts the base of the given subject (supposely URL).
144
+
145
+ :param subject:
146
+ The subject to work with.
147
+
148
+ Example:
147
149
 
148
- As example:
149
150
  Giving :code:`"hello.world/?is=beautiful"` returns :code:`"hello.world"`
150
151
  """
151
152
 
152
153
  if isinstance(subject, list):
153
- return [cls.extract_base(x) for x in subject]
154
+ return [AdblockInputLine2Subject.extract_base(x) for x in subject]
155
+
156
+ subject = subject.replace("*", "").replace("~", "")
154
157
 
155
158
  try:
156
159
  return Url2Netloc(subject).get_converted()
157
160
  except ValueError:
158
161
  return subject
159
162
 
160
- @classmethod
161
- def __format_decoded(
162
- cls, decoded: str, *, result: Optional[List[str]] = None
163
- ) -> List[str]:
163
+ def _decode_multiple_subject(self, decoded: str) -> Set[str]:
164
164
  """
165
- A recursive method which infinitly filter and format the decoded data
166
- in order to delete uneeded parts.
165
+ Implementation of the decoding of the case that multiple
166
+ subjects are possible in the given :py:class:`str`.
167
167
 
168
168
  :param decoded:
169
- The decoded part.
169
+ The decoded part to split.
170
170
  """
171
171
 
172
- if result is None:
173
- result = []
172
+ result = set()
174
173
 
175
- chars_to_split = ["^", "#", ",", "!", "|"]
174
+ rematch = self.__regex_helper.set_regex(r"((?:[^~\*,]+))").match(
175
+ decoded, rematch=True, return_match=True
176
+ )
176
177
 
177
- for data in decoded:
178
- if not data:
179
- continue
178
+ if rematch:
179
+ result.update({self.extract_base(x) for x in rematch})
180
180
 
181
- for char_to_split in chars_to_split:
182
- if char_to_split in data:
183
- return cls.__format_decoded(
184
- data.split(char_to_split), result=result
185
- )
181
+ return result
182
+
183
+ def _decode_options(self, decoded_options: List[str]) -> Set[str]:
184
+ """
185
+ Handle the decoding of the options.
186
+
187
+ What it does:
188
+
189
+ - It extracts all :code:`domain=` component - when found.
190
+ - It extracts all :code:`href` URL base - when found.
186
191
 
187
- data = cls.extract_base(data)
188
192
 
189
- if data and (
190
- DomainSyntaxChecker(data).is_valid() or IPSyntaxChecker(data).is_valid()
191
- ):
192
- result.append(data)
193
+ :param decoded_options:
194
+ The splitted list of options.
195
+ """
196
+
197
+ result = set()
198
+
199
+ for rule in decoded_options:
200
+ if "domain=" in rule:
201
+ rule = rule.replace("domain=", "").replace("|", ",")
202
+
203
+ result.update(self._decode_multiple_subject(rule))
204
+ continue
205
+
206
+ if "href" in rule:
207
+ matched = self.__regex_helper.set_regex(
208
+ r"((?:\"|\')(.*)(?:\"|\'))"
209
+ ).match(rule, return_match=True, rematch=True, group=1)
210
+
211
+ result.add(self.extract_base(matched))
212
+ continue
193
213
 
194
214
  return result
195
215
 
196
- def __filter_options(self, options: List[str]) -> Union[bool, List[str]]:
216
+ def _decode_v1(self, line: str) -> Set[str]:
197
217
  """
198
- Filters the interessting parts of the given list of options.
218
+ Implementation of our first decoding mode.
219
+
220
+ In this mode we try to decode the simple:
221
+
222
+ ||ads.example.com^
199
223
 
200
- :param options:
201
- The extracted options to filter.
224
+ rule.
202
225
 
203
- .. warning::
204
- Thís method only works if the aggressive method is given.
226
+ :param line:
227
+ The line to decode.
205
228
  """
206
229
 
207
- result = []
230
+ result = set()
208
231
 
209
- regex_domain_in_option = r"domain=(.*)"
232
+ local_line = line.strip()
210
233
 
211
- for option in options:
212
- try:
213
- domains = RegexHelper(regex_domain_in_option).match(
214
- option, return_match=True, rematch=True, group=0
215
- )[-1]
216
- except TypeError:
217
- continue
234
+ if local_line.startswith("||") and (
235
+ local_line.endswith("^") or local_line.endswith("$")
236
+ ):
237
+ local_line = local_line.replace("||", "", 1)
218
238
 
219
- result.extend(
220
- [x for x in domains.split("|") if x and not x.startswith("~")]
221
- )
239
+ if local_line.endswith("^"):
240
+ local_line = "".join(local_line.rsplit("^", 1))
241
+ elif local_line.endswith("$"):
242
+ local_line = "".join(local_line.rsplit("$", 1))
222
243
 
223
- if self.aggressive:
224
- return result
244
+ result.update(self._decode_multiple_subject(local_line))
225
245
 
226
- return bool(result)
246
+ return {x for x in result if "." in x}
227
247
 
228
- def __decode_v1(self, line: str) -> List[str]:
248
+ def _decode_v2(self, line: str) -> Set[str]:
229
249
  """
230
- Our first decoding version.
250
+ Implementation of our second decoding mode.
251
+
252
+ In this mode, we try to decode the simple:
231
253
 
232
- The main idea is to filter based on option and a pattern common to all
233
- AdBlock / Ublock format.
254
+ |https://ads.example.com|
255
+
256
+ rule.
234
257
 
235
258
  :param line:
236
259
  The line to decode.
237
260
  """
238
261
 
239
- result = []
262
+ result = set()
240
263
 
241
- # Get all groups :-)
242
- rematch = RegexHelper(r"^(?:.*\|\|)([^\/\$\^]{1,}).*$").match(
243
- line, return_match=True, group=0, rematch=True
244
- )
264
+ local_line = line.strip()
245
265
 
246
- if rematch:
247
- if self.OPTIONS_SEPARATOR in line:
248
- # We get the list of options for filtering.
249
- options = line.split(self.OPTIONS_SEPARATOR)[-1].split(
250
- self.OPTION_SEPARATOR
251
- )
252
-
253
- # pylint: disable=too-many-boolean-expressions
254
- if (
255
- not options[-1]
256
- or "third-party" in options
257
- or "script" in options
258
- or "popup" in options
259
- or "xmlhttprequest" in options
260
- or "all" in options
261
- or "document" in options
262
- ):
263
- result.extend(self.extract_base(rematch))
264
-
265
- extra = self.__filter_options(options)
266
-
267
- if extra:
268
- if isinstance(extra, list):
269
- extra.extend(self.extract_base(rematch))
270
- result.extend(self.extract_base(extra))
271
- else:
272
- result.extend(self.extract_base(rematch))
273
- else:
274
- result.extend(self.extract_base(rematch))
266
+ if local_line.startswith("|") and local_line.endswith("|"):
267
+ local_line = local_line.replace("|", "", 1)
268
+ local_line = "".join(local_line.rsplit("|", 1))
275
269
 
276
- return result
270
+ result.add(self.extract_base(local_line))
271
+
272
+ return {x for x in result if "." in x}
277
273
 
278
- def __decode_v2(self, line: str) -> List[str]:
274
+ def _decode_v3(self, line: str) -> Set[str]:
279
275
  """
280
- Our second decoding version.
276
+ Implementation of our third decoding mode.
281
277
 
282
- The main idea here is that we will match simple records.
278
+ In this mode, we try to decode the simple:
279
+
280
+ ||ads.example.com^$script,image,domain=example.com|~foo.example.info
281
+ ||ads.example.com$script,image,domain=example.com|~foo.example.info
282
+
283
+ rule.
283
284
 
284
285
  :param line:
285
286
  The line to decode.
286
287
  """
287
288
 
288
- result = []
289
+ result = set()
290
+
291
+ local_line = line.strip()
292
+
293
+ if not local_line.startswith("||"):
294
+ return result
289
295
 
290
- rematch = RegexHelper(r"^\|(.*\..*)\|$").match(
291
- line, return_match=True, rematch=True, group=0
296
+ if "$" in local_line:
297
+ v1_mode, options = local_line.split("$", 1)
298
+
299
+ if not v1_mode.endswith("^"):
300
+ v1_mode += "^"
301
+
302
+ result.update(self._decode_v1(v1_mode))
303
+
304
+ if self.aggressive:
305
+ result.update(self._decode_options(options.split(",")))
306
+ elif "^" not in local_line:
307
+ result.update(self._decode_v1(f"{local_line}^"))
308
+ else:
309
+ result.update(self._decode_v1(local_line[: local_line.find("^") + 1]))
310
+
311
+ return {x for x in result if "." in x}
312
+
313
+ def _decode_v4(self, line: str) -> Set[str]:
314
+ """
315
+ Implementation of our fourth decoding mode.
316
+
317
+ In this mode, we try to decode the simple:
318
+
319
+ @@||ads.example.com/notbanner^$~script
320
+
321
+ rule.
322
+
323
+ :param line:
324
+ The line to decode.
325
+ """
326
+
327
+ result = set()
328
+ local_line = line.strip()
329
+
330
+ if (
331
+ not self.aggressive
332
+ or not local_line.startswith("@@||")
333
+ or "^$" not in local_line
334
+ ):
335
+ return result
336
+
337
+ print(not local_line.startswith("@@||"), "^$" not in local_line)
338
+
339
+ v1_mode, options = local_line.split("$", 1)
340
+
341
+ result.update(
342
+ {self.extract_base(x) for x in self._decode_v1(v1_mode.replace("@@", ""))}
292
343
  )
293
344
 
294
- if rematch:
295
- result.extend(self.__format_decoded(rematch))
345
+ result.update(self._decode_options(options.split(",")))
296
346
 
297
- return result
347
+ return {x for x in result if "." in x}
298
348
 
299
- def __decode_v3(self, line: str) -> List[str]:
349
+ def _decode_v5(self, line: str) -> Set[str]:
300
350
  """
301
- Our third decoding version.
351
+ Implementation of our fifth decoding mode.
352
+
353
+ In this mode, we try to decode the simple:
354
+
355
+ example.com,example.net##.advert
356
+ exception.example.com#@#.advert
357
+ example.com,example.net#?#div:-abp-has(> div > img.advert)
358
+ exception.example.com#@#div:-abp-has(> div > img.advert)
302
359
 
303
- This one is for more complex formats (and Ublock).
360
+ rule.
304
361
 
305
362
  :param line:
306
363
  The line to decode.
307
364
  """
308
365
 
309
- result = []
366
+ local_line = line.strip()
367
+ result = set()
310
368
 
311
- rematch = RegexHelper(
312
- r"(?:#+(?:[a-z]+?)?\[[a-z]+(?:\^|\*)\=(?:\'|\"))(.*\..*)(?:(?:\'|\")\])"
313
- ).match(line, return_match=True, rematch=True, group=0)
369
+ if not self.aggressive:
370
+ return result
314
371
 
315
- if rematch:
316
- result.extend(self.__format_decoded(rematch))
372
+ separators = ["##", "#@#", "#?#"]
317
373
 
318
- return result
374
+ obj_of_interest, options = "", ""
375
+
376
+ for separator in separators:
377
+ if separator in local_line:
378
+ obj_of_interest, options = local_line.split(separator, 1)
379
+ break
380
+
381
+ result.update(self._decode_multiple_subject(obj_of_interest))
382
+ result.update(self._decode_options(options.split(",")))
319
383
 
320
- def __decode_v4(self, line: str) -> List[str]:
384
+ return {x for x in result if "." in x}
385
+
386
+ def _decode_v6(self, line: str) -> Set[str]:
321
387
  """
322
- Our fourth decoding version.
388
+ Implementation of our sixth decoding mode.
389
+
390
+ In this mode we try to decode the simple:
323
391
 
324
- This is is for the one who are surrounded by #.
392
+ $domain=exam.pl|elpmaxe.pl|example.pl
393
+
394
+ rule.
325
395
 
326
396
  :param line:
327
397
  The line to decode.
328
398
  """
329
399
 
330
- result = []
400
+ local_line = line.strip()
401
+ result = set()
331
402
 
332
- rematch = RegexHelper(r"^(.*?)(?:#{2}|#@#)").match(
333
- line, return_match=True, rematch=True, group=0
334
- )
403
+ if not self.aggressive:
404
+ return result
335
405
 
336
- if rematch:
337
- result.extend(self.__format_decoded(rematch))
406
+ separators = ["$"]
338
407
 
339
- return result
408
+ for separator in separators:
409
+ if not local_line.startswith(separator):
410
+ continue
411
+
412
+ options = local_line[len(separator) :]
413
+
414
+ result.update(self._decode_options(options.split(",")))
415
+
416
+ return {x for x in result if "." in x}
340
417
 
341
418
  def get_converted(self) -> List[str]:
342
419
  """
343
- Provides the subjects to test.
420
+ Provides the converted data.
344
421
  """
345
422
 
346
- result = []
423
+ result = set()
347
424
 
348
425
  if not self.should_be_ignored(self.data_to_convert.strip()):
349
- result.extend(self.__decode_v1(self.data_to_convert))
350
- result.extend(self.__decode_v2(self.data_to_convert))
351
- result.extend(self.__decode_v3(self.data_to_convert))
352
- result.extend(self.__decode_v4(self.data_to_convert))
426
+ result.update(self._decode_v1(self.data_to_convert))
427
+ result.update(self._decode_v2(self.data_to_convert))
428
+ result.update(self._decode_v3(self.data_to_convert))
429
+ result.update(self._decode_v5(self.data_to_convert))
430
+ result.update(self._decode_v6(self.data_to_convert))
431
+
432
+ result.update(self._decode_v4(self.data_to_convert))
353
433
 
354
- return ListHelper(result).remove_duplicates().sort().subject
434
+ return ListHelper(list(result)).sort().subject
@@ -0,0 +1,114 @@
1
+ # pylint:disable=line-too-long
2
+ """
3
+ The tool to check the availability or syntax of domain, IP or URL.
4
+
5
+ ::
6
+
7
+
8
+ ██████╗ ██╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗███████╗██████╗ ██╗ ███████╗
9
+ ██╔══██╗╚██╗ ██╔╝██╔════╝██║ ██║████╗ ██║██╔════╝██╔════╝██╔══██╗██║ ██╔════╝
10
+ ██████╔╝ ╚████╔╝ █████╗ ██║ ██║██╔██╗ ██║██║ █████╗ ██████╔╝██║ █████╗
11
+ ██╔═══╝ ╚██╔╝ ██╔══╝ ██║ ██║██║╚██╗██║██║ ██╔══╝ ██╔══██╗██║ ██╔══╝
12
+ ██║ ██║ ██║ ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
13
+ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝
14
+
15
+ Provides the converter of CIDR to subjects.
16
+
17
+ Author:
18
+ Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom
19
+
20
+ Special thanks:
21
+ https://pyfunceble.github.io/#/special-thanks
22
+
23
+ Contributors:
24
+ https://pyfunceble.github.io/#/contributors
25
+
26
+ Project link:
27
+ https://github.com/funilrys/PyFunceble
28
+
29
+ Project documentation:
30
+ https://pyfunceble.readthedocs.io/en/dev/
31
+
32
+ Project homepage:
33
+ https://pyfunceble.github.io/
34
+
35
+ License:
36
+ ::
37
+
38
+
39
+ Copyright 2017, 2018, 2019, 2020, 2021 Nissar Chababy
40
+
41
+ Licensed under the Apache License, Version 2.0 (the "License");
42
+ you may not use this file except in compliance with the License.
43
+ You may obtain a copy of the License at
44
+
45
+ http://www.apache.org/licenses/LICENSE-2.0
46
+
47
+ Unless required by applicable law or agreed to in writing, software
48
+ distributed under the License is distributed on an "AS IS" BASIS,
49
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
50
+ See the License for the specific language governing permissions and
51
+ limitations under the License.
52
+ """
53
+
54
+ from ipaddress import IPv4Network
55
+ from typing import Any, List, Optional
56
+
57
+ from PyFunceble.checker.syntax.ip import IPSyntaxChecker
58
+ from PyFunceble.converter.base import ConverterBase
59
+
60
+
61
+ class CIDR2Subject(ConverterBase):
62
+ """
63
+ Converts/Extracts the subjects of from the given CIDR.
64
+ """
65
+
66
+ ip_syntax_checker: Optional[IPSyntaxChecker] = None
67
+
68
+ def __init__(self, data_to_convert: Optional[Any] = None) -> None:
69
+ super().__init__(data_to_convert=data_to_convert)
70
+
71
+ self.ip_syntax_checker = IPSyntaxChecker()
72
+
73
+ @ConverterBase.data_to_convert.setter
74
+ def data_to_convert(self, value: Any) -> None:
75
+ """
76
+ Overrites the default behavior.
77
+
78
+ :raise TypeError:
79
+ When the given data to convert is not :py:class:`str`
80
+ """
81
+
82
+ if not isinstance(value, str):
83
+ raise TypeError(f"<value> should be {str}, {type(value)} given.")
84
+
85
+ # pylint: disable=no-member
86
+ super(CIDR2Subject, self.__class__).data_to_convert.fset(self, value)
87
+
88
+ def get_converted(self) -> List[str]:
89
+ """
90
+ Provides the subject-s to test.
91
+ """
92
+
93
+ result = set()
94
+
95
+ subject = self.data_to_convert.strip()
96
+
97
+ if subject:
98
+ try:
99
+ self.ip_syntax_checker.set_subject(subject)
100
+ if self.ip_syntax_checker.is_valid_v4_range():
101
+ result.update(
102
+ str(x) for x in IPv4Network(self.ip_syntax_checker.subject)
103
+ )
104
+ elif self.ip_syntax_checker.is_valid_v6_range():
105
+ ...
106
+
107
+ # Not Implemented yet.
108
+ result.add(subject)
109
+ else:
110
+ result.add(subject)
111
+ except ValueError:
112
+ result.add(subject)
113
+
114
+ return list(result)
@@ -45,6 +45,9 @@ cli_testing:
45
45
  # Activates the generation of complements.
46
46
  complements: False
47
47
 
48
+ # Activates the expansion of CIDR to single addresses.
49
+ cidr_expand: False
50
+
48
51
  # Sets the cooldown time to apply between each tests.
49
52
  cooldown_time: 0.0
50
53
 
@@ -116,7 +116,7 @@
116
116
  "logs": {
117
117
  ".gitignore": {
118
118
  "content": "*\n!.gitignore\n!/date_format/\n!/no_referrer/\n!/percentage/\n!/whois/\n",
119
- "hash": "475d7b0dedad050e4551466a8a17bff7cf0af0a5ef5e463979981cba"
119
+ "hash": "7e533b26a45b8712a1ed4895b52b2cc798a03a632074800af98a52e7"
120
120
  }
121
121
  },
122
122
  "logs/percentage": {
@@ -221,7 +221,7 @@ class DownloadHelper:
221
221
 
222
222
  :param destination: The download destination.
223
223
 
224
- :raise UnableToDownload: When could not unable to donwload the URL.
224
+ :raise UnableToDownload: When could not unable to download the URL.
225
225
  """
226
226
 
227
227
  session = requests.Session()
@@ -240,8 +240,10 @@ class DownloadHelper:
240
240
  if destination and isinstance(destination, str):
241
241
  FileHelper(destination).write(req.text, overwrite=True)
242
242
 
243
+ req.close()
243
244
  return response
244
245
 
246
+ session.close()
245
247
  raise PyFunceble.helpers.exceptions.UnableToDownload(
246
248
  f"{req.url} (retries: {self.retries} | status code: {req.status_code})"
247
249
  )
@@ -144,13 +144,13 @@ class EnvironmentVariableHelper:
144
144
  The name to set.
145
145
  """
146
146
 
147
- self.name = value
147
+ self.env_file_path = value
148
148
 
149
149
  return self
150
150
 
151
151
  def exists(self) -> bool:
152
152
  """
153
- Checks if the given environement variable name exists.
153
+ Checks if the given environment variable name exists.
154
154
  """
155
155
 
156
156
  return self.name in os.environ
@@ -204,6 +204,10 @@ class EnvironmentVariableHelper:
204
204
  """
205
205
  Sets the given value and save it into the given dotenv file.
206
206
 
207
+ .. warning::
208
+ This method also set the environment variable from the current
209
+ environment.
210
+
207
211
  :param value:
208
212
  The value to set.
209
213
  """
@@ -227,8 +231,14 @@ class EnvironmentVariableHelper:
227
231
  def delete_from_env_file(self) -> "EnvironmentVariableHelper":
228
232
  """
229
233
  Deletes the given environment file from the given dotenv file.
234
+
235
+ .. warning::
236
+ This method also delete the environment variable from the current
237
+ environment.
230
238
  """
231
239
 
240
+ self.delete()
241
+
232
242
  dotenv.unset_key(self.env_file_path, self.name)
233
243
 
234
244
  return self
@@ -268,7 +268,7 @@ class DNSQueryTool:
268
268
  except ValueError:
269
269
  return dns.name.from_text(self.subject)
270
270
  return dns.name.from_text(self.subject)
271
- except dns.name.LabelTooLong:
271
+ except (dns.name.LabelTooLong, dns.name.EmptyLabel):
272
272
  return None
273
273
 
274
274
  @property
PyFunceble/storage.py CHANGED
@@ -61,7 +61,7 @@ from dotenv import load_dotenv
61
61
  from PyFunceble.storage_facility import get_config_directory
62
62
 
63
63
  PROJECT_NAME: str = "PyFunceble"
64
- PROJECT_VERSION: str = "4.0.0b34.dev (Blue Duckling)"
64
+ PROJECT_VERSION: str = "4.0.0b36.dev (Blue Duckling)"
65
65
 
66
66
  DISTRIBUTED_CONFIGURATION_FILENAME: str = ".PyFunceble_production.yaml"
67
67
  DISTRIBUTED_DIR_STRUCTURE_FILENAME: str = "dir_structure_production.json"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: PyFunceble-dev
3
- Version: 4.0.0b34
3
+ Version: 4.0.0b36
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
@@ -4,7 +4,7 @@ PyFunceble/facility.py,sha256=HCwrdsuPDvkoIoWC5MgXkpHJeLjySY8vY6ZYEael3t4,2627
4
4
  PyFunceble/factory.py,sha256=-CwpjMvOdrREMM7e4pC4y4mGUAORtJPeQ33ggXqFg94,2577
5
5
  PyFunceble/logger.py,sha256=-vOChPJV-qlBFyzbChaO_UopcUMcr55TNkGqIUqy43Q,16757
6
6
  PyFunceble/sessions.py,sha256=AJZon_02K__w8cjF7zH4n5TPDWSndE2T_dV-kqLfMjY,2569
7
- PyFunceble/storage.py,sha256=MA0ftsAtKDr7pfo0_P5fAPEwGarQ7ZWXJTDaKd2x12A,6098
7
+ PyFunceble/storage.py,sha256=I7w5qCk6fPNNMEEqtGo9uol1Fbo_8Y7aPvO84DWqTxc,6098
8
8
  PyFunceble/storage_facility.py,sha256=5ajP3o4WpXp1Bt-SvyRZJWx8vc0Cvih19POFGMDW-Eg,4820
9
9
  PyFunceble/.vscode/settings.json,sha256=CNwEGC910aIFzMRFJ32nSq86EbSaoSmtmMWjdCXMrpM,49
10
10
  PyFunceble/checker/__init__.py,sha256=VujZifUlm9gvVrMBgQ6SVPseVJwbX1-NTSVywdglkb4,2431
@@ -13,7 +13,7 @@ PyFunceble/checker/complex_json_encoder.py,sha256=xmcR2YRnI2ZgvCoRfkwvHo8NMZlrOu
13
13
  PyFunceble/checker/params_base.py,sha256=pctIvGJbj7IHVmMJIfr1cMUl7w50ICkg0trM_bUbL3c,3242
14
14
  PyFunceble/checker/status_base.py,sha256=NhQgk2j6UGCQ7qXR0Ft7t8ipjmwhyM3dsgRvnwHIXV4,3512
15
15
  PyFunceble/checker/availability/__init__.py,sha256=tWupDPM5pCI1VOKChZLwuni73-mi4pKEkrSyWvGOAGY,2476
16
- PyFunceble/checker/availability/base.py,sha256=gIkFZ9ZQQ7QGF_aXnQQScUIpNXVKvgsT-bL_EZ8pZ3s,33093
16
+ PyFunceble/checker/availability/base.py,sha256=hwKD183pDzYg1M0QGRirspEGOZ16Y0MdXK9TwETDBmQ,33175
17
17
  PyFunceble/checker/availability/domain.py,sha256=DVz1x8qTV--LZpiyy-4Z5QLLf9PenjD3DFaPN3XetXs,7221
18
18
  PyFunceble/checker/availability/domain_and_ip.py,sha256=AP8a_6Zh7lfOOEnwMuNM0Zl0prfkZbRi1IHjtb5yn9A,4837
19
19
  PyFunceble/checker/availability/extra_rules.py,sha256=njFOZqSVXy-Bn7120-VwI_Qw7oml3EmkyU2O2_NHoWs,12966
@@ -30,7 +30,7 @@ PyFunceble/checker/reputation/params.py,sha256=p9BiVPUFnTCCR0P2VMbB5Wa4WBvjAIY_m
30
30
  PyFunceble/checker/reputation/status.py,sha256=cTLUbIefHZEdyWMupLrKItvrS5YV3YFCyhgndWhfc4Y,4056
31
31
  PyFunceble/checker/reputation/url.py,sha256=xtcvf2gmXcwdNFSHcji2jidGgY08cNuXIxzI2ydgArc,3394
32
32
  PyFunceble/checker/syntax/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- PyFunceble/checker/syntax/base.py,sha256=v6AOYVfRD7BkPpOdtGFVBunjNBcorms9u0-WzcDFNB8,4435
33
+ PyFunceble/checker/syntax/base.py,sha256=Ka1HQUORCt8Y6KIZi-kVOox453SXg0mJ2pXFdYlt3z4,4481
34
34
  PyFunceble/checker/syntax/domain.py,sha256=xW85OY5ciDTR0qDlFZODwV917mNyIqdFqmGx71k7XDY,4816
35
35
  PyFunceble/checker/syntax/domain_base.py,sha256=1i8VXAMrjrx5ePnzJqEmqW2eAcWgn5x3WOHnos8E0yE,6894
36
36
  PyFunceble/checker/syntax/ip.py,sha256=IdO2n-Q86IyWBF8UZ0RqMyui67YraICx6ldjlbPelOI,5634
@@ -48,7 +48,7 @@ PyFunceble/cli/credential_loader.py,sha256=WbC2AxV2jzbMNFuoWZ2K9qkTsrCkHWfrDG_Or
48
48
  PyFunceble/cli/execution_time.py,sha256=D_WOJnfewBM9YnReeb0kmiH4ZJn7RyWrjlxSXVQ2STI,7188
49
49
  PyFunceble/cli/facility.py,sha256=ijIimxvJgd-cpdYMOMtbtT-59QHL1AcPpRHNMY4ZTXs,2577
50
50
  PyFunceble/cli/factory.py,sha256=lLvIekTi9nhn9wgTse5RIauatlVGKznLIGk3uCUAvTc,2571
51
- PyFunceble/cli/file_preloader.py,sha256=Ew07UGC_mpGqt-5pyLx-sB8yLR2j8AT1pzMvj0bmYt4,16183
51
+ PyFunceble/cli/file_preloader.py,sha256=Y4peWAptiju8J_IUgwFoih0WbWSaWDgvotj0glALIkE,16444
52
52
  PyFunceble/cli/storage.py,sha256=6isOX-o6ecPs2jkOWyvhiLcq-BD4nbo1kvW9GrYQWwc,7406
53
53
  PyFunceble/cli/storage_facility.py,sha256=C4hUXLFGiNWORF3l3q7nu1tibI55VYtcQaykAF_WAhE,3157
54
54
  PyFunceble/cli/continuous_integration/__init__.py,sha256=XlwitnhRZA-jWnNxZUmm2OBrr2aNNczezBT_u5J-FXk,2502
@@ -66,7 +66,7 @@ PyFunceble/cli/entry_points/production.py,sha256=x8kycojmB4VnINNbCQAXwhSZLLWUJ-_
66
66
  PyFunceble/cli/entry_points/public_suffix.py,sha256=mo4wXpW6_AdSNwPDvDN_Or5eJ42Z8-U_VrVu0tOm4js,4333
67
67
  PyFunceble/cli/entry_points/pyfunceble/__init__.py,sha256=2zUGcG7Zw7eFZkEWDxmCm3P_dG28oU4D6EFYj-P-mWc,2486
68
68
  PyFunceble/cli/entry_points/pyfunceble/argsparser.py,sha256=b3lE1jn7H9Frp3GgTZmvQwMHyPzo7J6j-SqhJ_v1A3Q,4150
69
- PyFunceble/cli/entry_points/pyfunceble/cli.py,sha256=zXYZuio7-C6kOlrNyy08yHUJthN-GU1XP0UKJDXP8nU,36372
69
+ PyFunceble/cli/entry_points/pyfunceble/cli.py,sha256=fLyMpDwDD2IygdhwF9yo9cFEDbFCWXSlhPQA9VShuXA,36702
70
70
  PyFunceble/cli/filesystem/__init__.py,sha256=mU4QwMrg5x7pFqrFM06s32EYWiVNRxdcJAn1jg9Zb7c,2484
71
71
  PyFunceble/cli/filesystem/cleanup.py,sha256=DPSeT-TGqjl8vH-YYMFkZzRW-AaQdaI7auw20xyPmBk,4814
72
72
  PyFunceble/cli/filesystem/counter.py,sha256=Hs0nuSW9ziGh1NyUKBbGR0PobKw3tyMtuzyneIJdq2A,8272
@@ -101,7 +101,7 @@ PyFunceble/cli/migrators/mariadb/base.py,sha256=JiDxtkVnW-UOI5AUOwXD8KNake-AA-k7
101
101
  PyFunceble/cli/migrators/mariadb/file_and_status.py,sha256=hyYMcK1HnBg325XD68F5Ip3GtPIu7Zwe22AjHcJS75U,7048
102
102
  PyFunceble/cli/migrators/mariadb/whois_record_idna_subject.py,sha256=9YcQnZo7MZUE1BBj_nVua04OMkvdQCciXBZnLGBljho,4437
103
103
  PyFunceble/cli/processes/__init__.py,sha256=idorOeJrcr9mBf9gxKUcaRZ1PmledpVOodrhcOYnphA,2641
104
- PyFunceble/cli/processes/base.py,sha256=QW_3PSdHXxuaI4M3K_FZ5N5b9vm2cq-9Grws9lPY6eg,14281
104
+ PyFunceble/cli/processes/base.py,sha256=XeZz-BpjnHRJJjR8cz5wfhT0UeYDMRfrNEdb0e_HE0w,14735
105
105
  PyFunceble/cli/processes/file_sorter.py,sha256=FlcIohQiCdkfbRbe7fuA7V21ZW7LWaK-0K3D7CcrsLo,2745
106
106
  PyFunceble/cli/processes/migrator.py,sha256=6XXS5iXaHxlQHMPtdzbXbYEKt3osnzCRUCu9ky1Bnvs,15182
107
107
  PyFunceble/cli/processes/miner.py,sha256=Bz-O4adtBdeGiCQCr5XboIDsjFYi327iZfCSIrSGGGA,2707
@@ -121,19 +121,20 @@ PyFunceble/cli/scripts/public_suffix.py,sha256=DnBCOao-o9QIu-FZh7b8h5oMEk_ab6FjZ
121
121
  PyFunceble/cli/system/__init__.py,sha256=WjBYbOUyy81ki-nFfMi-xTkCNxE06r_Y13LsOMvUxTE,2509
122
122
  PyFunceble/cli/system/base.py,sha256=sHGCDuIMEEUAIh1YLp5vov3yNn2A4zUFuQ2hOPQw2pw,4875
123
123
  PyFunceble/cli/system/integrator.py,sha256=z7OANfIJ_ZEzoe70FAR9xQ1c4nuHEt_5RG6mOGWR75Y,6784
124
- PyFunceble/cli/system/launcher.py,sha256=p3DyttId8u3HvWe3XaE86QC7Tvbh-ZJkEymryjKxAS0,34712
124
+ PyFunceble/cli/system/launcher.py,sha256=GZv-z6B5vcoxRKu3WddQSVfogWu9ihf7p3Sw5dOJ-m8,34931
125
125
  PyFunceble/cli/utils/__init__.py,sha256=_eRWl7tVeeVrEGovqiV99KgCCf2HG3Geyj7ZaAR8VT8,2452
126
126
  PyFunceble/cli/utils/ascii_logo.py,sha256=bOJ9N6sbnwKaoYXJBTZifx1-AE0Xoi6ORTl1O33vUX8,3790
127
127
  PyFunceble/cli/utils/sort.py,sha256=751BXHCJtsSvmtnVmq4kKY_RNZv2febyySaafUoeAcM,4362
128
128
  PyFunceble/cli/utils/stdout.py,sha256=ehi4OpotHmPF6mk6hWH3CPTgREIjbfQuGR3qIB3ee4o,5625
129
- PyFunceble/cli/utils/testing.py,sha256=0WjRlBqeExlHb0c6F7vNP6xEyWIvALVS03FwjViUMzA,9246
129
+ PyFunceble/cli/utils/testing.py,sha256=pYVpAFcfg7963YpJg6AKVUl3D919t7tfGWVfBtSl7S0,9632
130
130
  PyFunceble/cli/utils/version.py,sha256=WQ9fLBZdmF8bF5iYliLDvSIf4cgtNCpGNPLTaltdHrg,13162
131
131
  PyFunceble/config/__init__.py,sha256=2GgOQWwdClM28JicoTwZEM77aLz0iZwDpwwtSXGepZs,2455
132
132
  PyFunceble/config/compare.py,sha256=l7V-nu5_AohW7O8sL3EIpsM_aknLrfuCRTOHZO3crUA,12483
133
133
  PyFunceble/config/loader.py,sha256=U4rn_w1zZzCcRdQr0y93Kvjn4IaHYUu-b6fOE5eiKhE,12868
134
134
  PyFunceble/converter/__init__.py,sha256=HDk64s6MDLEPlGOQA1vLyT04Wd7Zaq2r51PtmP_QbRg,2437
135
- PyFunceble/converter/adblock_input_line2subject.py,sha256=FOX74K4cJOkxjl6jo3xO0NaZs56IdJrxayIgUsKlYes,11088
135
+ PyFunceble/converter/adblock_input_line2subject.py,sha256=5QjavRM2jTNvEUHh-jfdFzGS1OYgKGRsKT-ZGhKYwtU,12947
136
136
  PyFunceble/converter/base.py,sha256=vLs77XK5PCMcAKqFiQO4Zy7GB5bnSlh42CA9whU6878,3625
137
+ PyFunceble/converter/cidr2subject.py,sha256=Z2xzogLMkmNFPqyFj1jBUvmEtNNLbI6DAj5NHIYkpWs,4314
137
138
  PyFunceble/converter/input_line2subject.py,sha256=EpUxicwp3Gxi24MyrKMQc8XeqDIC0Qx6nZyixOBLQGM,4596
138
139
  PyFunceble/converter/internal_url.py,sha256=RxgdADi_bWAgQQUPxiN7x_cVKl5rrXrpvR_80dNKDbY,3692
139
140
  PyFunceble/converter/rpz_input_line2subject.py,sha256=t_ArngI-zzu6QF66CldytYlPFY7WVONAKlnQLaYqm2I,3653
@@ -159,9 +160,9 @@ PyFunceble/data/alembic/versions/ade87195b0a0_base.py,sha256=zlkuOT7tpF1xlghF9DQ
159
160
  PyFunceble/data/alembic/versions/bef7bcaac3f2_make_id_a_bigint.py,sha256=6BFuOb8zRIgvuD1hZhvIxA29ovUQF2ZAoGPE53S2CJc,1721
160
161
  PyFunceble/data/alembic/versions/d8893cd406db_allow_whois_record_to_be_empty_null.py,sha256=w16SOfBzxyZnH1-ANAIzRAEoJMyXAFfgiXXXF1TmY7o,930
161
162
  PyFunceble/data/alembic/versions/e04e8301d1a2_deletion_of_the_mined_table.py,sha256=Hi6CDWBP05Izxi0LunanymCWRunRhG4Grtu0BB1O0mg,2125
162
- PyFunceble/data/infrastructure/.PyFunceble_production.yaml,sha256=feP08iqapt48LhK8q4gLgYUOtmDBQ0umY_OPuz995UE,8279
163
+ PyFunceble/data/infrastructure/.PyFunceble_production.yaml,sha256=i9d1z_dWk7YNPHAug8YPOmtPqbqkoRlB8YHo4EJ_qWM,8358
163
164
  PyFunceble/data/infrastructure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
164
- PyFunceble/data/infrastructure/dir_structure_production.json,sha256=XinN8Wecs7VXXq2I8-oDoSBXkV2K-zWy7RXxtFpBSNg,4376
165
+ PyFunceble/data/infrastructure/dir_structure_production.json,sha256=g4lH9Htwiy0ng1XtYbt2Uq7pr_Te2417vvEdQrCs7Lo,4376
165
166
  PyFunceble/database/__init__.py,sha256=niuIAXaZNcXfudA1J_6GzuFrsfh_ZV8x6k2l-kNShFI,2493
166
167
  PyFunceble/database/session.py,sha256=r4VSAzXKvy0v9r9MwzEJ9ieL-Tr9zLc3vdZ0SqqsZOg,7321
167
168
  PyFunceble/database/credential/__init__.py,sha256=zUJxCClDzD_HR_MsHF_zj-_PzJCGtlEdAXdmYcvzA-I,2463
@@ -211,8 +212,8 @@ PyFunceble/helpers/__init__.py,sha256=aLAVgls7bcEDLufVmZceihffrf71SvuMyOyzfKI8Vd
211
212
  PyFunceble/helpers/command.py,sha256=S1WgFRFUmogXHHZ8TkR9Niw_T7ajHTuAJU3jVWSCzA0,7632
212
213
  PyFunceble/helpers/dict.py,sha256=58SbFjGCEKZdhswpgl0yaNS19OVyy2Loy9Nzf0T77Zo,13782
213
214
  PyFunceble/helpers/directory.py,sha256=zGl8eKwruntTwxoEzmCbJXz3AvLx4aHkJzKpc4mG_eY,5977
214
- PyFunceble/helpers/download.py,sha256=Yc-R1pDfEZdsI5UCdExj-9iW_qS3XgZc8YBfzF0Ar5E,7378
215
- PyFunceble/helpers/environment_variable.py,sha256=L6QKp5d2TLE-jC3d1CXMf1ocSHCIHzMkiLEkzuydTvM,6957
215
+ PyFunceble/helpers/download.py,sha256=b7spkPXppz47dzJUaqwewo7q7KJm45YHP1vZSV1gJ6s,7426
216
+ PyFunceble/helpers/environment_variable.py,sha256=1nRxAVTopWIA3W-3PavWlaAcfGFitOHl8fPk67h9qO8,7235
216
217
  PyFunceble/helpers/exceptions.py,sha256=dKiqWn7XYYup5nI2WzW_Clh1jUiIMNyQTkJUO2phulo,2761
217
218
  PyFunceble/helpers/file.py,sha256=ru-7_Ay1_Xc8N_XwD1j2nRRRKb1i9xhmd36I9n32UbY,6536
218
219
  PyFunceble/helpers/hash.py,sha256=iDDnz7fHDiaKUlktVwhEwp_TAGNtZy41IZoWLwpChTI,5261
@@ -223,7 +224,7 @@ PyFunceble/query/__init__.py,sha256=kUyR68yCr6G4kvg2y0vTLN9AcfK1bbclnbtlTWQmr_g,
223
224
  PyFunceble/query/http_status_code.py,sha256=BGy2iS1J921HdnSkRAhDcpnfe-3eYAML6LdRDht_xJs,10323
224
225
  PyFunceble/query/dns/__init__.py,sha256=UrNTiliUGopGzsKFz6j4HwAse6w7gzZUzmSycHlj-Tw,2466
225
226
  PyFunceble/query/dns/nameserver.py,sha256=keLbJDpUYdsPXeXokvPanE-L87xp-qwRaMjXDIYw9Os,8957
226
- PyFunceble/query/dns/query_tool.py,sha256=wLZI3pWfK4Xo8hMAb4a0szvGRCZ4g8pgLz4qM2eGhco,29718
227
+ PyFunceble/query/dns/query_tool.py,sha256=WtdQWwuj_3_YzLEPgXf-Pcuo9ELMiDxpwCkf3S_72ew,29741
227
228
  PyFunceble/query/dns/resolver.py,sha256=xKmbfJVUbx1l2pzodeGBjt344rSi0HE32LibhdCqjf4,6402
228
229
  PyFunceble/query/netinfo/__init__.py,sha256=sp2OLxGgO6TJlthbN1NLGYrwIfefwWJ_iDzdcJjp1F8,2459
229
230
  PyFunceble/query/netinfo/address.py,sha256=URGdVoZwOUw0qAY5aL7SQ0fhMKZAQKuz7zd_bNH-gic,3186
@@ -250,9 +251,9 @@ PyFunceble/utils/__init__.py,sha256=zMW-yHa0L363-x09n9ECqaeNWMqXwhjM1nf9DKlm0W0,
250
251
  PyFunceble/utils/platform.py,sha256=H_xWL4xXu_eTTtGsxNg7ETrffAeQlS9Ik5OcJXZdfKY,3907
251
252
  PyFunceble/utils/profile.py,sha256=o8reJzVWHOz89IblQxmLafNYdIxnLyF4uRyyEyuApYA,3255
252
253
  PyFunceble/utils/version.py,sha256=f3_QrarCmOaguHfs8Z7a4PG7QCPjc5uExjjpbQVbyJo,11309
253
- PyFunceble_dev-4.0.0b34.dist-info/LICENSE,sha256=aenEcfHNnA3RjzJYjI__qB9TxU2NBKGvhgPlCo014Z0,10783
254
- PyFunceble_dev-4.0.0b34.dist-info/METADATA,sha256=qSd4zL_Z-1OKegzSJKUNQ3492ynS8PKf3yRL6fNUSjQ,15943
255
- PyFunceble_dev-4.0.0b34.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
256
- PyFunceble_dev-4.0.0b34.dist-info/entry_points.txt,sha256=CjpbvIUzYzeHRLep_c-gfngDihweQzDfOGSdZ6xvhfw,414
257
- PyFunceble_dev-4.0.0b34.dist-info/top_level.txt,sha256=J7GBKIiNYv93m1AxLy8_gr6ExXyZbMmCVXHMQBTUq2Y,11
258
- PyFunceble_dev-4.0.0b34.dist-info/RECORD,,
254
+ PyFunceble_dev-4.0.0b36.dist-info/LICENSE,sha256=aenEcfHNnA3RjzJYjI__qB9TxU2NBKGvhgPlCo014Z0,10783
255
+ PyFunceble_dev-4.0.0b36.dist-info/METADATA,sha256=gt7fZ5XaHsgPY3B3HHPZcsLMivEywrsdPwBIekexLrw,15943
256
+ PyFunceble_dev-4.0.0b36.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
257
+ PyFunceble_dev-4.0.0b36.dist-info/entry_points.txt,sha256=CjpbvIUzYzeHRLep_c-gfngDihweQzDfOGSdZ6xvhfw,414
258
+ PyFunceble_dev-4.0.0b36.dist-info/top_level.txt,sha256=J7GBKIiNYv93m1AxLy8_gr6ExXyZbMmCVXHMQBTUq2Y,11
259
+ PyFunceble_dev-4.0.0b36.dist-info/RECORD,,