Skip to content

Commit d4e7ff2

Browse files
authored
Refactor implementation (#17)
* Use a faster editops implementation provided by RapidFuzz * Fixed memory leak in error path of setratio * Reduce code duplication * reuse implementations from rapidfuzz-cpp * Transition to scikit-build
1 parent 7f35ced commit d4e7ff2

File tree

19 files changed

+2239
-17835
lines changed

19 files changed

+2239
-17835
lines changed

.github/workflows/pythonbuild.yml

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,30 @@ on:
88
- published
99

1010
jobs:
11-
build_wheels:
12-
name: Build wheel on ${{ matrix.os }}/auto/${{matrix.python_tag}}
13-
runs-on: ${{ matrix.os }}
11+
build_wheels_windows:
12+
name: Build wheel on windows-latest/${{matrix.arch}}/${{matrix.python_tag}}
13+
runs-on: windows-latest
1414
strategy:
1515
fail-fast: false
1616
matrix:
17-
python_tag: ["cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*"]
18-
os: [windows-latest, macos-latest]
17+
arch: [auto32, auto64]
18+
python_tag: ["cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*", "pp37-*", "pp38-*"]
19+
exclude:
20+
# PyPy only supports x86_64 on Windows
21+
- arch: auto32
22+
python_tag: "pp37-*"
23+
- arch: auto32
24+
python_tag: "pp38-*"
25+
26+
# PyPy Windows is currently broken in scikit-build
27+
- arch: auto64
28+
python_tag: "pp37-*"
29+
- arch: auto64
30+
python_tag: "pp38-*"
1931
env:
2032
CIBW_BUILD: ${{matrix.python_tag}}
21-
CIBW_TEST_REQUIRES: pytest hypothesis
33+
CIBW_ARCHS: ${{matrix.arch}}
34+
CIBW_TEST_REQUIRES: pytest hypothesis pandas
2235
CIBW_TEST_COMMAND: pytest {package}/tests
2336
CIBW_BUILD_VERBOSITY: 3
2437

@@ -27,6 +40,8 @@ jobs:
2740
with:
2841
submodules: 'true'
2942

43+
- uses: actions/setup-python@v2
44+
3045
- name: Build wheels
3146
uses: pypa/cibuildwheel@v2.3.1
3247
with:
@@ -37,19 +52,39 @@ jobs:
3752
with:
3853
path: ./wheelhouse/*.whl
3954

40-
build_wheels_apple_silicon:
41-
name: Build wheel on macos-latest/universal2+arm64/${{matrix.python_tag}}
55+
build_wheels_macos:
56+
name: Build wheel on macos-latest/${{matrix.arch}}/${{matrix.python_tag}}
4257
runs-on: macos-latest
4358
strategy:
4459
fail-fast: false
4560
matrix:
46-
python_tag: ["cp38-*", "cp39-*", "cp310-*"]
61+
arch: [x86_64, arm64, universal2]
62+
python_tag: ["cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*"]
63+
exclude:
64+
# MacOS Arm only supported since Python 3.8
65+
- arch: arm64
66+
python_tag: "cp36-*"
67+
- arch: arm64
68+
python_tag: "cp37-*"
69+
- arch: universal2
70+
python_tag: "cp36-*"
71+
- arch: universal2
72+
python_tag: "cp37-*"
73+
env:
74+
CIBW_BUILD: ${{matrix.python_tag}}
75+
CIBW_ARCHS: ${{matrix.arch}}
76+
CIBW_TEST_SKIP: "*-macosx_{arm64,universal2}"
77+
CIBW_TEST_REQUIRES: pytest hypothesis pandas
78+
CIBW_TEST_COMMAND: pytest {package}/tests
79+
CIBW_BUILD_VERBOSITY: 3
4780

4881
steps:
4982
- uses: actions/checkout@v2
5083
with:
5184
submodules: 'true'
5285

86+
- uses: actions/setup-python@v2
87+
5388
- name: Build wheels
5489
uses: pypa/cibuildwheel@v2.3.1
5590
with:
@@ -60,20 +95,30 @@ jobs:
6095
with:
6196
path: ./wheelhouse/*.whl
6297

63-
build_wheels_manylinux:
98+
build_wheels_linux:
6499
name: Build wheels on ubuntu-latest/${{matrix.arch}}/${{matrix.python_tag}}
65100
runs-on: ubuntu-latest
66101
strategy:
67102
fail-fast: false
68103
matrix:
69104
arch: [auto, aarch64, ppc64le, s390x]
70-
python_tag: ["cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*"]
105+
python_tag: [ "cp36-*", "cp37-*", "cp38-*", "cp39-*", "cp310-*", "pp37-*", "pp38-*"]
106+
exclude:
107+
# PyPy builds not supported on ppc64le / s390x
108+
- arch: ppc64le
109+
python_tag: "pp37-*"
110+
- arch: ppc64le
111+
python_tag: "pp38-*"
112+
- arch: s390x
113+
python_tag: "pp37-*"
114+
- arch: s390x
115+
python_tag: "pp38-*"
71116
env:
72117
CIBW_ARCHS_LINUX: ${{matrix.arch}}
73118
CIBW_BUILD: ${{matrix.python_tag}}
74119
CIBW_SKIP: "*musllinux_*"
75120
CIBW_TEST_SKIP: "*-manylinux_{aarch64,ppc64le,s390x}"
76-
CIBW_TEST_REQUIRES: pytest hypothesis
121+
CIBW_TEST_REQUIRES: pytest hypothesis pandas
77122
CIBW_TEST_COMMAND: pytest {package}/tests
78123
CIBW_BUILD_VERBOSITY: 3
79124

@@ -82,6 +127,8 @@ jobs:
82127
with:
83128
submodules: 'true'
84129

130+
- uses: actions/setup-python@v2
131+
85132
- uses: docker/setup-qemu-action@v1
86133
name: Set up QEMU
87134

@@ -95,33 +142,6 @@ jobs:
95142
with:
96143
path: ./wheelhouse/*.whl
97144

98-
#build_wheels_pypy:
99-
# name: Build wheel on ${{ matrix.os }}/auto/${{matrix.python_tag}}
100-
# runs-on: ${{ matrix.os }}
101-
# strategy:
102-
# fail-fast: false
103-
# matrix:
104-
# python_tag: ["pp37-*"]
105-
# os: [ubuntu-latest, windows-latest, macos-latest]
106-
# env:
107-
# CIBW_BUILD: ${{matrix.python_tag}}
108-
# CIBW_BUILD_VERBOSITY: 3
109-
#
110-
# steps:
111-
# - uses: actions/checkout@v2
112-
# with:
113-
# submodules: 'true'
114-
#
115-
# - name: Build wheels
116-
# uses: pypa/cibuildwheel@v2.1.1
117-
# with:
118-
# output-dir: wheelhouse
119-
#
120-
# - name: Upload wheels
121-
# uses: actions/upload-artifact@v2
122-
# with:
123-
# path: ./wheelhouse/*.whl
124-
125145
build_sdist:
126146
name: Build source distribution
127147
runs-on: ubuntu-latest
@@ -148,7 +168,7 @@ jobs:
148168

149169
deploy-wheels:
150170
if: github.event_name == 'release' && github.event.action == 'published'
151-
needs: [build_wheels_apple_silicon, build_wheels_manylinux, build_sdist]
171+
needs: [build_wheels_windows, build_wheels_macos, build_wheels_linux, build_sdist]
152172
name: deploy wheels to pypi
153173
runs-on: ubuntu-18.04
154174

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,7 @@ dmypy.json
135135
.pytype/
136136

137137
# Cython debug symbols
138-
cython_debug/
138+
cython_debug/
139+
140+
# vscode
141+
.vscode/

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "extern/rapidfuzz-cpp"]
2+
path = extern/rapidfuzz-cpp
3+
url = ../../maxbachmann/rapidfuzz-cpp.git

CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cmake_minimum_required(VERSION 3.12.0)
2+
3+
cmake_policy(SET CMP0054 NEW)
4+
set(SKBUILD_LINK_LIBRARIES_KEYWORD PRIVATE)
5+
6+
set(THREADS_PREFER_PTHREAD_FLAG ON)
7+
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
8+
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.9" CACHE STRING "Minimum OS X deployment version")
9+
endif()
10+
11+
project(Levenshtein LANGUAGES C CXX)
12+
13+
if (MSVC)
14+
add_compile_options(/W4)
15+
else()
16+
add_compile_options(-Wall -Wextra -pedantic)
17+
endif()
18+
19+
find_package(PythonExtensions REQUIRED)
20+
find_package(Python COMPONENTS Interpreter Development)
21+
find_package(Cython REQUIRED)
22+
add_subdirectory(extern/rapidfuzz-cpp)
23+
24+
set(LEV_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
25+
26+
add_subdirectory(src/cython)

HISTORY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
## Changelog
22

3+
### v0.18.0
4+
* Use a faster editops implementation provided by RapidFuzz
5+
* Fixed memory leak in error path of setratio
6+
* Reduce code duplication
7+
* reuse implementations from rapidfuzz-cpp
8+
* Transition to scikit-build
9+
310
### v0.17.0
411
* Removed support for Python 3.5
512

MANIFEST.in

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
recursive-include src/ *.cpp *.c *.h *.hpp *.py
1+
include setup.py
2+
include CMakeLists.txt
23
include README.md
3-
include HISTORY.md
44
include COPYING
5-
global-exclude *pyc
6-
global-exclude *so
7-
global-exclude .project
8-
global-exclude .pydevproject
5+
include HISTORY.md
6+
include pyproject.toml
7+
include src/rapidfuzz/**/*.pyi
8+
include src/rapidfuzz/py.typed
9+
10+
recursive-include src/cython CMakeLists.txt
11+
recursive-include src/cython *.hpp *.h *.cpp *.pyx *.pxd
12+
13+
include extern/rapidfuzz-cpp/LICENSE
14+
include extern/rapidfuzz-cpp/CMakeLists.txt
15+
recursive-include extern/rapidfuzz-cpp/rapidfuzz *.hpp *.impl

extern/rapidfuzz-cpp

Submodule rapidfuzz-cpp added at 2876ffe

pyproject.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[build-system]
2+
requires = [
3+
"setuptools",
4+
"wheel",
5+
"scikit-build>=0.13.0",
6+
"cmake",
7+
"ninja; platform_system!='Windows'",
8+
"Cython==3.0.0a10"
9+
]
10+
build-backend = "setuptools.build_meta"

setup.cfg

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

setup.py

Lines changed: 30 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,34 @@
1-
from setuptools import setup, Extension
2-
from setuptools.command.build_ext import build_ext
3-
import sys
1+
from skbuild import setup
42

5-
class BuildExt(build_ext):
6-
"""A custom build extension for adding compiler-specific options."""
7-
c_opts = {
8-
'msvc': ['/EHsc', '/O2', '/W4'],
9-
'unix': ['-O3', '-Wextra', '-Wall', '-Wconversion', '-g0'],
10-
}
11-
l_opts = {
12-
'msvc': [],
13-
'unix': [],
14-
}
3+
with open('README.md', 'rt', encoding="utf8") as f:
4+
readme = f.read()
155

16-
def build_extensions(self):
17-
ct = self.compiler.compiler_type
18-
opts = self.c_opts.get(ct, [])
19-
link_opts = self.l_opts.get(ct, [])
20-
if ct == 'unix':
21-
opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version())
22-
elif ct == 'msvc':
23-
opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version())
24-
for ext in self.extensions:
25-
ext.extra_compile_args += opts
26-
ext.extra_link_args += link_opts
27-
build_ext.build_extensions(self)
6+
setup(
7+
name="Levenshtein",
8+
version="0.18.0",
9+
url="https://github.com/maxbachmann/Levenshtein",
10+
author="Max Bachmann",
11+
install_requires=["rapidfuzz >= 2.0, < 3.0"],
12+
author_email="contact@maxbachmann.de",
13+
description="Python extension for computing string edit distances and similarities.",
14+
long_description=readme,
15+
long_description_content_type="text/markdown",
2816

29-
ext_modules = [
30-
Extension(
31-
name='Levenshtein._levenshtein',
32-
sources=[
33-
'src/Levenshtein-c/_levenshtein.c',
34-
'src/_levenshtein.c'
35-
],
36-
include_dirs=[
37-
"src/Levenshtein-c/",
38-
]
39-
),
40-
Extension(
41-
name='Levenshtein.c_levenshtein',
42-
sources=[
43-
'src/Levenshtein-c/_levenshtein.c',
44-
'src/c_levenshtein.c'
45-
],
46-
include_dirs=[
47-
"src/Levenshtein-c/",
48-
]
49-
),
50-
]
17+
license="GPL",
18+
license_file = "COPYING",
19+
classifiers=[
20+
"Programming Language :: Python :: 3",
21+
"Programming Language :: Python :: 3.6",
22+
"Programming Language :: Python :: 3.7",
23+
"Programming Language :: Python :: 3.8",
24+
"Programming Language :: Python :: 3.9",
25+
"Programming Language :: Python :: 3.10",
26+
"License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)"
27+
],
5128

52-
if __name__ == "__main__":
53-
setup(
54-
cmdclass={'build_ext': BuildExt},
55-
ext_modules = ext_modules
56-
)
29+
packages=["Levenshtein"],
30+
package_dir={'':'src'},
31+
zip_safe=True,
32+
include_package_data=True,
33+
python_requires=">=3.6"
34+
)

0 commit comments

Comments
 (0)