Prepare wikiq for release: fixes, dependency cleanup, and packaging #2

Open
mako wants to merge 33 commits from release_review into jsonl-output
3 changed files with 42 additions and 5 deletions
Showing only changes of commit 5725c66040 - Show all commits

View File

@@ -14,7 +14,6 @@ dependencies = [
"mwtypes>=0.4.0",
"mwxml>=0.3.6",
"pyarrow>=20.0.0",
"pywikidiff2",
"sortedcontainers>=2.4.0",
"yamlconf>=0.2.6",
]
@@ -34,7 +33,6 @@ packages = ["src/wikiq"]
yamlconf = { git = "https://github.com/groceryheist/yamlconf" }
mwxml = { git = "https://github.com/groceryheist/python-mwxml" }
deltas = { git = "https://github.com/groceryheist/deltas" }
pywikidiff2 = { git = "ssh://gitea@gitea.communitydata.science:2200/groceryheist/pywikidiff2.git"}
[dependency-groups]
dev = [

View File

@@ -22,13 +22,11 @@ from typing import IO, Any, Generator, TextIO, Union
import mwpersistence
import mwreverts
import mwxml
import pywikidiff2
from deltas.tokenizers import wikitext_split
from more_itertools import peekable
from mwxml import Dump
import wikiq.tables as tables
from wikiq.tables import RevisionTable
from wikiq.wiki_diff_matcher import WikiDiffMatcher
from wikiq.wikitext_parser import WikitextParser
from wikiq.resume import get_resume_point
@@ -42,6 +40,33 @@ import pyarrow.csv as pacsv
from deltas import SegmentMatcher, SequenceMatcher
# Some dependencies serve a single feature and are awkward enough to install
# that wikiq leaves them out of the base install. Each is imported inside the
# code path that needs it, so importing wikiq works without them and a plain
# `pip install` needs no C++ compiler. These helpers do that import and, when
# it fails, explain what to install rather than raising an ImportError.
def require_pywikidiff2(feature: str):
"""Import and return pywikidiff2, or exit explaining how to install it.
feature names the wikiq option that needs it, so the message points at
whatever the user actually asked for.
"""
try:
import pywikidiff2
except ImportError:
raise SystemExit(
f"{feature} requires pywikidiff2, which wikiq does not install by "
"default because it compiles a C++ extension.\n"
"Install it with:\n"
" pip install 'pywikidiff2 @ git+"
"https://gitea.communitydata.science/groceryheist/pywikidiff2.git'\n"
"A C++ compiler and libthai must be available. Other persistence "
"methods (-p sequence, -p segment, -p legacy) do not need it."
)
return pywikidiff2
def pyarrow_type_to_spark(pa_type):
"""Convert a PyArrow type to Spark JSON schema format."""
if pa.types.is_int64(pa_type):
@@ -725,6 +750,7 @@ class WikiqParser:
differ = None
fast_differ = None
if self.diff:
pywikidiff2 = require_pywikidiff2("--diff")
differ = pywikidiff2.pywikidiff2(
num_context_lines=1000000,
max_word_level_diff_complexity=-1,
@@ -812,6 +838,8 @@ class WikiqParser:
revert_radius=PERSISTENCE_RADIUS,
)
elif self.persist == PersistMethod.wikidiff2:
require_pywikidiff2("-p wikidiff2")
from wikiq.wiki_diff_matcher import WikiDiffMatcher
wikidiff_matcher = WikiDiffMatcher(tokenizer=wikitext_split)
persist_state = mwpersistence.DiffState(
wikidiff_matcher, revert_radius=PERSISTENCE_RADIUS
@@ -1264,6 +1292,13 @@ def main():
else:
persist = PersistMethod.sequence
# Check for the optional dependencies up front. Both are used deep in the
# per-revision loop, and a run can stream for hours before reaching them.
if args.diff:
require_pywikidiff2("--diff")
if persist == PersistMethod.wikidiff2:
require_pywikidiff2("-p wikidiff2")
if args.namespace_filter is not None:
namespaces = args.namespace_filter
else:

View File

@@ -10,7 +10,6 @@ from mwpersistence import Token
from sortedcontainers import SortedDict
TOKENIZER = tokenizers.wikitext_split
import pywikidiff2
class DiffToOperationMap:
@@ -332,6 +331,11 @@ class WikiDiffMatcher:
class Processor(DiffEngine.Processor):
def __init__(self, tokenizer=None):
# imported here rather than at module scope so that importing
# wikiq does not require the pywikidiff2 C++ extension
from wikiq import require_pywikidiff2
pywikidiff2 = require_pywikidiff2("-p wikidiff2")
self.tokenizer = tokenizer or TOKENIZER
self.last_tokens = []
self.previous_text = ""