promnesia 1.2.20240810__py3-none-any.whl → 1.4.20250909__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.
Files changed (79) hide show
  1. promnesia/__init__.py +18 -4
  2. promnesia/__main__.py +104 -78
  3. promnesia/cannon.py +108 -107
  4. promnesia/common.py +107 -88
  5. promnesia/compare.py +33 -30
  6. promnesia/compat.py +10 -10
  7. promnesia/config.py +37 -34
  8. promnesia/database/common.py +4 -3
  9. promnesia/database/dump.py +13 -13
  10. promnesia/database/load.py +7 -7
  11. promnesia/extract.py +19 -17
  12. promnesia/logging.py +27 -15
  13. promnesia/misc/install_server.py +32 -27
  14. promnesia/server.py +106 -79
  15. promnesia/sources/auto.py +104 -77
  16. promnesia/sources/auto_logseq.py +6 -5
  17. promnesia/sources/auto_obsidian.py +2 -2
  18. promnesia/sources/browser.py +20 -10
  19. promnesia/sources/browser_legacy.py +65 -50
  20. promnesia/sources/demo.py +7 -8
  21. promnesia/sources/fbmessenger.py +3 -3
  22. promnesia/sources/filetypes.py +22 -16
  23. promnesia/sources/github.py +9 -8
  24. promnesia/sources/guess.py +6 -2
  25. promnesia/sources/hackernews.py +7 -9
  26. promnesia/sources/hpi.py +5 -3
  27. promnesia/sources/html.py +11 -7
  28. promnesia/sources/hypothesis.py +3 -2
  29. promnesia/sources/instapaper.py +3 -2
  30. promnesia/sources/markdown.py +22 -12
  31. promnesia/sources/org.py +36 -17
  32. promnesia/sources/plaintext.py +41 -39
  33. promnesia/sources/pocket.py +5 -3
  34. promnesia/sources/reddit.py +24 -26
  35. promnesia/sources/roamresearch.py +5 -2
  36. promnesia/sources/rss.py +6 -8
  37. promnesia/sources/shellcmd.py +21 -11
  38. promnesia/sources/signal.py +27 -26
  39. promnesia/sources/smscalls.py +2 -3
  40. promnesia/sources/stackexchange.py +5 -4
  41. promnesia/sources/takeout.py +37 -34
  42. promnesia/sources/takeout_legacy.py +29 -19
  43. promnesia/sources/telegram.py +18 -12
  44. promnesia/sources/telegram_legacy.py +22 -11
  45. promnesia/sources/twitter.py +7 -6
  46. promnesia/sources/vcs.py +11 -6
  47. promnesia/sources/viber.py +11 -10
  48. promnesia/sources/website.py +8 -7
  49. promnesia/sources/zulip.py +3 -2
  50. promnesia/sqlite.py +13 -7
  51. promnesia/tests/common.py +10 -5
  52. promnesia/tests/server_helper.py +13 -10
  53. promnesia/tests/sources/test_auto.py +2 -3
  54. promnesia/tests/sources/test_filetypes.py +11 -8
  55. promnesia/tests/sources/test_hypothesis.py +10 -6
  56. promnesia/tests/sources/test_org.py +9 -5
  57. promnesia/tests/sources/test_plaintext.py +9 -8
  58. promnesia/tests/sources/test_shellcmd.py +13 -13
  59. promnesia/tests/sources/test_takeout.py +3 -5
  60. promnesia/tests/test_cannon.py +256 -239
  61. promnesia/tests/test_cli.py +12 -8
  62. promnesia/tests/test_compare.py +17 -13
  63. promnesia/tests/test_config.py +7 -8
  64. promnesia/tests/test_db_dump.py +15 -15
  65. promnesia/tests/test_extract.py +17 -10
  66. promnesia/tests/test_indexer.py +24 -18
  67. promnesia/tests/test_server.py +12 -13
  68. promnesia/tests/test_traverse.py +0 -2
  69. promnesia/tests/utils.py +3 -7
  70. promnesia-1.4.20250909.dist-info/METADATA +66 -0
  71. promnesia-1.4.20250909.dist-info/RECORD +80 -0
  72. {promnesia-1.2.20240810.dist-info → promnesia-1.4.20250909.dist-info}/WHEEL +1 -2
  73. promnesia/kjson.py +0 -121
  74. promnesia/sources/__init__.pyi +0 -0
  75. promnesia-1.2.20240810.dist-info/METADATA +0 -54
  76. promnesia-1.2.20240810.dist-info/RECORD +0 -83
  77. promnesia-1.2.20240810.dist-info/top_level.txt +0 -1
  78. {promnesia-1.2.20240810.dist-info → promnesia-1.4.20250909.dist-info}/entry_points.txt +0 -0
  79. {promnesia-1.2.20240810.dist-info → promnesia-1.4.20250909.dist-info/licenses}/LICENSE +0 -0
promnesia/kjson.py DELETED
@@ -1,121 +0,0 @@
1
- """
2
- Some experimental ideas on JSON processing.
3
- This is a bit overengineered and I admit it!
4
- I'll make it more readable, but in the meantime feel free to open an issue if you're confused about something.
5
- """
6
-
7
- from typing import Any, Dict, List, Union, Tuple, cast
8
-
9
-
10
- JDict = Dict[str, Any] # TODO not sure if we can do recursive..
11
- JList = List[Any]
12
- JPrim = Union[str, int, float] # , type(None)]
13
-
14
- Json = Union[JDict, JList, JPrim]
15
-
16
- JPathPart = Tuple[Json, Union[str, int]]
17
-
18
- JPath = Tuple[JPathPart, ...]
19
-
20
-
21
- class JsonProcessor:
22
- SKIP = object()
23
-
24
- def handle_dict(self, js: JDict, jp: JPath) -> Any:
25
- pass
26
-
27
- def handle_list(self, js: JList, jp: JPath) -> Any:
28
- pass
29
-
30
- def handle_str(self, js: str, jp: JPath) -> Any:
31
- pass
32
-
33
- def do_dict(self, js: JDict, jp: JPath) -> None:
34
- # pylint: disable=assignment-from-no-return
35
- res = self.handle_dict(js, jp)
36
- if res is self.SKIP:
37
- return
38
- for k, v in js.items():
39
- path = cast(JPath, jp + ((js, k), ))
40
- self._do(v, path)
41
-
42
- def do_list(self, js: JList, jp: JPath) -> None:
43
- # pylint: disable=assignment-from-no-return
44
- res = self.handle_list(js, jp)
45
- if res is self.SKIP:
46
- return
47
- for i, x in enumerate(js):
48
- path = cast(JPath, jp + ((js, i), ))
49
- self._do(x, path)
50
-
51
- def _do(self, js: Json, path: JPath) -> None:
52
- if isinstance(js, dict): # TODO have functions for dict like, list like etc
53
- self.do_dict(js, path)
54
- elif isinstance(js, list):
55
- self.do_list(js, path)
56
- elif isinstance(js, str):
57
- self.handle_str(js, path)
58
- elif isinstance(js, (int, bool, float, type(None))):
59
- pass # TODO process that as well
60
- else:
61
- raise RuntimeError(f'unexpected item {js} of type {type(js)}')
62
-
63
- def run(self, js: Json) -> None:
64
- path = cast(JPath, ())
65
- self._do(js, path)
66
-
67
- @classmethod
68
- def kpath(cls, path: JPath) -> Tuple[JPathPart, ...]:
69
- return tuple(x[1] for x in path) # type: ignore
70
-
71
- # TODO path is a sequence of jsons and keys?
72
-
73
- def test_json_processor():
74
- handled = []
75
- class Proc(JsonProcessor):
76
- def handle_dict(self, value: JDict, path):
77
- if 'skipme' in self.kpath(path): # type: ignore[comparison-overlap]
78
- return JsonProcessor.SKIP
79
-
80
- def handle_str(self, value: str, path):
81
- if 'http' in value:
82
- handled.append((value, path))
83
-
84
- j = {
85
- 'skipme': {
86
- 'x': {
87
- 'y': [
88
- 123,
89
- {
90
- 'description': 'whatever',
91
- 'link': 'http://ya.ru',
92
- },
93
- ]
94
- }
95
- },
96
- 'a': [1, 2, 3],
97
- 'x': {
98
- 'y': [
99
- 123,
100
- {
101
- 'description': 'whatever',
102
- 'link': 'http://reddit.com',
103
- },
104
- ]
105
- },
106
- }
107
-
108
- p = Proc()
109
- p.run(j)
110
- assert len(handled) > 0
111
-
112
- [h1] = handled
113
- (link, path) = h1
114
- assert link == 'http://reddit.com'
115
- pp = [p[1] for p in path]
116
- assert pp == ['x', 'y', 1, 'link']
117
-
118
-
119
- if __name__ == '__main__':
120
- test_json_processor()
121
-
File without changes
@@ -1,54 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: promnesia
3
- Version: 1.2.20240810
4
- Summary: Enhancement of your browsing history
5
- Home-page: https://github.com/karlicoss/promnesia
6
- Author: Dmitrii Gerasimov
7
- Author-email: karlicoss@gmail.com
8
- Requires-Python: >=3.8
9
- License-File: LICENSE
10
- Requires-Dist: appdirs
11
- Requires-Dist: tzlocal
12
- Requires-Dist: more-itertools
13
- Requires-Dist: pytz
14
- Requires-Dist: sqlalchemy >=2.0
15
- Requires-Dist: urlextract
16
- Requires-Dist: fastapi
17
- Requires-Dist: uvicorn[standard]
18
- Provides-Extra: hpi
19
- Requires-Dist: HPI ; extra == 'hpi'
20
- Provides-Extra: all
21
- Requires-Dist: logzero ; extra == 'all'
22
- Requires-Dist: python-magic ; extra == 'all'
23
- Requires-Dist: HPI ; extra == 'all'
24
- Requires-Dist: beautifulsoup4 ; extra == 'all'
25
- Requires-Dist: lxml ; extra == 'all'
26
- Requires-Dist: mistletoe ; extra == 'all'
27
- Requires-Dist: orgparse >=0.3.0 ; extra == 'all'
28
- Provides-Extra: html
29
- Requires-Dist: beautifulsoup4 ; extra == 'html'
30
- Requires-Dist: lxml ; extra == 'html'
31
- Provides-Extra: markdown
32
- Requires-Dist: mistletoe ; extra == 'markdown'
33
- Provides-Extra: optional
34
- Requires-Dist: logzero ; extra == 'optional'
35
- Requires-Dist: python-magic ; extra == 'optional'
36
- Provides-Extra: org
37
- Requires-Dist: orgparse >=0.3.0 ; extra == 'org'
38
- Provides-Extra: telegram
39
- Provides-Extra: testing
40
- Requires-Dist: pytest ; extra == 'testing'
41
- Requires-Dist: pytest-timeout ; extra == 'testing'
42
- Requires-Dist: pytest-xdist ; extra == 'testing'
43
- Requires-Dist: hypothesis ; extra == 'testing'
44
- Requires-Dist: psutil ; extra == 'testing'
45
- Requires-Dist: requests ; extra == 'testing'
46
- Requires-Dist: selenium ; extra == 'testing'
47
- Requires-Dist: click ; extra == 'testing'
48
- Requires-Dist: ruff ; extra == 'testing'
49
- Requires-Dist: mypy ; extra == 'testing'
50
- Requires-Dist: lxml ; extra == 'testing'
51
- Requires-Dist: loguru ; extra == 'testing'
52
- Provides-Extra: testing-gui
53
- Requires-Dist: pyautogui ; extra == 'testing-gui'
54
-
@@ -1,83 +0,0 @@
1
- promnesia/__init__.py,sha256=rxVINCLqxpZFknz9QeMA6McpnzR8Hi0zhZdoyYCGUlM,367
2
- promnesia/__main__.py,sha256=5HVE6tyBCzTKs19rDGZIkotrmaoeTRBVtTCgRnKluh8,15251
3
- promnesia/cannon.py,sha256=dRfRk4bnII5D0rxKnimZiN727imYuyR2Kfw3pWEOxLs,24596
4
- promnesia/common.py,sha256=iMBdyYHzjma1mGP02-ugDpkN-WoyBE6Uku4Il8fuWzc,19546
5
- promnesia/compare.py,sha256=XjhleEzl_hzSvuinDR_I9oin5U65HkAbNCJRJQ6BwM8,4639
6
- promnesia/compat.py,sha256=SP1Nj3jwFoKKYLnx5qVirHdsufehcb42DShqS3PPzR4,389
7
- promnesia/config.py,sha256=JFLY28C11tpvwBnPYT-VfdbsD1hivPvZMzojOh5tSJs,4743
8
- promnesia/extract.py,sha256=JIVCxCvkn02YnGoUvLL0pAGPHXpepq-C_2brYbtN4ts,2804
9
- promnesia/kjson.py,sha256=9hMw-sY-avA99aWV8cG03HL2AlfvlzE5YfWw1_5LwM4,3313
10
- promnesia/logging.py,sha256=s_dhobXuTl8tibcpKCxktGduECKWIiEkYe0atcAToIQ,5923
11
- promnesia/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- promnesia/server.py,sha256=42sByMUialuZQoKRF_zgxky7ykc9d-cNMwKBJAEaH68,14636
13
- promnesia/sqlite.py,sha256=lB7YZ9jdALbo_gblmVn7z3Dn5M6FJg7Nz2y51Z0pl1c,1353
14
- promnesia/database/common.py,sha256=HRw47RhxqN6Wfb5LVfbc1eRzT8LSJus1colY_S9ijm8,1814
15
- promnesia/database/dump.py,sha256=JV3j8J5pJJmPocRZalJqq0zz1532p9lVxW7_lcXbvx4,6101
16
- promnesia/database/load.py,sha256=Q2TLyV0rzvfvq8kkAhIIvcCC4D-eEbCH5wmsZL6jYg0,1353
17
- promnesia/misc/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- promnesia/misc/config_example.py,sha256=MXxJCVjm9MrEwPR8SHTwkJRDcqWcqJWtfJg_M6yhRMo,364
19
- promnesia/misc/install_server.py,sha256=-dPTJjM-jktVf25mcrXRL6Uj6Pji72lPnC3iyg_m8Gk,4820
20
- promnesia/sources/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
- promnesia/sources/auto.py,sha256=MhOesdn2YfPPepNkOBSihT_CDoGXfyTIA0y8wxcKqn0,11710
22
- promnesia/sources/auto_logseq.py,sha256=eXOHIOx9MladhyD1IyLd90lyqO6gG2F5uObnuHFQrZA,439
23
- promnesia/sources/auto_obsidian.py,sha256=PLWPHj9U3pnwLWw7-fzEk12F4Xdigq0VrvSAn_yS-yw,213
24
- promnesia/sources/browser.py,sha256=BzdVVMm6N-U0F8_sng51deara9maY1TzMF6e7s8VCXg,2992
25
- promnesia/sources/browser_legacy.py,sha256=3vARw78yXWvp3RQzfPbkXgtZB5iWSbXIKgadMIG4gGs,10400
26
- promnesia/sources/demo.py,sha256=-5vADo4S-fDNEEPHGrh9pYoIIW_tzApRl6hIy8K3b2Q,1041
27
- promnesia/sources/fbmessenger.py,sha256=_QdM3-vLutN-dh4vxfQlQkRDiorWA2EwixL49AH7lbM,969
28
- promnesia/sources/filetypes.py,sha256=W0OVmhtvJKbWk2dju8Uwbo0TfNHye--cKrCPfL_DfBw,3593
29
- promnesia/sources/github.py,sha256=hHTlJZvxe6TzzALX_z8R9FUQgVw39n22XYWPc62oPfo,2753
30
- promnesia/sources/guess.py,sha256=-km2_hsrznYrws1lA3ZN5L6ixJunEsgQBFDU7juqPpM,776
31
- promnesia/sources/hackernews.py,sha256=ReI362AKjZ79Lu99qJNPZtCoyHr6AycghvQrmDFRKgw,1228
32
- promnesia/sources/hpi.py,sha256=yQIOT-OQ4Rhs7xXbszkNWjj46jvLDgP-xt7bSQV9wRk,361
33
- promnesia/sources/html.py,sha256=FOLcXzV3J5VEHMkpuF4Q0rrht5zdGsDNQZJMu2WWYZ8,1108
34
- promnesia/sources/hypothesis.py,sha256=PNuYKV-G7o8trMtgEzK3qX2NcBOhlZuf5Yg71FpWoQY,1359
35
- promnesia/sources/instapaper.py,sha256=K2feGkgiFp6pNJoDYlyLs9m8MkDizoXy2QUg-Fjm-O0,969
36
- promnesia/sources/markdown.py,sha256=acI2FwkawcAZX21i4kK44ligKKbj7TZDB5c0a9ihZOk,3762
37
- promnesia/sources/org.py,sha256=oiZsNdW-oxq4a2D5_TYBUXPdPkPguSosaoyEp9dnyvc,5499
38
- promnesia/sources/plaintext.py,sha256=aiMwd7WWtE65iTWiLFIow-RBDqozbjGfPgTdkzuMjaI,3259
39
- promnesia/sources/pocket.py,sha256=4JCNrYs23Nq0c0hw_UxaxaIJbiqF2JVu5GAql-hfNZM,1105
40
- promnesia/sources/reddit.py,sha256=DIEWQoWGpuQXGOmcZ9lANkPYuLhB9rzq1u23HllqLF4,5623
41
- promnesia/sources/roamresearch.py,sha256=Su-2ykyjdylvDMogQjAgiGpLkh4Inw-K8yeAhGv678E,1068
42
- promnesia/sources/rss.py,sha256=5-DmUesDv_GCOF5Qo7e7P3QrS6WdryZpFidazfI24Wg,870
43
- promnesia/sources/shellcmd.py,sha256=m2tT8RSoOjXz7eC-OOXGGKleod-1A_XtWFlOucO3so0,2644
44
- promnesia/sources/signal.py,sha256=iTU9z3hFiWjuGr5noLl8Vy3TlKj8zIMFlhNj2741h00,14728
45
- promnesia/sources/smscalls.py,sha256=HHM8SGDx9qS5tZfpIn_iUcKYQIyryQMZvIkqUNZKHtk,755
46
- promnesia/sources/stackexchange.py,sha256=vlidNoqWNUtR8dyHya9D7ZlHX5a2OIfoZq951M_V8c8,630
47
- promnesia/sources/takeout.py,sha256=jDhpJkjtzC7OIlBASXHw0QNwwincBkEMgqyAhuboL7o,7918
48
- promnesia/sources/takeout_legacy.py,sha256=ZuaP9jOuxKrbm03IOudeneWHlgT95Qr86fcGqvplKeE,4040
49
- promnesia/sources/telegram.py,sha256=HCft7kWHdkBJiVI8OR6Wg34k4nW1vhb3tMAEJwGO1QA,2947
50
- promnesia/sources/telegram_legacy.py,sha256=E4izRfxJWy25R0Rm-E78Op2lxcl2w6Rq5XUeYfXw2wc,4468
51
- promnesia/sources/twitter.py,sha256=8vtLKyhtqioMmp_IKKVozLZC32TIQKjs_toB5cU2_6Q,1848
52
- promnesia/sources/vcs.py,sha256=K2rRopKlwiNQ2_2TMWSHrwpsd5nYtPMUjHvnpNBvzBg,1609
53
- promnesia/sources/viber.py,sha256=uFBtiJGWwuEE-gFIV0GV7eLExc0ddt3U3F_Wnkh1XKA,5948
54
- promnesia/sources/website.py,sha256=Ii0Xka3PZk2_KJHJy9l3EYvGgSKkUehhHSmWI9tXec4,1781
55
- promnesia/sources/zulip.py,sha256=s1bhYmx26VKC35CJF_2yiO4jdYHH0QwRYtAD3Ss6tt8,742
56
- promnesia/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
- promnesia/tests/common.py,sha256=eOFyfOLBUM8hK0gJ7JTXdjAMwRL6QN5DlRsZYAudMOM,4026
58
- promnesia/tests/server_helper.py,sha256=W76vmwozoqJEPrlxQB0azklR28gf2RzimTHAJWOgclg,2181
59
- promnesia/tests/test_cannon.py,sha256=bvfL5foAtDm6QzqE_nqtiSF6zAQnkWU0dlMoQp9kX0s,12702
60
- promnesia/tests/test_cli.py,sha256=YZAsqbJcka1rjlDkb925V4A97FkiQc63JF0eT4Zb5wE,1406
61
- promnesia/tests/test_compare.py,sha256=8pxY1DPZuGnrU1p0z4VzEawJVzzmL3sNVPce1CeiSNI,945
62
- promnesia/tests/test_config.py,sha256=zkZXQkADHhgFzoFjqTr3zv-o6hqS0eED3wuYIMvw6dw,6532
63
- promnesia/tests/test_db_dump.py,sha256=k6FPtcuSImMdealbgNr7mCW5NG1_jG8eESNwO1TSW1o,6751
64
- promnesia/tests/test_extract.py,sha256=Hn-4B7T_4YrUtcO6tLxYJUkXknU97i0nEGRxejRnozI,2306
65
- promnesia/tests/test_extract_urls.py,sha256=Ybez16VdYoveL9b_50Ca9vbMogWHOvFqDOJPGZrzQJg,1961
66
- promnesia/tests/test_indexer.py,sha256=ec5xR9whW6z6GwKjnCGrHDp9WgTebbq7qKOIXHPLGlU,8911
67
- promnesia/tests/test_server.py,sha256=pwlXT-qU6KXjE0ftlWB9CE1FxhpTrwJRdX8r4QDctYs,10787
68
- promnesia/tests/test_traverse.py,sha256=F2qd1vvX2u9jJ4GVksAh6Dum-XEVLg9iCyFU6H8CZhI,1352
69
- promnesia/tests/utils.py,sha256=etNWsXIeTMaYCTN9sIlgMKHyvY_Ek3l0Btu5rIpQEcI,1117
70
- promnesia/tests/sources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
- promnesia/tests/sources/test_auto.py,sha256=d9MwY8taALdT5C64u8G7uvk4iubZ3SHSCR50qmXzz3E,1855
72
- promnesia/tests/sources/test_filetypes.py,sha256=w5uPsfzHfl8hS3BbXxkA3TR8rKqniRGWSO8zeIKOiM4,1338
73
- promnesia/tests/sources/test_hypothesis.py,sha256=nUsfET_X0yGVdlpmvxaDGAPjznYsA0Jc04vXGl83QCU,1400
74
- promnesia/tests/sources/test_org.py,sha256=BYJqAkI7TfgOkWk1W33MMQUDSBGpvSgGbFvb2r9qqYo,2572
75
- promnesia/tests/sources/test_plaintext.py,sha256=O6lLrCvZpLaaWuyeKU3eZyf4Mx1rmarU689nifTw3hk,828
76
- promnesia/tests/sources/test_shellcmd.py,sha256=4wyoFB3UzdviNdQX_dOpIlrzZSMXtPqRgTkRb3pk3go,679
77
- promnesia/tests/sources/test_takeout.py,sha256=We0gSDpENuxoO9kInSmBExJrAqmfNZkA3cVQf876SsQ,1559
78
- promnesia-1.2.20240810.dist-info/LICENSE,sha256=rgO9acPmnw53ZBxiXBdp8kfxmRcekhg_Q7HN65BPihs,1074
79
- promnesia-1.2.20240810.dist-info/METADATA,sha256=7ilgQnAz53XkvjLFIZgf8cjh5qWwyyZ_i3G2dw5mfkI,1870
80
- promnesia-1.2.20240810.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
81
- promnesia-1.2.20240810.dist-info/entry_points.txt,sha256=hz1qfzQSRh4kkVkJWk4hnYqE9A1nobEbKlLG_0nNxzE,54
82
- promnesia-1.2.20240810.dist-info/top_level.txt,sha256=7yvIpooFiuNLf9yLdu9MTADz57z0YTAqSu7aSG9ujSU,10
83
- promnesia-1.2.20240810.dist-info/RECORD,,
@@ -1 +0,0 @@
1
- promnesia