polars-corpus 0.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.
Files changed (61) hide show
  1. polars_corpus-0.2.0/.cargo/config.toml +7 -0
  2. polars_corpus-0.2.0/.gitignore +40 -0
  3. polars_corpus-0.2.0/AGENTS.md +96 -0
  4. polars_corpus-0.2.0/CLAUDE.md +1 -0
  5. polars_corpus-0.2.0/Cargo.lock +3678 -0
  6. polars_corpus-0.2.0/Cargo.toml +54 -0
  7. polars_corpus-0.2.0/DEVELOPMENT_STATUS.md +257 -0
  8. polars_corpus-0.2.0/LICENSE.txt +21 -0
  9. polars_corpus-0.2.0/Makefile +35 -0
  10. polars_corpus-0.2.0/PKG-INFO +107 -0
  11. polars_corpus-0.2.0/README.md +61 -0
  12. polars_corpus-0.2.0/pyproject.toml +110 -0
  13. polars_corpus-0.2.0/python/polars_corpus/__init__.py +29 -0
  14. polars_corpus-0.2.0/python/polars_corpus/_internal.pyi +100 -0
  15. polars_corpus-0.2.0/python/polars_corpus/_typing.py +26 -0
  16. polars_corpus-0.2.0/python/polars_corpus/assoc.py +1221 -0
  17. polars_corpus-0.2.0/python/polars_corpus/chunk.py +120 -0
  18. polars_corpus-0.2.0/python/polars_corpus/collocations.py +237 -0
  19. polars_corpus-0.2.0/python/polars_corpus/convert.py +587 -0
  20. polars_corpus-0.2.0/python/polars_corpus/corpus_io.py +378 -0
  21. polars_corpus-0.2.0/python/polars_corpus/cqp_parser.py +218 -0
  22. polars_corpus-0.2.0/python/polars_corpus/dispersion.py +281 -0
  23. polars_corpus-0.2.0/python/polars_corpus/embeddings.py +213 -0
  24. polars_corpus-0.2.0/python/polars_corpus/exprs.py +820 -0
  25. polars_corpus-0.2.0/python/polars_corpus/frequency.py +150 -0
  26. polars_corpus-0.2.0/python/polars_corpus/keywords.py +350 -0
  27. polars_corpus-0.2.0/python/polars_corpus/lexical.py +261 -0
  28. polars_corpus-0.2.0/python/polars_corpus/matcher.py +397 -0
  29. polars_corpus-0.2.0/python/polars_corpus/search.py +1524 -0
  30. polars_corpus-0.2.0/python/polars_corpus/simple_parser.py +349 -0
  31. polars_corpus-0.2.0/python/polars_corpus/utils.py +342 -0
  32. polars_corpus-0.2.0/python/polars_corpus/view.py +797 -0
  33. polars_corpus-0.2.0/python/polars_corpus/visualizations.py +441 -0
  34. polars_corpus-0.2.0/python/tests/__init__.py +0 -0
  35. polars_corpus-0.2.0/python/tests/helpers.py +46 -0
  36. polars_corpus-0.2.0/python/tests/test_assoc.py +557 -0
  37. polars_corpus-0.2.0/python/tests/test_collocations.py +342 -0
  38. polars_corpus-0.2.0/python/tests/test_concordance.py +775 -0
  39. polars_corpus-0.2.0/python/tests/test_convert.py +249 -0
  40. polars_corpus-0.2.0/python/tests/test_dispersion.py +370 -0
  41. polars_corpus-0.2.0/python/tests/test_embeddings.py +305 -0
  42. polars_corpus-0.2.0/python/tests/test_frequency.py +211 -0
  43. polars_corpus-0.2.0/python/tests/test_keywords.py +432 -0
  44. polars_corpus-0.2.0/python/tests/test_lazy_search.py +374 -0
  45. polars_corpus-0.2.0/python/tests/test_lexical.py +262 -0
  46. polars_corpus-0.2.0/python/tests/test_matcher.py +496 -0
  47. polars_corpus-0.2.0/python/tests/test_simple_query.py +485 -0
  48. polars_corpus-0.2.0/python/tests/test_spans.py +267 -0
  49. polars_corpus-0.2.0/python/tests/test_text_corpus_reader.py +96 -0
  50. polars_corpus-0.2.0/python/tests/test_utils.py +345 -0
  51. polars_corpus-0.2.0/python/tests/test_view.py +166 -0
  52. polars_corpus-0.2.0/python/tests/test_visualizations.py +222 -0
  53. polars_corpus-0.2.0/python/tests/test_wlp_corpus_reader.py +233 -0
  54. polars_corpus-0.2.0/rust-toolchain.toml +2 -0
  55. polars_corpus-0.2.0/rustfmt.toml +3 -0
  56. polars_corpus-0.2.0/src/assoc.rs +213 -0
  57. polars_corpus-0.2.0/src/io.rs +157 -0
  58. polars_corpus-0.2.0/src/lexical.rs +90 -0
  59. polars_corpus-0.2.0/src/lib.rs +34 -0
  60. polars_corpus-0.2.0/src/matcher.rs +262 -0
  61. polars_corpus-0.2.0/src/span.rs +409 -0
@@ -0,0 +1,7 @@
1
+ # Copied from polars/.github/workflows/release-python.yml
2
+
3
+ [target.'cfg(target_arch = "x86_64")']
4
+ rustflags = [
5
+ "-C",
6
+ "target-feature=+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt,+cmpxchg16b,+avx,+avx2,+fma,+bmi1,+bmi2,+lzcnt,+pclmulqdq,+movbe",
7
+ ]
@@ -0,0 +1,40 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+ *.so
9
+ *.dll
10
+ *.pyd
11
+ target/
12
+
13
+
14
+ # Virtual environments
15
+ .venv
16
+ .env
17
+
18
+ # IDEs
19
+ .idea/
20
+ .ipynb_checkpoints/
21
+
22
+ site/
23
+ .coverage
24
+ # Claude Code: shared project config is tracked, per-machine settings are not.
25
+ .claude/*
26
+ !.claude/skills/
27
+ !.claude/commands/
28
+ .pytest_cache/
29
+ stuff/
30
+ .DS_Store
31
+ *.parquet
32
+ /.quarto/
33
+ **/*.quarto_ipynb
34
+ /_site/
35
+ /objects.json
36
+ /site/
37
+ scratch.ipynb
38
+ /scratch.py
39
+ .cache/
40
+ data/
@@ -0,0 +1,96 @@
1
+ # AGENTS.md
2
+
3
+ ## Overview
4
+ `polars-corpus` is a hybrid Python/Rust extension for Polars providing corpus
5
+ search, concordancing, and statistical measures: high-level APIs in Python, the
6
+ matching engine in Rust, bridged zero-copy by pyo3-polars and hung off Polars
7
+ frames and exprs as a `.corpus` namespace. Designed to comfortably handle 100M+
8
+ word corpora on 16GB memory. Target audience: linguists and data scientists,
9
+ especially students.
10
+
11
+ ## Development Workflow
12
+ ```bash
13
+ ruff format && ruff check # Format and lint Python
14
+ cargo fmt && cargo clippy # Format and lint Rust
15
+ pyrefly check python/polars_corpus/
16
+ pytest # Python changes need no rebuild
17
+ make develop # Rebuild after Rust changes (required); ~1s
18
+ make develop-release # Same, release profile (benchmarking)
19
+ make grid # Test 3.11-3.14 x oldest/newest polars
20
+ make build # Distribution wheels (slow: full LTO)
21
+ make docs # Build the user guide
22
+ ```
23
+
24
+ ## Environment
25
+ The venv lives **outside** the source tree, at `~/.venvs/polars_corpus`, and is
26
+ activated automatically by a shell extension. Run `pytest`, `ruff`, etc.
27
+ directly -- do **not** prefix them with `uv run`, which would create a `./.venv`
28
+ here. That breaks two things: this directory is synced via Dropbox to machines
29
+ with different paths, and nltk's `inisec` import guard rejects any module
30
+ resolving under the cwd, so a venv in the project root makes `import nltk` fail
31
+ during test collection.
32
+
33
+ ## Dependencies
34
+ All declared in `pyproject.toml` and pinned by `uv.lock` (both tracked):
35
+ - `[project] dependencies`: runtime
36
+ - `[project.optional-dependencies] examples`: published extra for end users
37
+ - `[dependency-groups] dev`: development tools (pytest, pyrefly, maturin, ...)
38
+ - `[dependency-groups] notebooks`: `dev` plus what the example notebooks import
39
+
40
+ Re-resolve with `uv lock` after editing `pyproject.toml`. It only writes the
41
+ lockfile and does not touch the venv, so it is safe to run here.
42
+
43
+ ## Data Format
44
+ DataFrame with: `token`, `pos`/`c5`, `mode`, `file_id`, plus annotation columns.
45
+ Column names are defaults, not requirements: every function that reads one of
46
+ these roles takes a `*_column` parameter to point it elsewhere.
47
+
48
+ ## Query Languages
49
+ The package supports Simple (BNCweb-style) and CQP query syntaxes. See
50
+ [docs/simple_query.md](docs/simple_query.md) for the Simple language; the CQP
51
+ grammar in `cqp_parser.py` and the `search_cqp()` docstring cover the other.
52
+
53
+ ## Coding Standards
54
+ - Use numpy-style docstrings. Keep them minimal, focused on API usage
55
+ - Use **parameterized tests** when possible
56
+ - Avoid code bloat - keep implementations focused
57
+ - **Avoid gratuitous defensive programming**: validate inputs at public APIs and
58
+ give helpful error messages; trust invariants in internal functions. Use
59
+ assertions for debugging, not runtime validation of established invariants
60
+
61
+ ### Design principles
62
+ 1. When possible, functions should take exprs and return exprs.
63
+ 2. When a function must take a frame, prefer accepting both DataFrame and
64
+ LazyFrame, and return whichever type it was given.
65
+ 3. Work lazily inside even when given a DataFrame; principle 2 decides the
66
+ return type.
67
+ 4. When a function can only work on a DataFrame, check up front and raise
68
+ an error if given a LazyFrame.
69
+
70
+ ### Public functions
71
+ Student-facing functions share a shape, with the pieces in `utils.py`
72
+ (internal, so not in its `__all__`):
73
+ ```python
74
+ def analyze(corpus, expr, method="ll", file_id_column="file_id"):
75
+ method = check_choice(method, METHODS) # names the options, suggests near misses
76
+ term = as_expr(expr) # column name or expression
77
+ lf = as_corpus(corpus) # rejects non-frames and empty frames
78
+ check_columns(lf, [file_id_column], param="file_id_column")
79
+ ... # all internal work lazy
80
+ return collect_like(result, corpus) # eager in, eager out
81
+ ```
82
+ Read only the columns the arguments name, so corpora annotated differently
83
+ still work together and column errors surface here rather than out of a
84
+ query plan.
85
+
86
+ A function that can only work eagerly (principle 4) opens with
87
+ `as_eager(corpus)` in place of `as_corpus`, and has no `collect_like` to
88
+ return through: `SearchResults` and `encode_terms` take a corpus that way.
89
+ `search` and `search_cqp` accept a LazyFrame too, but down a separate
90
+ out-of-core path (chunked on `file_id_column`, or a single chunk when the
91
+ frame has no such column) rather than through `as_corpus`.
92
+
93
+ ### Rust-Specific
94
+ - **Minimize allocations**: Use `&str` over `String`, `&[T]` over `Vec<T>`; avoid `.clone()` in hot paths
95
+ - **Use iterators** without collecting when possible
96
+ - **Reuse buffers** in hot loops rather than allocating per iteration
@@ -0,0 +1 @@
1
+ @AGENTS.md