Compare commits

...

77 Commits

Author SHA1 Message Date
Matthew Honnibal f69c32f7a0 Install click with previous spaCy in upgrade test
spacy <=3.8.14 imports click without declaring it (#13971), and modern
typer no longer depends on click, so the pre-upgrade install fails on
import without it.
2026-08-07 13:44:28 +02:00
Matthew Honnibal 29bc4f2a5a Fix release smoke/upgrade tests
- Download wheels from the run's own artifacts: the release created by
  build_wheels is a draft, and drafts can't be looked up by tag, so the
  release-downloader step always 404'd
- Drop the checkout: the source tree shadowed the installed wheel when
  running python from the workspace root (No module named spacy.symbols)
- Strip the release-v prefix from the tag before using it as a pip
  version specifier
2026-08-07 12:12:52 +02:00
Matthew Honnibal 86edb26d60 Build linux wheels in manylinux_2_28 containers
numpy >=2.3 only publishes manylinux_2_28 wheels, so pip inside the
manylinux2014 build container falls back to compiling numpy from
source, which fails (container GCC is too old for numpy's meson
build). Bump the x86_64 and aarch64 build images to manylinux_2_28,
matching numpy's own baseline.
2026-08-07 10:17:55 +02:00
Matthew Honnibal 7a64151619 Cap hypothesis below 6.156 to keep win_arm64 wheel builds working 2026-08-07 09:58:05 +02:00
Matthew Honnibal 768e8d572c Fix CI: bump mypy pin for numpy 2.5 stubs, sync confection pin
mypy 1.5.x crashes with an internal error on numpy>=2.3 type stubs,
which killed the mypy step on Python 3.12+. Bump to mypy 1.20.x and
fix the type errors the newer mypy reports.

Also sync the confection pin in requirements.txt with setup.cfg
(>=1.3.2), which was the single test failure on Python 3.10/3.11.
2026-08-07 09:34:11 +02:00
Matthew Honnibal edd3d0fcca Format tests README code blocks for ruff 0.16 markdown formatting 2026-08-07 09:13:50 +02:00
Matthew Honnibal 82d98b2d96 Update version 2026-08-06 23:03:15 +02:00
Matthew Honnibal 47ce793778 Merge branch 'master' of https://github.com/explosion/spaCy 2026-08-06 23:02:36 +02:00
Mart Ratas dbe520e702 Fix click dependency issue (#13971) (#13973)
* Add click dependency in requirements.txt

* Add click dependency in setup.cfg
2026-08-06 22:59:47 +02:00
Ines Montani e67199550e Update README.md [ci skip] 2026-05-19 08:48:33 +02:00
Ines Montani 9af7b84777 Add note about Ellf [ci skip] 2026-05-19 08:48:27 +02:00
Matthew Honnibal 0f7e41d148 Add release notes for v3.8.14 2026-03-29 09:22:47 +02:00
Matthew Honnibal 0069cf99b6 Set version to 3.8.14 2026-03-28 21:59:08 +01:00
Taylor Satula 56032260f2 fix: check pip module availability instead of PATH binary in download (#13947)
_get_pip_install_cmd() uses shutil.which("pip") to check for pip, then
returns [sys.executable, "-m", "pip", "install"] which invokes pip as a
module. The binary check fails in venvs where ensurepip creates pip3 but
not pip (common on Debian/Ubuntu), even though python -m pip works.

Replace shutil.which("pip") with importlib.util.find_spec("pip"), which
tests the actual precondition: whether pip is importable in the current
interpreter. The uv branch is unchanged since uv is a standalone binary.

Fixes #13946
2026-03-28 21:56:56 +01:00
Matthew Honnibal d4bb796b5e Add least-privilege permissions to CI workflow 2026-03-27 08:49:43 +01:00
Matthew Honnibal 9d29209d04 Pass github context via stdin instead of CLI arg 2026-03-27 08:49:41 +01:00
Matthew Honnibal 4216738cf8 Pin GitHub Actions to commit SHAs for supply chain security 2026-03-26 15:48:47 +01:00
Matthew Honnibal 297938e704 Add smoke test and upgrade test to release build workflow
After wheels are built:
- smoke_test: install from wheel, download en_core_web_sm, verify entities
- upgrade_test: install previous spacy, download model, upgrade from wheel,
  verify model still loads and produces entities
2026-03-23 18:46:43 +01:00
Matthew Honnibal fdca647b1b Set version to 3.8.13 2026-03-23 16:52:52 +01:00
Matthew Honnibal 0d94a9d66d Pin confection>=1.3.2 — older versions crash with pydantic v2 2026-03-23 16:50:20 +01:00
Matthew Honnibal f175a51e2d Fully migrate to Pydantic v2 (#13940)
Use confection v1.3 and Thinc v8.3.13, which implement custom validation logic in place of Pydantic, allowing us to properly adopt Pydantic v2 and provide full Python 3.14 support.

Our dependency tree used Pydantic v1 in unusual ways, and relied on behaviours that Pydantic v2 reformed. In the time since Pydantic v2 was released there were a few attempts to migrate over to it, but the task has been complicated by the fact that the confection library has a fairly tangled implementation and I had reduced availability for open-source work in 2024 and 2025.

Specifically, our library confection provides the extensible configuration system we use in spaCy and Thinc. The config system allows you to refer to values that will be supplied by arbitrary functions, that e.g. define some neural network model or its sublayers. The functionality in confection is complicated because we aggressively prioritised user experience in the specification, even if it required increased implementation complexity.

Confection's original implementation built a dynamic Pydantic v1 schema for function-supplied values ("promises"). We validate the schema before calling any promises, and then validate the schema again after calling all the promises and substituting in their values. The variable-interpolation system adds further difficulties to the implementation, and we have to do it all subclassing the Python built-in configparser, which ties us to implementation choices I'd do differently if I had a clean slate.

Here's one summary of Pydantic v1-specific behaviours that the migration to v2 particularly difficult for us. This particular summary was produced during a session with Claude Code Opus 4.6, so nuances of it might be wrong. The full history of attempts at doing this spans over different refactors separated by a few months at a time, so I don't have a full record of all the things that I struggled with. It's possible some details of this summary are incorrect though.

The core problem we kept hitting: Pydantic v2 compiles validation schemas upfront and has much stricter immutability. The whole session has been a series of workarounds for this:

```
 1. Schema mutation — v1 let you mutate __fields__ in place; v2 needs model_rebuild() which loses forward ref namespaces, or create_model subclasses which don't propagate to parent schemas.
 2. model_dump vs dict — v2 converts dataclasses to dicts, breaking resolved objects. Needed a custom _model_to_dict helper.
 3. model_construct drops extras — v2 silently drops fields with extra="forbid", needed manual workarounds.
 4. Strict coercion — v2 coerces ndarray to List[Floats1d] via iteration, needed strict=True.
 5. Forward refs — Every schema with TYPE_CHECKING imports needs model_rebuild() with the right namespace, and that breaks when confection re-rebuilds later.
In order to adjust for behavioural differences like this, I'd refactored confection to build the different versions of the schema in multiple passes, instead of building all the representations together as we'd been doing. However this refactor itself had problems, further complicating the migration.
```

~I've now bitten the bullet and rolled back the refactor I'd been attempting of confection, and instead replaced the Pydantic validation with custom logic. This allows Confection to remove Pydantic as a dependency entirely.~ Update: Actually I went back and got the refactor working. All much nicer now.

I've taken some lengths to explain this because migrating off a dependency after breaking changes can be a sensitive topic. I want to stress that the changes Pydantic made from v1 to v2 are very good, and I greatly appreciate them as a user of FastAPI in our services. It would be very bad for the ecosystem if Pydantic pinned themselves to exactly matching the behaviours they had in v1 just to avoid breaking support for the sort of thing we'd been doing. Instead users who were relying on those behaviours like us should just find some way to adapt --- either vendor the v1 version we need, or change our behaviours, or implement an alternative. I would have liked to do this sooner but we've ultimately gone with the third option.
2026-03-23 13:45:02 +01:00
Matthew Honnibal 24255bd1e2 Fix import sorting for ruff isort compliance 2026-03-21 08:44:43 +01:00
Matthew Honnibal 8e6bd6d1c5 Apply ruff formatting to 8 files 2026-03-21 08:43:52 +01:00
Matthew Honnibal 47b5504e90 Autofix autofixable things from ruff 2026-03-21 08:43:16 +01:00
Matthew Honnibal 86f7ce303a Limit CI ruff lint to isort-only checks for now 2026-03-21 08:41:25 +01:00
Matthew Honnibal 79b5f811bf Update CI validation workflow: replace black, isort, flake8 with ruff 2026-03-21 08:39:43 +01:00
Matthew Honnibal 32c4b638ae Format with ruff 2026-03-21 08:38:53 +01:00
Matthew Honnibal a7f629bb91 Fix ruff isort config: replace unsupported profile with equivalent settings 2026-03-21 08:38:28 +01:00
Matthew Honnibal adeb1620ec Remove W503 from ruff ignore list (not a valid ruff rule) 2026-03-21 08:38:28 +01:00
Matthew Honnibal fd99ed312b Replace black, isort, and flake8 with ruff for linting and formatting
- requirements.txt: remove black, isort, flake8; add ruff
- pyproject.toml: replace [tool.isort] with [tool.ruff] config
- setup.cfg: remove [flake8] section (rules moved to pyproject.toml)
- .pre-commit-config.yaml: replace black/flake8 hooks with ruff/ruff-format
2026-03-21 08:38:28 +01:00
Matthew Honnibal 501ccfd5fb Fix pydantic v2 pattern validation error counts and attributeruler type annotation
- Update expected error counts in test_pattern_validation.py for pydantic v2
  (v2 reports errors for all union members, increasing counts for OP and
  nested pattern validation)
- Fix AttributeRulerPatternType to include List[MatcherPatternType] in
  the union (v2 is strict about nested list-of-list-of-dict types that
  v1 accepted laxly)
2026-03-20 20:50:56 +01:00
Matthew Honnibal b8bade1a57 Update spaCy to pydantic v2 native API
- Replace pydantic.v1 compat imports with direct v2 imports
- Replace class Config with model_config = ConfigDict(...)
- Replace @validator with @field_validator
- Replace ConstrainedStr with constr()
- Replace min_items with min_length, allow_population_by_field_name
  with populate_by_name
- Add model_rebuild() calls in __init__.py for forward ref resolution
- Update test error type assertions for v2
2026-03-20 15:03:41 +01:00
Matthew Honnibal f835985f3f Increment version 2026-03-20 14:38:21 +01:00
Matthew Honnibal d5f67dc92d Update spaCy pydantic imports from v1 compat to v2 native API 2026-03-20 14:31:59 +01:00
Matthew Honnibal 3154ede82a Revert pydantic v2 migration, restore v1 compat imports 2026-03-20 14:09:37 +01:00
Matthew Honnibal 4f19800b4e Revert to weasel <0.5 2026-03-20 14:04:12 +01:00
Matthew Honnibal 60a19cb800 Revert to confection <1 and allow pydantic v1 2026-03-20 14:02:03 +01:00
Matthew Honnibal 2afc3fd41c Escape braces in TokenPatternOperatorMinMax regex for Rust regex engine 2026-03-20 11:34:12 +01:00
Matthew Honnibal d41afc2966 isort 2026-03-20 11:13:21 +01:00
Matthew Honnibal 21439ec09d Migrate from pydantic v1 to v2, require pydantic>=2.0.0
Replace all pydantic.v1 compat imports with direct pydantic v2 imports.
Migrate schemas to v2 API: ConfigDict instead of inner Config class,
field_validator instead of validator, RootModel instead of __root__,
model_dump() instead of dict(), model_validate() instead of parse_obj(),
Annotated[str, StringConstraints()] instead of ConstrainedStr,
min_length instead of min_items, populate_by_name instead of
allow_population_by_field_name.
2026-03-20 11:10:26 +01:00
Matthew Honnibal f22ff91476 Fix vuln scan by not calling test file requirements requirements.txt 2026-03-20 09:55:49 +01:00
Matthew Honnibal ed20f79abe Require confection 2026-03-20 09:43:20 +01:00
Matthew Honnibal c6c78d6c33 Allow use of uv as a fallback to pip in spacy download 2026-03-20 09:20:38 +01:00
Matthew Honnibal 2f6142b43e Require weasel 1.0 2026-03-20 09:17:28 +01:00
Sofie Van Landeghem 37b4a74fa7 Switch dependency back from typer-slim to typer (#13922)
* change typer-slim dependency to typer

* set rich_markup_mode to None to preserve behaviour
2026-03-20 09:14:19 +01:00
Kaushik Rajan cfa1d3a59a fix: ensure memory_zone cleanup runs on exception (#13924) (#13932)
Wrap yield in try/finally in StringStore.memory_zone and
Vocab.memory_zone so transient state is always cleaned up,
even when an exception propagates through the context manager.
2026-03-15 11:29:09 +01:00
Matthew Honnibal 453732d32d Format (#13929) 2026-03-03 09:56:06 +01:00
Nathan Goldbaum c1e7cb2ebf Merge pull request #13865 from reonokiy/fix-ipython-display-import 2025-11-27 11:55:45 -07:00
reonokiy b85cf89b0b chore(ipython): import from IPython.display instead of IPython.core.display 2025-11-27 12:20:20 +08:00
Matthew Honnibal e7a662acf8 Skip Python 3.10 on Windows ARM 2025-11-17 18:21:33 +01:00
Matthew Honnibal f628c69bdb Increment version 2025-11-17 18:21:16 +01:00
Matthew Honnibal e7d1c3a30d Windows arm needs to be disabled at the ci level, so remove this skip selector 2025-11-17 14:41:17 +01:00
Matthew Honnibal c273c231e1 Try again to fix the skip selector 2025-11-17 14:36:48 +01:00
Matthew Honnibal 160d72852e Try again to skip windows arm 2025-11-17 14:29:41 +01:00
Matthew Honnibal 75f1160c8c Skip windows arm 2025-11-17 14:23:39 +01:00
Matthew Honnibal 71e938dbf7 Skip windows arm 2025-11-17 14:11:25 +01:00
Matthew Honnibal 7abd196000 Set version to 3.8.10 2025-11-17 13:19:29 +01:00
Matthew Honnibal a24bb01613 Support python 3.14 2025-11-17 13:19:11 +01:00
Matthew Honnibal 305ffd5560 Fix cdef declaration for cython 3 2025-11-13 14:25:38 +01:00
Matthew Honnibal 6d386bf707 Skip building free-threaded 2025-11-13 14:24:43 +01:00
Matthew Honnibal a534b43ced Fix wheel path name on cibuildwheel 2025-11-13 14:23:55 +01:00
Matthew Honnibal c9d77932f9 Update pyproject.yml 2025-11-10 11:56:03 +01:00
Matthew Honnibal b49c537a0b Update version 2025-11-10 11:54:00 +01:00
Matthew Honnibal 09b4eb4ebe Use reuseable gha 2025-11-10 11:53:30 +01:00
Matthew Honnibal 38056e9012 Disable 3.9 2025-11-06 01:55:38 +01:00
Matthew Honnibal 2d7f850676 Increment version 2025-11-05 14:57:37 +01:00
Matthew Honnibal b0ba71d4e7 Update weasel dependency 2025-11-05 14:57:08 +01:00
Matthew Honnibal ac95fc541c Update weasel dependency 2025-11-05 14:56:48 +01:00
Matthew Honnibal d01a180a7f Update build matrix for tests 2025-11-05 10:26:48 +01:00
Matthew Honnibal 68bf84ec5c Fix type errors 2025-11-05 10:10:42 +01:00
Matthew Honnibal 4ebe774120 isort 2025-11-04 15:50:26 +01:00
Matthew Honnibal 352d774cb7 Update black 2025-11-04 15:19:56 +01:00
Matthew Honnibal 54f54fc4cc Reformat with black 25 2025-11-04 15:19:43 +01:00
Etienne.bfx 68679d6f85 Add custom download URL (#13848)
* add download url

* Update .pre-commit-config.yaml

* Update cli.mdx

---------

Co-authored-by: ebonnafoux <etienne.bonnafoux@gmail.com>
2025-10-28 09:43:47 +01:00
Marwan Mohammed Sayed 94d6be8a9b Fixed the import issue in displacy/__init__.py (#13876)
IPython deprecated IPython.core.display.display. The new one became IPython.display.display. So, I just fixed the import issue based on the new changes in IPython
2025-10-28 09:43:08 +01:00
Matthew Hernandez f5d04868e1 Update _util.py to fix Deprecation Warning (#13844)
Fixes issue 13843 involving a Deprecation Warning with the python package Click.
2025-10-28 09:42:23 +01:00
OMOTAYO OMOYEMI f40ceb5378 docs(website): remove spaCy Quickstart from Universe/Courses due to spam redirect (fixes #13853) (#13877) 2025-10-28 09:41:50 +01:00
222 changed files with 1625 additions and 1029 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ SLACK_TOKEN = os.environ.get("SLACK_BOT_TOKEN", "ENV VAR not available!")
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ"
client = WebClient(SLACK_TOKEN)
github_context = json.loads(sys.argv[1])
github_context = json.loads(sys.stdin.read())
event = github_context['event']
pr_title = event['pull_request']["title"]
+96 -81
View File
@@ -7,93 +7,108 @@ on:
# ** matches 'zero or more of any character'
- 'release-v[0-9]+.[0-9]+.[0-9]+**'
- 'prerelease-v[0-9]+.[0-9]+.[0-9]+**'
permissions: {}
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ubuntu-latest, windows-latest, macos-13, macos-14, ubuntu-24.04-arm]
steps:
- uses: actions/checkout@v4
# aarch64 (arm) is built via qemu emulation
# QEMU is sadly too slow. We need to wait for public ARM support
#- name: Set up QEMU
# if: runner.os == 'Linux'
# uses: docker/setup-qemu-action@v3
# with:
# platforms: all
- name: Build wheels
uses: pypa/cibuildwheel@v2.21.3
env:
CIBW_ARCHS_LINUX: auto
with:
package-dir: .
output-dir: wheelhouse
config-file: "{package}/pyproject.toml"
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
build_sdist:
name: Build source distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build sdist
run: pipx run build --sdist
- uses: actions/upload-artifact@v4
with:
name: cibw-sdist
path: dist/*.tar.gz
create_release:
needs: [build_wheels, build_sdist]
runs-on: ubuntu-latest
uses: explosion/gha-cibuildwheel/.github/workflows/cibuildwheel.yml@2c98f757f13d112cf73fcf4b627249f1fffb5aae # main
permissions:
contents: write
checks: write
actions: read
issues: read
packages: write
pull-requests: read
repository-projects: read
statuses: read
with:
wheel-name-pattern: "spacy-*.whl"
pure-python: false
secrets:
gh-token: ${{ secrets.GITHUB_TOKEN }}
smoke_test:
name: Smoke test
# No checkout here: the jobs below must import the installed wheel, and a
# checked-out source tree in the working directory would shadow it.
needs: build_wheels
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Get the tag name and determine if it's a prerelease
id: get_tag_info
run: |
FULL_TAG=${GITHUB_REF#refs/tags/}
if [[ $FULL_TAG == release-* ]]; then
TAG_NAME=${FULL_TAG#release-}
IS_PRERELEASE=false
elif [[ $FULL_TAG == prerelease-* ]]; then
TAG_NAME=${FULL_TAG#prerelease-}
IS_PRERELEASE=true
else
echo "Tag does not match expected patterns" >&2
exit 1
fi
echo "FULL_TAG=$TAG_NAME" >> $GITHUB_ENV
echo "TAG_NAME=$TAG_NAME" >> $GITHUB_ENV
echo "IS_PRERELEASE=$IS_PRERELEASE" >> $GITHUB_ENV
- uses: actions/download-artifact@v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
# unpacks all CIBW artifacts into dist/
pattern: cibw-*
path: dist
python-version: "3.12"
# The release created by build_wheels is a draft, which can't be looked
# up by tag, so pull the wheel from this run's artifacts instead
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: "cibw-wheels-ubuntu-latest-*"
merge-multiple: true
- name: Create Draft Release
id: create_release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
path: "dist"
- name: Install from wheel
run: |
WHEEL=$(ls dist/spacy-*cp312*manylinux*x86_64*.whl | head -1)
pip install "$WHEEL"
- name: Test import
run: python -c "import spacy; print('spacy==' + spacy.__version__)"
- name: Download and load model
run: |
python -m spacy download en_core_web_sm
python -c "
import spacy
nlp = spacy.load('en_core_web_sm')
doc = nlp('Apple is looking at buying U.K. startup for \$1 billion')
assert len(doc.ents) > 0, 'No entities found'
print('Model load OK:', nlp.meta['name'], '@', nlp.meta['version'])
print('Entities:', [(ent.text, ent.label_) for ent in doc.ents])
"
upgrade_test:
name: Upgrade test
# No checkout here: the jobs below must import the installed wheel, and a
# checked-out source tree in the working directory would shadow it.
needs: build_wheels
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
name: ${{ env.TAG_NAME }}
draft: true
prerelease: ${{ env.IS_PRERELEASE }}
files: "./dist/*"
python-version: "3.12"
- name: Install previous spaCy version
run: |
# strip the release-v/prerelease-v prefix to get a version specifier;
# click is needed because spacy <=3.8.14 imports it without
# declaring it (#13971) and modern typer no longer pulls it in
pip install "spacy>=3.8.0,<${GITHUB_REF_NAME##*-v}" click || pip install "spacy<4" click
python -m spacy download en_core_web_sm
python -c "
import spacy
nlp = spacy.load('en_core_web_sm')
print('Pre-upgrade:', spacy.__version__, nlp.meta['name'], '@', nlp.meta['version'])
"
# The release created by build_wheels is a draft, which can't be looked
# up by tag, so pull the wheel from this run's artifacts instead
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: "cibw-wheels-ubuntu-latest-*"
merge-multiple: true
path: "dist"
- name: Upgrade to new version
run: |
WHEEL=$(ls dist/spacy-*cp312*manylinux*x86_64*.whl | head -1)
pip install "$WHEEL"
- name: Test model still loads after upgrade
run: |
python -c "
import spacy
nlp = spacy.load('en_core_web_sm')
doc = nlp('Apple is looking at buying U.K. startup for \$1 billion')
assert len(doc.ents) > 0, 'No entities found after upgrade'
print('Post-upgrade:', spacy.__version__, nlp.meta['name'], '@', nlp.meta['version'])
print('Entities:', [(ent.text, ent.label_) for ent in doc.ents])
"
+7 -3
View File
@@ -6,6 +6,8 @@ on:
- created
- edited
permissions: {}
jobs:
explosion-bot:
if: github.repository_owner == 'explosion'
@@ -15,13 +17,15 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
- name: Install and run explosion-bot
run: |
pip install git+https://${{ secrets.EXPLOSIONBOT_TOKEN }}@github.com/explosion/explosion-bot
git config --global url."https://x-access-token:${EXPLOSIONBOT_TOKEN}@github.com/".insteadOf "https://github.com/"
pip install git+https://github.com/explosion/explosion-bot
python -m explosionbot
env:
EXPLOSIONBOT_TOKEN: ${{ secrets.EXPLOSIONBOT_TOKEN }}
INPUT_TOKEN: ${{ secrets.EXPLOSIONBOT_TOKEN }}
INPUT_BK_TOKEN: ${{ secrets.BUILDKITE_SECRET }}
ENABLED_COMMANDS: "test_gpu,test_slow,test_slow_gpu"
+5 -1
View File
@@ -11,12 +11,16 @@ on:
types:
- labeled
permissions: {}
jobs:
issue-manager:
permissions:
issues: write
if: github.repository_owner == 'explosion'
runs-on: ubuntu-latest
steps:
- uses: tiangolo/issue-manager@0.4.0
- uses: tiangolo/issue-manager@4d1b7e05935a404dc8337d30bd23be46be8bb8e5 # 0.4.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
config: >
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
if: github.repository_owner == 'explosion'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@1bf7ec25051fe7c00bdd17e6a7cf3d7bfb7dc771 # v5
with:
process-only: 'issues'
issue-inactive-days: '30'
+4 -2
View File
@@ -8,6 +8,8 @@ on:
types:
- published
permissions: {}
jobs:
upload_pypi:
runs-on: ubuntu-latest
@@ -21,9 +23,9 @@ jobs:
# or, alternatively, upload to PyPI on every tag starting with 'v' (remove on: release above to use this)
# if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
steps:
- uses: robinraju/release-downloader@v1
- uses: robinraju/release-downloader@daf26c55d821e836577a15f77d86ddc078948b05 # v1
with:
tag: ${{ github.event.release.tag_name }}
fileName: '*'
out-file-path: 'dist'
- uses: pypa/gh-action-pypi-publish@release/v1
- uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1
+5 -10
View File
@@ -5,21 +5,16 @@ on:
paths:
- "website/meta/universe.json"
permissions: {}
jobs:
build:
if: github.repository_owner == 'explosion'
runs-on: ubuntu-latest
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
PR_NUMBER: ${{github.event.number}}
run: |
echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: '3.10'
- name: Install Bernadette app dependency and send an alert
@@ -30,4 +25,4 @@ jobs:
run: |
pip install slack-sdk==3.17.2 aiohttp==3.8.1
echo "$CHANNEL"
python .github/spacy_universe_alert.py "$GITHUB_CONTEXT"
echo "$GITHUB_CONTEXT" | python .github/spacy_universe_alert.py
+16 -24
View File
@@ -19,6 +19,9 @@ on:
- "*.mdx"
- "website/**"
permissions:
contents: read
jobs:
validate:
name: Validate
@@ -26,49 +29,38 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Configure Python version
uses: actions/setup-python@v4
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.10"
- name: black
- name: ruff format
run: |
python -m pip install black -c requirements.txt
python -m black spacy --check
- name: isort
python -m pip install ruff -c requirements.txt
python -m ruff format spacy --check
- name: ruff isort
run: |
python -m pip install isort -c requirements.txt
python -m isort spacy --check
- name: flake8
run: |
python -m pip install flake8==5.0.4
python -m flake8 spacy --count --select=E901,E999,F821,F822,F823,W605 --show-source --statistics
# Unfortunately cython-lint isn't working after the shift to Cython 3.
#- name: cython-lint
# run: |
# python -m pip install cython-lint -c requirements.txt
# # E501: line too log, W291: trailing whitespace, E266: too many leading '#' for block comment
# cython-lint spacy --ignore E501,W291,E266
python -m ruff check spacy --select I
tests:
name: Test
needs: Validate
strategy:
fail-fast: true
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python_version: ["3.9", "3.12", "3.13"]
python_version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
runs-on: ${{ matrix.os }}
steps:
- name: Check out repo
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Configure Python version
uses: actions/setup-python@v4
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: ${{ matrix.python_version }}
@@ -104,7 +96,7 @@ jobs:
shell: bash
- name: Test import
run: python -W error -c "import spacy"
run: python -W error -W 'ignore:Core Pydantic V1:UserWarning:pydantic' -c "import spacy"
- name: "Test download CLI"
run: |
@@ -165,7 +157,7 @@ jobs:
- name: "Run CPU tests"
run: |
python -m pytest --pyargs spacy -W error
python -m pytest --pyargs spacy -W error -W 'ignore:Core Pydantic V1:UserWarning:pydantic'
if: "!(startsWith(matrix.os, 'macos') && matrix.python_version == '3.11')"
- name: "Run CPU tests with thinc-apple-ops"
+5 -2
View File
@@ -13,6 +13,9 @@ on:
paths:
- "website/meta/universe.json"
permissions:
contents: read
jobs:
validate:
name: Validate
@@ -20,10 +23,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Configure Python version
uses: actions/setup-python@v4
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.7"
+5 -11
View File
@@ -1,13 +1,7 @@
repos:
- repo: https://github.com/ambv/black
rev: 22.3.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
hooks:
- id: black
language_version: python3.7
additional_dependencies: ['click==8.0.4']
- repo: https://github.com/pycqa/flake8
rev: 5.0.4
hooks:
- id: flake8
args:
- "--config=setup.cfg"
- id: ruff
args: ['--fix']
- id: ruff-format
+1 -1
View File
@@ -46,7 +46,7 @@ open-source software, released under the
| 👩‍🏫 **[Online Course]** | Learn spaCy in this free and interactive online course. |
| 📰 **[Blog]** | Read about current spaCy and Prodigy development, releases, talks and more from Explosion. |
| 📺 **[Videos]** | Our YouTube channel with video tutorials, talks and more. |
| 🔴 **[Live Stream]** | Join Matt as he works on spaCy and chat about NLP, live every week. |
| 🔴 **[Live Stream]** | Join Matt as he works on spaCy and chat about NLP. |
| 🛠 **[Changelog]** | Changes and version history. |
| 💝 **[Contribute]** | How to contribute to the spaCy project and code base. |
| 👕 **[Swag]** | Support us and our work with unique, custom-designed swag! |
+5
View File
@@ -0,0 +1,5 @@
Bug fix for model downloading in environments without pip on PATH
## Fixes
- Fix `spacy download` failing in environments where `pip` is not on PATH but is available as a Python module (e.g., some virtual environments and containers)
+16 -7
View File
@@ -5,16 +5,15 @@ requires = [
"cymem>=2.0.2,<2.1.0",
"preshed>=3.0.2,<3.1.0",
"murmurhash>=0.28.0,<1.1.0",
"thinc>=8.3.4,<8.4.0",
"thinc>=8.3.12,<8.4.0",
"numpy>=2.0.0,<3.0.0"
]
build-backend = "setuptools.build_meta"
[tool.cibuildwheel]
build = "*"
skip = "pp* cp36* cp37* cp38* *-win32 *i686*"
skip = "cp39* *-win32 *i686* cp3??t-* *cp310-win_arm64"
test-skip = ""
free-threaded-support = false
archs = ["native"]
@@ -37,9 +36,11 @@ test-extras = []
container-engine = "docker"
manylinux-x86_64-image = "manylinux2014"
# numpy >=2.3 only ships manylinux_2_28 wheels, so the build container must
# be at least that; i686 keeps manylinux2014 (no 2_28 image) but isn't built
manylinux-x86_64-image = "manylinux_2_28"
manylinux-i686-image = "manylinux2014"
manylinux-aarch64-image = "manylinux2014"
manylinux-aarch64-image = "manylinux_2_28"
manylinux-ppc64le-image = "manylinux2014"
manylinux-s390x-image = "manylinux2014"
manylinux-pypy_x86_64-image = "manylinux2014"
@@ -63,5 +64,13 @@ repair-wheel-command = "delocate-wheel --require-archs {delocate_archs} -w {dest
[tool.cibuildwheel.pyodide]
[tool.isort]
profile = "black"
[tool.ruff]
line-length = 88
[tool.ruff.lint]
select = ["E", "F", "W", "C", "B", "B9"]
ignore = ["E203", "E266", "E501", "E731", "E741", "F541"]
[tool.ruff.lint.isort]
combine-as-imports = true
split-on-trailing-comma = true
+13 -11
View File
@@ -3,19 +3,20 @@ spacy-legacy>=3.0.11,<3.1.0
spacy-loggers>=1.0.0,<2.0.0
cymem>=2.0.2,<2.1.0
preshed>=3.0.2,<3.1.0
thinc>=8.3.4,<8.4.0
ml_datasets>=0.2.0,<0.3.0
thinc>=8.3.12,<8.4.0
ml_datasets>=0.2.1,<0.3.0
murmurhash>=0.28.0,<1.1.0
wasabi>=0.9.1,<1.2.0
srsly>=2.4.3,<3.0.0
srsly>=2.5.3,<3.0.0
catalogue>=2.0.6,<2.1.0
typer-slim>=0.3.0,<1.0.0
weasel>=0.1.0,<0.5.0
typer>=0.3.0,<1.0.0
click>=8.2.1,<9.0.0
weasel>=1.0.0,<2.0.0
# Third party dependencies
numpy>=2.0.0,<3.0.0
requests>=2.13.0,<3.0.0
tqdm>=4.38.0,<5.0.0
pydantic>=1.7.4,!=1.8,!=1.8.1,<3.0.0
pydantic>=2.0.0,<3.0.0
jinja2
# Official Python utilities
setuptools
@@ -26,13 +27,14 @@ cython>=3.0,<4.0
pytest>=5.2.0,!=7.1.0
pytest-timeout>=1.3.0,<2.0.0
mock>=2.0.0,<3.0.0
flake8>=3.8.0,<6.0.0
hypothesis>=3.27.0,<7.0.0
mypy>=1.5.0,<1.6.0; platform_machine != "aarch64" and python_version >= "3.8"
# hypothesis >=6.156 ships a Rust extension with no win_arm64 wheels, which
# breaks wheel builds on windows-11-arm (sdist needs maturin)
hypothesis>=3.27.0,<6.156.0
mypy>=1.20.2,<1.21.0; platform_machine != "aarch64" and python_version >= "3.8"
types-mock>=0.1.1
types-setuptools>=57.0.0
types-requests
types-setuptools>=57.0.0
black==22.3.0
ruff>=0.9.0
cython-lint>=0.15.0
isort>=5.0,<6.0
confection>=1.3.2,<2.0.0
+13 -17
View File
@@ -22,6 +22,7 @@ classifiers =
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Programming Language :: Python :: 3.13
Programming Language :: Python :: 3.14
Topic :: Scientific/Engineering
project_urls =
Release notes = https://github.com/explosion/spaCy/releases
@@ -30,7 +31,7 @@ project_urls =
[options]
zip_safe = false
include_package_data = true
python_requires = >=3.9,<3.14
python_requires = >=3.9,<3.15
# NOTE: This section is superseded by pyproject.toml and will be removed in
# spaCy v4
setup_requires =
@@ -41,7 +42,7 @@ setup_requires =
cymem>=2.0.2,<2.1.0
preshed>=3.0.2,<3.1.0
murmurhash>=0.28.0,<1.1.0
thinc>=8.3.4,<8.4.0
thinc>=8.3.12,<8.4.0
install_requires =
# Our libraries
spacy-legacy>=3.0.11,<3.1.0
@@ -49,18 +50,20 @@ install_requires =
murmurhash>=0.28.0,<1.1.0
cymem>=2.0.2,<2.1.0
preshed>=3.0.2,<3.1.0
thinc>=8.3.4,<8.4.0
thinc>=8.3.12,<8.4.0
wasabi>=0.9.1,<1.2.0
srsly>=2.4.3,<3.0.0
srsly>=2.5.3,<3.0.0
catalogue>=2.0.6,<2.1.0
weasel>=0.1.0,<0.5.0
weasel>=1.0.0,<2.0.0
confection>=1.3.2,<2.0.0
# Third-party dependencies
typer-slim>=0.3.0,<1.0.0
typer>=0.3.0,<1.0.0
click>=8.2.1,<9.0.0
tqdm>=4.38.0,<5.0.0
numpy>=1.15.0; python_version < "3.9"
numpy>=1.19.0; python_version >= "3.9"
requests>=2.13.0,<3.0.0
pydantic>=1.7.4,!=1.8,!=1.8.1,<3.0.0
pydantic>=2.0.0,<3.0.0
jinja2
# Official Python utilities
setuptools
@@ -130,20 +133,13 @@ universal = false
[sdist]
formats = gztar
[flake8]
ignore = E203, E266, E501, E731, W503, E741, F541
max-line-length = 80
select = B,C,E,F,W,T4,B9
exclude =
.env,
.git,
__pycache__,
_tokenizer_exceptions_list.py,
[tool:pytest]
markers =
slow: mark a test as slow
issue: reference specific issue
filterwarnings =
error
ignore:Core Pydantic V1:UserWarning:pydantic
[mypy]
ignore_missing_imports = True
+6 -6
View File
@@ -82,9 +82,9 @@ COMPILER_DIRECTIVES = {
}
# Files to copy into the package that are otherwise not included
COPY_FILES = {
ROOT / "setup.cfg": PACKAGE_ROOT / "tests" / "package",
ROOT / "pyproject.toml": PACKAGE_ROOT / "tests" / "package",
ROOT / "requirements.txt": PACKAGE_ROOT / "tests" / "package",
ROOT / "setup.cfg": PACKAGE_ROOT / "tests" / "package" / "test.cfg",
ROOT / "pyproject.toml": PACKAGE_ROOT / "tests" / "package" / "test.toml",
ROOT / "requirements.txt": PACKAGE_ROOT / "tests" / "package" / "test.txt",
}
@@ -173,10 +173,10 @@ def setup_package():
about = {}
exec(f.read(), about)
for copy_file, target_dir in COPY_FILES.items():
for copy_file, target_file in COPY_FILES.items():
if copy_file.exists():
shutil.copy(str(copy_file), str(target_dir))
print(f"Copied {copy_file} -> {target_dir}")
shutil.copyfile(str(copy_file), str(target_file))
print(f"Copied {copy_file} -> {target_file}")
include_dirs = [
numpy.get_include(),
+24 -2
View File
@@ -10,17 +10,39 @@ setup_default_warnings() # noqa: E402
# These are imported as part of the API
from thinc.api import Config, prefer_gpu, require_cpu, require_gpu # noqa: F401
from . import pipeline # noqa: F401
from . import util
from . import (
pipeline, # noqa: F401
util,
)
from .about import __version__ # noqa: F401
from .cli.info import info # noqa: F401
from .errors import Errors
from .glossary import explain # noqa: F401
from .language import Language
from .registrations import REGISTRY_POPULATED, populate_registry
# Rebuild pydantic v2 schemas that use forward references to Language/Vocab
from .schemas import ( # noqa: F401
ConfigSchema,
ConfigSchemaInit,
ConfigSchemaNlp,
ConfigSchemaPretrain,
ConfigSchemaTraining,
)
from .training import Example # noqa: F401
from .util import logger, registry # noqa: F401
from .vocab import Vocab
_rebuild_ns = {"Language": Language, "Vocab": Vocab, "Example": Example}
for _schema in (
ConfigSchemaTraining,
ConfigSchemaNlp,
ConfigSchemaPretrain,
ConfigSchemaInit,
ConfigSchema,
):
_schema.model_rebuild(_types_namespace=_rebuild_ns) # type: ignore[attr-defined]
if sys.maxunicode == 65535:
raise SystemError(Errors.E130)
+1 -1
View File
@@ -1,5 +1,5 @@
# fmt: off
__title__ = "spacy"
__version__ = "3.8.7"
__version__ = "3.8.15"
__download_url__ = "https://github.com/explosion/spacy-models/releases/download"
__compatibility__ = "https://raw.githubusercontent.com/explosion/spacy-models/master/compatibility.json"
+5 -16
View File
@@ -1,15 +1,11 @@
import hashlib
import os
import shutil
import sys
from configparser import InterpolationError
from contextlib import contextmanager
from pathlib import Path
from typing import (
TYPE_CHECKING,
Any,
Dict,
Iterable,
List,
Optional,
Tuple,
@@ -20,23 +16,18 @@ from typing import (
import srsly
import typer
from click import NoSuchOption
from click.parser import split_arg_string
from thinc.api import Config, ConfigValidationError, require_gpu
from click.shell_completion import split_arg_string
from thinc.api import ConfigValidationError, require_gpu
from thinc.util import gpu_is_available
from typer.main import get_command
from wasabi import Printer, msg
from weasel import app as project_cli
from .. import about
from ..compat import Literal
from ..schemas import validate
from ..util import (
ENV_VARS,
SimpleFrozenDict,
import_file,
is_compatible_version,
logger,
make_tempdir,
registry,
run_command,
)
@@ -68,7 +59,7 @@ INIT_HELP = """Commands for initializing configs and pipeline packages."""
Arg = typer.Argument
Opt = typer.Option
app = typer.Typer(name=NAME, help=HELP)
app = typer.Typer(name=NAME, help=HELP, rich_markup_mode=None)
benchmark_cli = typer.Typer(name="benchmark", help=BENCHMARK_HELP, no_args_is_help=True)
debug_cli = typer.Typer(name="debug", help=DEBUG_HELP, no_args_is_help=True)
init_cli = typer.Typer(name="init", help=INIT_HELP, no_args_is_help=True)
@@ -225,13 +216,11 @@ def get_git_version(
@overload
def string_to_list(value: str, intify: Literal[False] = ...) -> List[str]:
...
def string_to_list(value: str, intify: Literal[False] = ...) -> List[str]: ...
@overload
def string_to_list(value: str, intify: Literal[True]) -> List[int]:
...
def string_to_list(value: str, intify: Literal[True]) -> List[int]: ...
def string_to_list(value: str, intify: bool = False) -> Union[List[str], List[int]]:
+9 -6
View File
@@ -22,7 +22,7 @@ to be grabbed ("text" by default)."""
out_help = "Path to save the resulting .spacy file"
code_help = (
"Path to Python file with additional " "code (registered functions) to be imported"
"Path to Python file with additional code (registered functions) to be imported"
)
gold_help = "Use gold preprocessing provided in the .spacy files"
force_msg = (
@@ -72,11 +72,15 @@ def apply_cli(
data_path: Path = Arg(..., help=path_help, exists=True),
output_file: Path = Arg(..., help=out_help, dir_okay=False),
code_path: Optional[Path] = Opt(None, "--code", "-c", help=code_help),
text_key: str = Opt("text", "--text-key", "-tk", help="Key containing text string for JSONL"),
force_overwrite: bool = Opt(False, "--force", "-F", help="Force overwriting the output file"),
text_key: str = Opt(
"text", "--text-key", "-tk", help="Key containing text string for JSONL"
),
force_overwrite: bool = Opt(
False, "--force", "-F", help="Force overwriting the output file"
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU."),
batch_size: int = Opt(1, "--batch-size", "-b", help="Batch size."),
n_process: int = Opt(1, "--n-process", "-n", help="number of processors to use.")
n_process: int = Opt(1, "--n-process", "-n", help="number of processors to use."),
):
"""
Apply a trained pipeline to documents to get predictions.
@@ -114,8 +118,7 @@ def apply(
if len(paths) == 0:
docbin.to_disk(output_file)
msg.warn(
"Did not find data to process,"
f" {data_path} seems to be an empty directory."
f"Did not find data to process, {data_path} seems to be an empty directory."
)
return
nlp = load_model(model)
+19 -4
View File
@@ -24,10 +24,25 @@ from ._util import (
def assemble_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
output_path: Path = Arg(..., help="Output directory to store assembled pipeline in"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
output_path: Path = Arg(
..., help="Output directory to store assembled pipeline in"
),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
# fmt: on
):
"""
+22 -6
View File
@@ -24,13 +24,29 @@ def benchmark_speed_cli(
# fmt: off
ctx: typer.Context,
model: str = Arg(..., help="Model name or path"),
data_path: Path = Arg(..., help="Location of binary evaluation data in .spacy format", exists=True),
batch_size: Optional[int] = Opt(None, "--batch-size", "-b", min=1, help="Override the pipeline batch size"),
data_path: Path = Arg(
..., help="Location of binary evaluation data in .spacy format", exists=True
),
batch_size: Optional[int] = Opt(
None, "--batch-size", "-b", min=1, help="Override the pipeline batch size"
),
no_shuffle: bool = Opt(False, "--no-shuffle", help="Do not shuffle benchmark data"),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
n_batches: int = Opt(50, "--batches", help="Minimum number of batches to benchmark", min=30,),
warmup_epochs: int = Opt(3, "--warmup", "-w", min=0, help="Number of iterations over the data for warmup"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
n_batches: int = Opt(
50,
"--batches",
help="Minimum number of batches to benchmark",
min=30,
),
warmup_epochs: int = Opt(
3, "--warmup", "-w", min=0, help="Number of iterations over the data for warmup"
),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
# fmt: on
):
"""
@@ -151,7 +167,7 @@ def print_mean_with_ci(sample: numpy.ndarray):
low = bootstrap_means[int(len(bootstrap_means) * 0.025)]
high = bootstrap_means[int(len(bootstrap_means) * 0.975)]
print(f"Mean: {mean:.1f} words/s (95% CI: {low-mean:.1f} +{high-mean:.1f})")
print(f"Mean: {mean:.1f} words/s (95% CI: {low - mean:.1f} +{high - mean:.1f})")
def print_outliers(sample: numpy.ndarray):
+41 -11
View File
@@ -48,17 +48,47 @@ class FileTypes(str, Enum):
def convert_cli(
# fmt: off
input_path: str = Arg(..., help="Input file or directory", exists=True),
output_dir: Path = Arg("-", help="Output directory. '-' for stdout.", allow_dash=True, exists=True),
file_type: FileTypes = Opt("spacy", "--file-type", "-t", help="Type of data to produce"),
n_sents: int = Opt(1, "--n-sents", "-n", help="Number of sentences per doc (0 to disable)"),
seg_sents: bool = Opt(False, "--seg-sents", "-s", help="Segment sentences (for -c ner)"),
model: Optional[str] = Opt(None, "--model", "--base", "-b", help="Trained spaCy pipeline for sentence segmentation to use as base (for --seg-sents)"),
morphology: bool = Opt(False, "--morphology", "-m", help="Enable appending morphology to tags"),
merge_subtokens: bool = Opt(False, "--merge-subtokens", "-T", help="Merge CoNLL-U subtokens"),
converter: str = Opt(AUTO, "--converter", "-c", help=f"Converter: {tuple(CONVERTERS.keys())}"),
ner_map: Optional[Path] = Opt(None, "--ner-map", "-nm", help="NER tag mapping (as JSON-encoded dict of entity types)", exists=True),
lang: Optional[str] = Opt(None, "--lang", "-l", help="Language (if tokenizer required)"),
concatenate: bool = Opt(None, "--concatenate", "-C", help="Concatenate output to a single file"),
output_dir: Path = Arg(
"-", help="Output directory. '-' for stdout.", allow_dash=True, exists=True
),
file_type: FileTypes = Opt(
"spacy", "--file-type", "-t", help="Type of data to produce"
),
n_sents: int = Opt(
1, "--n-sents", "-n", help="Number of sentences per doc (0 to disable)"
),
seg_sents: bool = Opt(
False, "--seg-sents", "-s", help="Segment sentences (for -c ner)"
),
model: Optional[str] = Opt(
None,
"--model",
"--base",
"-b",
help="Trained spaCy pipeline for sentence segmentation to use as base (for --seg-sents)",
),
morphology: bool = Opt(
False, "--morphology", "-m", help="Enable appending morphology to tags"
),
merge_subtokens: bool = Opt(
False, "--merge-subtokens", "-T", help="Merge CoNLL-U subtokens"
),
converter: str = Opt(
AUTO, "--converter", "-c", help=f"Converter: {tuple(CONVERTERS.keys())}"
),
ner_map: Optional[Path] = Opt(
None,
"--ner-map",
"-nm",
help="NER tag mapping (as JSON-encoded dict of entity types)",
exists=True,
),
lang: Optional[str] = Opt(
None, "--lang", "-l", help="Language (if tokenizer required)"
),
concatenate: bool = Opt(
None, "--concatenate", "-C", help="Concatenate output to a single file"
),
# fmt: on
):
"""
+24 -6
View File
@@ -26,10 +26,28 @@ from ._util import (
def debug_config_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
code_path: Optional[Path] = Opt(None, "--code-path", "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
show_funcs: bool = Opt(False, "--show-functions", "-F", help="Show an overview of all registered functions used in the config and where they come from (modules, files etc.)"),
show_vars: bool = Opt(False, "--show-variables", "-V", help="Show an overview of all variables referenced in the config and their values. This will also reflect variables overwritten on the CLI.")
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
code_path: Optional[Path] = Opt(
None,
"--code-path",
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
show_funcs: bool = Opt(
False,
"--show-functions",
"-F",
help="Show an overview of all registered functions used in the config and where they come from (modules, files etc.)",
),
show_vars: bool = Opt(
False,
"--show-variables",
"-V",
help="Show an overview of all variables referenced in the config and their values. This will also reflect variables overwritten on the CLI.",
),
# fmt: on
):
"""Debug a config file and show validation errors. The command will
@@ -64,10 +82,10 @@ def debug_config(
config = nlp.config.interpolate()
msg.divider("Config validation for [initialize]")
with show_validation_error(config_path):
T = registry.resolve(config["initialize"], schema=ConfigSchemaInit)
T = registry.resolve(config["initialize"], schema=ConfigSchemaInit) # type: ignore[arg-type]
msg.divider("Config validation for [training]")
with show_validation_error(config_path):
T = registry.resolve(config["training"], schema=ConfigSchemaTraining)
T = registry.resolve(config["training"], schema=ConfigSchemaTraining) # type: ignore[arg-type]
dot_names = [T["train_corpus"], T["dev_corpus"]]
util.resolve_dot_names(config, dot_names)
msg.good("Config is valid")
+27 -12
View File
@@ -71,11 +71,28 @@ SPAN_LENGTH_THRESHOLD_PERCENTAGE = 90
def debug_data_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
code_path: Optional[Path] = Opt(None, "--code-path", "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
ignore_warnings: bool = Opt(False, "--ignore-warnings", "-IW", help="Ignore warnings, only show stats and errors"),
verbose: bool = Opt(False, "--verbose", "-V", help="Print additional information and explanations"),
no_format: bool = Opt(False, "--no-format", "-NF", help="Don't pretty-print the results"),
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
code_path: Optional[Path] = Opt(
None,
"--code-path",
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
ignore_warnings: bool = Opt(
False,
"--ignore-warnings",
"-IW",
help="Ignore warnings, only show stats and errors",
),
verbose: bool = Opt(
False, "--verbose", "-V", help="Print additional information and explanations"
),
no_format: bool = Opt(
False, "--no-format", "-NF", help="Don't pretty-print the results"
),
# fmt: on
):
"""
@@ -120,7 +137,7 @@ def debug_data(
cfg = util.load_config(config_path, overrides=config_overrides)
nlp = util.load_model_from_config(cfg)
config = nlp.config.interpolate()
T = registry.resolve(config["training"], schema=ConfigSchemaTraining)
T = registry.resolve(config["training"], schema=ConfigSchemaTraining) # type: ignore[arg-type]
# Use original config here, not resolved version
sourced_components = get_sourced_components(cfg)
frozen_components = T["frozen_components"]
@@ -562,7 +579,7 @@ def debug_data(
if "morphologizer" in factory_names:
msg.divider("Morphologizer (POS+Morph)")
label_list = [label for label in gold_train_data["morphs"]]
label_list = tuple(gold_train_data["morphs"])
model_labels = _get_labels_from_model(nlp, "morphologizer")
msg.info(f"{len(label_list)} label(s) in train data")
labels = set(label_list)
@@ -708,7 +725,7 @@ def debug_data(
if len(dev_not_train) != 0:
pct = len(dev_not_train) / len(trees_dev)
msg.info(
f"{len(dev_not_train)} lemmatizer trees ({pct*100:.1f}% of dev trees)"
f"{len(dev_not_train)} lemmatizer trees ({pct * 100:.1f}% of dev trees)"
" were found exclusively in the dev data."
)
else:
@@ -968,16 +985,14 @@ def _compile_gold(
@overload
def _format_labels(labels: Iterable[str], counts: Literal[False] = False) -> str:
...
def _format_labels(labels: Iterable[str], counts: Literal[False] = False) -> str: ...
@overload
def _format_labels(
labels: Iterable[Tuple[str, int]],
counts: Literal[True],
) -> str:
...
) -> str: ...
def _format_labels(
+31 -8
View File
@@ -2,11 +2,10 @@ from pathlib import Path
from typing import Optional
import typer
from thinc.api import Config
from wasabi import MarkdownRenderer, Printer, diff_strings
from ..util import load_config
from ._util import Arg, Opt, debug_cli, parse_config_overrides, show_validation_error
from ._util import Arg, Opt, debug_cli, show_validation_error
from .init_config import Optimizations, init_config
@@ -17,12 +16,36 @@ from .init_config import Optimizations, init_config
def debug_diff_cli(
# fmt: off
ctx: typer.Context,
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
compare_to: Optional[Path] = Opt(None, help="Path to a config file to diff against, or `None` to compare against default settings", exists=True, allow_dash=True),
optimize: Optimizations = Opt(Optimizations.efficiency.value, "--optimize", "-o", help="Whether the user config was optimized for efficiency or accuracy. Only relevant when comparing against the default config."),
gpu: bool = Opt(False, "--gpu", "-G", help="Whether the original config can run on a GPU. Only relevant when comparing against the default config."),
pretraining: bool = Opt(False, "--pretraining", "--pt", help="Whether to compare on a config with pretraining involved. Only relevant when comparing against the default config."),
markdown: bool = Opt(False, "--markdown", "-md", help="Generate Markdown for GitHub issues")
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
compare_to: Optional[Path] = Opt(
None,
help="Path to a config file to diff against, or `None` to compare against default settings",
exists=True,
allow_dash=True,
),
optimize: Optimizations = Opt(
Optimizations.efficiency.value,
"--optimize",
"-o",
help="Whether the user config was optimized for efficiency or accuracy. Only relevant when comparing against the default config.",
),
gpu: bool = Opt(
False,
"--gpu",
"-G",
help="Whether the original config can run on a GPU. Only relevant when comparing against the default config.",
),
pretraining: bool = Opt(
False,
"--pretraining",
"--pt",
help="Whether to compare on a config with pretraining involved. Only relevant when comparing against the default config.",
),
markdown: bool = Opt(
False, "--markdown", "-md", help="Generate Markdown for GitHub issues"
),
# fmt: on
):
"""Show a diff of a config file with respect to spaCy's defaults or another config file. If
+14 -6
View File
@@ -36,18 +36,26 @@ from ._util import (
def debug_model_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
component: str = Arg(..., help="Name of the pipeline component of which the model should be analysed"),
layers: str = Opt("", "--layers", "-l", help="Comma-separated names of layer IDs to print"),
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
component: str = Arg(
..., help="Name of the pipeline component of which the model should be analysed"
),
layers: str = Opt(
"", "--layers", "-l", help="Comma-separated names of layer IDs to print"
),
dimensions: bool = Opt(False, "--dimensions", "-DIM", help="Show dimensions"),
parameters: bool = Opt(False, "--parameters", "-PAR", help="Show parameters"),
gradients: bool = Opt(False, "--gradients", "-GRAD", help="Show gradients"),
attributes: bool = Opt(False, "--attributes", "-ATTR", help="Show attributes"),
P0: bool = Opt(False, "--print-step0", "-P0", help="Print model before training"),
P1: bool = Opt(False, "--print-step1", "-P1", help="Print model after initialization"),
P1: bool = Opt(
False, "--print-step1", "-P1", help="Print model after initialization"
),
P2: bool = Opt(False, "--print-step2", "-P2", help="Print model after training"),
P3: bool = Opt(False, "--print-step3", "-P3", help="Print final predictions"),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU")
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
# fmt: on
):
"""
@@ -81,7 +89,7 @@ def debug_model_cli(
with show_validation_error(config_path):
nlp = util.load_model_from_config(raw_config)
config = nlp.config.interpolate()
T = registry.resolve(config["training"], schema=ConfigSchemaTraining)
T = registry.resolve(config["training"], schema=ConfigSchemaTraining) # type: ignore[arg-type]
seed = T["seed"]
if seed is not None:
msg.info(f"Fixing random seed: {seed}")
+34 -7
View File
@@ -1,3 +1,5 @@
import importlib.util
import shutil
import sys
from typing import Optional, Sequence
from urllib.parse import urljoin
@@ -27,8 +29,16 @@ def download_cli(
# fmt: off
ctx: typer.Context,
model: str = Arg(..., help="Name of pipeline package to download"),
direct: bool = Opt(False, "--direct", "-d", "-D", help="Force direct download of name + version"),
sdist: bool = Opt(False, "--sdist", "-S", help="Download sdist (.tar.gz) archive instead of pre-built binary wheel"),
direct: bool = Opt(
False, "--direct", "-d", "-D", help="Force direct download of name + version"
),
sdist: bool = Opt(
False,
"--sdist",
"-S",
help="Download sdist (.tar.gz) archive instead of pre-built binary wheel",
),
url: str = Opt(None, "--url", "-U", help="Download from given url"),
# fmt: on
):
"""
@@ -41,13 +51,14 @@ def download_cli(
DOCS: https://spacy.io/api/cli#download
AVAILABLE PACKAGES: https://spacy.io/models
"""
download(model, direct, sdist, *ctx.args)
download(model, direct, sdist, url, *ctx.args)
def download(
model: str,
direct: bool = False,
sdist: bool = False,
custom_url: Optional[str] = None,
*pip_args,
) -> None:
if (
@@ -87,7 +98,7 @@ def download(
filename = get_model_filename(model_name, version, sdist)
download_model(filename, pip_args)
download_model(filename, pip_args, custom_url)
msg.good(
"Download and installation successful",
f"You can now load the package via spacy.load('{model_name}')",
@@ -159,12 +170,14 @@ def get_latest_version(model: str) -> str:
def download_model(
filename: str, user_pip_args: Optional[Sequence[str]] = None
filename: str,
user_pip_args: Optional[Sequence[str]] = None,
custom_url: Optional[str] = None,
) -> None:
# Construct the download URL carefully. We need to make sure we don't
# allow relative paths or other shenanigans to trick us into download
# from outside our own repo.
base_url = about.__download_url__
base_url = custom_url if custom_url else about.__download_url__
# urljoin requires that the path ends with /, or the last path part will be dropped
if not base_url.endswith("/"):
base_url = about.__download_url__ + "/"
@@ -172,5 +185,19 @@ def download_model(
if not download_url.startswith(about.__download_url__):
raise ValueError(f"Download from {filename} rejected. Was it a relative path?")
pip_args = list(user_pip_args) if user_pip_args is not None else []
cmd = [sys.executable, "-m", "pip", "install"] + pip_args + [download_url]
cmd = _get_pip_install_cmd() + pip_args + [download_url]
run_command(cmd)
def _get_pip_install_cmd() -> list:
if importlib.util.find_spec("pip") is not None:
return [sys.executable, "-m", "pip", "install"]
elif shutil.which("uv"):
return ["uv", "pip", "install"]
else:
msg.fail(
"No package installer found",
"spaCy requires either pip or uv to download models. "
"Please install one of them and try again.",
exits=1,
)
+37 -11
View File
@@ -1,13 +1,12 @@
import re
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional
import srsly
from thinc.api import fix_random_seed
from wasabi import Printer
from .. import displacy, util
from ..scorer import Scorer
from ..tokens import Doc
from ..training import Corpus
from ._util import Arg, Opt, app, benchmark_cli, import_code, setup_gpu
@@ -20,15 +19,42 @@ from ._util import Arg, Opt, app, benchmark_cli, import_code, setup_gpu
def evaluate_cli(
# fmt: off
model: str = Arg(..., help="Model name or path"),
data_path: Path = Arg(..., help="Location of binary evaluation data in .spacy format", exists=True),
output: Optional[Path] = Opt(None, "--output", "-o", help="Output JSON file for metrics", dir_okay=False),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
data_path: Path = Arg(
..., help="Location of binary evaluation data in .spacy format", exists=True
),
output: Optional[Path] = Opt(
None, "--output", "-o", help="Output JSON file for metrics", dir_okay=False
),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
gold_preproc: bool = Opt(False, "--gold-preproc", "-G", help="Use gold preprocessing"),
displacy_path: Optional[Path] = Opt(None, "--displacy-path", "-dp", help="Directory to output rendered parses as HTML", exists=True, file_okay=False),
displacy_limit: int = Opt(25, "--displacy-limit", "-dl", help="Limit of parses to render as HTML"),
per_component: bool = Opt(False, "--per-component", "-P", help="Return scores per component, only applicable when an output JSON file is specified."),
spans_key: str = Opt("sc", "--spans-key", "-sk", help="Spans key to use when evaluating Doc.spans"),
gold_preproc: bool = Opt(
False, "--gold-preproc", "-G", help="Use gold preprocessing"
),
displacy_path: Optional[Path] = Opt(
None,
"--displacy-path",
"-dp",
help="Directory to output rendered parses as HTML",
exists=True,
file_okay=False,
),
displacy_limit: int = Opt(
25, "--displacy-limit", "-dl", help="Limit of parses to render as HTML"
),
per_component: bool = Opt(
False,
"--per-component",
"-P",
help="Return scores per component, only applicable when an output JSON file is specified.",
),
spans_key: str = Opt(
"sc", "--spans-key", "-sk", help="Spans key to use when evaluating Doc.spans"
),
# fmt: on
):
"""
@@ -123,7 +149,7 @@ def evaluate(
if key == "speed":
results[metric] = f"{scores[key]:.0f}"
else:
results[metric] = f"{scores[key]*100:.2f}"
results[metric] = f"{scores[key] * 100:.2f}"
else:
results[metric] = "-"
data[re.sub(r"[\s/]", "_", key.lower())] = scores[key]
+3 -1
View File
@@ -11,7 +11,9 @@ from ._util import Arg, Opt, app
def find_function_cli(
# fmt: off
func_name: str = Arg(..., help="Name of the registered function."),
registry_name: Optional[str] = Opt(None, "--registry", "-r", help="Name of the catalogue registry."),
registry_name: Optional[str] = Opt(
None, "--registry", "-r", help="Name of the catalogue registry."
),
# fmt: on
):
"""
+48 -20
View File
@@ -27,15 +27,39 @@ _DEFAULTS = {
def find_threshold_cli(
# fmt: off
model: str = Arg(..., help="Model name or path"),
data_path: Path = Arg(..., help="Location of binary evaluation data in .spacy format", exists=True),
data_path: Path = Arg(
..., help="Location of binary evaluation data in .spacy format", exists=True
),
pipe_name: str = Arg(..., help="Name of pipe to examine thresholds for"),
threshold_key: str = Arg(..., help="Key of threshold attribute in component's configuration"),
threshold_key: str = Arg(
..., help="Key of threshold attribute in component's configuration"
),
scores_key: str = Arg(..., help="Metric to optimize"),
n_trials: int = Opt(_DEFAULTS["n_trials"], "--n_trials", "-n", help="Number of trials to determine optimal thresholds"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
use_gpu: int = Opt(_DEFAULTS["use_gpu"], "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
gold_preproc: bool = Opt(_DEFAULTS["gold_preproc"], "--gold-preproc", "-G", help="Use gold preprocessing"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
n_trials: int = Opt(
_DEFAULTS["n_trials"],
"--n_trials",
"-n",
help="Number of trials to determine optimal thresholds",
),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
use_gpu: int = Opt(
_DEFAULTS["use_gpu"], "--gpu-id", "-g", help="GPU ID or -1 for CPU"
),
gold_preproc: bool = Opt(
_DEFAULTS["gold_preproc"], "--gold-preproc", "-G", help="Use gold preprocessing"
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
# fmt: on
):
"""
@@ -157,9 +181,11 @@ def find_threshold(
exits=1,
)
return {
keys[0]: filter_config(config[keys[0]], keys[1:], full_key)
if len(keys) > 1
else config[keys[0]]
keys[0]: (
filter_config(config[keys[0]], keys[1:], full_key)
if len(keys) > 1
else config[keys[0]]
)
}
# Evaluate with varying threshold values.
@@ -181,10 +207,10 @@ def find_threshold(
),
)
if hasattr(pipe, "cfg"):
setattr(
nlp.get_pipe(pipe_name),
"cfg",
set_nested_item(getattr(pipe, "cfg"), config_keys, threshold),
nlp.get_pipe(pipe_name).cfg = set_nested_item( # type: ignore[attr-defined]
pipe.cfg,
config_keys,
threshold, # type: ignore[attr-defined]
)
eval_scores = nlp.evaluate(dev_dataset)
@@ -216,12 +242,14 @@ def find_threshold(
if len(set(scores.values())) == 1:
wasabi.msg.warn(
title="All scores are identical. Verify that all settings are correct.",
text=""
if (
not isinstance(pipe, MultiLabel_TextCategorizer)
or scores_key in ("cats_macro_f", "cats_micro_f")
)
else "Use `cats_macro_f` or `cats_micro_f` when optimizing the threshold for `textcat_multilabel`.",
text=(
""
if (
not isinstance(pipe, MultiLabel_TextCategorizer)
or scores_key in ("cats_macro_f", "cats_micro_f")
)
else "Use `cats_macro_f` or `cats_micro_f` when optimizing the threshold for `textcat_multilabel`."
),
)
else:
+18 -4
View File
@@ -16,10 +16,24 @@ from .download import get_latest_version, get_model_filename
def info_cli(
# fmt: off
model: Optional[str] = Arg(None, help="Optional loadable spaCy pipeline"),
markdown: bool = Opt(False, "--markdown", "-md", help="Generate Markdown for GitHub issues"),
silent: bool = Opt(False, "--silent", "-s", "-S", help="Don't print anything (just return)"),
exclude: str = Opt("labels", "--exclude", "-e", help="Comma-separated keys to exclude from the print-out"),
url: bool = Opt(False, "--url", "-u", help="Print the URL to download the most recent compatible version of the pipeline"),
markdown: bool = Opt(
False, "--markdown", "-md", help="Generate Markdown for GitHub issues"
),
silent: bool = Opt(
False, "--silent", "-s", "-S", help="Don't print anything (just return)"
),
exclude: str = Opt(
"labels",
"--exclude",
"-e",
help="Comma-separated keys to exclude from the print-out",
),
url: bool = Opt(
False,
"--url",
"-u",
help="Print the URL to download the most recent compatible version of the pipeline",
),
# fmt: on
):
"""
+66 -16
View File
@@ -49,13 +49,44 @@ class InitValues:
@init_cli.command("config")
def init_config_cli(
# fmt: off
output_file: Path = Arg(..., help="File to save the config to or - for stdout (will only output config and no additional logging info)", allow_dash=True),
lang: str = Opt(InitValues.lang, "--lang", "-l", help="Two-letter code of the language to use"),
pipeline: str = Opt(",".join(InitValues.pipeline), "--pipeline", "-p", help="Comma-separated names of trainable pipeline components to include (without 'tok2vec' or 'transformer')"),
optimize: Optimizations = Opt(InitValues.optimize, "--optimize", "-o", help="Whether to optimize for efficiency (faster inference, smaller model, lower memory consumption) or higher accuracy (potentially larger and slower model). This will impact the choice of architecture, pretrained weights and related hyperparameters."),
gpu: bool = Opt(InitValues.gpu, "--gpu", "-G", help="Whether the model can run on GPU. This will impact the choice of architecture, pretrained weights and related hyperparameters."),
pretraining: bool = Opt(InitValues.pretraining, "--pretraining", "-pt", help="Include config for pretraining (with 'spacy pretrain')"),
force_overwrite: bool = Opt(InitValues.force_overwrite, "--force", "-F", help="Force overwriting the output file"),
output_file: Path = Arg(
...,
help="File to save the config to or - for stdout (will only output config and no additional logging info)",
allow_dash=True,
),
lang: str = Opt(
InitValues.lang, "--lang", "-l", help="Two-letter code of the language to use"
),
pipeline: str = Opt(
",".join(InitValues.pipeline),
"--pipeline",
"-p",
help="Comma-separated names of trainable pipeline components to include (without 'tok2vec' or 'transformer')",
),
optimize: Optimizations = Opt(
InitValues.optimize,
"--optimize",
"-o",
help="Whether to optimize for efficiency (faster inference, smaller model, lower memory consumption) or higher accuracy (potentially larger and slower model). This will impact the choice of architecture, pretrained weights and related hyperparameters.",
),
gpu: bool = Opt(
InitValues.gpu,
"--gpu",
"-G",
help="Whether the model can run on GPU. This will impact the choice of architecture, pretrained weights and related hyperparameters.",
),
pretraining: bool = Opt(
InitValues.pretraining,
"--pretraining",
"-pt",
help="Include config for pretraining (with 'spacy pretrain')",
),
force_overwrite: bool = Opt(
InitValues.force_overwrite,
"--force",
"-F",
help="Force overwriting the output file",
),
# fmt: on
):
"""
@@ -88,11 +119,28 @@ def init_config_cli(
@init_cli.command("fill-config")
def init_fill_config_cli(
# fmt: off
base_path: Path = Arg(..., help="Path to base config to fill", exists=True, dir_okay=False),
output_file: Path = Arg("-", help="Path to output .cfg file (or - for stdout)", allow_dash=True),
pretraining: bool = Opt(False, "--pretraining", "-pt", help="Include config for pretraining (with 'spacy pretrain')"),
diff: bool = Opt(False, "--diff", "-D", help="Print a visual diff highlighting the changes"),
code_path: Optional[Path] = Opt(None, "--code-path", "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
base_path: Path = Arg(
..., help="Path to base config to fill", exists=True, dir_okay=False
),
output_file: Path = Arg(
"-", help="Path to output .cfg file (or - for stdout)", allow_dash=True
),
pretraining: bool = Opt(
False,
"--pretraining",
"-pt",
help="Include config for pretraining (with 'spacy pretrain')",
),
diff: bool = Opt(
False, "--diff", "-D", help="Print a visual diff highlighting the changes"
),
code_path: Optional[Path] = Opt(
None,
"--code-path",
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
# fmt: on
):
"""
@@ -168,7 +216,7 @@ def init_config(
# Filter out duplicates since tok2vec and transformer are added by template
pipeline = [pipe for pipe in pipeline if pipe not in ("tok2vec", "transformer")]
defaults = RECOMMENDATIONS["__default__"]
reco = RecommendationSchema(**RECOMMENDATIONS.get(lang, defaults)).dict()
reco = RecommendationSchema(**RECOMMENDATIONS.get(lang, defaults)).model_dump()
variables = {
"lang": lang,
"components": pipeline,
@@ -195,9 +243,11 @@ def init_config(
"Pipeline": ", ".join(pipeline),
"Optimize for": optimize,
"Hardware": variables["hardware"].upper(),
"Transformer": template_vars.transformer.get("name") # type: ignore[attr-defined]
if template_vars.use_transformer # type: ignore[attr-defined]
else None,
"Transformer": (
template_vars.transformer.get("name") # type: ignore[attr-defined]
if template_vars.use_transformer # type: ignore[attr-defined]
else None
),
}
msg.info("Generated config template specific for your use case")
for label, value in use_case.items():
+69 -14
View File
@@ -26,13 +26,42 @@ def init_vectors_cli(
lang: str = Arg(..., help="The language of the nlp object to create"),
vectors_loc: Path = Arg(..., help="Vectors file in Word2Vec format", exists=True),
output_dir: Path = Arg(..., help="Pipeline output directory"),
prune: int = Opt(-1, "--prune", "-p", help="Optional number of vectors to prune to"),
truncate: int = Opt(0, "--truncate", "-t", help="Optional number of vectors to truncate to when reading in vectors file"),
prune: int = Opt(
-1, "--prune", "-p", help="Optional number of vectors to prune to"
),
truncate: int = Opt(
0,
"--truncate",
"-t",
help="Optional number of vectors to truncate to when reading in vectors file",
),
mode: str = Opt("default", "--mode", "-m", help="Vectors mode: default or floret"),
name: Optional[str] = Opt(None, "--name", "-n", help="Optional name for the word vectors, e.g. en_core_web_lg.vectors"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
jsonl_loc: Optional[Path] = Opt(None, "--lexemes-jsonl", "-j", help="Location of JSONL-formatted attributes file", hidden=True),
attr: str = Opt("ORTH", "--attr", "-a", help="Optional token attribute to use for vectors, e.g. LOWER or NORM"),
name: Optional[str] = Opt(
None,
"--name",
"-n",
help="Optional name for the word vectors, e.g. en_core_web_lg.vectors",
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
jsonl_loc: Optional[Path] = Opt(
None,
"--lexemes-jsonl",
"-j",
help="Location of JSONL-formatted attributes file",
hidden=True,
),
attr: str = Opt(
"ORTH",
"--attr",
"-a",
help="Optional token attribute to use for vectors, e.g. LOWER or NORM",
),
# fmt: on
):
"""Convert word vectors for use with spaCy. Will export an nlp object that
@@ -81,11 +110,24 @@ def update_lexemes(nlp: Language, jsonl_loc: Path) -> None:
def init_pipeline_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
output_path: Path = Arg(..., help="Output directory for the prepared data"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU")
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
# fmt: on
):
if verbose:
@@ -108,11 +150,24 @@ def init_pipeline_cli(
def init_labels_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
output_path: Path = Arg(..., help="Output directory for the labels"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU")
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
# fmt: on
):
"""Generate JSON files for the labels in the data. This helps speed up the
+53 -15
View File
@@ -21,16 +21,56 @@ from ._util import SDIST_SUFFIX, WHEEL_SUFFIX, Arg, Opt, app, string_to_list
@app.command("package")
def package_cli(
# fmt: off
input_dir: Path = Arg(..., help="Directory with pipeline data", exists=True, file_okay=False),
output_dir: Path = Arg(..., help="Output parent directory", exists=True, file_okay=False),
code_paths: str = Opt("", "--code", "-c", help="Comma-separated paths to Python file with additional code (registered functions) to be included in the package"),
meta_path: Optional[Path] = Opt(None, "--meta-path", "--meta", "-m", help="Path to meta.json", exists=True, dir_okay=False),
create_meta: bool = Opt(False, "--create-meta", "-C", help="Create meta.json, even if one exists"),
name: Optional[str] = Opt(None, "--name", "-n", help="Package name to override meta"),
version: Optional[str] = Opt(None, "--version", "-v", help="Package version to override meta"),
build: str = Opt("sdist", "--build", "-b", help="Comma-separated formats to build: sdist and/or wheel, or none."),
force: bool = Opt(False, "--force", "-f", "-F", help="Force overwriting existing data in output directory"),
require_parent: bool = Opt(True, "--require-parent/--no-require-parent", "-R", "-R", help="Include the parent package (e.g. spacy) in the requirements"),
input_dir: Path = Arg(
..., help="Directory with pipeline data", exists=True, file_okay=False
),
output_dir: Path = Arg(
..., help="Output parent directory", exists=True, file_okay=False
),
code_paths: str = Opt(
"",
"--code",
"-c",
help="Comma-separated paths to Python file with additional code (registered functions) to be included in the package",
),
meta_path: Optional[Path] = Opt(
None,
"--meta-path",
"--meta",
"-m",
help="Path to meta.json",
exists=True,
dir_okay=False,
),
create_meta: bool = Opt(
False, "--create-meta", "-C", help="Create meta.json, even if one exists"
),
name: Optional[str] = Opt(
None, "--name", "-n", help="Package name to override meta"
),
version: Optional[str] = Opt(
None, "--version", "-v", help="Package version to override meta"
),
build: str = Opt(
"sdist",
"--build",
"-b",
help="Comma-separated formats to build: sdist and/or wheel, or none.",
),
force: bool = Opt(
False,
"--force",
"-f",
"-F",
help="Force overwriting existing data in output directory",
),
require_parent: bool = Opt(
True,
"--require-parent/--no-require-parent",
"-R",
"-R",
help="Include the parent package (e.g. spacy) in the requirements",
),
# fmt: on
):
"""
@@ -410,7 +450,7 @@ def generate_readme(meta: Dict[str, Any]) -> str:
pipeline = ", ".join([md.code(p) for p in meta.get("pipeline", [])])
components = ", ".join([md.code(p) for p in meta.get("components", [])])
vecs = meta.get("vectors", {})
vectors = f"{vecs.get('keys', 0)} keys, {vecs.get('vectors', 0)} unique vectors ({ vecs.get('width', 0)} dimensions)"
vectors = f"{vecs.get('keys', 0)} keys, {vecs.get('vectors', 0)} unique vectors ({vecs.get('width', 0)} dimensions)"
author = meta.get("author") or "n/a"
notes = meta.get("notes", "")
license_name = meta.get("license")
@@ -469,7 +509,7 @@ def _format_accuracy(data: Dict[str, Any], exclude: List[str] = ["speed"]) -> st
md = MarkdownRenderer()
scalars = [(k, v) for k, v in data.items() if isinstance(v, (int, float))]
scores = [
(md.code(acc.upper()), f"{score*100:.2f}")
(md.code(acc.upper()), f"{score * 100:.2f}")
for acc, score in scalars
if acc not in exclude
]
@@ -488,9 +528,7 @@ def _format_label_scheme(data: Dict[str, Any]) -> str:
if not labels:
continue
col1 = md.bold(md.code(pipe))
col2 = ", ".join(
[md.code(str(label).replace("|", "\\|")) for label in labels]
) # noqa: W605
col2 = ", ".join([md.code(str(label).replace("|", "\\|")) for label in labels]) # noqa: W605
label_data.append((col1, col2))
n_labels += len(labels)
n_pipes += 1
+24 -5
View File
@@ -25,13 +25,32 @@ from ._util import (
def pretrain_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, dir_okay=False, allow_dash=True),
config_path: Path = Arg(
..., help="Path to config file", exists=True, dir_okay=False, allow_dash=True
),
output_dir: Path = Arg(..., help="Directory to write weights to on each epoch"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
resume_path: Optional[Path] = Opt(None, "--resume-path", "-r", help="Path to pretrained weights from which to resume pretraining"),
epoch_resume: Optional[int] = Opt(None, "--epoch-resume", "-er", help="The epoch to resume counting from when using --resume-path. Prevents unintended overwriting of existing weight files."),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
resume_path: Optional[Path] = Opt(
None,
"--resume-path",
"-r",
help="Path to pretrained weights from which to resume pretraining",
),
epoch_resume: Optional[int] = Opt(
None,
"--epoch-resume",
"-er",
help="The epoch to resume counting from when using --resume-path. Prevents unintended overwriting of existing weight files.",
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
skip_last: bool = Opt(False, "--skip-last", "-L", help="Skip saving model-last.bin"),
skip_last: bool = Opt(
False, "--skip-last", "-L", help="Skip saving model-last.bin"
),
# fmt: on
):
"""
+10 -3
View File
@@ -21,8 +21,15 @@ def profile_cli(
# fmt: off
ctx: typer.Context, # This is only used to read current calling context
model: str = Arg(..., help="Trained pipeline to load"),
inputs: Optional[Path] = Arg(None, help="Location of input file. '-' for stdin.", exists=True, allow_dash=True),
n_texts: int = Opt(10000, "--n-texts", "-n", help="Maximum number of texts to use if available"),
inputs: Optional[Path] = Arg(
None,
help="Location of input file. '-' for stdin.",
exists=True,
allow_dash=True,
),
n_texts: int = Opt(
10000, "--n-texts", "-n", help="Maximum number of texts to use if available"
),
# fmt: on
):
"""
@@ -59,7 +66,7 @@ def profile(model: str, inputs: Optional[Path] = None, n_texts: int = 10000) ->
with msg.loading("Loading IMDB dataset via ml_datasets..."):
imdb_train, _ = ml_datasets.imdb(train_limit=n_texts, dev_limit=0)
texts, _ = zip(*imdb_train)
texts = [text for text, _ in imdb_train]
msg.info(f"Loaded IMDB dataset and using {n_texts} examples")
with msg.loading(f"Loading pipeline '{model}'..."):
nlp = load_model(model)
+24 -5
View File
@@ -26,11 +26,30 @@ from ._util import (
def train_cli(
# fmt: off
ctx: typer.Context, # This is only used to read additional arguments
config_path: Path = Arg(..., help="Path to config file", exists=True, allow_dash=True),
output_path: Optional[Path] = Opt(None, "--output", "--output-path", "-o", help="Output directory to store trained pipeline in"),
code_path: Optional[Path] = Opt(None, "--code", "-c", help="Path to Python file with additional code (registered functions) to be imported"),
verbose: bool = Opt(False, "--verbose", "-V", "-VV", help="Display more information for debugging purposes"),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU")
config_path: Path = Arg(
..., help="Path to config file", exists=True, allow_dash=True
),
output_path: Optional[Path] = Opt(
None,
"--output",
"--output-path",
"-o",
help="Output directory to store trained pipeline in",
),
code_path: Optional[Path] = Opt(
None,
"--code",
"-c",
help="Path to Python file with additional code (registered functions) to be imported",
),
verbose: bool = Opt(
False,
"--verbose",
"-V",
"-VV",
help="Display more information for debugging purposes",
),
use_gpu: int = Opt(-1, "--gpu-id", "-g", help="GPU ID or -1 for CPU"),
# fmt: on
):
"""
+4 -1
View File
@@ -1,4 +1,5 @@
"""Helpers for Python and platform compatibility."""
import sys
from thinc.util import copy_array
@@ -34,7 +35,9 @@ else:
try: # Python 3.8+
import importlib.metadata as importlib_metadata
except ImportError:
from catalogue import _importlib_metadata as importlib_metadata # type: ignore[no-redef] # noqa: F401
from catalogue import ( # type: ignore[no-redef]
_importlib_metadata as importlib_metadata, # noqa: F401
)
from thinc.api import Optimizer # noqa: F401
+2 -1
View File
@@ -4,6 +4,7 @@ spaCy's built in visualization suite for dependencies and named entities.
DOCS: https://spacy.io/api/top-level#displacy
USAGE: https://spacy.io/usage/visualizers
"""
import warnings
from typing import Any, Callable, Dict, Iterable, Optional, Union
@@ -66,7 +67,7 @@ def render(
if jupyter or (jupyter is None and is_in_jupyter()):
# return HTML rendered by IPython display()
# See #4840 for details on span wrapper to disable mathjax
from IPython.core.display import HTML, display
from IPython.display import HTML, display
return display(HTML('<span class="tex2jax_ignore">{}</span>'.format(html)))
return html
+1 -1
View File
@@ -388,7 +388,7 @@ class DependencyRenderer:
lang=self.lang,
)
def render_word(self, text: str, tag: str, lemma: str, i: int) -> str:
def render_word(self, text: str, tag: str, lemma: Optional[str], i: int) -> str:
"""Render individual word.
text (str): Word text.
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"አፕል የዩኬን ጅምር ድርጅት በ 1 ቢሊዮን ዶላር ለመግዛት አስቧል።",
"የራስ ገዝ መኪኖች የኢንሹራንስ ኃላፊነትን ወደ አምራቾች ያዛውራሉ",
+1 -1
View File
@@ -60,7 +60,7 @@ _ordinal_words = [
"አስራ ስምንተኛ",
"አስራ ዘጠነኛ",
"ሃያኛ",
"ሰላሳኛ" "አርባኛ",
"ሰላሳኛአርባኛ",
"አምሳኛ",
"ስድሳኛ",
"ሰባኛ",
-1
View File
@@ -4,7 +4,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Bu bir cümlədir.",
"Necəsən?",
+1
View File
@@ -3,6 +3,7 @@ References:
https://github.com/Alir3z4/stop-words - Original list, serves as a base.
https://postvai.com/books/stop-dumi.pdf - Additions to the original list in order to improve it.
"""
STOP_WORDS = set(
"""
а автентичен аз ако ала
-1
View File
@@ -5,5 +5,4 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = ["তুই খুব ভালো", "আজ আমরা ডাক্তার দেখতে যাবো", "আমি জানি না "]
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"དོན་དུ་རྒྱ་མཚོ་བླ་མ་ཞེས་བྱ་ཞིང༌།",
"ཏཱ་ལའི་ཞེས་པ་ནི་སོག་སྐད་ཡིན་པ་དེ་བོད་སྐད་དུ་རྒྱ་མཚོའི་དོན་དུ་འཇུག",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple està buscant comprar una startup del Regne Unit per mil milions de dòlars",
"Els cotxes autònoms deleguen la responsabilitat de l'assegurança als seus fabricants",
+3 -3
View File
@@ -277,10 +277,10 @@ _currency = (
# These expressions contain various unicode variations, including characters
# used in Chinese (see #1333, #1340, #1351) unless there are cross-language
# conflicts, spaCy's base tokenizer should handle all of those by default
_punct = (
r"… …… , : ; \! \? ¿ ؟ ¡ \( \) \[ \] \{ \} < > _ # \* & 。 ? ! , 、 ; : ~ · । ، ۔ ؛ ٪"
_punct = r"… …… , : ; \! \? ¿ ؟ ¡ \( \) \[ \] \{ \} < > _ # \* & 。 ? ! , 、 ; : ~ · । ، ۔ ؛ ٪"
_quotes = (
r'\' " ” “ ` ‘ ´ ’ ‚ , „ » « 「 」 『 』 ( ) 〔 〕 【 】 《 》 〈 〉 〈 〉 ⟦ ⟧'
)
_quotes = r'\' " ” “ ` ‘ ´ ’ ‚ , „ » « 「 」 『 』 ( ) 〔 〕 【 】 《 》 〈 〉 〈 〉 ⟦ ⟧'
_hyphens = "- — -- --- —— ~"
# Various symbols like dingbats, but also emoji
-1
View File
@@ -4,7 +4,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Máma mele maso.",
"Příliš žluťoučký kůň úpěl ďábelské ódy.",
+1
View File
@@ -2,6 +2,7 @@
Tokenizer Exceptions.
Source: https://forkortelse.dk/ and various others.
"""
from ...symbols import NORM, ORTH
from ...util import update_exc
from ..tokenizer_exceptions import BASE_EXCEPTIONS
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Die ganze Stadt ist ein Startup: Shenzhen ist das Silicon Valley für Hardware-Firmen",
"Wie deutsche Startups die Technologie vorantreiben wollen: Künstliche Intelligenz",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Z tym stwori so wuměnjenje a zakład za dalše wobdźěłanje přez analyzu tekstoweje struktury a semantisku anotaciju a z tym tež za tu předstajenu digitalnu online-wersiju.",
"Mi so tu jara derje spodoba.",
-1
View File
@@ -128,7 +128,6 @@ _other_exc = {
_exc.update(_other_exc)
for h in range(1, 12 + 1):
for period in ["π.μ.", "πμ"]:
_exc[f"{h}{period}"] = [
{ORTH: f"{h}"},
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple is looking at buying U.K. startup for $1 billion",
"Autonomous cars shift insurance liability toward manufacturers",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple está buscando comprar una startup del Reino Unido por mil millones de dólares.",
"Los coches autónomos delegan la responsabilidad del seguro en sus fabricantes.",
+4 -1
View File
@@ -415,7 +415,10 @@ class SpanishLemmatizer(Lemmatizer):
else:
rule = self.select_rule("verb", features)
verb_lemma = self.lemmatize_verb(
verb, features - {"PronType=Prs"}, rule, index # type: ignore[operator]
verb,
features - {"PronType=Prs"}, # type: ignore[operator]
rule,
index, # type: ignore[operator]
)[0]
pron_lemmas = []
for pron in prons:
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"این یک جمله نمونه می باشد.",
"قرار ما، امروز ساعت ۲:۳۰ بعدازظهر هست!",
+3 -3
View File
@@ -611,8 +611,8 @@ narrative_ends = ["ه‌ام", "ه‌ای", "ه", "ه‌ایم", "ه‌اید",
present_ends = ["م", "ی", "د", "یم", "ید", "ند"]
# special case of '#هست':
VERBS_EXC.update({conj: "هست" for conj in ["هست" + end for end in simple_ends]})
VERBS_EXC.update({conj: "هست" for conj in ["نیست" + end for end in simple_ends]})
VERBS_EXC.update(dict.fromkeys(["هست" + end for end in simple_ends], "هست"))
VERBS_EXC.update(dict.fromkeys(["نیست" + end for end in simple_ends], "هست"))
for verb_root in verb_roots:
conjugations = []
@@ -648,4 +648,4 @@ for verb_root in verb_roots:
)
)
VERBS_EXC.update({conj: (past,) if past else present for conj in conjugations})
VERBS_EXC.update(dict.fromkeys(conjugations, (past,) if past else present))
+2 -2
View File
@@ -100,9 +100,9 @@ conj_contraction_negations = [
("eivat", "eivät"),
("eivät", "eivät"),
]
for (base_lower, base_norm) in conj_contraction_bases:
for base_lower, base_norm in conj_contraction_bases:
for base in [base_lower, base_lower.title()]:
for (suffix, suffix_norm) in conj_contraction_negations:
for suffix, suffix_norm in conj_contraction_negations:
_exc[base + suffix] = [
{ORTH: base, NORM: base_norm},
{ORTH: suffix, NORM: suffix_norm},
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple cherche à acheter une start-up anglaise pour 1 milliard de dollars",
"Les voitures autonomes déplacent la responsabilité de l'assurance vers les constructeurs",
+1 -1
View File
@@ -1,4 +1,4 @@
from typing import Dict, List, Tuple
from typing import List, Tuple
from ...pipeline import Lemmatizer
from ...tokens import Token
+1 -3
View File
@@ -382,7 +382,5 @@ urrainn
ì
ò
ó
""".split(
"\n"
)
""".split("\n")
)
+1 -3
View File
@@ -1974,9 +1974,7 @@ Tron an
tuilleadh 's a chòir
Tuilleadh 's a chòir
tuilleadh sa chòir
Tuilleadh sa chòir""".split(
"\n"
):
Tuilleadh sa chòir""".split("\n"):
_exc[orth] = [{ORTH: orth}]
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"ἐρᾷ μὲν ἁγνὸς οὐρανὸς τρῶσαι χθόνα, ἔρως δὲ γαῖαν λαμβάνει γάμου τυχεῖν·",
"εὐδαίμων Χαρίτων καὶ Μελάνιππος ἔφυ, θείας ἁγητῆρες ἐφαμερίοις φιλότατος.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"લોકશાહી એ સરકારનું એક એવું તંત્ર છે જ્યાં નાગરિકો મત દ્વારા સત્તાનો ઉપયોગ કરે છે.",
"તે ગુજરાત રાજ્યના ધરમપુર શહેરમાં આવેલું હતું",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"סין מקימה קרן של 440 מיליון דולר להשקעה בהייטק בישראל",
'רה"מ הודיע כי יחרים טקס בחסותו',
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"एप्पल 1 अरब डॉलर के लिए यू.के. स्टार्टअप खरीदने पर विचार कर रहा है।",
"स्वायत्त कारें निर्माताओं की ओर बीमा दायित्व रखतीं हैं।",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"To běšo wjelgin raźone a jo se wót luźi derje pśiwzeło. Tak som dožywiła wjelgin",
"Jogo pśewóźowarce stej groniłej, až how w serbskich stronach njama Santa Claus nic pytaś.",
+5 -2
View File
@@ -5,11 +5,11 @@ from thinc.api import Model
from ...language import BaseDefaults, Language
from .lemmatizer import HaitianCreoleLemmatizer
from .lex_attrs import LEX_ATTRS
from .punctuation import TOKENIZER_PREFIXES, TOKENIZER_INFIXES, TOKENIZER_SUFFIXES
from .punctuation import TOKENIZER_INFIXES, TOKENIZER_PREFIXES, TOKENIZER_SUFFIXES
from .stop_words import STOP_WORDS
from .syntax_iterators import SYNTAX_ITERATORS
from .tokenizer_exceptions import TOKENIZER_EXCEPTIONS
from .tag_map import TAG_MAP
from .tokenizer_exceptions import TOKENIZER_EXCEPTIONS
class HaitianCreoleDefaults(BaseDefaults):
@@ -22,10 +22,12 @@ class HaitianCreoleDefaults(BaseDefaults):
stop_words = STOP_WORDS
tag_map = TAG_MAP
class HaitianCreole(Language):
lang = "ht"
Defaults = HaitianCreoleDefaults
@HaitianCreole.factory(
"lemmatizer",
assigns=["token.lemma"],
@@ -49,4 +51,5 @@ def make_lemmatizer(
nlp.vocab, model, name, mode=mode, overwrite=overwrite, scorer=scorer
)
__all__ = ["HaitianCreole"]
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple ap panse achte yon demaraj nan Wayòm Ini pou $1 milya dola",
"Machin otonòm fè responsablite asirans lan ale sou men fabrikan yo",
-1
View File
@@ -2,7 +2,6 @@ from typing import List, Tuple
from ...pipeline import Lemmatizer
from ...tokens import Token
from ...lookups import Lookups
class HaitianCreoleLemmatizer(Lemmatizer):
+3
View File
@@ -49,6 +49,7 @@ NORM_MAP = {
"P": "Pa",
}
def like_num(text):
text = text.strip().lower()
if text.startswith(("+", "-", "±", "~")):
@@ -69,9 +70,11 @@ def like_num(text):
return True
return False
def norm_custom(text):
return NORM_MAP.get(text, text.lower())
LEX_ATTRS = {
LIKE_NUM: like_num,
NORM: norm_custom,
+40 -25
View File
@@ -4,10 +4,10 @@ from ..char_classes import (
ALPHA_UPPER,
CONCAT_QUOTES,
HYPHENS,
LIST_PUNCT,
LIST_QUOTES,
LIST_ELLIPSES,
LIST_ICONS,
LIST_PUNCT,
LIST_QUOTES,
merge_chars,
)
@@ -16,28 +16,43 @@ ELISION = "'".replace(" ", "")
_prefixes_elision = "m n l y t k w"
_prefixes_elision += " " + _prefixes_elision.upper()
TOKENIZER_PREFIXES = LIST_PUNCT + LIST_QUOTES + [
r"(?:({pe})[{el}])(?=[{a}])".format(
a=ALPHA, el=ELISION, pe=merge_chars(_prefixes_elision)
)
]
TOKENIZER_PREFIXES = (
LIST_PUNCT
+ LIST_QUOTES
+ [
r"(?:({pe})[{el}])(?=[{a}])".format(
a=ALPHA, el=ELISION, pe=merge_chars(_prefixes_elision)
)
]
)
TOKENIZER_SUFFIXES = LIST_PUNCT + LIST_QUOTES + LIST_ELLIPSES + [
r"(?<=[0-9])%", # numbers like 10%
r"(?<=[0-9])(?:{h})".format(h=HYPHENS), # hyphens after numbers
r"(?<=[{a}])[']".format(a=ALPHA), # apostrophes after letters
r"(?<=[{a}])['][mwlnytk](?=\s|$)".format(a=ALPHA), # contractions
r"(?<=[{a}0-9])\)", # right parenthesis after letter/number
r"(?<=[{a}])\.(?=\s|$)".format(a=ALPHA), # period after letter if space or end of string
r"(?<=\))[\.\?!]", # punctuation immediately after right parenthesis
]
TOKENIZER_SUFFIXES = (
LIST_PUNCT
+ LIST_QUOTES
+ LIST_ELLIPSES
+ [
r"(?<=[0-9])%", # numbers like 10%
r"(?<=[0-9])(?:{h})".format(h=HYPHENS), # hyphens after numbers
r"(?<=[{a}])[']".format(a=ALPHA), # apostrophes after letters
r"(?<=[{a}])['][mwlnytk](?=\s|$)".format(a=ALPHA), # contractions
r"(?<=[{a}0-9])\)", # right parenthesis after letter/number
r"(?<=[{a}])\.(?=\s|$)".format(
a=ALPHA
), # period after letter if space or end of string
r"(?<=\))[\.\?!]", # punctuation immediately after right parenthesis
]
)
TOKENIZER_INFIXES = LIST_ELLIPSES + LIST_ICONS + [
r"(?<=[0-9])[+\-\*^](?=[0-9-])",
r"(?<=[{al}{q}])\.(?=[{au}{q}])".format(
al=ALPHA_LOWER, au=ALPHA_UPPER, q=CONCAT_QUOTES
),
r"(?<=[{a}]),(?=[{a}])".format(a=ALPHA),
r"(?<=[{a}0-9])(?:{h})(?=[{a}])".format(a=ALPHA, h=HYPHENS),
r"(?<=[{a}][{el}])(?=[{a}])".format(a=ALPHA, el=ELISION),
]
TOKENIZER_INFIXES = (
LIST_ELLIPSES
+ LIST_ICONS
+ [
r"(?<=[0-9])[+\-\*^](?=[0-9-])",
r"(?<=[{al}{q}])\.(?=[{au}{q}])".format(
al=ALPHA_LOWER, au=ALPHA_UPPER, q=CONCAT_QUOTES
),
r"(?<=[{a}]),(?=[{a}])".format(a=ALPHA),
r"(?<=[{a}0-9])(?:{h})(?=[{a}])".format(a=ALPHA, h=HYPHENS),
r"(?<=[{a}][{el}])(?=[{a}])".format(a=ALPHA, el=ELISION),
]
)
+1 -2
View File
@@ -39,8 +39,7 @@ sa san si swa si
men mèsi oswa osinon
"""
.split()
""".split()
)
# Add common contractions, with and without apostrophe variants
+19 -1
View File
@@ -1,4 +1,22 @@
from spacy.symbols import NOUN, VERB, AUX, ADJ, ADV, PRON, DET, ADP, SCONJ, CCONJ, PART, INTJ, NUM, PROPN, PUNCT, SYM, X
from spacy.symbols import (
ADJ,
ADP,
ADV,
AUX,
CCONJ,
DET,
INTJ,
NOUN,
NUM,
PART,
PRON,
PROPN,
PUNCT,
SCONJ,
SYM,
VERB,
X,
)
TAG_MAP = {
"NOUN": {"pos": NOUN},
+101 -96
View File
@@ -1,4 +1,5 @@
from spacy.symbols import ORTH, NORM
from spacy.symbols import NORM, ORTH
def make_variants(base, first_norm, second_orth, second_norm):
return {
@@ -7,14 +8,16 @@ def make_variants(base, first_norm, second_orth, second_norm):
{ORTH: second_orth, NORM: second_norm},
],
base.capitalize(): [
{ORTH: base.split("'")[0].capitalize() + "'", NORM: first_norm.capitalize()},
{
ORTH: base.split("'")[0].capitalize() + "'",
NORM: first_norm.capitalize(),
},
{ORTH: second_orth, NORM: second_norm},
]
],
}
TOKENIZER_EXCEPTIONS = {
"Dr.": [{ORTH: "Dr."}]
}
TOKENIZER_EXCEPTIONS = {"Dr.": [{ORTH: "Dr."}]}
# Apostrophe forms
TOKENIZER_EXCEPTIONS.update(make_variants("m'ap", "mwen", "ap", "ap"))
@@ -29,93 +32,95 @@ TOKENIZER_EXCEPTIONS.update(make_variants("p'ap", "pa", "ap", "ap"))
TOKENIZER_EXCEPTIONS.update(make_variants("t'ap", "te", "ap", "ap"))
# Non-apostrophe contractions (with capitalized variants)
TOKENIZER_EXCEPTIONS.update({
"map": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "ap", NORM: "ap"},
],
"Map": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "ap", NORM: "ap"},
],
"lem": [
{ORTH: "le", NORM: "le"},
{ORTH: "m", NORM: "mwen"},
],
"Lem": [
{ORTH: "Le", NORM: "Le"},
{ORTH: "m", NORM: "mwen"},
],
"lew": [
{ORTH: "le", NORM: "le"},
{ORTH: "w", NORM: "ou"},
],
"Lew": [
{ORTH: "Le", NORM: "Le"},
{ORTH: "w", NORM: "ou"},
],
"nap": [
{ORTH: "n", NORM: "nou"},
{ORTH: "ap", NORM: "ap"},
],
"Nap": [
{ORTH: "N", NORM: "Nou"},
{ORTH: "ap", NORM: "ap"},
],
"lap": [
{ORTH: "l", NORM: "li"},
{ORTH: "ap", NORM: "ap"},
],
"Lap": [
{ORTH: "L", NORM: "Li"},
{ORTH: "ap", NORM: "ap"},
],
"yap": [
{ORTH: "y", NORM: "yo"},
{ORTH: "ap", NORM: "ap"},
],
"Yap": [
{ORTH: "Y", NORM: "Yo"},
{ORTH: "ap", NORM: "ap"},
],
"mte": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "te", NORM: "te"},
],
"Mte": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "te", NORM: "te"},
],
"mpral": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "pral", NORM: "pral"},
],
"Mpral": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "pral", NORM: "pral"},
],
"wap": [
{ORTH: "w", NORM: "ou"},
{ORTH: "ap", NORM: "ap"},
],
"Wap": [
{ORTH: "W", NORM: "Ou"},
{ORTH: "ap", NORM: "ap"},
],
"kap": [
{ORTH: "k", NORM: "ki"},
{ORTH: "ap", NORM: "ap"},
],
"Kap": [
{ORTH: "K", NORM: "Ki"},
{ORTH: "ap", NORM: "ap"},
],
"tap": [
{ORTH: "t", NORM: "te"},
{ORTH: "ap", NORM: "ap"},
],
"Tap": [
{ORTH: "T", NORM: "Te"},
{ORTH: "ap", NORM: "ap"},
],
})
TOKENIZER_EXCEPTIONS.update(
{
"map": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "ap", NORM: "ap"},
],
"Map": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "ap", NORM: "ap"},
],
"lem": [
{ORTH: "le", NORM: "le"},
{ORTH: "m", NORM: "mwen"},
],
"Lem": [
{ORTH: "Le", NORM: "Le"},
{ORTH: "m", NORM: "mwen"},
],
"lew": [
{ORTH: "le", NORM: "le"},
{ORTH: "w", NORM: "ou"},
],
"Lew": [
{ORTH: "Le", NORM: "Le"},
{ORTH: "w", NORM: "ou"},
],
"nap": [
{ORTH: "n", NORM: "nou"},
{ORTH: "ap", NORM: "ap"},
],
"Nap": [
{ORTH: "N", NORM: "Nou"},
{ORTH: "ap", NORM: "ap"},
],
"lap": [
{ORTH: "l", NORM: "li"},
{ORTH: "ap", NORM: "ap"},
],
"Lap": [
{ORTH: "L", NORM: "Li"},
{ORTH: "ap", NORM: "ap"},
],
"yap": [
{ORTH: "y", NORM: "yo"},
{ORTH: "ap", NORM: "ap"},
],
"Yap": [
{ORTH: "Y", NORM: "Yo"},
{ORTH: "ap", NORM: "ap"},
],
"mte": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "te", NORM: "te"},
],
"Mte": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "te", NORM: "te"},
],
"mpral": [
{ORTH: "m", NORM: "mwen"},
{ORTH: "pral", NORM: "pral"},
],
"Mpral": [
{ORTH: "M", NORM: "Mwen"},
{ORTH: "pral", NORM: "pral"},
],
"wap": [
{ORTH: "w", NORM: "ou"},
{ORTH: "ap", NORM: "ap"},
],
"Wap": [
{ORTH: "W", NORM: "Ou"},
{ORTH: "ap", NORM: "ap"},
],
"kap": [
{ORTH: "k", NORM: "ki"},
{ORTH: "ap", NORM: "ap"},
],
"Kap": [
{ORTH: "K", NORM: "Ki"},
{ORTH: "ap", NORM: "ap"},
],
"tap": [
{ORTH: "t", NORM: "te"},
{ORTH: "ap", NORM: "ap"},
],
"Tap": [
{ORTH: "T", NORM: "Te"},
{ORTH: "ap", NORM: "ap"},
],
}
)
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Az Apple egy brit startup vásárlását tervezi 1 milliárd dollár értékben.",
"San Francisco vezetése mérlegeli a járdát használó szállító robotok betiltását.",
+1 -1
View File
@@ -11,7 +11,7 @@ from ..char_classes import (
)
# removing ° from the special icons to keep e.g. 99° as one token
_concat_icons = CONCAT_ICONS.replace("\u00B0", "")
_concat_icons = CONCAT_ICONS.replace("\u00b0", "")
_currency = r"\$¢£€¥฿"
_quotes = CONCAT_QUOTES.replace("'", "")
-1
View File
@@ -4,7 +4,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Լոնդոնը Միացյալ Թագավորության մեծ քաղաք է։",
"Ո՞վ է Ֆրանսիայի նախագահը։",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Indonesia merupakan negara kepulauan yang kaya akan budaya.",
"Berapa banyak warga yang dibutuhkan saat kerja bakti?",
+2 -2
View File
@@ -156,7 +156,7 @@ for orth in [
"S.T.",
"S.T.Han",
"S.Th.",
"S.Th.I" "S.TI.",
"S.Th.IS.TI.",
"S.T.P.",
"S.TrK",
"S.Tekp.",
@@ -210,7 +210,7 @@ for orth in [
"hlm.",
"i/o",
"n.b.",
"p.p." "pjs.",
"p.p.pjs.",
"s.d.",
"tel.",
"u.p.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple vuole comprare una startup del Regno Unito per un miliardo di dollari",
"Le automobili a guida autonoma spostano la responsabilità assicurativa verso i produttori",
+4 -4
View File
@@ -61,7 +61,7 @@ class JapaneseTokenizer(DummyTokenizer):
zip(*dtokens) if dtokens else [[]] * 7
)
sub_tokens_list = list(sub_tokens_list)
doc = Doc(self.vocab, words=words, spaces=spaces)
doc = Doc(self.vocab, words=list(words), spaces=spaces)
next_pos = None # for bi-gram rules
for idx, (token, dtoken) in enumerate(zip(doc, dtokens)):
token.tag_ = dtoken.tag
@@ -102,9 +102,9 @@ class JapaneseTokenizer(DummyTokenizer):
token.dictionary_form(), # lemma
token.normalized_form(),
token.reading_form(),
sub_tokens_list[idx]
if sub_tokens_list
else None, # user_data['sub_tokens']
(
sub_tokens_list[idx] if sub_tokens_list else None
), # user_data['sub_tokens']
)
for idx, token in enumerate(sudachipy_tokens)
if len(token.surface()) > 0
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"アップルがイギリスの新興企業を10億ドルで購入を検討",
"自動運転車の損害賠償責任、自動車メーカーに一定の負担を求める",
+6 -2
View File
@@ -25,7 +25,9 @@ TAG_MAP = {
# Universal Dependencies Mapping: (Some of the entries in this mapping are updated to v2.6 in the list below)
# http://universaldependencies.org/ja/overview/morphology.html
# http://universaldependencies.org/ja/pos/all.html
"記号-一般": {POS: NOUN}, # this includes characters used to represent sounds like ドレミ
"記号-一般": {
POS: NOUN
}, # this includes characters used to represent sounds like ドレミ
"記号-文字": {
POS: NOUN
}, # this is for Greek and Latin characters having some meanings, or used as symbols, as in math
@@ -72,7 +74,9 @@ TAG_MAP = {
"名詞-固有名詞-地名-国": {POS: PROPN}, # country name
"名詞-助動詞語幹": {POS: AUX},
"名詞-数詞": {POS: NUM}, # includes Chinese numerals
"名詞-普通名詞-サ変可能": {POS: NOUN}, # XXX: sometimes VERB in UDv2; suru-verb noun
"名詞-普通名詞-サ変可能": {
POS: NOUN
}, # XXX: sometimes VERB in UDv2; suru-verb noun
"名詞-普通名詞-サ変形状詞可能": {POS: NOUN},
"名詞-普通名詞-一般": {POS: NOUN},
"名詞-普通名詞-形状詞可能": {POS: NOUN}, # XXX: sometimes ADJ in UDv2
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"ಆಪಲ್ ಒಂದು ಯು.ಕೆ. ಸ್ಟಾರ್ಟ್ಅಪ್ ಅನ್ನು ೧ ಶತಕೋಟಿ ಡಾಲರ್ಗಳಿಗೆ ಖರೀದಿಸಲು ನೋಡುತ್ತಿದೆ.",
"ಸ್ವಾಯತ್ತ ಕಾರುಗಳು ವಿಮಾ ಹೊಣೆಗಾರಿಕೆಯನ್ನು ತಯಾರಕರ ಕಡೆಗೆ ಬದಲಾಯಿಸುತ್ತವೆ.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Sciusciâ e sciorbî no se peu.",
"Graçie di çetroin, che me son arrivæ.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Jaunikis pirmąją vestuvinę naktį iškeitė į areštinės gultą",
"Bepiločiai automobiliai išnaikins vairavimo mokyklas, autoservisus ir eismo nelaimes",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"അനാവശ്യമായി കണ്ണിലും മൂക്കിലും വായിലും സ്പർശിക്കാതിരിക്കുക",
"പൊതുരംഗത്ത് മലയാള ഭാഷയുടെ സമഗ്രപുരോഗതി ലക്ഷ്യമാക്കി പ്രവർത്തിക്കുന്ന സംഘടനയായ മലയാളഐക്യവേദിയുടെ വിദ്യാർത്ഥിക്കൂട്ടായ്മയാണ് വിദ്യാർത്ഥി മലയാളവേദി",
+1 -2
View File
@@ -5,13 +5,12 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Malaysia ialah sebuah negara yang terletak di Asia Tenggara.",
"Berapa banyak pelajar yang akan menghadiri majlis perpisahan sekolah?",
"Pengeluaran makanan berasal dari beberapa lokasi termasuk Cameron Highlands, Johor Bahru, dan Kuching.",
"Syarikat XYZ telah menghasilkan 20,000 unit produk baharu dalam setahun terakhir",
"Kuala Lumpur merupakan ibu negara Malaysia." "Kau berada di mana semalam?",
"Kuala Lumpur merupakan ibu negara Malaysia.Kau berada di mana semalam?",
"Siapa yang akan memimpin projek itu?",
"Siapa perdana menteri Malaysia sekarang?",
]
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple vurderer å kjøpe britisk oppstartfirma for en milliard dollar.",
"Selvkjørende biler flytter forsikringsansvaret over på produsentene.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"एप्पलले अमेरिकी स्टार्टअप १ अर्ब डलरमा किन्ने सोच्दै छ",
"स्वायत्त कारहरूले बीमा दायित्व निर्माताहरु तिर बदल्छन्",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple overweegt om voor 1 miljard een U.K. startup te kopen",
"Autonome auto's verschuiven de verzekeringverantwoordelijkheid naar producenten",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
# sentences taken from Omsetjingsminne frå Nynorsk pressekontor 2022 (https://www.nb.no/sprakbanken/en/resource-catalogue/oai-nb-no-sbr-80/)
sentences = [
"Konseptet går ut på at alle tre omgangar tel, alle hopparar må stille i kvalifiseringa og poengsummen skal telje.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Poczuł przyjemną woń mocnej kawy.",
"Istnieje wiele dróg oddziaływania substancji psychoaktywnej na układ nerwowy.",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple está querendo comprar uma startup do Reino Unido por 100 milhões de dólares",
"Carros autônomos empurram a responsabilidade do seguro para os fabricantes."
+5 -3
View File
@@ -1,6 +1,8 @@
from ..punctuation import TOKENIZER_INFIXES as BASE_TOKENIZER_INFIXES
from ..punctuation import TOKENIZER_PREFIXES as BASE_TOKENIZER_PREFIXES
from ..punctuation import TOKENIZER_SUFFIXES as BASE_TOKENIZER_SUFFIXES
from ..punctuation import (
TOKENIZER_INFIXES as BASE_TOKENIZER_INFIXES,
TOKENIZER_PREFIXES as BASE_TOKENIZER_PREFIXES,
TOKENIZER_SUFFIXES as BASE_TOKENIZER_SUFFIXES,
)
_prefixes = [r"\w{1,3}\$"] + BASE_TOKENIZER_PREFIXES
-1
View File
@@ -7,7 +7,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
"Apple plănuiește să cumpere o companie britanică pentru un miliard de dolari",
"Municipalitatea din San Francisco ia în calcul interzicerea roboților curieri pe trotuar",
-1
View File
@@ -5,7 +5,6 @@ Example sentences to test spaCy and its language models.
>>> docs = nlp.pipe(sentences)
"""
sentences = [
# Translations from English:
"Apple рассматривает возможность покупки стартапа из Соединённого Королевства за $1 млрд",

Some files were not shown because too many files have changed in this diff Show More