Skip to content

Commit 657f3cc

Browse files
committed
Add the ability to build parsing with mypyc
If called with `PARSING_USE_MYPYC=1` environment variable set, `setup.py` will now produce a compiled version of parser table generation code, which speeds it up by roughly a factor of two, reducing total EdgeDB parser table generation time to about 13 seconds.
1 parent bd2e59e commit 657f3cc

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

.github/workflows/test.yml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ on:
88
- "releases/*"
99
pull_request:
1010
branches:
11-
- '*'
11+
- "*"
1212

1313
jobs:
1414
test:
1515
runs-on: ubuntu-latest
1616
strategy:
1717
matrix:
1818
python-version: [3.7, 3.8, 3.9, 3.10.0-rc.1]
19+
build: ["mypyc", "pure-python"]
1920

2021
env:
2122
PIP_DISABLE_PIP_VERSION_CHECK: 1
@@ -27,6 +28,17 @@ jobs:
2728
with:
2829
python-version: ${{ matrix.python-version }}
2930
- name: Test
31+
env:
32+
PARSING_USE_MYPYC: "${{ matrix.build == 'mypyc' && '1' || '0' }}"
3033
run: |
3134
python -m pip install -e .[test]
3235
python -m unittest -v parsing.tests.suite
36+
37+
# This job exists solely to act as the test job aggregate to be
38+
# targeted by branch policies.
39+
regression-tests:
40+
name: "Regression Tests"
41+
needs: [test]
42+
runs-on: ubuntu-latest
43+
steps:
44+
- run: echo OK

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.pyc
22
*.pyo
3+
*.so
34
__pycache__/
45
/build
56
/dist
@@ -8,3 +9,4 @@ __pycache__/
89
/.eggs
910
/.vscode
1011
/.mypy_cache
12+
/.eggs

setup.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,83 @@
1+
import os
2+
import sys
3+
4+
from setuptools import extension as setuptools_ext
15
from setuptools import setup
6+
from setuptools.command import build_ext as setuptools_build_ext
27

38

49
extra = {}
510

611
f = open("README.rst", "r")
712
try:
813
extra["long_description"] = f.read()
14+
extra["long_description_content_type"] = "text/x-rst"
915
finally:
1016
f.close()
1117

1218

19+
USE_MYPYC = False
20+
MYPY_DEPENDENCY = "mypy>=0.910"
21+
setup_requires = []
22+
ext_modules = []
23+
24+
if (
25+
os.environ.get("PARSING_USE_MYPYC", None) in {"true", "1", "on"}
26+
or "--use-mypyc" in sys.argv
27+
):
28+
setup_requires.append(MYPY_DEPENDENCY)
29+
# Fool setuptools into calling build_ext. The actual list of
30+
# extensions would get replaced by mypycify.
31+
ext_modules.append(
32+
setuptools_ext.Extension("parsing.foo", ["parsing/foo.c"])
33+
)
34+
USE_MYPYC = True
35+
36+
37+
class build_ext(setuptools_build_ext.build_ext): # type: ignore
38+
def finalize_options(self) -> None:
39+
# finalize_options() may be called multiple times on the
40+
# same command object, so make sure not to override previously
41+
# set options.
42+
if getattr(self, "_initialized", False):
43+
return
44+
45+
if USE_MYPYC:
46+
import pkg_resources
47+
48+
# Double check Cython presence in case setup_requires
49+
# didn't go into effect (most likely because someone
50+
# imported Cython before setup_requires injected the
51+
# correct egg into sys.path.
52+
try:
53+
import mypy.version
54+
from mypyc.build import mypycify
55+
except ImportError:
56+
raise RuntimeError(
57+
"please install {} to compile parsing from source".format(
58+
MYPY_DEPENDENCY
59+
)
60+
)
61+
62+
mypy_dep = pkg_resources.Requirement.parse(MYPY_DEPENDENCY)
63+
if mypy.version.__version__ not in mypy_dep:
64+
raise RuntimeError(
65+
"parsing requires {}, got mypy=={}".format(
66+
MYPY_DEPENDENCY, mypy.version.__version__
67+
)
68+
)
69+
70+
self.distribution.ext_modules = mypycify(
71+
[
72+
"parsing/automaton.py",
73+
"parsing/grammar.py",
74+
],
75+
separate=True,
76+
)
77+
78+
super(build_ext, self).finalize_options()
79+
80+
1381
setup(
1482
name="parsing",
1583
version="2.0.0.dev0",
@@ -31,11 +99,14 @@
3199
],
32100
packages=["parsing", "parsing.tests", "parsing.tests.specs"],
33101
package_data={"parsing": ["py.typed"]},
102+
setup_requires=setup_requires,
103+
ext_modules=ext_modules,
34104
extras_require={
35105
"test": [
36106
"flake8",
37107
MYPY_DEPENDENCY,
38108
]
39109
},
110+
cmdclass={"build_ext": build_ext},
40111
**extra,
41112
)

0 commit comments

Comments
 (0)