promnesia 1.2.20240810__py3-none-any.whl → 1.3.20241021__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.
- promnesia/__init__.py +14 -3
- promnesia/__main__.py +38 -25
- promnesia/cannon.py +23 -23
- promnesia/common.py +49 -42
- promnesia/compare.py +18 -20
- promnesia/compat.py +10 -10
- promnesia/config.py +20 -22
- promnesia/database/common.py +4 -3
- promnesia/database/dump.py +14 -13
- promnesia/database/load.py +7 -7
- promnesia/extract.py +13 -11
- promnesia/kjson.py +11 -10
- promnesia/logging.py +1 -1
- promnesia/misc/install_server.py +7 -8
- promnesia/server.py +42 -31
- promnesia/sources/auto.py +43 -30
- promnesia/sources/auto_logseq.py +6 -5
- promnesia/sources/auto_obsidian.py +2 -2
- promnesia/sources/browser.py +14 -9
- promnesia/sources/browser_legacy.py +17 -13
- promnesia/sources/demo.py +7 -7
- promnesia/sources/fbmessenger.py +3 -2
- promnesia/sources/filetypes.py +9 -7
- promnesia/sources/github.py +5 -7
- promnesia/sources/guess.py +2 -1
- promnesia/sources/hackernews.py +2 -2
- promnesia/sources/hpi.py +2 -2
- promnesia/sources/html.py +7 -5
- promnesia/sources/hypothesis.py +3 -2
- promnesia/sources/instapaper.py +2 -2
- promnesia/sources/markdown.py +17 -7
- promnesia/sources/org.py +20 -10
- promnesia/sources/plaintext.py +30 -31
- promnesia/sources/pocket.py +3 -2
- promnesia/sources/reddit.py +19 -18
- promnesia/sources/roamresearch.py +2 -1
- promnesia/sources/rss.py +3 -4
- promnesia/sources/shellcmd.py +19 -6
- promnesia/sources/signal.py +14 -13
- promnesia/sources/smscalls.py +2 -2
- promnesia/sources/stackexchange.py +3 -2
- promnesia/sources/takeout.py +23 -13
- promnesia/sources/takeout_legacy.py +15 -11
- promnesia/sources/telegram.py +13 -11
- promnesia/sources/telegram_legacy.py +18 -7
- promnesia/sources/twitter.py +6 -5
- promnesia/sources/vcs.py +5 -3
- promnesia/sources/viber.py +10 -9
- promnesia/sources/website.py +4 -4
- promnesia/sources/zulip.py +3 -2
- promnesia/sqlite.py +7 -4
- promnesia/tests/common.py +8 -5
- promnesia/tests/server_helper.py +11 -8
- promnesia/tests/sources/test_auto.py +2 -3
- promnesia/tests/sources/test_filetypes.py +2 -1
- promnesia/tests/sources/test_hypothesis.py +3 -3
- promnesia/tests/sources/test_org.py +2 -3
- promnesia/tests/sources/test_plaintext.py +0 -1
- promnesia/tests/sources/test_shellcmd.py +3 -4
- promnesia/tests/sources/test_takeout.py +3 -5
- promnesia/tests/test_cannon.py +5 -5
- promnesia/tests/test_cli.py +4 -6
- promnesia/tests/test_compare.py +1 -1
- promnesia/tests/test_config.py +7 -8
- promnesia/tests/test_db_dump.py +11 -12
- promnesia/tests/test_extract.py +10 -6
- promnesia/tests/test_indexer.py +14 -8
- promnesia/tests/test_server.py +2 -3
- promnesia/tests/test_traverse.py +0 -2
- promnesia/tests/utils.py +4 -4
- {promnesia-1.2.20240810.dist-info → promnesia-1.3.20241021.dist-info}/METADATA +3 -2
- promnesia-1.3.20241021.dist-info/RECORD +83 -0
- {promnesia-1.2.20240810.dist-info → promnesia-1.3.20241021.dist-info}/WHEEL +1 -1
- promnesia-1.2.20240810.dist-info/RECORD +0 -83
- {promnesia-1.2.20240810.dist-info → promnesia-1.3.20241021.dist-info}/LICENSE +0 -0
- {promnesia-1.2.20240810.dist-info → promnesia-1.3.20241021.dist-info}/entry_points.txt +0 -0
- {promnesia-1.2.20240810.dist-info → promnesia-1.3.20241021.dist-info}/top_level.txt +0 -0
promnesia/sources/telegram.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
from
|
2
|
-
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
3
|
import warnings
|
4
|
+
from urllib.parse import unquote # TODO mm, make it easier to rememember to use...
|
4
5
|
|
5
|
-
from promnesia.common import
|
6
|
+
from promnesia.common import Loc, PathIsh, Results, Visit, extract_urls, logger
|
6
7
|
|
7
8
|
|
8
|
-
def index(database:
|
9
|
+
def index(database: PathIsh | None=None, *, http_only: bool=False, with_extra_media_info: bool=False) -> Results:
|
9
10
|
if database is None:
|
10
11
|
# fully relying on HPI
|
11
12
|
yield from _index_new(http_only=http_only, with_extra_media_info=with_extra_media_info)
|
@@ -17,10 +18,11 @@ def index(database: Optional[PathIsh]=None, *, http_only: bool=False, with_extra
|
|
17
18
|
)
|
18
19
|
try:
|
19
20
|
yield from _index_new_with_adhoc_config(database=database, http_only=http_only, with_extra_media_info=with_extra_media_info)
|
20
|
-
return
|
21
21
|
except Exception as e:
|
22
22
|
logger.exception(e)
|
23
23
|
warnings.warn("Hacking my.config.telegram.telegram_backup didn't work. You probably need to update HPI.")
|
24
|
+
else:
|
25
|
+
return
|
24
26
|
|
25
27
|
logger.warning("Falling back onto promnesia.sources.telegram_legacy module")
|
26
28
|
yield from _index_legacy(database=database, http_only=http_only)
|
@@ -32,7 +34,7 @@ def _index_legacy(*, database: PathIsh, http_only: bool) -> Results:
|
|
32
34
|
|
33
35
|
|
34
36
|
def _index_new_with_adhoc_config(*, database: PathIsh, http_only: bool, with_extra_media_info: bool) -> Results:
|
35
|
-
from . import hpi
|
37
|
+
from . import hpi # noqa: F401,I001
|
36
38
|
|
37
39
|
class config:
|
38
40
|
class telegram:
|
@@ -45,14 +47,14 @@ def _index_new_with_adhoc_config(*, database: PathIsh, http_only: bool, with_ext
|
|
45
47
|
|
46
48
|
|
47
49
|
def _index_new(*, http_only: bool, with_extra_media_info: bool) -> Results:
|
48
|
-
from . import hpi
|
50
|
+
from . import hpi # noqa: F401,I001
|
49
51
|
from my.telegram.telegram_backup import messages
|
50
52
|
|
51
53
|
extra_where = "(has_media == 1 OR text LIKE '%http%')" if http_only else None
|
52
|
-
for
|
53
|
-
|
54
|
-
|
55
|
-
)
|
54
|
+
for m in messages(
|
55
|
+
with_extra_media_info=with_extra_media_info,
|
56
|
+
extra_where=extra_where,
|
57
|
+
):
|
56
58
|
text = m.text
|
57
59
|
|
58
60
|
urls = extract_urls(text)
|
@@ -2,23 +2,34 @@
|
|
2
2
|
Uses [[https://github.com/fabianonline/telegram_backup#readme][telegram_backup]] database for messages data
|
3
3
|
'''
|
4
4
|
|
5
|
-
from
|
5
|
+
from __future__ import annotations
|
6
|
+
|
6
7
|
import sqlite3
|
8
|
+
from pathlib import Path
|
7
9
|
from textwrap import dedent
|
8
|
-
from typing import
|
9
|
-
from urllib.parse import unquote
|
10
|
+
from typing import TypeVar
|
11
|
+
from urllib.parse import unquote # TODO mm, make it easier to rememember to use...
|
12
|
+
|
13
|
+
from promnesia.common import (
|
14
|
+
Loc,
|
15
|
+
PathIsh,
|
16
|
+
Results,
|
17
|
+
Visit,
|
18
|
+
echain,
|
19
|
+
extract_urls,
|
20
|
+
from_epoch,
|
21
|
+
get_logger,
|
22
|
+
)
|
10
23
|
|
11
|
-
from ..common import PathIsh, Visit, get_logger, Loc, extract_urls, from_epoch, Results, echain
|
12
24
|
from ..sqlite import sqlite_connection
|
13
25
|
|
14
26
|
T = TypeVar("T")
|
15
27
|
|
16
28
|
|
17
|
-
def unwrap(res:
|
29
|
+
def unwrap(res: T | Exception) -> T:
|
18
30
|
if isinstance(res, Exception):
|
19
31
|
raise res
|
20
|
-
|
21
|
-
return res
|
32
|
+
return res
|
22
33
|
|
23
34
|
|
24
35
|
def index(database: PathIsh, *, http_only: bool=False) -> Results:
|
promnesia/sources/twitter.py
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
'''
|
2
2
|
Uses [[https://github.com/karlicoss/HPI][HPI]] for Twitter data.
|
3
3
|
'''
|
4
|
-
from typing import Iterable
|
5
4
|
|
6
|
-
from
|
5
|
+
from collections.abc import Iterable
|
6
|
+
|
7
|
+
from promnesia.common import Loc, Res, Results, Visit, extract_urls, logger
|
7
8
|
|
8
9
|
|
9
10
|
def index() -> Results:
|
10
|
-
from . import hpi
|
11
|
+
from . import hpi # noqa: F401,I001
|
11
12
|
import my.twitter.all as tw
|
13
|
+
from my.twitter.archive import Tweet # todo extract to common or something?
|
14
|
+
|
12
15
|
# TODO hmm. tweets themselves are sort of visits? not sure if they should contribute..
|
13
16
|
processed = 0
|
14
|
-
|
15
|
-
from my.twitter.archive import Tweet # todo extract to common or something?
|
16
17
|
tweets: Iterable[Res[Tweet]] = tw.tweets()
|
17
18
|
for t in tweets:
|
18
19
|
if isinstance(t, Exception):
|
promnesia/sources/vcs.py
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
'''
|
2
2
|
Clones & indexes Git repositories (via sources.auto)
|
3
3
|
'''
|
4
|
-
|
4
|
+
from __future__ import annotations
|
5
5
|
|
6
|
-
from pathlib import Path
|
7
6
|
import re
|
7
|
+
from collections.abc import Iterable
|
8
|
+
|
9
|
+
# TODO not sure if worth exposing... could be just handled by auto or something?)
|
10
|
+
from pathlib import Path
|
8
11
|
from subprocess import check_call
|
9
|
-
from typing import Iterable
|
10
12
|
|
11
13
|
from ..common import Extraction, PathIsh, get_tmpdir, slugify
|
12
14
|
|
promnesia/sources/viber.py
CHANGED
@@ -2,17 +2,18 @@
|
|
2
2
|
Collects visits from Viber desktop app (e.g. `~/.ViberPC/XYZ123/viber.db`)
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
6
|
+
|
5
7
|
import logging
|
8
|
+
import sqlite3
|
6
9
|
import textwrap
|
10
|
+
from collections.abc import Iterable
|
7
11
|
from os import PathLike
|
8
12
|
from pathlib import Path
|
9
|
-
import sqlite3
|
10
|
-
from typing import Iterable, Optional
|
11
13
|
|
12
14
|
from ..common import Loc, PathIsh, Results, Visit, extract_urls, from_epoch, join_tags
|
13
15
|
from ..sqlite import sqlite_connection
|
14
16
|
|
15
|
-
|
16
17
|
logger = logging.getLogger(__name__)
|
17
18
|
|
18
19
|
|
@@ -34,12 +35,12 @@ def index(
|
|
34
35
|
|
35
36
|
msgs_query = messages_query(http_only)
|
36
37
|
|
37
|
-
for
|
38
|
-
assert
|
39
|
-
yield from _harvest_db(
|
38
|
+
for db in _get_files(db_path):
|
39
|
+
assert db.is_file(), f"Is it a (Viber-desktop sqlite) file? {db}"
|
40
|
+
yield from _harvest_db(db, msgs_query, locator_schema)
|
40
41
|
|
41
42
|
|
42
|
-
def messages_query(http_only:
|
43
|
+
def messages_query(http_only: bool | None) -> str:
|
43
44
|
"""
|
44
45
|
An SQL-query returning 1 row for each message
|
45
46
|
|
@@ -123,7 +124,7 @@ def _handle_row(row: sqlite3.Row, db_path: PathLike, locator_schema: str) -> Res
|
|
123
124
|
tags: str = row["tags"]
|
124
125
|
url_title: str = row["url_title"]
|
125
126
|
|
126
|
-
assert (
|
127
|
+
assert ( # noqa: PT018
|
127
128
|
text and mid and sender and chatname
|
128
129
|
), f"sql-query should eliminate messages without 'http' or missing ids: {row}"
|
129
130
|
|
@@ -154,7 +155,7 @@ def _get_files(path: PathIsh) -> Iterable[Path]:
|
|
154
155
|
"""
|
155
156
|
path = Path(path).expanduser()
|
156
157
|
parts = path.parts[1:] if path.is_absolute() else path.parts
|
157
|
-
return Path(path.root).glob(str(Path("").joinpath(*parts)))
|
158
|
+
return Path(path.root).glob(str(Path("").joinpath(*parts))) # noqa: PTH201
|
158
159
|
|
159
160
|
|
160
161
|
def _harvest_db(db_path: PathIsh, msgs_query: str, locator_schema: str) -> Results:
|
promnesia/sources/website.py
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
Clones a website with wget and indexes via sources.auto
|
3
3
|
'''
|
4
4
|
|
5
|
-
from pathlib import Path
|
6
5
|
import re
|
6
|
+
from collections.abc import Iterable
|
7
|
+
from pathlib import Path
|
7
8
|
from subprocess import run
|
8
|
-
from typing import Iterable
|
9
9
|
|
10
|
-
from
|
10
|
+
from promnesia.common import Extraction, PathIsh, get_logger, get_tmpdir, slugify
|
11
11
|
|
12
12
|
|
13
13
|
def index(path: PathIsh, *args, **kwargs) -> Iterable[Extraction]:
|
@@ -30,7 +30,7 @@ def index(path: PathIsh, *args, **kwargs) -> Iterable[Extraction]:
|
|
30
30
|
]
|
31
31
|
# TODO follow sitemap? e.g. gwern
|
32
32
|
logger.info(' '.join(cmd))
|
33
|
-
res = run(cmd)
|
33
|
+
res = run(cmd, check=False)
|
34
34
|
|
35
35
|
if res.returncode == 8:
|
36
36
|
# man wget: 8 means server error (e.g. broken link)
|
promnesia/sources/zulip.py
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
Uses [[https://github.com/karlicoss/HPI][HPI]] for Zulip data.
|
3
3
|
'''
|
4
4
|
|
5
|
-
from
|
5
|
+
from promnesia.common import Loc, Results, Visit, iter_urls
|
6
6
|
|
7
7
|
|
8
8
|
def index() -> Results:
|
9
|
-
from . import hpi
|
9
|
+
from . import hpi # noqa: F401,I001
|
10
10
|
import my.zulip.organization as Z
|
11
|
+
|
11
12
|
for m in Z.messages():
|
12
13
|
if isinstance(m, Exception):
|
13
14
|
yield m
|
promnesia/sqlite.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
|
+
|
2
3
|
import sqlite3
|
3
|
-
from
|
4
|
+
from collections.abc import Iterator
|
5
|
+
from contextlib import contextmanager
|
6
|
+
from typing import Any, Callable, Literal, Union
|
4
7
|
|
5
8
|
from .common import PathIsh
|
6
9
|
|
@@ -10,13 +13,13 @@ SqliteRowFactory = Callable[[sqlite3.Cursor, sqlite3.Row], Any]
|
|
10
13
|
|
11
14
|
def dict_factory(cursor, row):
|
12
15
|
fields = [column[0] for column in cursor.description]
|
13
|
-
return
|
16
|
+
return dict(zip(fields, row))
|
14
17
|
|
15
18
|
|
16
19
|
Factory = Union[SqliteRowFactory, Literal['row', 'dict']]
|
17
20
|
|
18
21
|
@contextmanager
|
19
|
-
def sqlite_connection(db: PathIsh, *, immutable: bool=False, row_factory:
|
22
|
+
def sqlite_connection(db: PathIsh, *, immutable: bool=False, row_factory: Factory | None=None) -> Iterator[sqlite3.Connection]:
|
20
23
|
dbp = f'file:{db}'
|
21
24
|
# https://www.sqlite.org/draft/uri.html#uriimmutable
|
22
25
|
if immutable:
|
promnesia/tests/common.py
CHANGED
@@ -1,16 +1,19 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
|
+
|
2
3
|
import gc
|
3
4
|
import inspect
|
4
5
|
import os
|
5
|
-
from pathlib import Path
|
6
6
|
import socket
|
7
7
|
import sys
|
8
|
+
from collections.abc import Iterator
|
9
|
+
from contextlib import closing, contextmanager
|
10
|
+
from pathlib import Path
|
8
11
|
from textwrap import dedent
|
9
|
-
from typing import
|
12
|
+
from typing import NoReturn, TypeVar
|
10
13
|
|
11
14
|
import pytest
|
12
15
|
|
13
|
-
from ..common import
|
16
|
+
from ..common import Res, _is_windows
|
14
17
|
|
15
18
|
|
16
19
|
def under_ci() -> bool:
|
@@ -25,7 +28,7 @@ def throw(x: Exception) -> NoReturn:
|
|
25
28
|
|
26
29
|
|
27
30
|
@pytest.fixture
|
28
|
-
def gc_control(gc_on: bool):
|
31
|
+
def gc_control(*, gc_on: bool):
|
29
32
|
if gc_on:
|
30
33
|
# no need to do anything, should be on by default
|
31
34
|
yield
|
promnesia/tests/server_helper.py
CHANGED
@@ -1,15 +1,18 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import sys
|
4
|
+
import time
|
5
|
+
from collections.abc import Iterator
|
1
6
|
from contextlib import contextmanager
|
2
7
|
from dataclasses import dataclass
|
3
8
|
from pathlib import Path
|
4
|
-
import
|
5
|
-
import time
|
6
|
-
from typing import Any, Dict, Iterator, Optional
|
9
|
+
from typing import Any
|
7
10
|
|
8
11
|
import psutil
|
9
12
|
import requests
|
10
13
|
|
11
14
|
from ..common import PathIsh
|
12
|
-
from .common import
|
15
|
+
from .common import free_port, promnesia_bin, tmp_popen
|
13
16
|
|
14
17
|
|
15
18
|
@dataclass
|
@@ -18,18 +21,18 @@ class Helper:
|
|
18
21
|
port: str
|
19
22
|
process: psutil.Popen
|
20
23
|
|
21
|
-
def get(self, path: str
|
24
|
+
def get(self, path: str):
|
22
25
|
# check it's alive first so the error is cleaner
|
23
26
|
assert self.process.poll() is None, self.process
|
24
27
|
return requests.get(f'http://{self.host}:{self.port}' + path)
|
25
28
|
|
26
|
-
def post(self, path: str, *, json:
|
29
|
+
def post(self, path: str, *, json: dict[str, Any] | None = None):
|
27
30
|
assert self.process.poll() is None, self.process
|
28
31
|
return requests.post(f'http://{self.host}:{self.port}' + path, json=json)
|
29
32
|
|
30
33
|
|
31
34
|
@contextmanager
|
32
|
-
def run_server(db:
|
35
|
+
def run_server(db: PathIsh | None = None, *, timezone: str | None = None) -> Iterator[Helper]:
|
33
36
|
# TODO not sure, perhaps best to use a thread or something?
|
34
37
|
# but for some tests makes more sense to test in a separate process
|
35
38
|
with free_port() as pp:
|
@@ -56,7 +59,7 @@ def run_server(db: Optional[PathIsh] = None, *, timezone: Optional[str] = None)
|
|
56
59
|
time.sleep(0.1)
|
57
60
|
else:
|
58
61
|
raise RuntimeError("Cooldn't connect to '{st}' after 50 attempts")
|
59
|
-
print("Started server up, db: {db}"
|
62
|
+
print(f"Started server up, db: {db}", file=sys.stderr)
|
60
63
|
|
61
64
|
yield server
|
62
65
|
|
@@ -1,8 +1,7 @@
|
|
1
|
-
from itertools import groupby
|
2
1
|
import os
|
2
|
+
from itertools import groupby
|
3
3
|
|
4
4
|
from ...sources import auto
|
5
|
-
|
6
5
|
from ..common import get_testdata, throw
|
7
6
|
|
8
7
|
sa2464 = 'https://www.scottaaronson.com/blog/?p=2464'
|
@@ -19,7 +18,7 @@ def makemap(visits):
|
|
19
18
|
def it():
|
20
19
|
vit = (throw(v) if isinstance(v, Exception) else v for v in visits)
|
21
20
|
for k, g in groupby(sorted(vit, key=key), key=key):
|
22
|
-
yield k,
|
21
|
+
yield k, sorted(g)
|
23
22
|
|
24
23
|
return dict(it())
|
25
24
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
|
3
|
-
from
|
3
|
+
from my.core.cfg import tmp_config
|
4
|
+
|
4
5
|
from ...__main__ import do_index
|
5
6
|
from ...database.load import get_all_db_visits
|
6
|
-
|
7
|
-
from my.core.cfg import tmp_config
|
7
|
+
from ..common import get_testdata, write_config
|
8
8
|
|
9
9
|
|
10
10
|
def index_hypothesis(tmp_path: Path) -> None:
|
@@ -1,12 +1,11 @@
|
|
1
|
-
from
|
1
|
+
from __future__ import annotations
|
2
2
|
|
3
3
|
from ...common import Visit
|
4
4
|
from ...sources.org import extract_from_file
|
5
|
-
|
6
5
|
from ..common import get_testdata, throw
|
7
6
|
|
8
7
|
|
9
|
-
def delrf(s:
|
8
|
+
def delrf(s: str | None) -> str | None:
|
10
9
|
if s is None:
|
11
10
|
return None
|
12
11
|
# meh.. not sure how ot handle this properly, ideally should be via pytest?
|
@@ -1,9 +1,8 @@
|
|
1
|
-
from ...common import _is_windows, Source
|
2
|
-
from ...extract import extract_visits
|
3
|
-
from ...sources import shellcmd
|
4
|
-
|
5
1
|
import pytest
|
6
2
|
|
3
|
+
from ...common import Source, _is_windows
|
4
|
+
from ...extract import extract_visits
|
5
|
+
from ...sources import shellcmd
|
7
6
|
from ..common import get_testdata
|
8
7
|
|
9
8
|
|
@@ -1,15 +1,13 @@
|
|
1
1
|
from datetime import datetime, timezone
|
2
2
|
|
3
|
+
import pytest
|
4
|
+
from my.core.cfg import tmp_config
|
5
|
+
|
3
6
|
from ...common import Source
|
4
7
|
from ...extract import extract_visits
|
5
8
|
from ...sources import takeout
|
6
|
-
|
7
|
-
import pytest
|
8
|
-
|
9
9
|
from ..common import get_testdata, unwrap
|
10
10
|
|
11
|
-
from my.core.cfg import tmp_config
|
12
|
-
|
13
11
|
|
14
12
|
# TODO apply in conftest so it's used in all tests?
|
15
13
|
@pytest.fixture
|
promnesia/tests/test_cannon.py
CHANGED
@@ -2,7 +2,7 @@ from typing import cast
|
|
2
2
|
|
3
3
|
import pytest
|
4
4
|
|
5
|
-
from ..cannon import
|
5
|
+
from ..cannon import CanonifyException, canonify
|
6
6
|
|
7
7
|
# TODO should actually understand 'sequences'?
|
8
8
|
# e.g.
|
@@ -134,7 +134,7 @@ def test_reddit(url, expected):
|
|
134
134
|
def test_pocket(url, expected):
|
135
135
|
assert canonify(url) == expected
|
136
136
|
|
137
|
-
@pytest.mark.parametrize("url,expected", [
|
137
|
+
@pytest.mark.parametrize(("url", "expected"), [
|
138
138
|
# TODO ?? 'https://groups.google.com/a/list.hypothes.is/forum/#!topic/dev/kcmS7H8ssis',
|
139
139
|
#
|
140
140
|
# TODO FIXME fragment handling
|
@@ -295,7 +295,7 @@ def test(url, expected):
|
|
295
295
|
},
|
296
296
|
])
|
297
297
|
def test_same_norm(urls):
|
298
|
-
urls =
|
298
|
+
urls = sorted(urls)
|
299
299
|
u0 = urls[0]
|
300
300
|
c0 = canonify(u0)
|
301
301
|
for u in urls[1:]:
|
@@ -308,7 +308,7 @@ def test_error():
|
|
308
308
|
# borrowed from https://bugs.mageia.org/show_bug.cgi?id=24640#c7
|
309
309
|
canonify('https://example.com\uFF03@bing.com')
|
310
310
|
|
311
|
-
@pytest.mark.parametrize("url,expected", [
|
311
|
+
@pytest.mark.parametrize(("url", "expected"), [
|
312
312
|
('https://news.ycombinator.com/item?id=', 'news.ycombinator.com/item?id='),
|
313
313
|
('https://www.youtube.com/watch?v=hvoQiF0kBI8&list&index=2',
|
314
314
|
'youtube.com/watch?v=hvoQiF0kBI8&list='),
|
@@ -316,7 +316,7 @@ def test_error():
|
|
316
316
|
def test_empty_query_parameter(url, expected):
|
317
317
|
assert canonify(url) == expected
|
318
318
|
|
319
|
-
@pytest.mark.parametrize("url,expected", [
|
319
|
+
@pytest.mark.parametrize(("url", "expected"), [
|
320
320
|
('http://www.isfdb.org/cgi-bin/title.cgi?2172', 'isfdb.org/cgi-bin/title.cgi?2172='),
|
321
321
|
('http://www.isfdb.org/cgi-bin/title.cgi?2172+1', 'isfdb.org/cgi-bin/title.cgi?2172%201='),
|
322
322
|
('http://www.isfdb.org/cgi-bin/title.cgi?2172&foo=bar&baz&quux', 'isfdb.org/cgi-bin/title.cgi?2172=&baz=&foo=bar&quux='),
|
promnesia/tests/test_cli.py
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
3
|
|
4
|
-
from ..common import _is_windows
|
5
|
-
|
6
|
-
from .common import get_testdata, promnesia_bin, tmp_popen
|
7
|
-
|
8
4
|
import pytest
|
9
5
|
import requests
|
10
6
|
|
7
|
+
from ..common import _is_windows
|
8
|
+
from .common import get_testdata, promnesia_bin, tmp_popen
|
11
9
|
|
12
10
|
ox_hugo_data = get_testdata('ox-hugo/test/site')
|
13
11
|
|
@@ -22,12 +20,12 @@ def test_demo() -> None:
|
|
22
20
|
# TODO why does it want post??
|
23
21
|
time.sleep(2) # meh.. need a generic helper to wait till ready...
|
24
22
|
res = {}
|
25
|
-
for
|
23
|
+
for _attempt in range(30):
|
26
24
|
time.sleep(1)
|
27
25
|
try:
|
28
26
|
res = requests.post(
|
29
27
|
"http://localhost:16789/search",
|
30
|
-
json=
|
28
|
+
json={'url': "https://github.com/kaushalmodi/ox-hugo/issues"},
|
31
29
|
).json()
|
32
30
|
break
|
33
31
|
except:
|
promnesia/tests/test_compare.py
CHANGED
promnesia/tests/test_config.py
CHANGED
@@ -1,15 +1,14 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
from contextlib import contextmanager
|
2
4
|
from pathlib import Path
|
3
5
|
from tempfile import TemporaryDirectory
|
4
|
-
from typing import Union, List
|
5
|
-
|
6
|
-
from ..common import Source
|
7
|
-
from ..config import import_config, Config
|
8
|
-
|
9
6
|
|
10
|
-
from more_itertools import ilen
|
11
7
|
import pytest
|
8
|
+
from more_itertools import ilen
|
12
9
|
|
10
|
+
from ..common import Source
|
11
|
+
from ..config import Config, import_config
|
13
12
|
from .common import throw
|
14
13
|
|
15
14
|
|
@@ -22,7 +21,7 @@ def make(body: str) -> Config:
|
|
22
21
|
|
23
22
|
|
24
23
|
@contextmanager
|
25
|
-
def with_config(cfg:
|
24
|
+
def with_config(cfg: str | Config):
|
26
25
|
from .. import config as C
|
27
26
|
|
28
27
|
assert not C.has()
|
@@ -35,7 +34,7 @@ def with_config(cfg: Union[str, Config]):
|
|
35
34
|
C.reset()
|
36
35
|
|
37
36
|
|
38
|
-
def index(cfg:
|
37
|
+
def index(cfg: str | Config, *, check: bool = True) -> list[Exception]:
|
39
38
|
from ..__main__ import _do_index
|
40
39
|
|
41
40
|
with with_config(cfg):
|
promnesia/tests/test_db_dump.py
CHANGED
@@ -4,30 +4,29 @@ from concurrent.futures import ProcessPoolExecutor
|
|
4
4
|
from datetime import datetime, timedelta, timezone
|
5
5
|
from pathlib import Path
|
6
6
|
from tempfile import TemporaryDirectory
|
7
|
-
from typing import Any
|
7
|
+
from typing import Any
|
8
8
|
|
9
|
-
|
10
|
-
from hypothesis import settings, given
|
11
|
-
from hypothesis.strategies import from_type
|
12
9
|
# NOTE: pytest ... -s --hypothesis-verbosity=debug is useful for seeing what hypothesis is doing
|
13
10
|
import pytest
|
14
11
|
import pytz
|
15
|
-
|
12
|
+
from hypothesis import given, settings
|
13
|
+
from hypothesis.strategies import from_type
|
16
14
|
|
17
15
|
from ..common import Loc
|
18
16
|
from ..database.common import DbVisit
|
19
17
|
from ..database.dump import visits_to_sqlite
|
20
18
|
from ..database.load import get_all_db_visits
|
21
19
|
from ..sqlite import sqlite_connection
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
HSETTINGS: dict[str, Any] = dict(
|
27
|
-
derandomize=True,
|
28
|
-
deadline=timedelta(seconds=2), # sometimes slow on ci
|
20
|
+
from .common import (
|
21
|
+
gc_control, # noqa: F401
|
22
|
+
running_on_ci,
|
29
23
|
)
|
30
24
|
|
25
|
+
HSETTINGS: dict[str, Any] = {
|
26
|
+
'derandomize': True,
|
27
|
+
'deadline': timedelta(seconds=2), # sometimes slow on ci
|
28
|
+
}
|
29
|
+
|
31
30
|
|
32
31
|
def test_no_visits(tmp_path: Path) -> None:
|
33
32
|
visits: list[DbVisit] = []
|
promnesia/tests/test_extract.py
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
from datetime import datetime, timezone
|
2
2
|
|
3
|
-
from ..common import Visit, DbVisit, Loc, Source
|
4
|
-
from ..extract import extract_visits
|
5
|
-
|
6
|
-
from .common import get_testdata, unwrap, running_on_ci, gc_control
|
7
|
-
|
8
|
-
from more_itertools import ilen
|
9
3
|
import pytest
|
4
|
+
from more_itertools import ilen
|
5
|
+
|
6
|
+
from ..common import DbVisit, Loc, Source, Visit
|
7
|
+
from ..extract import extract_visits
|
8
|
+
from .common import (
|
9
|
+
gc_control, # noqa: F401
|
10
|
+
get_testdata,
|
11
|
+
running_on_ci,
|
12
|
+
unwrap,
|
13
|
+
)
|
10
14
|
|
11
15
|
|
12
16
|
def test_with_error() -> None:
|