Commit Graph

220 Commits

Author SHA1 Message Date
d4111dc4f3 update README for the current tool
Describe what wikiq is and rewrite the installation, usage, and test
instructions to match the current code: pip or uv installation from the
gitea repository, the Python 3.11 requirement, output format selection
by extension, and the current option set including persistence methods,
wikitext extraction, regex matching and counting, and JSONL resume. Add
an authors section crediting the Community Data Science Collective
contributors and the earlier Python and C++ versions of the tool.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit d6d0aab604)
2026-08-13 13:35:33 -07:00
ceb230904e license under the GNU GPL, version 3 or later
Add the full license text as COPYING (the same text Debian ships in
common-licenses), declare the license and license file in
pyproject.toml, add copyright and permission notices to the source
files, and describe the license in the README. Also replace the
placeholder package description in pyproject.toml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 90a14cf999)
2026-08-13 13:35:33 -07:00
c31833e064 convert README to markdown
Replace the auto-converted README.md (which carried pandoc title-ref
spans and a garbled Tests heading from a malformed rst underline) with
a clean conversion of README.rst, and remove the rst version.
pyproject.toml already declares README.md as the package readme.
Content is unchanged; bringing it up to date is left for a separate
change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit fa8adc30ca)
2026-08-13 13:35:33 -07:00
15379c1c1a require Python 3.11
Python 3.9 reached end of life in October 2025, and 3.11 is where the
current ecosystem sits: it unlocks pyarrow 25 (we were held at 21, the
last release supporting 3.9), more-itertools 11, and pandas 3 for the
test suite, along with the large CPython 3.11 interpreter speedups on
exactly the kind of CPU-bound work wikiq does. Nothing in the code
needed changes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:35:14 -07:00
ac8110894b resolve dependencies from PyPI instead of pinned git forks
Drop the [tool.uv.sources] pins of deltas, mwxml, and yamlconf to forks
under a personal github account:

- The deltas fork was byte-identical to upstream.
- The mwxml fork carried one patch to mwxml.map(), which wikiq does not
  call, and was missing eleven upstream commits of fixes. Require
  mwxml >= 0.3.8 for those fixes; note that 0.3.7 changed namespace
  handling to trust the dump's embedded <ns> tag rather than overriding
  it based on the title prefix.
- The yamlconf fork loosened an old pyyaml pin. yamlconf is not imported
  by wikiq and is only needed transitively via deltas, so drop the direct
  dependency. PyPI's 0.2.6 pinned pyyaml == 5.4.1, which has no wheels
  for 3.11+ and no longer builds from source; that was fixed upstream in
  0.2.7, and the project has since moved to the mediawiki-utilities
  organization.

With pywikidiff2 no longer a dependency at all, no uv-specific
configuration remains and the package installs with plain pip.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 13:35:14 -07:00
b10a7d0130 skip tests whose optional dependency is not installed
With pywikidiff2 and mediawiki-utilities no longer installed by default,
the tests covering --diff, -p wikidiff2, and -p legacy cannot run on a
base install. Mark them so a base install reports skips rather than
failures, and keep the markers in wikiq_test_utils.py so all three test
modules share one definition of what each feature needs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 59d5a9d46a04320bad5d81e0edf5ecd11f9c2a9b)
2026-08-13 13:32:08 -07:00
70b0ebcf0c make mediawiki-utilities an optional dependency
-p legacy is the only thing that uses mediawiki-utilities, and it exists
solely to reproduce numbers from research predating the mwxml and
mwtypes split. The package is a 2015 monolith that also contains
mw.database and mw.api, so it declares requests and pymysql
unconditionally: every wikiq install pulled a MySQL client and six other
packages to support one flag, building them from an sdist that has no
wheel.

Move it to a `legacy` extra. mw.lib.persistence imports nothing from
mw.database or mw.api, so nothing about -p legacy changes for people who
install the extra, and everyone else stops paying for it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 66dcc6d8cea620a619fc19121b5c27a085b11991)
2026-08-13 13:32:08 -07:00
5725c66040 make pywikidiff2 an optional dependency
pywikidiff2 was imported at module scope, so every invocation of wikiq
required it -- including `wikiq --help`. It is not on PyPI, compiles a
C++ extension, and needs libthai, which made a compiler a hard
requirement for installing a tool that mostly does not need one.

Only --diff and -p wikidiff2 actually use it. Import it inside those two
code paths instead, and report what to install when it is missing rather
than failing with an ImportError traceback. The check also runs once at
startup, since both use sites sit deep in the per-revision loop and a run
can stream for hours before reaching them.

Dropping the dependency also removes the PEP 508 direct reference from
the package metadata, and with it the need for hatchling's
allow-direct-references. PyPI rejects uploads whose metadata contains a
direct URL, so this is a prerequisite for publishing wikiq there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
(cherry picked from commit 12325afd46670e949abf1c0e14799e212d7ff6ce)
2026-08-13 13:31:53 -07:00
6013e8c4e9 remove pyspark dependency and wikiq_spark packaging references
The spark indexing pass is moving out of this repository, and
src/wikiq_spark was never committed here: pyproject.toml declared a
wikiq-spark console script and wheel package that do not exist in the
tree, and pulled in pyspark for every install of a tool that never
imports it. The --print-schema flag and its Spark-format schema
converters remain, since they are pure Python and produce the schema
the external indexing pass consumes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 392211af17)
2026-08-13 13:30:25 -07:00
015d4f9164 remove parquet output support
Nate has given up on getting wikiq to output parquet directly because it
makes too many unpredictable large memory allocations. The workflow now
outputs JSONL in a single pass and then uses spark (wikiq_spark) to index
it as parquet in a second pass.

Remove the parquet output path along with the machinery that existed only
to support it: checkpoint files, resume temp-file merging, namespace
partitioning, and file rotation (--partition-namespaces,
--max-revisions-per-file). Resume support remains for JSONL output, where
the resume point is derived from the last complete line of the output
file. Also remove the parquet tests and baseline files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 72a8851373)
2026-08-13 13:30:25 -07:00
caf604e43d document the requirements of the two skipped diff matcher tests
test_diff_consistency and test_benchmark_diff both read an uncompressed
test/dumps/ikwiki.xml that is not in the repository, so enabling them
requires decompressing the .bz2 first; test_diff_consistency also
writes debug files to the current directory. Say so where the skip
markers are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit fde1452666)
2026-08-13 13:30:25 -07:00
04ccea4848 remove orphaned regextest.tsv baseline
No test reads this file; the regex tests use the basic_regextest and
capturegroup_regextest baselines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 5fb7b5596c)
2026-08-13 13:30:25 -07:00
f4f0ed72a0 stop writing debug files from the diff matcher test helper
assert_equal_enough wrote its inputs to files named "token" and "rev"
in the current directory on every invocation, littering the repository
root whenever the test suite ran.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 45f0680200)
2026-08-13 13:30:25 -07:00
7fbf62e5e0 add test for --resume with --collapse-user
Resume with collapsed revision groups was untested: the resume point is
the (articleid, revid) of the last written row, which for collapsed
output is the last revision of a group, and nothing verified that the
replay reconstructs group boundaries and collapsed_revs counts
identically across the resume point. Run sailormoon with
--collapse-user, truncate the output at the midpoint, resume, and
assert the result is identical to an uninterrupted run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 6634de51e6)
2026-08-13 13:30:25 -07:00
1b3093dec0 regenerate test baselines for the redirect_target column
Commit 59fea19 added a redirect_target column to wikiq output but did
not regenerate the test baselines, leaving 14 baseline-comparison tests
failing. Regenerate the affected baselines from current output. Each
regenerated file was verified to differ from its old baseline only by
the addition of the new column: row counts and all values in shared
columns are identical.

Also add the noargs_sailormoon.jsonl baseline used by test_jsonl_noargs,
which was never committed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 791be0aa56)
2026-08-13 13:30:24 -07:00
a26abe0e68 fix test helper for build_table's three-value return
build_table returns (table, reverts_column, wikitext_parser) but the
jsonl test helper still unpacked two values, so test_jsonl_noargs and
test_jsonl_tsv_equivalence failed with a ValueError before reading any
output. Also update the docstring, which still described the two-value
return.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 7c27942cb0)
2026-08-13 13:30:24 -07:00
97e21e3634 only prefix namespace names onto titles that lack them
WikiqPage unconditionally prepended the namespace name to titles of
pages outside the main namespace. mwxml >= 0.3.7 keeps the namespace
prefix on the title when the dump carries <ns> tags (it previously
stripped it), which made wikiq emit double-prefixed titles like
"Category:Category:Alaska". Check for the prefix before adding it.
mwxml still strips the prefix on its fallback path for dumps without
<ns> tags, so those titles are still prefixed as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit ec09641545)
2026-08-13 13:28:48 -07:00
c61eb10e47 fix regex matching on revisions with deleted text or comments
RegexPair.matchmake crashed with a TypeError when a capture-group
pattern was applied to a revision whose text or comment was deleted or
suppressed (content is None). Guard both matching paths against None,
and make the no-capture-group path emit a None column for such
revisions instead of omitting the key entirely.

This carries forward the fix Kaylea Champion and Mako Hill made on the
mako_changes-20230429 branch (7e6cd5b), which predated the rewrite.

Adds a unit test for matchmake(None) and an end-to-end test against the
ikwiki dump, which contains revisions with deleted text and comments.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit dbcae5c64e)
2026-08-13 13:28:48 -07:00
Nathan TeBlunthuis
41fda639d8 add infobox test fixtures 2026-08-07 22:27:10 -05:00
Nathan TeBlunthuis
72410d090b wikiq: skip parse on subsequent same-size revs after timeout
Per-page adaptive parse skip: once mwparserfromhell times out on a
revision of size N bytes, force-timeout future revisions on the same
page whose text is >= N bytes instead of waiting another 60s on each
one. State resets per page, so well-behaved pages are unaffected.

Motivated by zhwiki bot-vandalism log pages (e.g. ns=4
'Wikipedia:当前的破坏/...' at 4.6GB across 6133 revisions) where every
revision triggers the 60s SIGALRM, blocking the worker for hours.
v0.1.1
2026-05-07 21:43:05 +00:00
Nathan TeBlunthuis
59fea1919e Add redirect_target column to wikiq output.
Exposes page.redirect as a nullable string column so downstream pipelines
can build redirect maps for link target resolution.
2026-03-01 20:05:12 -08:00
Nathan TeBlunthuis
c7eb374ceb use signalling to timeout mwparserfromhell instead of asyncio. 2026-01-07 12:42:37 -08:00
Nathan TeBlunthuis
4b8288c016 add some debug lines. 2026-01-06 19:58:18 -08:00
Nathan TeBlunthuis
8590e5f920 fix jsonl.d output. 2025-12-30 11:26:24 -08:00
Nathan TeBlunthuis
93f6ed0ff5 fix bug by truncating corrupted jsonl lines. 2025-12-23 19:52:37 -08:00
Nathan TeBlunthuis
5ebdb26d82 make resume with jsonl output fault tolerant. 2025-12-23 09:09:51 -08:00
Nathan TeBlunthuis
9e6b0fb64c make updating the checkpoint files atomic. 2025-12-23 08:41:38 -08:00
Nathan TeBlunthuis
d822085698 support .jsonl.d 2025-12-22 20:13:04 -08:00
Nathan TeBlunthuis
618c343898 allow output dir to be jsonl.d. 2025-12-21 23:50:00 -08:00
Nathan TeBlunthuis
3f1a9ba862 refactor and enable jsonl output. 2025-12-21 23:42:18 -08:00
Nathan TeBlunthuis
6988a281dc output parquet files in chunks to avoid memory issues with parquet. 2025-12-20 21:45:39 -08:00
Nathan TeBlunthuis
6a4bf81e1a add test for two wikiq jobs in the same directory. 2025-12-19 11:50:56 -08:00
Nathan TeBlunthuis
38dabd0547 only merge the correct partitioned files. 2025-12-19 11:47:18 -08:00
Nathan TeBlunthuis
006feb795c fix interruption handling by breaking the diff loop. 2025-12-18 18:00:30 -08:00
Nathan TeBlunthuis
d7f5abef2d resume starts fresh if the first run didn't happen 2025-12-13 15:41:44 -08:00
Nathan TeBlunthuis
2c54425726 use the wikidiff2 diff timeout instead of async. 2025-12-13 14:29:16 -08:00
Nathan TeBlunthuis
5d1a246898 don't try to remove files that don't exist. 2025-12-13 11:57:47 -08:00
Nathan TeBlunthuis
70a10db228 save work after a time limit. 2025-12-11 08:30:32 -08:00
Nathan TeBlunthuis
1001c780fa start fresh if output and resume are both broken. 2025-12-10 21:20:52 -08:00
Nathan TeBlunthuis
6b4f3939a5 more work on resuming. 2025-12-10 21:07:52 -08:00
Nathan TeBlunthuis
c3d31b4ab5 handle case when we have a valid resume file, but a corrupted original. 2025-12-10 20:33:04 -08:00
Nathan TeBlunthuis
f4a9491ff2 improve print debugging. 2025-12-10 19:50:47 -08:00
Nathan TeBlunthuis
c6e96c2f54 try/catch opening original file in resume. 2025-12-10 19:49:29 -08:00
Nathan TeBlunthuis
f427291fd8 add logic for resuming after a resume. 2025-12-10 19:26:54 -08:00
Nathan TeBlunthuis
d1fc094c96 don't put checkpoint files inside namespace directories. 2025-12-07 06:24:04 -08:00
Nathan TeBlunthuis
783f5fd8bc improve resume logic. 2025-12-07 06:06:26 -08:00
Nathan TeBlunthuis
577ddc87f5 Add per-namespace resume support for partitioned parquet output.
- Implement per-namespace resume points (dict mapping namespace -> (pageid, revid))
  to correctly handle interleaved dump ordering in partitioned output
- Extract resume functionality to dedicated resume.py module
- Add graceful shutdown handling via shutdown_requested flag (CLI-level only)
- Use lazy ParquetWriter creation to avoid empty files on early exit
- Refactor writing logic to _write_batch() helper method
- Simplify control flow by replacing continue statements with should_write flag
2025-12-06 06:56:19 -08:00
Nathan TeBlunthuis
d69d8b0df2 fix baseline output for new columns. 2025-12-02 19:22:08 -08:00
Nathan TeBlunthuis
5ce9808b50 add templates and headings to wikiq. 2025-12-02 17:51:08 -08:00
Nathan TeBlunthuis
d3517ed5ca extract wikilinks. 2025-12-02 14:09:29 -08:00