WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import base64
|
||||
import io
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import uuid
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from docreader.parser.concurrency import parser_worker_limit
|
||||
from docreader.parser.pdf_parser import PDFScannedParser, _normalize_image_quality
|
||||
|
||||
|
||||
class ParserConcurrencyTest(unittest.TestCase):
|
||||
def test_parser_worker_limit_serializes_work(self):
|
||||
limiter_name = f"test-{uuid.uuid4()}"
|
||||
active_workers = 0
|
||||
max_active_workers = 0
|
||||
state_lock = threading.Lock()
|
||||
start = threading.Barrier(3)
|
||||
|
||||
def worker():
|
||||
nonlocal active_workers, max_active_workers
|
||||
start.wait()
|
||||
with parser_worker_limit(limiter_name, 1):
|
||||
with state_lock:
|
||||
active_workers += 1
|
||||
max_active_workers = max(max_active_workers, active_workers)
|
||||
time.sleep(0.02)
|
||||
with state_lock:
|
||||
active_workers -= 1
|
||||
|
||||
threads = [threading.Thread(target=worker) for _ in range(2)]
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
start.wait()
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
self.assertEqual(max_active_workers, 1)
|
||||
|
||||
def test_scanned_pdf_parser_outputs_jpeg_images(self):
|
||||
pdf_bytes = io.BytesIO()
|
||||
pages = [
|
||||
Image.new("RGB", (64, 64), "white"),
|
||||
Image.new("RGB", (64, 64), "black"),
|
||||
]
|
||||
pages[0].save(
|
||||
pdf_bytes,
|
||||
format="PDF",
|
||||
save_all=True,
|
||||
append_images=pages[1:],
|
||||
)
|
||||
|
||||
document = PDFScannedParser(file_name="scan.pdf").parse_into_text(
|
||||
pdf_bytes.getvalue()
|
||||
)
|
||||
|
||||
image_ref = "images/scan_page_1.jpg"
|
||||
self.assertIn(f"", document.content)
|
||||
self.assertIn(image_ref, document.images)
|
||||
self.assertEqual(document.metadata["image_source_type"], "scanned_pdf")
|
||||
self.assertEqual(document.metadata["page_count"], 2)
|
||||
self.assertEqual(len(document.images), 2)
|
||||
self.assertIn("images/scan_page_2.jpg", document.images)
|
||||
image_bytes = base64.b64decode(document.images[image_ref])
|
||||
self.assertTrue(image_bytes.startswith(b"\xff\xd8"))
|
||||
|
||||
def test_scanned_pdf_parser_logs_malformed_pdf_without_format_error(self):
|
||||
parser = PDFScannedParser(file_name="broken.pdf")
|
||||
|
||||
with self.assertLogs("docreader.parser.pdf_parser", level="ERROR") as logs:
|
||||
with self.assertRaises(Exception):
|
||||
parser.parse_into_text(b"not a pdf")
|
||||
|
||||
self.assertTrue(
|
||||
any("PDFScannedParser failed to parse PDF:" in line for line in logs.output)
|
||||
)
|
||||
|
||||
def test_normalize_image_quality_bounds_jpeg_quality(self):
|
||||
self.assertEqual(_normalize_image_quality(-1), 1)
|
||||
self.assertEqual(_normalize_image_quality(90), 90)
|
||||
self.assertEqual(_normalize_image_quality(120), 95)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user