tibiawikisql 8.1.0__tar.gz → 8.2.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.
- {tibiawikisql-8.1.0/tibiawikisql.egg-info → tibiawikisql-8.2.0}/PKG-INFO +6 -7
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/pyproject.toml +3 -3
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/requirements-docs.txt +2 -3
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/test_generation.py +97 -1
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/__init__.py +1 -1
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/__main__.py +8 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/generation.py +16 -2
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/tasks/images.py +35 -5
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0/tibiawikisql.egg-info}/PKG-INFO +6 -7
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql.egg-info/requires.txt +2 -3
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/LICENSE +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/MANIFEST.in +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/README.md +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/requirements-server.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/requirements-testing.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/requirements.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/setup.cfg +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/tests_models.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/tests_parsers.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/tests_schema.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/tests_utils.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tests/tests_wikiapi.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/api.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/database.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/errors.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/__init__.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/achievement.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/base.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/charm.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/creature.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/house.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/imbuement.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/item.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/mount.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/npc.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/outfit.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/quest.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/spell.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/update.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/models/world.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/__init__.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/achievement.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/base.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/book.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/charm.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/creature.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/house.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/imbuement.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/item.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/key.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/mount.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/npc.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/outfit.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/quest.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/spell.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/update.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/parsers/world.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/schema.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/server.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/tasks/__init__.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/tasks/item_offers.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/tasks/item_proficiency_perks.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/tasks/loot_statistics.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql/utils.py +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql.egg-info/SOURCES.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql.egg-info/dependency_links.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql.egg-info/entry_points.txt +0 -0
- {tibiawikisql-8.1.0 → tibiawikisql-8.2.0}/tibiawikisql.egg-info/top_level.txt +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tibiawikisql
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0
|
|
4
4
|
Summary: Python script that generates a SQLite database from TibiaWiki articles
|
|
5
5
|
Author-email: Allan Galarza <contact@galarzaa.com>
|
|
6
6
|
Maintainer-email: Allan Galarza <contact@galarzaa.com>
|
|
7
7
|
License: Apache 2.0
|
|
8
|
-
Project-URL: Homepage, https://
|
|
9
|
-
Project-URL: Documentation, https://
|
|
8
|
+
Project-URL: Homepage, https://galarzaa90.github.io/tibiawiki-sql/
|
|
9
|
+
Project-URL: Documentation, https://galarzaa90.github.io/tibiawiki-sql/
|
|
10
10
|
Project-URL: Repository, https://github.com/Galarzaa90/tibiawiki-sql
|
|
11
|
-
Project-URL: Changelog, https://
|
|
11
|
+
Project-URL: Changelog, https://galarzaa90.github.io/tibiawiki-sql/changelog/
|
|
12
12
|
Project-URL: Docker Hub: Repo, https://hub.docker.com/repository/docker/galarzaa90/tibiawiki-sql
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Environment :: Console
|
|
@@ -42,9 +42,8 @@ Requires-Dist: griffe-inherited-docstrings; extra == "docs"
|
|
|
42
42
|
Requires-Dist: docstring-inheritance; extra == "docs"
|
|
43
43
|
Requires-Dist: griffe-pydantic; extra == "docs"
|
|
44
44
|
Requires-Dist: griffe-generics; extra == "docs"
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
Requires-Dist: ruff; extra == "docs"
|
|
45
|
+
Requires-Dist: mkdocstrings-python; extra == "docs"
|
|
46
|
+
Requires-Dist: zensical; extra == "docs"
|
|
48
47
|
Provides-Extra: testing
|
|
49
48
|
Requires-Dist: coverage; extra == "testing"
|
|
50
49
|
Requires-Dist: ruff; extra == "testing"
|
|
@@ -42,10 +42,10 @@ classifiers = [
|
|
|
42
42
|
]
|
|
43
43
|
|
|
44
44
|
[project.urls]
|
|
45
|
-
"Homepage" = "https://
|
|
46
|
-
"Documentation" = "https://
|
|
45
|
+
"Homepage" = "https://galarzaa90.github.io/tibiawiki-sql/"
|
|
46
|
+
"Documentation" = "https://galarzaa90.github.io/tibiawiki-sql/"
|
|
47
47
|
"Repository" = "https://github.com/Galarzaa90/tibiawiki-sql"
|
|
48
|
-
"Changelog" = "https://
|
|
48
|
+
"Changelog" = "https://galarzaa90.github.io/tibiawiki-sql/changelog/"
|
|
49
49
|
"Docker Hub: Repo" = "https://hub.docker.com/repository/docker/galarzaa90/tibiawiki-sql"
|
|
50
50
|
|
|
51
51
|
[project.scripts]
|
|
@@ -8,9 +8,10 @@ from click.testing import CliRunner
|
|
|
8
8
|
from tests import load_resource
|
|
9
9
|
from tibiawikisql import __main__ as cli_module
|
|
10
10
|
from tibiawikisql import generation as generation_module
|
|
11
|
-
from tibiawikisql.api import Article
|
|
11
|
+
from tibiawikisql.api import Article, WikiEntry
|
|
12
12
|
from tibiawikisql.generation import WEAPON_PROFICIENCY_NAME_ARTICLE, WEAPON_PROFICIENCY_TABLES_ARTICLE
|
|
13
13
|
from tibiawikisql.schema import ItemProficiencyPerkTable, ItemTable
|
|
14
|
+
from tibiawikisql.tasks import images as image_tasks
|
|
14
15
|
from tibiawikisql.tasks.item_proficiency_perks import generate_item_proficiency_perks
|
|
15
16
|
from tibiawikisql.tasks.loot_statistics import generate_loot_statistics
|
|
16
17
|
|
|
@@ -197,6 +198,35 @@ class TestGeneration(unittest.TestCase):
|
|
|
197
198
|
).fetchall()
|
|
198
199
|
self.assertEqual([(3, 1, "Club Skill Bonus", None, "+1 Club Fighting")], [tuple(row) for row in rows])
|
|
199
200
|
|
|
201
|
+
def test_save_images_includes_additional_titles(self):
|
|
202
|
+
wiki_client = Mock()
|
|
203
|
+
wiki_client.get_images_info.return_value = []
|
|
204
|
+
with (
|
|
205
|
+
patch("tibiawikisql.tasks.images.os.makedirs"),
|
|
206
|
+
patch("tibiawikisql.tasks.images.get_cache_info", return_value={}),
|
|
207
|
+
patch("tibiawikisql.tasks.images.save_cache_info"),
|
|
208
|
+
):
|
|
209
|
+
image_tasks.save_images(
|
|
210
|
+
self.conn,
|
|
211
|
+
"items",
|
|
212
|
+
generation_module.CATEGORIES["items"],
|
|
213
|
+
additional_titles=["Old Axe"],
|
|
214
|
+
wiki_client=wiki_client,
|
|
215
|
+
progress_bar=generation_module.progress_bar,
|
|
216
|
+
img_label=generation_module.img_label,
|
|
217
|
+
timed=generation_module.timed,
|
|
218
|
+
echo=Mock(),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
wiki_client.get_images_info.assert_called_once_with(["Amber Axe.gif", "Amber Cudgel.gif", "Old Axe.gif"])
|
|
222
|
+
|
|
223
|
+
def test_additional_outfit_titles_have_no_database_id(self):
|
|
224
|
+
rows = image_tasks.add_additional_outfit_names([(1, "Barbarian")], ["Demon Outfits"])
|
|
225
|
+
titles, image_info = image_tasks.generate_outfit_image_names(rows)
|
|
226
|
+
|
|
227
|
+
self.assertIn("Outfit Demon Male.gif", titles)
|
|
228
|
+
self.assertIsNone(image_info["Outfit Demon Male.gif"][0])
|
|
229
|
+
|
|
200
230
|
|
|
201
231
|
class TestGenerationOrchestration(unittest.TestCase):
|
|
202
232
|
def setUp(self):
|
|
@@ -252,6 +282,45 @@ class TestGenerationOrchestration(unittest.TestCase):
|
|
|
252
282
|
messages = " ".join(call.args[0] for call in mock_echo.call_args_list if call.args)
|
|
253
283
|
self.assertIn("Skipping task 'needs_items'", messages)
|
|
254
284
|
|
|
285
|
+
def test_deprecated_titles_are_retained_for_images_only(self):
|
|
286
|
+
timestamp = datetime.datetime.fromisoformat("2024-01-01T00:00:00+00:00")
|
|
287
|
+
active = WikiEntry(article_id=1, title="Amber Axe", timestamp=timestamp)
|
|
288
|
+
deprecated = WikiEntry(article_id=2, title="Old Axe", timestamp=timestamp)
|
|
289
|
+
captured_data_store = {}
|
|
290
|
+
|
|
291
|
+
def fetch_entries(category: str, _exclude_titles: set[str] | None = None) -> list[WikiEntry]:
|
|
292
|
+
if category == "Deprecated":
|
|
293
|
+
return [deprecated]
|
|
294
|
+
return [active, deprecated]
|
|
295
|
+
|
|
296
|
+
post_tasks = (
|
|
297
|
+
generation_module.PostTask(
|
|
298
|
+
"capture",
|
|
299
|
+
lambda _conn, data_store, _enabled: captured_data_store.update(data_store),
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
with (
|
|
303
|
+
patch.dict(
|
|
304
|
+
generation_module.CATEGORIES,
|
|
305
|
+
{"items": generation_module.CATEGORIES["items"]},
|
|
306
|
+
clear=True,
|
|
307
|
+
),
|
|
308
|
+
patch(
|
|
309
|
+
"tibiawikisql.generation.fetch_category_entries",
|
|
310
|
+
side_effect=fetch_entries,
|
|
311
|
+
),
|
|
312
|
+
patch.object(generation_module.wiki_client, "get_articles", return_value=[]),
|
|
313
|
+
patch("tibiawikisql.generation.POST_TASKS", post_tasks),
|
|
314
|
+
):
|
|
315
|
+
generation_module.generate(
|
|
316
|
+
self.conn,
|
|
317
|
+
skip_deprecated=True,
|
|
318
|
+
include_deprecated_images=True,
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
self.assertEqual([active], captured_data_store["items"])
|
|
322
|
+
self.assertEqual({"items": ["Old Axe"]}, captured_data_store["deprecated_image_titles"])
|
|
323
|
+
|
|
255
324
|
def test_generate_loot_statistics_early_return_without_maps(self):
|
|
256
325
|
wiki_client = Mock()
|
|
257
326
|
generate_loot_statistics(
|
|
@@ -299,3 +368,30 @@ class TestGenerateCommand(unittest.TestCase):
|
|
|
299
368
|
self.assertNotEqual(0, result.exit_code)
|
|
300
369
|
self.assertIn("Invalid value", result.output)
|
|
301
370
|
self.assertIn("--skip-category", result.output)
|
|
371
|
+
|
|
372
|
+
def test_include_deprecated_images_option_is_passed_to_generate(self):
|
|
373
|
+
with patch("tibiawikisql.__main__.generation.generate") as mock_generate:
|
|
374
|
+
result = self.runner.invoke(
|
|
375
|
+
cli_module.cli,
|
|
376
|
+
[
|
|
377
|
+
"generate",
|
|
378
|
+
"--db-name",
|
|
379
|
+
":memory:",
|
|
380
|
+
"--skip-deprecated",
|
|
381
|
+
"--include-deprecated-images",
|
|
382
|
+
],
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
self.assertEqual(0, result.exit_code, result.output)
|
|
386
|
+
self.assertTrue(mock_generate.call_args.kwargs["skip_deprecated"])
|
|
387
|
+
self.assertTrue(mock_generate.call_args.kwargs["include_deprecated_images"])
|
|
388
|
+
|
|
389
|
+
def test_include_deprecated_images_short_option_is_passed_to_generate(self):
|
|
390
|
+
with patch("tibiawikisql.__main__.generation.generate") as mock_generate:
|
|
391
|
+
result = self.runner.invoke(
|
|
392
|
+
cli_module.cli,
|
|
393
|
+
["generate", "--db-name", ":memory:", "-d", "-I"],
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
self.assertEqual(0, result.exit_code, result.output)
|
|
397
|
+
self.assertTrue(mock_generate.call_args.kwargs["include_deprecated_images"])
|
|
@@ -24,6 +24,12 @@ def cli() -> None:
|
|
|
24
24
|
@click.option("-i", "--skip-images", help="Skip fetching and loading images to the database.", is_flag=True)
|
|
25
25
|
@click.option("-o", "--db-name", help="Name for the database file.", default=DATABASE_FILE)
|
|
26
26
|
@click.option("-d", "--skip-deprecated", help="Skips fetching deprecated articles and their images.", is_flag=True)
|
|
27
|
+
@click.option(
|
|
28
|
+
"-I",
|
|
29
|
+
"--include-deprecated-images",
|
|
30
|
+
help="Fetch and save images for articles skipped by --skip-deprecated.",
|
|
31
|
+
is_flag=True,
|
|
32
|
+
)
|
|
27
33
|
@click.option(
|
|
28
34
|
"--log-parsing-errors",
|
|
29
35
|
help=f"Write every parsing error to {PARSING_ERRORS_FILE}.",
|
|
@@ -43,6 +49,7 @@ def generate(
|
|
|
43
49
|
skip_images: bool,
|
|
44
50
|
db_name: str,
|
|
45
51
|
skip_deprecated: bool,
|
|
52
|
+
include_deprecated_images: bool,
|
|
46
53
|
log_parsing_errors: bool,
|
|
47
54
|
skip_categories: tuple[str, ...],
|
|
48
55
|
) -> None:
|
|
@@ -52,6 +59,7 @@ def generate(
|
|
|
52
59
|
conn,
|
|
53
60
|
skip_images=skip_images,
|
|
54
61
|
skip_deprecated=skip_deprecated,
|
|
62
|
+
include_deprecated_images=include_deprecated_images,
|
|
55
63
|
skip_categories=skip_categories,
|
|
56
64
|
parsing_errors_file=PARSING_ERRORS_FILE if log_parsing_errors else None,
|
|
57
65
|
)
|
|
@@ -208,6 +208,7 @@ def _run_images(conn: sqlite3.Connection, _data_store: dict[str, Any], enabled_c
|
|
|
208
208
|
conn,
|
|
209
209
|
categories=CATEGORIES,
|
|
210
210
|
enabled_categories=enabled_categories,
|
|
211
|
+
additional_titles=_data_store.get("deprecated_image_titles", {}),
|
|
211
212
|
wiki_client=wiki_client,
|
|
212
213
|
progress_bar=progress_bar,
|
|
213
214
|
img_label=img_label,
|
|
@@ -341,6 +342,7 @@ def generate(
|
|
|
341
342
|
conn: sqlite3.Connection,
|
|
342
343
|
skip_images: bool = False,
|
|
343
344
|
skip_deprecated: bool = False,
|
|
345
|
+
include_deprecated_images: bool = False,
|
|
344
346
|
skip_categories: tuple[str, ...] = (),
|
|
345
347
|
parsing_errors_file: str | None = None,
|
|
346
348
|
) -> None:
|
|
@@ -365,11 +367,23 @@ def generate(
|
|
|
365
367
|
else:
|
|
366
368
|
deprecated = set()
|
|
367
369
|
|
|
370
|
+
deprecated_image_titles: dict[str, list[str]] = {}
|
|
371
|
+
|
|
368
372
|
for key, category in CATEGORIES.items():
|
|
369
373
|
if key not in enabled_categories:
|
|
370
374
|
continue
|
|
371
|
-
|
|
372
|
-
|
|
375
|
+
excludes_deprecated = skip_deprecated and not category.include_deprecated
|
|
376
|
+
category_has_images = not category.no_images or key == "outfits"
|
|
377
|
+
if include_deprecated_images and not skip_images and excludes_deprecated and category_has_images:
|
|
378
|
+
entries = fetch_category_entries(category.name)
|
|
379
|
+
data_store[key] = [entry for entry in entries if entry.title not in deprecated]
|
|
380
|
+
deprecated_image_titles[key] = [entry.title for entry in entries if entry.title in deprecated]
|
|
381
|
+
else:
|
|
382
|
+
excluded_titles = deprecated if excludes_deprecated else None
|
|
383
|
+
data_store[key] = fetch_category_entries(category.name, excluded_titles)
|
|
384
|
+
|
|
385
|
+
if deprecated_image_titles:
|
|
386
|
+
data_store["deprecated_image_titles"] = deprecated_image_titles
|
|
373
387
|
|
|
374
388
|
parsing_errors_path = Path(parsing_errors_file) if parsing_errors_file else None
|
|
375
389
|
if parsing_errors_path:
|
|
@@ -57,6 +57,7 @@ def save_images(
|
|
|
57
57
|
key: str,
|
|
58
58
|
category: Any,
|
|
59
59
|
*,
|
|
60
|
+
additional_titles: list[str] | None = None,
|
|
60
61
|
wiki_client: Any,
|
|
61
62
|
progress_bar: Any,
|
|
62
63
|
img_label: Any,
|
|
@@ -69,7 +70,9 @@ def save_images(
|
|
|
69
70
|
category_table = Table(table)
|
|
70
71
|
select_query = Query.from_(category_table).select(category_table.title)
|
|
71
72
|
results = conn.execute(select_query.get_sql())
|
|
72
|
-
|
|
73
|
+
article_titles = [row[0] for row in results]
|
|
74
|
+
article_titles.extend(additional_titles or ())
|
|
75
|
+
titles = [f"{title}{extension}" for title in dict.fromkeys(article_titles)]
|
|
73
76
|
os.makedirs(f"images/{table}", exist_ok=True)
|
|
74
77
|
cache_info = get_cache_info(table)
|
|
75
78
|
cache_count = 0
|
|
@@ -143,21 +146,42 @@ def save_maps(conn: sqlite3.Connection | sqlite3.Cursor) -> None:
|
|
|
143
146
|
conn.execute(insert_query.get_sql(), (z, image))
|
|
144
147
|
|
|
145
148
|
|
|
146
|
-
def generate_outfit_image_names(
|
|
149
|
+
def generate_outfit_image_names(
|
|
150
|
+
rows: list[tuple[int | None, str]],
|
|
151
|
+
) -> tuple[list[str], dict[str, tuple[int | None, int, str]]]:
|
|
147
152
|
"""Generate outfit image file names and tuple metadata."""
|
|
148
153
|
titles = []
|
|
149
|
-
image_info: dict[str, tuple[int, int, str]] = {}
|
|
154
|
+
image_info: dict[str, tuple[int | None, int, str]] = {}
|
|
150
155
|
for article_id, name in rows:
|
|
151
156
|
for i, template in enumerate(OUTFIT_NAME_TEMPLATES):
|
|
152
157
|
file_name = template % name
|
|
153
|
-
image_info[file_name] = (
|
|
158
|
+
image_info[file_name] = (
|
|
159
|
+
article_id,
|
|
160
|
+
OUTFIT_ADDON_SEQUENCE[i],
|
|
161
|
+
OUTFIT_SEX_SEQUENCE[i],
|
|
162
|
+
)
|
|
154
163
|
titles.append(file_name)
|
|
155
164
|
return titles, image_info
|
|
156
165
|
|
|
157
166
|
|
|
167
|
+
def add_additional_outfit_names(
|
|
168
|
+
rows: list[tuple[int, str]],
|
|
169
|
+
additional_titles: list[str] | None,
|
|
170
|
+
) -> list[tuple[int | None, str]]:
|
|
171
|
+
"""Add outfit names derived from article titles without database IDs."""
|
|
172
|
+
expanded_rows: list[tuple[int | None, str]] = list(rows)
|
|
173
|
+
existing_names = {row[1] for row in rows}
|
|
174
|
+
for title in additional_titles or ():
|
|
175
|
+
name = title.removesuffix(" Outfits")
|
|
176
|
+
if name not in existing_names:
|
|
177
|
+
expanded_rows.append((None, name))
|
|
178
|
+
return expanded_rows
|
|
179
|
+
|
|
180
|
+
|
|
158
181
|
def save_outfit_images(
|
|
159
182
|
conn: sqlite3.Connection | sqlite3.Cursor,
|
|
160
183
|
*,
|
|
184
|
+
additional_titles: list[str] | None = None,
|
|
161
185
|
wiki_client: Any,
|
|
162
186
|
progress_bar: Any,
|
|
163
187
|
img_label: Any,
|
|
@@ -184,6 +208,7 @@ def save_outfit_images(
|
|
|
184
208
|
results = conn.execute(query.get_sql())
|
|
185
209
|
except sqlite3.Error:
|
|
186
210
|
results = []
|
|
211
|
+
results = add_additional_outfit_names(list(results), additional_titles)
|
|
187
212
|
if not results:
|
|
188
213
|
return
|
|
189
214
|
|
|
@@ -219,7 +244,8 @@ def save_outfit_images(
|
|
|
219
244
|
failed.append(image.file_name)
|
|
220
245
|
continue
|
|
221
246
|
article_id, addons, sex = image_info[image.file_name]
|
|
222
|
-
|
|
247
|
+
if article_id is not None:
|
|
248
|
+
conn.execute(insert_query.get_sql(), (article_id, addons, sex, image_bytes))
|
|
223
249
|
save_cache_info(table, cache_info)
|
|
224
250
|
if failed:
|
|
225
251
|
echo(f"{Style.RESET_ALL}\tCould not fetch {len(failed):,} images.{Style.RESET_ALL}")
|
|
@@ -235,6 +261,7 @@ def fetch_images(
|
|
|
235
261
|
*,
|
|
236
262
|
categories: dict[str, Any],
|
|
237
263
|
enabled_categories: set[str],
|
|
264
|
+
additional_titles: dict[str, list[str]] | None = None,
|
|
238
265
|
wiki_client: Any,
|
|
239
266
|
progress_bar: Any,
|
|
240
267
|
img_label: Any,
|
|
@@ -242,6 +269,7 @@ def fetch_images(
|
|
|
242
269
|
echo: Any,
|
|
243
270
|
) -> None:
|
|
244
271
|
"""Fetch all images for enabled categories and always load map floors."""
|
|
272
|
+
additional_titles = additional_titles or {}
|
|
245
273
|
with conn:
|
|
246
274
|
for key, category in categories.items():
|
|
247
275
|
if key not in enabled_categories or category.no_images:
|
|
@@ -250,6 +278,7 @@ def fetch_images(
|
|
|
250
278
|
conn,
|
|
251
279
|
key,
|
|
252
280
|
category,
|
|
281
|
+
additional_titles=additional_titles.get(key),
|
|
253
282
|
wiki_client=wiki_client,
|
|
254
283
|
progress_bar=progress_bar,
|
|
255
284
|
img_label=img_label,
|
|
@@ -259,6 +288,7 @@ def fetch_images(
|
|
|
259
288
|
if "outfits" in enabled_categories:
|
|
260
289
|
save_outfit_images(
|
|
261
290
|
conn,
|
|
291
|
+
additional_titles=additional_titles.get("outfits"),
|
|
262
292
|
wiki_client=wiki_client,
|
|
263
293
|
progress_bar=progress_bar,
|
|
264
294
|
img_label=img_label,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tibiawikisql
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0
|
|
4
4
|
Summary: Python script that generates a SQLite database from TibiaWiki articles
|
|
5
5
|
Author-email: Allan Galarza <contact@galarzaa.com>
|
|
6
6
|
Maintainer-email: Allan Galarza <contact@galarzaa.com>
|
|
7
7
|
License: Apache 2.0
|
|
8
|
-
Project-URL: Homepage, https://
|
|
9
|
-
Project-URL: Documentation, https://
|
|
8
|
+
Project-URL: Homepage, https://galarzaa90.github.io/tibiawiki-sql/
|
|
9
|
+
Project-URL: Documentation, https://galarzaa90.github.io/tibiawiki-sql/
|
|
10
10
|
Project-URL: Repository, https://github.com/Galarzaa90/tibiawiki-sql
|
|
11
|
-
Project-URL: Changelog, https://
|
|
11
|
+
Project-URL: Changelog, https://galarzaa90.github.io/tibiawiki-sql/changelog/
|
|
12
12
|
Project-URL: Docker Hub: Repo, https://hub.docker.com/repository/docker/galarzaa90/tibiawiki-sql
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Environment :: Console
|
|
@@ -42,9 +42,8 @@ Requires-Dist: griffe-inherited-docstrings; extra == "docs"
|
|
|
42
42
|
Requires-Dist: docstring-inheritance; extra == "docs"
|
|
43
43
|
Requires-Dist: griffe-pydantic; extra == "docs"
|
|
44
44
|
Requires-Dist: griffe-generics; extra == "docs"
|
|
45
|
-
Requires-Dist:
|
|
46
|
-
Requires-Dist:
|
|
47
|
-
Requires-Dist: ruff; extra == "docs"
|
|
45
|
+
Requires-Dist: mkdocstrings-python; extra == "docs"
|
|
46
|
+
Requires-Dist: zensical; extra == "docs"
|
|
48
47
|
Provides-Extra: testing
|
|
49
48
|
Requires-Dist: coverage; extra == "testing"
|
|
50
49
|
Requires-Dist: ruff; extra == "testing"
|
|
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
|
|
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
|