instapaper-scraper 1.1.0__tar.gz → 1.1.1__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.
- {instapaper_scraper-1.1.0/src/instapaper_scraper.egg-info → instapaper_scraper-1.1.1}/PKG-INFO +22 -14
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/README.md +20 -13
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/pyproject.toml +7 -3
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/output.py +16 -4
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1/src/instapaper_scraper.egg-info}/PKG-INFO +22 -14
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/requires.txt +1 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_output.py +34 -13
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/LICENSE +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/setup.cfg +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/__init__.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/api.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/auth.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/cli.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/constants.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper/exceptions.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/SOURCES.txt +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/dependency_links.txt +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/entry_points.txt +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/top_level.txt +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_api.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_auth.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_cli.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_cli_priority.py +0 -0
- {instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/tests/test_init.py +0 -0
{instapaper_scraper-1.1.0/src/instapaper_scraper.egg-info → instapaper_scraper-1.1.1}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: instapaper-scraper
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: A tool to scrape articles from Instapaper.
|
|
5
5
|
Project-URL: Homepage, https://github.com/chriskyfung/InstapaperScraper
|
|
6
6
|
Project-URL: Source, https://github.com/chriskyfung/InstapaperScraper
|
|
@@ -43,12 +43,19 @@ Requires-Dist: build; extra == "dev"
|
|
|
43
43
|
Requires-Dist: twine; extra == "dev"
|
|
44
44
|
Requires-Dist: mypy; extra == "dev"
|
|
45
45
|
Requires-Dist: pre-commit; extra == "dev"
|
|
46
|
+
Requires-Dist: licensecheck; extra == "dev"
|
|
46
47
|
Dynamic: license-file
|
|
47
48
|
|
|
48
49
|
# Instapaper Scraper
|
|
49
50
|
|
|
50
51
|
<!-- Badges -->
|
|
51
52
|
<p align="center">
|
|
53
|
+
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
54
|
+
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
55
|
+
</a>
|
|
56
|
+
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
57
|
+
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
58
|
+
</a>
|
|
52
59
|
<a href="https://github.com/chriskyfung/InstapaperScraper">
|
|
53
60
|
<img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fchriskyfung%2FInstapaperScraper%2Frefs%2Fheads%2Fmaster%2Fpyproject.toml" alt="Python Version from PEP 621 TOML">
|
|
54
61
|
</a>
|
|
@@ -58,23 +65,18 @@ Dynamic: license-file
|
|
|
58
65
|
<a href="https://codecov.io/gh/chriskyfung/InstapaperScraper">
|
|
59
66
|
<img src="https://codecov.io/gh/chriskyfung/InstapaperScraper/graph/badge.svg" alt="Code Coverage">
|
|
60
67
|
</a>
|
|
68
|
+
<wbr />
|
|
61
69
|
<a href="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml">
|
|
62
70
|
<img src="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
63
71
|
</a>
|
|
64
|
-
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
65
|
-
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
66
|
-
</a>
|
|
67
|
-
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
68
|
-
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
69
|
-
</a>
|
|
70
72
|
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html">
|
|
71
73
|
<img src="https://img.shields.io/github/license/chriskyfung/InstapaperScraper" alt="GitHub License">
|
|
72
74
|
</a>
|
|
73
75
|
<a href="https://github.com/sponsors/chriskyfung" title="Sponsor on GitHub">
|
|
74
|
-
<img src="https://img.shields.io/badge/Sponsor-GitHub-
|
|
76
|
+
<img src="https://img.shields.io/badge/Sponsor-GitHub-blue?logo=github-sponsors&colorA=263238&colorB=EC407A" alt="GitHub Sponsors Default">
|
|
75
77
|
</a>
|
|
76
|
-
<a href="https://www.buymeacoffee.com/chriskyfung" title="
|
|
77
|
-
<img src="https://img.shields.io/badge/Support
|
|
78
|
+
<a href="https://www.buymeacoffee.com/chriskyfung" title="Support Coffee">
|
|
79
|
+
<img src="https://img.shields.io/badge/Support-Coffee-ffdd00?logo=buy-me-a-coffee&logoColor=ffdd00&colorA=263238" alt="Buy Me A Coffee">
|
|
78
80
|
</a>
|
|
79
81
|
</p>
|
|
80
82
|
|
|
@@ -336,6 +338,13 @@ To run static type checking with `mypy`:
|
|
|
336
338
|
mypy src
|
|
337
339
|
```
|
|
338
340
|
|
|
341
|
+
To run license checks:
|
|
342
|
+
|
|
343
|
+
```sh
|
|
344
|
+
licensecheck --show-only-failing
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
|
|
339
348
|
## 📜 Disclaimer
|
|
340
349
|
|
|
341
350
|
This script requires valid Instapaper credentials. Use it responsibly and in accordance with Instapaper’s Terms of Service.
|
|
@@ -344,9 +353,8 @@ This script requires valid Instapaper credentials. Use it responsibly and in acc
|
|
|
344
353
|
|
|
345
354
|
This project is licensed under the terms of the **GNU General Public License v3.0**. See the [LICENSE](LICENSE) file for the full license text.
|
|
346
355
|
|
|
347
|
-
##
|
|
356
|
+
## Contributors
|
|
348
357
|
|
|
349
|
-
|
|
358
|
+
[](https://github.com/chriskyfung/InstapaperScraper/graphs/contributors)
|
|
350
359
|
|
|
351
|
-
|
|
352
|
-
- **[Buy Me a Coffee](https://www.buymeacoffee.com/chriskyfung):** Perfect for a one-time thank you.
|
|
360
|
+
Made with [contrib.rocks](https://contrib.rocks).
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Badges -->
|
|
4
4
|
<p align="center">
|
|
5
|
+
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
6
|
+
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
7
|
+
</a>
|
|
8
|
+
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
9
|
+
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
10
|
+
</a>
|
|
5
11
|
<a href="https://github.com/chriskyfung/InstapaperScraper">
|
|
6
12
|
<img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fchriskyfung%2FInstapaperScraper%2Frefs%2Fheads%2Fmaster%2Fpyproject.toml" alt="Python Version from PEP 621 TOML">
|
|
7
13
|
</a>
|
|
@@ -11,23 +17,18 @@
|
|
|
11
17
|
<a href="https://codecov.io/gh/chriskyfung/InstapaperScraper">
|
|
12
18
|
<img src="https://codecov.io/gh/chriskyfung/InstapaperScraper/graph/badge.svg" alt="Code Coverage">
|
|
13
19
|
</a>
|
|
20
|
+
<wbr />
|
|
14
21
|
<a href="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml">
|
|
15
22
|
<img src="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
16
23
|
</a>
|
|
17
|
-
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
18
|
-
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
19
|
-
</a>
|
|
20
|
-
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
21
|
-
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
22
|
-
</a>
|
|
23
24
|
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html">
|
|
24
25
|
<img src="https://img.shields.io/github/license/chriskyfung/InstapaperScraper" alt="GitHub License">
|
|
25
26
|
</a>
|
|
26
27
|
<a href="https://github.com/sponsors/chriskyfung" title="Sponsor on GitHub">
|
|
27
|
-
<img src="https://img.shields.io/badge/Sponsor-GitHub-
|
|
28
|
+
<img src="https://img.shields.io/badge/Sponsor-GitHub-blue?logo=github-sponsors&colorA=263238&colorB=EC407A" alt="GitHub Sponsors Default">
|
|
28
29
|
</a>
|
|
29
|
-
<a href="https://www.buymeacoffee.com/chriskyfung" title="
|
|
30
|
-
<img src="https://img.shields.io/badge/Support
|
|
30
|
+
<a href="https://www.buymeacoffee.com/chriskyfung" title="Support Coffee">
|
|
31
|
+
<img src="https://img.shields.io/badge/Support-Coffee-ffdd00?logo=buy-me-a-coffee&logoColor=ffdd00&colorA=263238" alt="Buy Me A Coffee">
|
|
31
32
|
</a>
|
|
32
33
|
</p>
|
|
33
34
|
|
|
@@ -289,6 +290,13 @@ To run static type checking with `mypy`:
|
|
|
289
290
|
mypy src
|
|
290
291
|
```
|
|
291
292
|
|
|
293
|
+
To run license checks:
|
|
294
|
+
|
|
295
|
+
```sh
|
|
296
|
+
licensecheck --show-only-failing
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
|
|
292
300
|
## 📜 Disclaimer
|
|
293
301
|
|
|
294
302
|
This script requires valid Instapaper credentials. Use it responsibly and in accordance with Instapaper’s Terms of Service.
|
|
@@ -297,9 +305,8 @@ This script requires valid Instapaper credentials. Use it responsibly and in acc
|
|
|
297
305
|
|
|
298
306
|
This project is licensed under the terms of the **GNU General Public License v3.0**. See the [LICENSE](LICENSE) file for the full license text.
|
|
299
307
|
|
|
300
|
-
##
|
|
308
|
+
## Contributors
|
|
301
309
|
|
|
302
|
-
|
|
310
|
+
[](https://github.com/chriskyfung/InstapaperScraper/graphs/contributors)
|
|
303
311
|
|
|
304
|
-
|
|
305
|
-
- **[Buy Me a Coffee](https://www.buymeacoffee.com/chriskyfung):** Perfect for a one-time thank you.
|
|
312
|
+
Made with [contrib.rocks](https://contrib.rocks).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "instapaper-scraper"
|
|
7
|
-
version = "1.1.
|
|
7
|
+
version = "1.1.1"
|
|
8
8
|
description = "A tool to scrape articles from Instapaper."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -35,7 +35,7 @@ dependencies = [
|
|
|
35
35
|
"soupsieve~=2.8",
|
|
36
36
|
"typing_extensions~=4.15.0",
|
|
37
37
|
"urllib3>=2.5,<2.7",
|
|
38
|
-
"tomli~=2.0.1; python_version < '3.11'"
|
|
38
|
+
"tomli~=2.0.1; python_version < '3.11'"
|
|
39
39
|
]
|
|
40
40
|
|
|
41
41
|
[project.urls]
|
|
@@ -46,6 +46,9 @@ Issues = "https://github.com/chriskyfung/InstapaperScraper/issues"
|
|
|
46
46
|
[project.scripts]
|
|
47
47
|
instapaper-scraper = "instapaper_scraper.cli:main"
|
|
48
48
|
|
|
49
|
+
[tool.licensecheck]
|
|
50
|
+
license = "GPL-3.0"
|
|
51
|
+
|
|
49
52
|
[tool.pytest.ini_options]
|
|
50
53
|
pythonpath = "src"
|
|
51
54
|
|
|
@@ -77,5 +80,6 @@ dev = [
|
|
|
77
80
|
"build",
|
|
78
81
|
"twine",
|
|
79
82
|
"mypy",
|
|
80
|
-
"pre-commit"
|
|
83
|
+
"pre-commit",
|
|
84
|
+
"licensecheck"
|
|
81
85
|
]
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
|
-
import json
|
|
3
|
-
import sqlite3
|
|
4
2
|
import logging
|
|
5
|
-
import
|
|
6
|
-
from typing import List, Dict, Any
|
|
3
|
+
from typing import List, Dict, Any, TYPE_CHECKING
|
|
7
4
|
|
|
8
5
|
from .constants import INSTAPAPER_READ_URL, KEY_ID, KEY_TITLE, KEY_URL
|
|
9
6
|
|
|
@@ -19,6 +16,13 @@ LOG_NO_ARTICLES = "No articles found to save."
|
|
|
19
16
|
LOG_SAVED_ARTICLES = "Saved {count} articles to {filename}"
|
|
20
17
|
LOG_UNKNOWN_FORMAT = "Unknown output format: {format}"
|
|
21
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
# Import for type-checking purposes, and use an alias
|
|
21
|
+
# to signal to linters like ruff that it is being used.
|
|
22
|
+
import sqlite3 as sqlite3
|
|
23
|
+
|
|
24
|
+
__all__ = ["sqlite3"]
|
|
25
|
+
|
|
22
26
|
|
|
23
27
|
def get_sqlite_create_table_sql(add_instapaper_url: bool = False) -> str:
|
|
24
28
|
"""Returns the SQL statement to create the articles table."""
|
|
@@ -28,6 +32,8 @@ def get_sqlite_create_table_sql(add_instapaper_url: bool = False) -> str:
|
|
|
28
32
|
f"{KEY_URL} TEXT NOT NULL",
|
|
29
33
|
]
|
|
30
34
|
if add_instapaper_url:
|
|
35
|
+
import sqlite3
|
|
36
|
+
|
|
31
37
|
# The GENERATED ALWAYS AS syntax was added in SQLite 3.31.0
|
|
32
38
|
if sqlite3.sqlite_version_info >= (3, 31, 0):
|
|
33
39
|
columns.append(
|
|
@@ -55,6 +61,8 @@ def save_to_csv(
|
|
|
55
61
|
data: List[Dict[str, Any]], filename: str, add_instapaper_url: bool = False
|
|
56
62
|
) -> None:
|
|
57
63
|
"""Saves a list of articles to a CSV file."""
|
|
64
|
+
import csv
|
|
65
|
+
|
|
58
66
|
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
59
67
|
with open(filename, "w", newline="", encoding="utf-8") as f:
|
|
60
68
|
fieldnames = [KEY_ID, KEY_TITLE, KEY_URL]
|
|
@@ -71,6 +79,8 @@ def save_to_csv(
|
|
|
71
79
|
|
|
72
80
|
def save_to_json(data: List[Dict[str, Any]], filename: str) -> None:
|
|
73
81
|
"""Saves a list of articles to a JSON file."""
|
|
82
|
+
import json
|
|
83
|
+
|
|
74
84
|
os.makedirs(os.path.dirname(filename), exist_ok=True)
|
|
75
85
|
with open(filename, "w", encoding="utf-8") as f:
|
|
76
86
|
json.dump(data, f, indent=JSON_INDENT, ensure_ascii=False)
|
|
@@ -81,6 +91,8 @@ def save_to_sqlite(
|
|
|
81
91
|
data: List[Dict[str, Any]], db_name: str, add_instapaper_url: bool = False
|
|
82
92
|
) -> None:
|
|
83
93
|
"""Saves a list of articles to a SQLite database."""
|
|
94
|
+
import sqlite3
|
|
95
|
+
|
|
84
96
|
os.makedirs(os.path.dirname(db_name), exist_ok=True)
|
|
85
97
|
conn = sqlite3.connect(db_name)
|
|
86
98
|
cursor = conn.cursor()
|
{instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1/src/instapaper_scraper.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: instapaper-scraper
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: A tool to scrape articles from Instapaper.
|
|
5
5
|
Project-URL: Homepage, https://github.com/chriskyfung/InstapaperScraper
|
|
6
6
|
Project-URL: Source, https://github.com/chriskyfung/InstapaperScraper
|
|
@@ -43,12 +43,19 @@ Requires-Dist: build; extra == "dev"
|
|
|
43
43
|
Requires-Dist: twine; extra == "dev"
|
|
44
44
|
Requires-Dist: mypy; extra == "dev"
|
|
45
45
|
Requires-Dist: pre-commit; extra == "dev"
|
|
46
|
+
Requires-Dist: licensecheck; extra == "dev"
|
|
46
47
|
Dynamic: license-file
|
|
47
48
|
|
|
48
49
|
# Instapaper Scraper
|
|
49
50
|
|
|
50
51
|
<!-- Badges -->
|
|
51
52
|
<p align="center">
|
|
53
|
+
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
54
|
+
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
55
|
+
</a>
|
|
56
|
+
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
57
|
+
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
58
|
+
</a>
|
|
52
59
|
<a href="https://github.com/chriskyfung/InstapaperScraper">
|
|
53
60
|
<img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fchriskyfung%2FInstapaperScraper%2Frefs%2Fheads%2Fmaster%2Fpyproject.toml" alt="Python Version from PEP 621 TOML">
|
|
54
61
|
</a>
|
|
@@ -58,23 +65,18 @@ Dynamic: license-file
|
|
|
58
65
|
<a href="https://codecov.io/gh/chriskyfung/InstapaperScraper">
|
|
59
66
|
<img src="https://codecov.io/gh/chriskyfung/InstapaperScraper/graph/badge.svg" alt="Code Coverage">
|
|
60
67
|
</a>
|
|
68
|
+
<wbr />
|
|
61
69
|
<a href="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml">
|
|
62
70
|
<img src="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml/badge.svg" alt="CI Status">
|
|
63
71
|
</a>
|
|
64
|
-
<a href="https://pypi.org/project/instapaper-scraper/">
|
|
65
|
-
<img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
|
|
66
|
-
</a>
|
|
67
|
-
<a href="https://pepy.tech/projects/instapaper-scraper">
|
|
68
|
-
<img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
|
|
69
|
-
</a>
|
|
70
72
|
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html">
|
|
71
73
|
<img src="https://img.shields.io/github/license/chriskyfung/InstapaperScraper" alt="GitHub License">
|
|
72
74
|
</a>
|
|
73
75
|
<a href="https://github.com/sponsors/chriskyfung" title="Sponsor on GitHub">
|
|
74
|
-
<img src="https://img.shields.io/badge/Sponsor-GitHub-
|
|
76
|
+
<img src="https://img.shields.io/badge/Sponsor-GitHub-blue?logo=github-sponsors&colorA=263238&colorB=EC407A" alt="GitHub Sponsors Default">
|
|
75
77
|
</a>
|
|
76
|
-
<a href="https://www.buymeacoffee.com/chriskyfung" title="
|
|
77
|
-
<img src="https://img.shields.io/badge/Support
|
|
78
|
+
<a href="https://www.buymeacoffee.com/chriskyfung" title="Support Coffee">
|
|
79
|
+
<img src="https://img.shields.io/badge/Support-Coffee-ffdd00?logo=buy-me-a-coffee&logoColor=ffdd00&colorA=263238" alt="Buy Me A Coffee">
|
|
78
80
|
</a>
|
|
79
81
|
</p>
|
|
80
82
|
|
|
@@ -336,6 +338,13 @@ To run static type checking with `mypy`:
|
|
|
336
338
|
mypy src
|
|
337
339
|
```
|
|
338
340
|
|
|
341
|
+
To run license checks:
|
|
342
|
+
|
|
343
|
+
```sh
|
|
344
|
+
licensecheck --show-only-failing
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
|
|
339
348
|
## 📜 Disclaimer
|
|
340
349
|
|
|
341
350
|
This script requires valid Instapaper credentials. Use it responsibly and in accordance with Instapaper’s Terms of Service.
|
|
@@ -344,9 +353,8 @@ This script requires valid Instapaper credentials. Use it responsibly and in acc
|
|
|
344
353
|
|
|
345
354
|
This project is licensed under the terms of the **GNU General Public License v3.0**. See the [LICENSE](LICENSE) file for the full license text.
|
|
346
355
|
|
|
347
|
-
##
|
|
356
|
+
## Contributors
|
|
348
357
|
|
|
349
|
-
|
|
358
|
+
[](https://github.com/chriskyfung/InstapaperScraper/graphs/contributors)
|
|
350
359
|
|
|
351
|
-
|
|
352
|
-
- **[Buy Me a Coffee](https://www.buymeacoffee.com/chriskyfung):** Perfect for a one-time thank you.
|
|
360
|
+
Made with [contrib.rocks](https://contrib.rocks).
|
|
@@ -4,7 +4,7 @@ import sqlite3
|
|
|
4
4
|
import logging
|
|
5
5
|
import io
|
|
6
6
|
import csv
|
|
7
|
-
from unittest.mock import patch, MagicMock
|
|
7
|
+
from unittest.mock import patch, MagicMock, PropertyMock
|
|
8
8
|
|
|
9
9
|
from instapaper_scraper.output import (
|
|
10
10
|
_correct_ext,
|
|
@@ -47,6 +47,25 @@ def output_dir(tmp_path):
|
|
|
47
47
|
return tmp_path / "output"
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
@pytest.fixture
|
|
51
|
+
def mock_sqlite3():
|
|
52
|
+
"""
|
|
53
|
+
Fixture to mock the sqlite3 module for dynamic imports.
|
|
54
|
+
This fixture patches sys.modules to replace the sqlite3 module with a mock.
|
|
55
|
+
It yields a function that allows tests to configure the mock's version info.
|
|
56
|
+
"""
|
|
57
|
+
with patch.dict("sys.modules", {"sqlite3": MagicMock()}) as mock_modules:
|
|
58
|
+
mock_sqlite = mock_modules["sqlite3"]
|
|
59
|
+
|
|
60
|
+
def _configure_mock(version_info):
|
|
61
|
+
# Use PropertyMock to ensure the version comparison works correctly
|
|
62
|
+
type(mock_sqlite).sqlite_version_info = PropertyMock(
|
|
63
|
+
return_value=version_info
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
yield _configure_mock, mock_sqlite
|
|
67
|
+
|
|
68
|
+
|
|
50
69
|
class TestCorrectExt:
|
|
51
70
|
@pytest.mark.parametrize(
|
|
52
71
|
"filename, format, expected",
|
|
@@ -73,16 +92,18 @@ def test_get_sqlite_create_table_sql_without_url():
|
|
|
73
92
|
assert "instapaper_url" not in sql
|
|
74
93
|
|
|
75
94
|
|
|
76
|
-
|
|
77
|
-
def test_get_sqlite_create_table_sql_with_url_modern_sqlite():
|
|
95
|
+
def test_get_sqlite_create_table_sql_with_url_modern_sqlite(mock_sqlite3):
|
|
78
96
|
"""Test CREATE TABLE SQL with instapaper_url on modern SQLite."""
|
|
97
|
+
configure_mock, _ = mock_sqlite3
|
|
98
|
+
configure_mock((3, 31, 0))
|
|
79
99
|
sql = get_sqlite_create_table_sql(add_instapaper_url=True)
|
|
80
100
|
assert "instapaper_url TEXT GENERATED ALWAYS AS" in sql
|
|
81
101
|
|
|
82
102
|
|
|
83
|
-
|
|
84
|
-
def test_get_sqlite_create_table_sql_with_url_old_sqlite():
|
|
103
|
+
def test_get_sqlite_create_table_sql_with_url_old_sqlite(mock_sqlite3):
|
|
85
104
|
"""Test CREATE TABLE SQL with instapaper_url on old SQLite."""
|
|
105
|
+
configure_mock, _ = mock_sqlite3
|
|
106
|
+
configure_mock((3, 30, 0))
|
|
86
107
|
sql = get_sqlite_create_table_sql(add_instapaper_url=True)
|
|
87
108
|
assert "instapaper_url TEXT" in sql
|
|
88
109
|
assert "GENERATED" not in sql
|
|
@@ -188,15 +209,15 @@ def test_save_to_sqlite(sample_articles, output_dir):
|
|
|
188
209
|
conn.close()
|
|
189
210
|
|
|
190
211
|
|
|
191
|
-
@patch("sqlite3.connect")
|
|
192
|
-
@patch("sqlite3.sqlite_version_info", (3, 31, 0))
|
|
193
212
|
def test_save_to_sqlite_with_instapaper_url_modern_sqlite(
|
|
194
|
-
|
|
213
|
+
mock_sqlite3, sample_articles, output_dir
|
|
195
214
|
):
|
|
196
215
|
"""Test saving with instapaper_url on modern SQLite."""
|
|
216
|
+
configure_mock, mock_sqlite = mock_sqlite3
|
|
217
|
+
configure_mock((3, 31, 0))
|
|
197
218
|
mock_conn = MagicMock()
|
|
198
219
|
mock_cursor = MagicMock()
|
|
199
|
-
|
|
220
|
+
mock_sqlite.connect.return_value = mock_conn
|
|
200
221
|
mock_conn.cursor.return_value = mock_cursor
|
|
201
222
|
|
|
202
223
|
articles = sample_articles()
|
|
@@ -217,15 +238,15 @@ def test_save_to_sqlite_with_instapaper_url_modern_sqlite(
|
|
|
217
238
|
assert "instapaper_url" not in executed_data[0]
|
|
218
239
|
|
|
219
240
|
|
|
220
|
-
@patch("sqlite3.connect")
|
|
221
|
-
@patch("sqlite3.sqlite_version_info", (3, 30, 0))
|
|
222
241
|
def test_save_to_sqlite_with_instapaper_url_old_sqlite(
|
|
223
|
-
|
|
242
|
+
mock_sqlite3, sample_articles, output_dir
|
|
224
243
|
):
|
|
225
244
|
"""Test saving with instapaper_url on old SQLite."""
|
|
245
|
+
configure_mock, mock_sqlite = mock_sqlite3
|
|
246
|
+
configure_mock((3, 30, 0))
|
|
226
247
|
mock_conn = MagicMock()
|
|
227
248
|
mock_cursor = MagicMock()
|
|
228
|
-
|
|
249
|
+
mock_sqlite.connect.return_value = mock_conn
|
|
229
250
|
mock_conn.cursor.return_value = mock_cursor
|
|
230
251
|
|
|
231
252
|
articles = sample_articles()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{instapaper_scraper-1.1.0 → instapaper_scraper-1.1.1}/src/instapaper_scraper.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|