Skip to content

Commit 717af29

Browse files
committed
Merge branch 'master' of github.com:udapi/udapi-python
2 parents 57bacc8 + e28f953 commit 717af29

43 files changed

Lines changed: 2256 additions & 894 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.circleci/config.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ orbs:
1515
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
1616
jobs:
1717
build-and-test: # This is the name of the job, feel free to change it to better match what you're trying to do!
18+
parameters:
19+
python-version:
20+
type: string
1821
# These next lines defines a Docker executors: https://circleci.com/docs/2.0/executor-types/
1922
# You can specify an image from Dockerhub or use one of the convenience images from CircleCI's Developer Hub
2023
# A list of available CircleCI Docker convenience images are available here: https://circleci.com/developer/images/image/cimg/python
2124
# The executor is the environment in which the steps below will be executed - below will use a python 3.10.2 container
2225
# Change the version below to your required version of python
2326
docker:
24-
- image: cimg/python:3.9
27+
- image: cimg/python:<< parameters.python-version >>
2528
# Checkout the code as the first step. This is a dedicated CircleCI step.
2629
# The python orb's install-packages step will install the dependencies from a Pipfile via Pipenv by default.
2730
# Here we're making sure we use just use the system-wide pip. By default it uses the project root's requirements.txt.
@@ -31,15 +34,12 @@ jobs:
3134
- checkout
3235
- python/install-packages:
3336
pkg-manager: pip
34-
# app-dir: ~/project/package-directory/ # If you're requirements.txt isn't in the root directory.
35-
# pip-dependency-file: test-requirements.txt # if you have a different name for your requirements file, maybe one that combines your runtime and test requirements.
3637
- run:
3738
name: Install Udapi
3839
command: pip install ".[test]"
3940
- run: mkdir -p test-results
4041
- run:
4142
name: Run pytest tests
42-
# This assumes pytest is installed via the install-package step above
4343
command: pytest --junitxml=test-results/junit.xml -o junit_family=legacy
4444
- store_test_results:
4545
path: test-results
@@ -54,7 +54,9 @@ jobs:
5454
# Invoke jobs via workflows
5555
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
5656
workflows:
57-
sample: # This is the name of the workflow, feel free to change it to better match your workflow.
58-
# Inside the workflow, you define the jobs you want to run.
57+
test-matrix:
5958
jobs:
60-
- build-and-test
59+
- build-and-test:
60+
matrix:
61+
parameters:
62+
python-version: ["3.9", "3.11", "3.13"]
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# This workflow will upload a Python Package to PyPI when a release is created
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3+
4+
# This workflow uses actions that are not certified by GitHub.
5+
# They are provided by a third-party and are governed by
6+
# separate terms of service, privacy policy, and support
7+
# documentation.
8+
9+
name: Upload Python Package
10+
11+
on:
12+
release:
13+
types: [published]
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
release-build:
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.x"
28+
29+
- name: Build release distributions
30+
run: |
31+
# NOTE: put your own distribution build steps here.
32+
python -m pip install build
33+
python -m build
34+
35+
- name: Upload distributions
36+
uses: actions/upload-artifact@v4
37+
with:
38+
name: release-dists
39+
path: dist/
40+
41+
pypi-publish:
42+
runs-on: ubuntu-latest
43+
needs:
44+
- release-build
45+
permissions:
46+
# IMPORTANT: this permission is mandatory for trusted publishing
47+
id-token: write
48+
49+
# Dedicated environments with protections for publishing are strongly recommended.
50+
# For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51+
environment:
52+
name: pypi
53+
# OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54+
url: https://pypi.org/p/udapi
55+
#
56+
# ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57+
# ALTERNATIVE: exactly, uncomment the following line instead:
58+
# url: https://pypi.org/project/YOURPROJECT/${{ github.event.release.name }}
59+
60+
steps:
61+
- name: Retrieve release distributions
62+
uses: actions/download-artifact@v4
63+
with:
64+
name: release-dists
65+
path: dist/
66+
67+
- name: Publish release distributions to PyPI
68+
uses: pypa/gh-action-pypi-publish@release/v1
69+
with:
70+
packages-dir: dist/

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.cache
12
.idea
3+
*.egg-info/
24
*.pyc
3-
.cache
5+
dist/

CHANGES.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@ Udapi Change Log
22
----------------
33
See https://github.com/udapi/udapi-python/commits/master for details.
44

5-
0.4.0 2024-03-28
5+
0.5.1 2025-11-05
6+
- make udapy compatible with Python 3.13
7+
8+
0.5.0 2025-10-18
9+
- added mwt.feats
10+
- added root.prev_tree and root.next_tree
11+
- .github/workflows/python-publish.yml
12+
- edits by Dan Zeman in block.ud.*
13+
14+
0.4.0 2025-03-28
615
- support for CorefUD 1.3
716
- edits by Dan Zeman in block.ud.*
817
- requires Python 3.9+ (difficult to test older versions in Circle-CI)

README.md

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,24 @@ Python framework for processing Universal Dependencies data
66
[![Documentation Status](https://readthedocs.org/projects/udapi/badge/)](http://udapi.readthedocs.io)
77

88
## Requirements
9-
- You need Python 3.6 or higher.
10-
- If the [ufal.udpipe](https://pypi.python.org/pypi/ufal.udpipe/) parser is needed,
11-
make sure you have a C++11 compiler (e.g. [g++ 4.7 or newer](.travis.yml#L9))
12-
and install UDPipe with `pip3 install --user --upgrade ufal.udpipe`.
9+
- You need Python 3.9 or higher.
10+
- It is recommended to install Udapi in a Python virtual environment.
11+
- If you need the [ufal.udpipe](https://pypi.python.org/pypi/ufal.udpipe/) parser (to be used from Udapi)
12+
install it (with `pip install --upgrade ufal.udpipe`).
1313

1414
## Install Udapi for developers
15-
Let's clone the git repo to `~/udapi-python/`, install dependencies
16-
and setup `$PATH` and `$PYTHONPATH` accordingly.
15+
Let's clone the git repo e.g. to `~/udapi-python/` and make an [editable installation](https://setuptools.pypa.io/en/latest/userguide/development_mode.html)
1716
```bash
1817
cd
1918
git clone https://github.com/udapi/udapi-python.git
20-
pip3 install --user -r udapi-python/requirements.txt
21-
echo '## Use Udapi from ~/udapi-python/ ##' >> ~/.bashrc
22-
echo 'export PATH="$HOME/udapi-python/bin:$PATH"' >> ~/.bashrc
23-
echo 'export PYTHONPATH="$HOME/udapi-python/:$PYTHONPATH"' >> ~/.bashrc
24-
source ~/.bashrc # or open new bash
19+
cd udapi-python
20+
pip install -e .
2521
```
2622

2723
## Install Udapi for users
2824
This is similar to the above, but installs Udapi from PyPI to the standard (user) Python paths.
2925
```
30-
pip3 install --user --upgrade udapi
26+
pip install --upgrade udapi
3127
```
3228
Try `udapy -h` to check it is installed correctly.
3329
If it fails, make sure your `PATH` includes the directory where `pip3` installed the `udapy` script.

bin/udapy

Lines changed: 3 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,7 @@
11
#!/usr/bin/env python3
2-
import os
3-
import gc
2+
"""Thin wrapper for backward compatibility. Calls udapi.cli.main()."""
43
import sys
5-
import atexit
6-
import logging
7-
import argparse
4+
from udapi.cli import main
85

9-
from udapi.core.run import Run
10-
11-
# Parse command line arguments.
12-
argparser = argparse.ArgumentParser(
13-
formatter_class=argparse.RawTextHelpFormatter,
14-
usage="udapy [optional_arguments] scenario",
15-
epilog="See http://udapi.github.io",
16-
description="udapy - Python interface to Udapi - API for Universal Dependencies\n\n"
17-
"Examples of usage:\n"
18-
" udapy -s read.Sentences udpipe.En < in.txt > out.conllu\n"
19-
" udapy -T < sample.conllu | less -R\n"
20-
" udapy -HAM ud.MarkBugs < sample.conllu > bugs.html\n")
21-
argparser.add_argument(
22-
"-q", "--quiet", action="store_true",
23-
help="Warning, info and debug messages are suppressed. Only fatal errors are reported.")
24-
argparser.add_argument(
25-
"-v", "--verbose", action="store_true",
26-
help="Warning, info and debug messages are printed to the STDERR.")
27-
argparser.add_argument(
28-
"-s", "--save", action="store_true",
29-
help="Add write.Conllu to the end of the scenario")
30-
argparser.add_argument(
31-
"-T", "--save_text_mode_trees", action="store_true",
32-
help="Add write.TextModeTrees color=1 to the end of the scenario")
33-
argparser.add_argument(
34-
"-H", "--save_html", action="store_true",
35-
help="Add write.TextModeTreesHtml color=1 to the end of the scenario")
36-
argparser.add_argument(
37-
"-A", "--save_all_attributes", action="store_true",
38-
help="Add attributes=form,lemma,upos,xpos,feats,deprel,misc (to be used after -T and -H)")
39-
argparser.add_argument(
40-
"-C", "--save_comments", action="store_true",
41-
help="Add print_comments=1 (to be used after -T and -H)")
42-
argparser.add_argument(
43-
"-M", "--marked_only", action="store_true",
44-
help="Add marked_only=1 to the end of the scenario (to be used after -T and -H)")
45-
argparser.add_argument(
46-
"-N", "--no_color", action="store_true",
47-
help="Add color=0 to the end of the scenario, this overrides color=1 of -T and -H")
48-
argparser.add_argument(
49-
"-X", "--extra", action="append",
50-
help="Add a specified parameter (or a block name) to the end of the scenario\n"
51-
"For example 'udapy -TNX attributes=form,misc -X layout=align < my.conllu'")
52-
argparser.add_argument(
53-
"--gc", action="store_true",
54-
help="By default, udapy disables Python garbage collection and at-exit cleanup\n"
55-
"to speed up everything (especially reading CoNLL-U files). In edge cases,\n"
56-
"when processing many files and running out of memory, you can disable this\n"
57-
"optimization (i.e. enable garbage collection) with 'udapy --gc'.")
58-
argparser.add_argument(
59-
'scenario', nargs=argparse.REMAINDER, help="A sequence of blocks and their parameters.")
60-
61-
args = argparser.parse_args()
62-
63-
# Set the level of logs according to parameters.
64-
if args.verbose:
65-
level = logging.DEBUG
66-
elif args.quiet:
67-
level = logging.CRITICAL
68-
else:
69-
level = logging.INFO
70-
71-
logging.basicConfig(format='%(asctime)-15s [%(levelname)7s] %(funcName)s - %(message)s',
72-
level=level)
73-
74-
# Global flag to track if an unhandled exception occurred
75-
_unhandled_exception_occurred = False
76-
77-
def _custom_excepthook(exc_type, exc_value, traceback):
78-
global _unhandled_exception_occurred
79-
_unhandled_exception_occurred = True
80-
81-
# Call the default excepthook to allow normal error reporting
82-
sys.__excepthook__(exc_type, exc_value, traceback)
83-
84-
# Override the default excepthook
85-
sys.excepthook = _custom_excepthook
86-
87-
88-
# Process and provide the scenario.
896
if __name__ == "__main__":
90-
91-
# Disabling garbage collections makes the whole processing much faster.
92-
# Similarly, we can save several seconds by partially disabling the at-exit Python cleanup
93-
# (atexit hooks are called in reversed order of their registration,
94-
# so flushing stdio buffers etc. will be still done before the os._exit(0) call).
95-
# See https://instagram-engineering.com/dismissing-python-garbage-collection-at-instagram-4dca40b29172
96-
# Is it safe to disable GC?
97-
# OS will free the memory allocated by this process after it ends anyway.
98-
# The udapy wrapper is aimed for one-time tasks, not a long-running server,
99-
# so in a typical case a document is loaded and almost no memory is freed before the end.
100-
# Udapi documents have a many cyclic references, so running GC is quite slow.
101-
if not args.gc:
102-
gc.disable()
103-
# When an exception/error has happened, udapy should exit with a non-zero exit code,
104-
# so that users can use `udapy ... || echo "Error detected"` (or Makefile reports errors).
105-
# However, we cannot use `atexit.register(lambda: os._exit(1 if sys.exc_info()[0] else 0))`
106-
# because the Python has already exited the exception-handling block
107-
# (the exception/error has been already reported and sys.exc_info()[0] is None).
108-
# We thus keep record whether _unhandled_exception_occurred.
109-
atexit.register(lambda: os._exit(1 if _unhandled_exception_occurred else 0))
110-
atexit.register(sys.stderr.flush)
111-
if args.save:
112-
args.scenario = args.scenario + ['write.Conllu']
113-
if args.save_text_mode_trees:
114-
args.scenario = args.scenario + ['write.TextModeTrees', 'color=1']
115-
if args.save_html:
116-
args.scenario = args.scenario + ['write.TextModeTreesHtml', 'color=1']
117-
if args.save_all_attributes:
118-
args.scenario = args.scenario + ['attributes=form,lemma,upos,xpos,feats,deprel,misc']
119-
if args.save_comments:
120-
args.scenario = args.scenario + ['print_comments=1']
121-
if args.marked_only:
122-
args.scenario = args.scenario + ['marked_only=1']
123-
if args.no_color:
124-
args.scenario = args.scenario + ['color=0']
125-
if args.extra:
126-
args.scenario += args.extra
127-
128-
runner = Run(args)
129-
# udapy is often piped to head etc., e.g.
130-
# `seq 1000 | udapy -s read.Sentences | head`
131-
# Let's prevent Python from reporting (with distracting stacktrace)
132-
# "BrokenPipeError: [Errno 32] Broken pipe"
133-
try:
134-
runner.execute()
135-
except BrokenPipeError:
136-
pass
7+
sys.exit(main())

pyproject.toml

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
11
[build-system]
2-
requires = [
3-
"setuptools>=42",
4-
"wheel"
5-
]
2+
requires = ["setuptools>=42", "wheel"]
63
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "udapi"
7+
version = "0.5.2"
8+
description = "Python framework for processing Universal Dependencies data"
9+
readme = "README.md"
10+
requires-python = ">=3.9"
11+
license = "GPL-3.0-or-later"
12+
authors = [
13+
{name = "Martin Popel", email = "popel@ufal.mff.cuni.cz"}
14+
]
15+
classifiers = [
16+
"Programming Language :: Python :: 3",
17+
"Operating System :: OS Independent",
18+
]
19+
dependencies = [
20+
"colorama",
21+
"termcolor",
22+
]
23+
24+
[project.urls]
25+
Homepage = "https://github.com/udapi/udapi-python"
26+
27+
[project.optional-dependencies]
28+
test = ["pytest"]
29+
udpipe = ["ufal.udpipe"]
30+
31+
[project.scripts]
32+
udapy = "udapi.cli:main"
33+
34+
[tool.setuptools]
35+
packages = {find = {}}
36+
include-package-data = true

setup.cfg

Lines changed: 0 additions & 29 deletions
This file was deleted.

setup.py

Lines changed: 0 additions & 4 deletions
This file was deleted.

tutorial/udapi-tutorial-dz.odt

642 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)