absfuyu 3.3.3__tar.gz → 3.4.0__tar.gz

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.

Potentially problematic release.


This version of absfuyu might be problematic. Click here for more details.

Files changed (89) hide show
  1. {absfuyu-3.3.3 → absfuyu-3.4.0}/PKG-INFO +1 -1
  2. {absfuyu-3.3.3 → absfuyu-3.4.0}/pyproject.toml +2 -1
  3. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/__init__.py +1 -1
  4. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/cli/__init__.py +1 -1
  5. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/cli/do_group.py +24 -2
  6. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/general/data_extension.py +36 -23
  7. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/general/human.py +77 -3
  8. absfuyu-3.4.0/tests/test_beautiful.py +13 -0
  9. absfuyu-3.4.0/tests/test_data_analysis.py +157 -0
  10. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_everything.py +5 -0
  11. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_passwordlib.py +7 -6
  12. absfuyu-3.3.3/tests/test_beautiful.py +0 -7
  13. absfuyu-3.3.3/tests/test_data_analysis.py +0 -159
  14. {absfuyu-3.3.3 → absfuyu-3.4.0}/.gitignore +0 -0
  15. {absfuyu-3.3.3 → absfuyu-3.4.0}/LICENSE +0 -0
  16. {absfuyu-3.3.3 → absfuyu-3.4.0}/README.md +0 -0
  17. {absfuyu-3.3.3 → absfuyu-3.4.0}/dev_requirements.txt +0 -0
  18. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/Makefile +0 -0
  19. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/conf.py +0 -0
  20. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/index.rst +0 -0
  21. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/info.md +0 -0
  22. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/make.bat +0 -0
  23. {absfuyu-3.3.3 → absfuyu-3.4.0}/docs/modules.rst +0 -0
  24. {absfuyu-3.3.3 → absfuyu-3.4.0}/images/repository-image-crop.png +0 -0
  25. {absfuyu-3.3.3 → absfuyu-3.4.0}/images/repository-image-white.png +0 -0
  26. {absfuyu-3.3.3 → absfuyu-3.4.0}/images/repository-image.png +0 -0
  27. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/__main__.py +0 -0
  28. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/cli/color.py +0 -0
  29. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/cli/config_group.py +0 -0
  30. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/cli/game_group.py +0 -0
  31. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/config/__init__.py +0 -0
  32. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/config/config.json +0 -0
  33. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/core.py +0 -0
  34. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/everything.py +0 -0
  35. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/__init__.py +0 -0
  36. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/beautiful.py +0 -0
  37. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/dev/__init__.py +0 -0
  38. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/dev/password_hash.py +0 -0
  39. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/dev/passwordlib.py +0 -0
  40. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/dev/project_starter.py +0 -0
  41. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/dev/shutdownizer.py +0 -0
  42. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/extra/__init__.py +0 -0
  43. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/extensions/extra/data_analysis.py +0 -0
  44. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/fun/WGS.py +0 -0
  45. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/fun/__init__.py +0 -0
  46. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/fun/tarot.py +0 -0
  47. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/game/__init__.py +0 -0
  48. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/game/game_stat.py +0 -0
  49. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/game/sudoku.py +0 -0
  50. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/game/tictactoe.py +0 -0
  51. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/game/wordle.py +0 -0
  52. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/general/__init__.py +0 -0
  53. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/general/content.py +0 -0
  54. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/general/generator.py +0 -0
  55. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/logger.py +0 -0
  56. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/pkg_data/__init__.py +0 -0
  57. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/pkg_data/chemistry.pkl +0 -0
  58. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/pkg_data/tarot.pkl +0 -0
  59. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/py.typed +0 -0
  60. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/sort.py +0 -0
  61. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/__init__.py +0 -0
  62. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/converter.py +0 -0
  63. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/keygen.py +0 -0
  64. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/obfuscator.py +0 -0
  65. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/stats.py +0 -0
  66. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/tools/web.py +0 -0
  67. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/__init__.py +0 -0
  68. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/api.py +0 -0
  69. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/json_method.py +0 -0
  70. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/lunar.py +0 -0
  71. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/path.py +0 -0
  72. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/performance.py +0 -0
  73. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/pkl.py +0 -0
  74. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/util/zipped.py +0 -0
  75. {absfuyu-3.3.3 → absfuyu-3.4.0}/src/absfuyu/version.py +0 -0
  76. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/__init__.py +0 -0
  77. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/conftest.py +0 -0
  78. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_config.py +0 -0
  79. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_data_extension.py +0 -0
  80. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_extensions.py +0 -0
  81. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_fun.py +0 -0
  82. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_game.py +0 -0
  83. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_generator.py +0 -0
  84. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_logger.py +0 -0
  85. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_pkg_data.py +0 -0
  86. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_tarot.py +0 -0
  87. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_tools.py +0 -0
  88. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_util.py +0 -0
  89. {absfuyu-3.3.3 → absfuyu-3.4.0}/tests/test_version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: absfuyu
3
- Version: 3.3.3
3
+ Version: 3.4.0
4
4
  Summary: A small collection of code
5
5
  Project-URL: Homepage, https://github.com/AbsoluteWinter/absfuyu-public
6
6
  Project-URL: Documentation, https://absolutewinter.github.io/absfuyu-docs/
@@ -84,7 +84,6 @@ only-include = ["src", "tests", "docs", "images", "dev_requirements.txt"]
84
84
  # Set up virtual env: use hatch env show
85
85
  [tool.hatch.envs.default]
86
86
  dependencies = ["coverage[toml]", "pytest-cov", "pytest"]
87
- features = ["full"]
88
87
  description = """
89
88
  Default environment
90
89
 
@@ -102,6 +101,7 @@ cov = ["test-cov", "cov-report"] # use this
102
101
  cov2 = "pytest --cov-report=term-missing --cov=absfuyu --cov=tests" # use this
103
102
 
104
103
  [tool.hatch.envs.all]
104
+ features = ["full"]
105
105
  description = """
106
106
  All python version to test:
107
107
  hatch run all:test
@@ -125,6 +125,7 @@ check = "mypy --install-types --non-interactive {args:src/absfuyu}"
125
125
  # check = "mypy --install-types --non-interactive {args:src/absfuyu tests}"
126
126
 
127
127
  [tool.hatch.envs.docs]
128
+ features = ["full"]
128
129
  dependencies = [
129
130
  "sphinx>=7.0.0",
130
131
  "sphinx_rtd_theme",
@@ -22,7 +22,7 @@ Using in cmd (`absfuyu[cli]` required):
22
22
  __title__ = "absfuyu"
23
23
  __author__ = "AbsoluteWinter"
24
24
  __license__ = "MIT License"
25
- __version__ = "3.3.3"
25
+ __version__ = "3.4.0"
26
26
  __all__ = [
27
27
  "core",
28
28
  "config",
@@ -26,7 +26,7 @@ colorama.init(autoreset=True)
26
26
 
27
27
  @click.command()
28
28
  def version() -> None:
29
- """Check current version"""
29
+ """Show current version"""
30
30
  ver_msg = f"{__title__} v{__version__}"
31
31
  click.echo(
32
32
  f"{COLOR['green']}{ver_msg}{COLOR['reset']}\n"
@@ -3,8 +3,8 @@ ABSFUYU CLI
3
3
  -----------
4
4
  Do
5
5
 
6
- Version: 1.0.0
7
- Date updated: 14/04/2024 (dd/mm/yyyy)
6
+ Version: 1.1.0
7
+ Date updated: 15/08/2024 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  __all__ = ["do_group"]
@@ -16,6 +16,7 @@ import click
16
16
  from absfuyu import __title__
17
17
  from absfuyu.cli.color import COLOR
18
18
  from absfuyu.core import __package_feature__
19
+ from absfuyu.general.human import Human2
19
20
  from absfuyu.version import PkgVersion
20
21
 
21
22
 
@@ -65,6 +66,25 @@ def advice() -> None:
65
66
  click.echo(f"{COLOR['green']}{im_bored()}")
66
67
 
67
68
 
69
+ @click.command(name="fs")
70
+ @click.argument("date", type=str)
71
+ @click.argument("number_string", type=str)
72
+ def fs(date: str, number_string: str) -> None:
73
+ """Feng-shui W.I.P"""
74
+
75
+ instance = Human2(date)
76
+ print(instance.fs(number_string))
77
+
78
+
79
+ @click.command(name="info")
80
+ @click.argument("date", type=str)
81
+ def info(date: str) -> None:
82
+ """Day info"""
83
+
84
+ instance = Human2(date)
85
+ print(instance.info())
86
+
87
+
68
88
  @click.group(name="do")
69
89
  def do_group() -> None:
70
90
  """Perform functionalities"""
@@ -74,3 +94,5 @@ def do_group() -> None:
74
94
  do_group.add_command(update)
75
95
  do_group.add_command(install)
76
96
  do_group.add_command(advice)
97
+ do_group.add_command(fs)
98
+ do_group.add_command(info)
@@ -3,8 +3,8 @@ Absfuyu: Data extension
3
3
  -----------------------
4
4
  Extension for data type such as ``list``, ``str``, ``dict``, ...
5
5
 
6
- Version: 1.14.3
7
- Date updated: 05/04/2024 (dd/mm/yyyy)
6
+ Version: 1.15.0
7
+ Date updated: 27/04/2024 (dd/mm/yyyy)
8
8
 
9
9
  Features:
10
10
  ---------
@@ -61,9 +61,9 @@ from typing import (
61
61
  )
62
62
 
63
63
  if _python_version.minor >= 11:
64
- from typing import NotRequired
64
+ from typing import NotRequired, Self
65
65
  else:
66
- from typing_extensions import NotRequired # type: ignore
66
+ from typing_extensions import NotRequired, Self # type: ignore
67
67
 
68
68
  from deprecated.sphinx import versionadded, versionchanged
69
69
 
@@ -256,7 +256,7 @@ class Text(str):
256
256
  split_size: int = 60,
257
257
  split_var_len: int = 12,
258
258
  custom_var_name: Optional[str] = None,
259
- ) -> list:
259
+ ) -> List[str]:
260
260
  """
261
261
  Divide long string into smaller size,
262
262
  then assign a random variable to splited
@@ -277,7 +277,7 @@ class Text(str):
277
277
 
278
278
  Returns
279
279
  -------
280
- list
280
+ list[str]
281
281
  A list in which each item is a smaller
282
282
  string with the size of ``split_size``
283
283
  and a way to concaternate them (when using ``print()``)
@@ -398,7 +398,7 @@ class Text(str):
398
398
 
399
399
  return detail
400
400
 
401
- def reverse(self) -> "Text":
401
+ def reverse(self) -> Self:
402
402
  """
403
403
  Reverse the string
404
404
 
@@ -489,7 +489,7 @@ class Text(str):
489
489
  else:
490
490
  return hex_str
491
491
 
492
- def random_capslock(self, probability: int = 50) -> "Text":
492
+ def random_capslock(self, probability: int = 50) -> Self:
493
493
  """
494
494
  Randomly capslock letter in string
495
495
 
@@ -522,7 +522,7 @@ class Text(str):
522
522
  logger.debug(temp)
523
523
  return self.__class__("".join(temp))
524
524
 
525
- def reverse_capslock(self) -> "Text":
525
+ def reverse_capslock(self) -> Self:
526
526
  """
527
527
  Reverse capslock in string
528
528
 
@@ -934,7 +934,7 @@ class IntNumber(int):
934
934
  except Exception:
935
935
  return False
936
936
 
937
- def reverse(self) -> "IntNumber":
937
+ def reverse(self) -> Self:
938
938
  """
939
939
  Reverse a number. Reverse ``abs(number)`` if ``number < 0``
940
940
 
@@ -983,7 +983,7 @@ class IntNumber(int):
983
983
 
984
984
  # calculation stuff
985
985
  @versionchanged(version="3.3.0", reason="Fix bug")
986
- def lcm(self, with_number: int) -> "IntNumber":
986
+ def lcm(self, with_number: int) -> Self:
987
987
  """
988
988
  Least common multiple of ``self`` and ``with_number``
989
989
 
@@ -1010,7 +1010,7 @@ class IntNumber(int):
1010
1010
  return self.__class__((self * with_number) // math.gcd(self, with_number))
1011
1011
 
1012
1012
  @versionchanged(version="3.3.0", reason="Fix bug")
1013
- def gcd(self, with_number: int) -> "IntNumber":
1013
+ def gcd(self, with_number: int) -> Self:
1014
1014
  """
1015
1015
  Greatest common divisor of ``self`` and ``with_number``
1016
1016
 
@@ -1033,7 +1033,7 @@ class IntNumber(int):
1033
1033
  """
1034
1034
  return self.__class__(math.gcd(self, with_number))
1035
1035
 
1036
- def add_to_one_digit(self, master_number: bool = False) -> "IntNumber":
1036
+ def add_to_one_digit(self, master_number: bool = False) -> Self:
1037
1037
  """
1038
1038
  Convert ``self`` into 1-digit number
1039
1039
  by adding all of the digits together
@@ -1220,7 +1220,7 @@ class ListExt(list):
1220
1220
  ``list`` extension
1221
1221
  """
1222
1222
 
1223
- def stringify(self) -> "ListExt":
1223
+ def stringify(self) -> Self:
1224
1224
  """
1225
1225
  Convert all item in ``list`` into string
1226
1226
 
@@ -1278,7 +1278,7 @@ class ListExt(list):
1278
1278
  )
1279
1279
  return self[::-1][:number_of_items][::-1]
1280
1280
 
1281
- def sorts(self, reverse: bool = False) -> "ListExt":
1281
+ def sorts(self, reverse: bool = False) -> Self:
1282
1282
  """
1283
1283
  Sort all items (with different type) in ``list``
1284
1284
 
@@ -1458,7 +1458,7 @@ class ListExt(list):
1458
1458
  """
1459
1459
  return [self.pick_one() for _ in range(number_of_items)]
1460
1460
 
1461
- def len_items(self) -> "ListExt":
1461
+ def len_items(self) -> Self:
1462
1462
  """
1463
1463
  ``len()`` for every item in ``list[str]``
1464
1464
 
@@ -1499,7 +1499,7 @@ class ListExt(list):
1499
1499
  logger.debug(out)
1500
1500
  return out
1501
1501
 
1502
- def apply(self, func: Callable) -> "ListExt":
1502
+ def apply(self, func: Callable) -> Self:
1503
1503
  """
1504
1504
  Apply function to each entry
1505
1505
 
@@ -1523,7 +1523,7 @@ class ListExt(list):
1523
1523
  # return __class__(func(x) for x in self)
1524
1524
  return self.__class__(map(func, self))
1525
1525
 
1526
- def unique(self) -> "ListExt":
1526
+ def unique(self) -> Self:
1527
1527
  """
1528
1528
  Remove duplicates
1529
1529
 
@@ -1541,7 +1541,7 @@ class ListExt(list):
1541
1541
  """
1542
1542
  return self.__class__(set(self))
1543
1543
 
1544
- def group_by_unique(self) -> "ListExt":
1544
+ def group_by_unique(self) -> Self:
1545
1545
  """
1546
1546
  Group duplicated elements into list
1547
1547
 
@@ -1624,7 +1624,7 @@ class ListExt(list):
1624
1624
 
1625
1625
  return list(x for x, _ in groupby(iter))
1626
1626
 
1627
- def flatten(self) -> "ListExt":
1627
+ def flatten(self) -> Self:
1628
1628
  """
1629
1629
  Flatten the list
1630
1630
 
@@ -1646,7 +1646,7 @@ class ListExt(list):
1646
1646
  temp = list(map(lambda x: x if isinstance(x, list) else [x], self))
1647
1647
  return ListExt(chain(*temp))
1648
1648
 
1649
- def numbering(self, start: int = 0) -> "ListExt":
1649
+ def numbering(self, start: int = 0) -> Self:
1650
1650
  """
1651
1651
  Number the item in list
1652
1652
  (``enumerate`` wrapper)
@@ -1744,7 +1744,7 @@ class DictExt(dict):
1744
1744
  logger.error(err_msg)
1745
1745
  raise ValueError(err_msg) # noqa: B904
1746
1746
 
1747
- def swap_items(self) -> "DictExt":
1747
+ def swap_items(self) -> Self:
1748
1748
  """
1749
1749
  Swap ``dict.keys()`` with ``dict.values()``
1750
1750
 
@@ -1762,7 +1762,7 @@ class DictExt(dict):
1762
1762
  """
1763
1763
  return self.__class__(zip(self.values(), self.keys()))
1764
1764
 
1765
- def apply(self, func: Callable, apply_to_value: bool = True) -> "DictExt":
1765
+ def apply(self, func: Callable, apply_to_value: bool = True) -> Self:
1766
1766
  """
1767
1767
  Apply function to ``DictExt.keys()`` or ``DictExt.values()``
1768
1768
 
@@ -1795,6 +1795,19 @@ class DictExt(dict):
1795
1795
  v = self.values() # type: ignore
1796
1796
  return self.__class__(zip(k, v))
1797
1797
 
1798
+ @versionadded(version="3.4.0")
1799
+ def aggregate(
1800
+ self,
1801
+ other_dict: Dict[Any, Union[int, float]],
1802
+ default_value: Union[int, float] = 0,
1803
+ ) -> Self:
1804
+ """Dict with value type int or float"""
1805
+ out = {
1806
+ k: self.get(k, default_value) + other_dict.get(k, default_value)
1807
+ for k in set(self | other_dict)
1808
+ }
1809
+ return self.__class__(out)
1810
+
1798
1811
 
1799
1812
  # Run
1800
1813
  ###########################################################################
@@ -3,8 +3,8 @@ Absfuyu: Human
3
3
  --------------
4
4
  Human related stuff
5
5
 
6
- Version: 1.3.1
7
- Date updated: 05/04/2024 (dd/mm/yyyy)
6
+ Version: 1.4.0
7
+ Date updated: 15/08/2024 (dd/mm/yyyy)
8
8
  """
9
9
 
10
10
  # Module level
@@ -14,13 +14,16 @@ __all__ = ["Human", "Person"]
14
14
 
15
15
  # Library
16
16
  ###########################################################################
17
+ import re
17
18
  from datetime import datetime, time
18
19
  from typing import Optional, Union
20
+ from urllib.parse import urlencode
19
21
 
20
22
  from dateutil.relativedelta import relativedelta
21
23
 
22
24
  from absfuyu.fun import zodiac_sign
23
25
  from absfuyu.general.data_extension import IntNumber
26
+ from absfuyu.tools.web import soup_link
24
27
  from absfuyu.version import Version # type: ignore
25
28
 
26
29
 
@@ -349,7 +352,78 @@ class Person(Human):
349
352
  return IntNumber(temp).add_to_one_digit(master_number=True)
350
353
 
351
354
 
355
+ class Human2:
356
+ """W.I.P for cli"""
357
+
358
+ def __init__(self, birthday_string: str, is_male: bool = True) -> None:
359
+ """
360
+ :param birthday_string: Format ``<yyyymmddhhmm>`` or ``<yyyymmdd>``
361
+ """
362
+ if len(birthday_string) == 12:
363
+ day = datetime(
364
+ year=int(birthday_string[:4]),
365
+ month=int(birthday_string[4:6]),
366
+ day=int(birthday_string[6:8]),
367
+ hour=int(birthday_string[8:10]),
368
+ minute=int(birthday_string[10:]),
369
+ )
370
+ else:
371
+ day = datetime(
372
+ year=int(birthday_string[:4]),
373
+ month=int(birthday_string[4:6]),
374
+ day=int(birthday_string[6:]),
375
+ )
376
+ self._date_str = birthday_string[:8]
377
+ self.day = day
378
+ self.is_male = is_male
379
+
380
+ def __str__(self) -> str:
381
+ class_name = self.__class__.__name__
382
+ return f"{class_name}({str(self.day)})"
383
+
384
+ def __repr__(self) -> str:
385
+ class_name = self.__class__.__name__
386
+ return f"{class_name}({str(self.day)})"
387
+
388
+ def numerology(self) -> int:
389
+ # numerology
390
+ return IntNumber(self._date_str).add_to_one_digit(master_number=True)
391
+
392
+ def _make_fengshui_check_query(self) -> str:
393
+ """
394
+ Generate query to check Feng-shui
395
+ """
396
+ params = {
397
+ "ngay": self.day.day.__str__().rjust(2, "0"),
398
+ "thang": self.day.month.__str__().rjust(2, "0"),
399
+ "nam": self.day.year,
400
+ "gio": self.day.hour.__str__().rjust(2, "0"),
401
+ "phut": self.day.minute.__str__().rjust(2, "0"),
402
+ "gioitinh": "nam" if self.is_male else "nu",
403
+ }
404
+ output = urlencode(params)
405
+ return output
406
+
407
+ def fs(self, number_string: str) -> float:
408
+ # fengshui
409
+ base = "https://thanglongdaoquan.vn/boi-so-tai-khoan/?taikhoan="
410
+ link = f"{base}{number_string}&{self._make_fengshui_check_query()}"
411
+ soup = soup_link(link)
412
+ val = soup.find_all(class_="total_point")[0].get_text()
413
+ pattern = r"([0-9.]{1,3})/10"
414
+ res = re.findall(pattern, val)[0]
415
+ return float(res)
416
+
417
+ def info(self) -> dict:
418
+ out = {
419
+ "numerology": self.numerology(),
420
+ "zodiac": zodiac_sign(self.day.day, self.day.month),
421
+ }
422
+ return out
423
+
424
+
352
425
  # Run
353
426
  ###########################################################################
354
427
  if __name__ == "__main__":
355
- print(Person.JohnDoe().__dict__)
428
+ # print(Person.JohnDoe().__dict__)
429
+ pass
@@ -0,0 +1,13 @@
1
+ import pytest
2
+
3
+ try: # [beautiful] feature
4
+ import rich # type: ignore
5
+ except ImportError:
6
+ rich = pytest.importorskip("rich")
7
+
8
+ from absfuyu.extensions import beautiful as bu
9
+
10
+
11
+ class TestBeautiful:
12
+ def test_beau(self):
13
+ assert bu.demo() is None
@@ -0,0 +1,157 @@
1
+ """
2
+ Test: Data Analysis
3
+
4
+ Version: 1.2.1
5
+ Date updated: 19/04/2024 (dd/mm/yyyy)
6
+ """
7
+
8
+ import random
9
+
10
+ import pytest
11
+
12
+ try: # [extra] feature
13
+ import numpy as np
14
+ import pandas as pd
15
+ except ImportError:
16
+ np = pytest.importorskip("numpy")
17
+ pd = pytest.importorskip("pandas")
18
+
19
+ from absfuyu.extensions.extra.data_analysis import DADF, CityData, SplittedDF
20
+ from absfuyu.general.generator import Charset, Generator
21
+
22
+ SAMPLE_SIZE = 100
23
+ sample_city_data = CityData._sample_city_data(size=SAMPLE_SIZE)
24
+
25
+ # MARK: fixture
26
+ @pytest.fixture
27
+ def sample_df() -> DADF:
28
+ # Number of columns generated
29
+ num_of_cols: int = random.randint(5, 10)
30
+ # List of column name
31
+ col_name: list = Generator.generate_string(
32
+ Charset.LOWERCASE, unique=True, times=num_of_cols
33
+ )
34
+ # Create DataFrame
35
+ df = pd.DataFrame(
36
+ np.random.randn(random.randint(5, 100), num_of_cols), columns=col_name
37
+ )
38
+ out = DADF(df)
39
+ return out
40
+
41
+
42
+ @pytest.fixture
43
+ def sample_df_2() -> DADF:
44
+ return DADF.sample_df()
45
+
46
+
47
+ @pytest.fixture
48
+ def sample_df_3():
49
+ sample = DADF.sample_df(size=SAMPLE_SIZE)
50
+ sample["city"] = [x.city for x in sample_city_data]
51
+ return sample
52
+
53
+
54
+ # MARK: test
55
+ class TestDADF:
56
+ """absfuyu.extensions.extra.data_analysis.DADF"""
57
+
58
+ # Drop cols
59
+ def test_drop_rightmost(self, sample_df: DADF) -> None:
60
+ num_of_cols_drop = random.randint(1, 4)
61
+
62
+ num_of_cols_current = sample_df.shape[1]
63
+ sample_df.drop_rightmost(num_of_cols_drop)
64
+ num_of_cols_modified = sample_df.shape[1]
65
+
66
+ condition = (num_of_cols_current - num_of_cols_modified) == num_of_cols_drop
67
+ assert condition
68
+
69
+ # Add blank column
70
+ def test_add_blank_column(self, sample_df: DADF) -> None:
71
+ original_num_of_cols = sample_df.shape[1]
72
+ sample_df.add_blank_column("new_col", 0)
73
+ new_num_of_cols = sample_df.shape[1]
74
+
75
+ condition = (new_num_of_cols - original_num_of_cols) == 1 and sum(
76
+ sample_df["new_col"]
77
+ ) == 0
78
+ assert condition
79
+
80
+ # Add date column
81
+ def test_add_date_from_month(self, sample_df_2: DADF) -> None:
82
+ sample_df_2.add_detail_date("date", mode="m")
83
+ original_num_of_cols = sample_df_2.shape[1]
84
+ sample_df_2.add_date_from_month("month", col_name="mod_date")
85
+ new_num_of_cols = sample_df_2.shape[1]
86
+
87
+ original_month = sample_df_2["month"][0]
88
+ modified_month = sample_df_2["mod_date"][0].month
89
+
90
+ # assert original_month == modified_month
91
+ condition = (
92
+ new_num_of_cols - original_num_of_cols
93
+ ) == 1 and original_month == modified_month
94
+ assert condition
95
+
96
+ def test_add_date_column(self, sample_df_2: DADF) -> None:
97
+ # Get random mode
98
+ mode_list = ["d", "w", "m", "y"]
99
+ test_mode = list(
100
+ map(lambda x: "".join(x), Generator.combinations_range(mode_list))
101
+ )
102
+ random_mode = random.choice(test_mode)
103
+ num_of_new_cols = len(random_mode)
104
+
105
+ # Convert
106
+ original_num_of_cols = sample_df_2.shape[1]
107
+ sample_df_2.add_detail_date("date", mode=random_mode)
108
+ new_num_of_cols = sample_df_2.shape[1]
109
+ assert (new_num_of_cols - original_num_of_cols) == num_of_new_cols
110
+
111
+ # Join and split
112
+ def test_split_df(self, sample_df_2: DADF) -> None:
113
+ test = sample_df_2.split_na("missing_value")
114
+ assert len(test) > 1
115
+
116
+ def test_split_df_2(self, sample_df_2: DADF) -> None:
117
+ test = SplittedDF.divide_dataframe(sample_df_2, "number_range")
118
+ assert len(test) > 1
119
+
120
+ def test_join_df(self, sample_df_2: DADF) -> None:
121
+ test = sample_df_2.split_na("missing_value")
122
+ out = test.concat()
123
+ assert out.shape[0] == 100
124
+
125
+ def test_join_df_2(self, sample_df_2: DADF) -> None:
126
+ """This test static method"""
127
+ test = SplittedDF.divide_dataframe(sample_df_2, "number_range")
128
+ out = SplittedDF.concat_df(test)
129
+ assert out.shape[0] == 100
130
+
131
+ # Threshold filter
132
+ def test_threshold_filter(self, sample_df_2: DADF) -> None:
133
+ original_num_of_cols = sample_df_2.shape[1]
134
+ sample_df_2.threshold_filter("number_range", 11)
135
+ new_num_of_cols = sample_df_2.shape[1]
136
+
137
+ # Check new column
138
+ assert (new_num_of_cols - original_num_of_cols) == 1
139
+
140
+ # Check filler value
141
+ test: list = sample_df_2["number_range_filtered"].unique().tolist()
142
+ try:
143
+ test.index("Other")
144
+ assert True
145
+ except Exception:
146
+ pass
147
+
148
+ # Check len
149
+ test1 = sample_df_2["number_range"].unique().tolist()
150
+ assert (len(test1) - len(test)) >= 1
151
+
152
+ # Convert city
153
+ def test_convert_city(self, sample_df_3: DADF) -> None:
154
+ original_num_of_cols = sample_df_3.shape[1]
155
+ sample_df_3.convert_city("city", city_list=sample_city_data)
156
+ new_num_of_cols = sample_df_3.shape[1]
157
+ assert (new_num_of_cols - original_num_of_cols) == 2
@@ -9,6 +9,11 @@ Date updated: 14/04/2024 (dd/mm/yyyy)
9
9
  ###########################################################################
10
10
  import pytest
11
11
 
12
+ try: # [beautiful] feature
13
+ import rich # type: ignore
14
+ except ImportError:
15
+ rich = pytest.importorskip("rich")
16
+
12
17
  from absfuyu import __author__, __license__, __title__, __version__
13
18
  from absfuyu import everything as ab
14
19
  from absfuyu.config import (
@@ -1,21 +1,22 @@
1
1
  """
2
2
  Test: Passwordlib
3
3
 
4
- Version: 1.1.0
5
- Date updated: 30/11/2023 (dd/mm/yyyy)
4
+ Version: 1.1.1
5
+ Date updated: 19/04/2024 (dd/mm/yyyy)
6
6
  """
7
7
 
8
- # Library
9
- ###########################################################################
10
8
  from itertools import combinations_with_replacement
11
9
 
12
10
  import pytest
13
11
 
12
+ try: # [res] feature
13
+ import absfuyu_res
14
+ except ImportError:
15
+ absfuyu_res = pytest.importorskip("absfuyu_res")
16
+
14
17
  from absfuyu.extensions.dev.passwordlib import Password
15
18
  from absfuyu.general.data_extension import Text
16
19
 
17
- # Test
18
- ###########################################################################
19
20
  # def test_generate_password():
20
21
  # test = [password_check(Password.generate_password()) for _ in range(100)]
21
22
  # assert all(test)
@@ -1,7 +0,0 @@
1
- import pytest
2
-
3
- from absfuyu.extensions import beautiful as bu
4
-
5
-
6
- def test_beau():
7
- assert bu.demo() is None
@@ -1,159 +0,0 @@
1
- """
2
- Test: Data Analysis
3
-
4
- Version: 1.2.0
5
- Date updated: 08/03/2024 (dd/mm/yyyy)
6
- """
7
-
8
- # Library
9
- ###########################################################################
10
- import random
11
-
12
- import numpy as np
13
- import pandas as pd
14
- import pytest
15
-
16
- from absfuyu.extensions.extra.data_analysis import DADF, CityData, SplittedDF
17
- from absfuyu.general.generator import Charset, Generator
18
-
19
- # Test
20
- ###########################################################################
21
- SAMPLE_SIZE = 100
22
- sample_city_data = CityData._sample_city_data(size=SAMPLE_SIZE)
23
-
24
-
25
- @pytest.fixture
26
- def sample_df() -> DADF:
27
- # Number of columns generated
28
- num_of_cols: int = random.randint(5, 10)
29
- # List of column name
30
- col_name: list = Generator.generate_string(
31
- Charset.LOWERCASE, unique=True, times=num_of_cols
32
- )
33
- # Create DataFrame
34
- df = pd.DataFrame(
35
- np.random.randn(random.randint(5, 100), num_of_cols), columns=col_name
36
- )
37
- out = DADF(df)
38
- return out
39
-
40
-
41
- @pytest.fixture
42
- def sample_df_2() -> DADF:
43
- return DADF.sample_df()
44
-
45
-
46
- @pytest.fixture
47
- def sample_df_3():
48
- sample = DADF.sample_df(size=SAMPLE_SIZE)
49
- sample["city"] = [x.city for x in sample_city_data]
50
- return sample
51
-
52
-
53
- # Drop cols
54
- def test_drop_rightmost(sample_df: DADF):
55
- num_of_cols_drop = random.randint(1, 4)
56
-
57
- num_of_cols_current = sample_df.shape[1]
58
- sample_df.drop_rightmost(num_of_cols_drop)
59
- num_of_cols_modified = sample_df.shape[1]
60
-
61
- condition = (num_of_cols_current - num_of_cols_modified) == num_of_cols_drop
62
- assert condition
63
-
64
-
65
- # Add blank column
66
- def test_add_blank_column(sample_df: DADF):
67
- original_num_of_cols = sample_df.shape[1]
68
- sample_df.add_blank_column("new_col", 0)
69
- new_num_of_cols = sample_df.shape[1]
70
-
71
- condition = (new_num_of_cols - original_num_of_cols) == 1 and sum(
72
- sample_df["new_col"]
73
- ) == 0
74
- assert condition
75
-
76
-
77
- # Add date column
78
- def test_add_date_from_month(sample_df_2: DADF):
79
- sample_df_2.add_detail_date("date", mode="m")
80
- original_num_of_cols = sample_df_2.shape[1]
81
- sample_df_2.add_date_from_month("month", col_name="mod_date")
82
- new_num_of_cols = sample_df_2.shape[1]
83
-
84
- original_month = sample_df_2["month"][0]
85
- modified_month = sample_df_2["mod_date"][0].month
86
-
87
- # assert original_month == modified_month
88
- condition = (
89
- new_num_of_cols - original_num_of_cols
90
- ) == 1 and original_month == modified_month
91
- assert condition
92
-
93
-
94
- def test_add_date_column(sample_df_2: DADF):
95
- # Get random mode
96
- mode_list = ["d", "w", "m", "y"]
97
- test_mode = list(map(lambda x: "".join(x), Generator.combinations_range(mode_list)))
98
- random_mode = random.choice(test_mode)
99
- num_of_new_cols = len(random_mode)
100
-
101
- # Convert
102
- original_num_of_cols = sample_df_2.shape[1]
103
- sample_df_2.add_detail_date("date", mode=random_mode)
104
- new_num_of_cols = sample_df_2.shape[1]
105
- assert (new_num_of_cols - original_num_of_cols) == num_of_new_cols
106
-
107
-
108
- # Join and split
109
- def test_split_df(sample_df_2: DADF):
110
- test = sample_df_2.split_na("missing_value")
111
- assert len(test) > 1
112
-
113
-
114
- def test_split_df_2(sample_df_2: DADF):
115
- test = SplittedDF.divide_dataframe(sample_df_2, "number_range")
116
- assert len(test) > 1
117
-
118
-
119
- def test_join_df(sample_df_2: DADF):
120
- test = sample_df_2.split_na("missing_value")
121
- out = test.concat()
122
- assert out.shape[0] == 100
123
-
124
-
125
- def test_join_df_2(sample_df_2: DADF):
126
- """This test static method"""
127
- test = SplittedDF.divide_dataframe(sample_df_2, "number_range")
128
- out = SplittedDF.concat_df(test)
129
- assert out.shape[0] == 100
130
-
131
-
132
- # Threshold filter
133
- def test_threshold_filter(sample_df_2: DADF):
134
- original_num_of_cols = sample_df_2.shape[1]
135
- sample_df_2.threshold_filter("number_range", 11)
136
- new_num_of_cols = sample_df_2.shape[1]
137
-
138
- # Check new column
139
- assert (new_num_of_cols - original_num_of_cols) == 1
140
-
141
- # Check filler value
142
- test: list = sample_df_2["number_range_filtered"].unique().tolist()
143
- try:
144
- test.index("Other")
145
- assert True
146
- except Exception:
147
- pass
148
-
149
- # Check len
150
- test1 = sample_df_2["number_range"].unique().tolist()
151
- assert (len(test1) - len(test)) >= 1
152
-
153
-
154
- # Convert city
155
- def test_convert_city(sample_df_3: DADF):
156
- original_num_of_cols = sample_df_3.shape[1]
157
- sample_df_3.convert_city("city", city_list=sample_city_data)
158
- new_num_of_cols = sample_df_3.shape[1]
159
- assert (new_num_of_cols - original_num_of_cols) == 2
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes