Skip to content

Commit

Permalink
generate import handling
Browse files Browse the repository at this point in the history
  • Loading branch information
maxbachmann committed Jan 15, 2025
1 parent dbfb7ce commit 90811df
Show file tree
Hide file tree
Showing 50 changed files with 1,780 additions and 335 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ BraceWrapping:
AllowAllConstructorInitializersOnNextLine: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
AllowShortCaseLabelsOnASingleLine: true
SortIncludes: false
8 changes: 4 additions & 4 deletions .github/workflows/branchbuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
- name: Generate cython
run: |
chmod +x ./src/rapidfuzz/generate.sh
./src/rapidfuzz/generate.sh
chmod +x ./tools/generate_cython.sh
./tools/generate_cython.sh
- name: build
run: |
Expand Down Expand Up @@ -60,7 +60,7 @@ jobs:
run: |
git clone https://github.com/rapidfuzz/rapidfuzz-cpp.git
cd rapidfuzz-cpp
git checkout v3.1.1
git checkout v3.2.0
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
run: |
git clone https://github.com/rapidfuzz/rapidfuzz-cpp.git
cd rapidfuzz-cpp
git checkout v3.1.1
git checkout v3.2.0
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build .
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
- name: Generate cython
run: |
chmod +x ./src/rapidfuzz/generate.sh
./src/rapidfuzz/generate.sh
chmod +x ./tools/generate_cython.sh
./tools/generate_cython.sh
# for cython tests inplace installation is required
- name: build
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/releasebuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
# The cythonized files allow installation from the sdist without cython
- name: Generate cython
run: |
chmod +x ./src/rapidfuzz/generate.sh
./src/rapidfuzz/generate.sh
chmod +x ./tools/generate_cython.sh
./tools/generate_cython.sh
- name: Build sdist
run: |
Expand Down
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#
# See https://github.com/pre-commit/pre-commit

exclude: |
(?x)(
tools/sdist.patch
)
repos:
# Standard hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
4 changes: 2 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Added
Fixed
~~~~~
- drop support for Python 3.8
- switch build system to `scikit-build-core`
- switch build system to ``scikit-build-core``

[3.9.7] - 2024-09-02
^^^^^^^^^^^^^^^^^^^^
Expand All @@ -47,7 +47,7 @@ Changed
Fixed
~~~~~
* include simd binaries in pyinstaller builds
* fix builds with setuptools 72 by upgrading `scikit-build`
* fix builds with setuptools 72 by upgrading ``scikit-build``

[3.9.4] - 2024-07-02
^^^^^^^^^^^^^^^^^^^^
Expand Down
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ endif()
if(MSVC)
add_compile_options(/W4 /bigobj /wd4127)

# NOTE: _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR is temporary. When building on
# VS 2022 17.10 or newer, but using an older runtime, mutexes can crash
# NOTE: _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR is temporary. When building on VS
# 2022 17.10 or newer, but using an older runtime, mutexes can crash
add_compile_options(/D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
else()
add_compile_options(-Wall -Wextra -pedantic -Wno-psabi)
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ wheel.exclude = [
"**.cpp",
"**.hpp",
"**.h",
"CMakeLists.txt",
"generate.sh"
"CMakeLists.txt"
]
wheel.packages = ["src/rapidfuzz"]
wheel.cmake = false
Expand Down Expand Up @@ -162,7 +161,6 @@ select = [
extend-ignore = [
"PLR", # Design related pylint codes
"E501", # Line too long
"PT004", # Use underscore for non-returning fixture (use usefixture instead)
"PTH123", # use pathlib instead of builtin open
]
unfixable = [
Expand All @@ -171,6 +169,7 @@ unfixable = [
]
flake8-unused-arguments.ignore-variadic-names = true
isort.required-imports = ["from __future__ import annotations"]
isort.combine-as-imports = true

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["T20"]
Expand Down
4 changes: 2 additions & 2 deletions src/rapidfuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ function(create_cython_target _name)
VERBATIM
COMMAND
Python::Interpreter -m cython "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx"
--cplus -I "${CMAKE_CURRENT_LIST_DIR}"
--output-file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx")
--cplus -I "${CMAKE_CURRENT_LIST_DIR}" --output-file
"${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx")

set(${_name}
${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx
Expand Down
10 changes: 6 additions & 4 deletions src/rapidfuzz/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ __author__: str
__license__: str
__version__: str

from rapidfuzz import distance as distance
from rapidfuzz import fuzz as fuzz
from rapidfuzz import process as process
from rapidfuzz import utils as utils
from rapidfuzz import (
distance as distance,
fuzz as fuzz,
process as process,
utils as utils,
)
1 change: 1 addition & 0 deletions src/rapidfuzz/__pyinstaller/hook-rapidfuzz.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@


def filterUnneededImports(name):
return False
if "__pyinstaller" in name:
return False

Expand Down
2 changes: 1 addition & 1 deletion src/rapidfuzz/_common_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from __future__ import annotations

from array import array
from typing import Hashable, Sequence
from collections.abc import Hashable, Sequence


def conv_sequence(s: Sequence[Hashable]) -> Sequence[Hashable]:
Expand Down
64 changes: 0 additions & 64 deletions src/rapidfuzz/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@

from __future__ import annotations

import importlib
import os
import sys
from math import isnan
from typing import Any, Callable

from rapidfuzz._feature_detector import AVX2, SSE2, supports

pandas_NA = None


Expand Down Expand Up @@ -80,66 +76,6 @@ def add_scorer_attrs(func: Any, cached_scorer_call: dict[str, Callable[..., dict
func._RF_OriginalScorer = func


def optional_import_module(module: str) -> Any:
"""
try to import module. Return None on failure
"""
try:
return importlib.import_module(module)
except Exception:
return None


def vectorized_import(name: str) -> tuple[Any, list[Any]]:
"""
import module best fitting for current CPU
"""
if supports(AVX2):
module = optional_import_module(name + "_avx2")
if module is not None:
return module
if supports(SSE2):
module = optional_import_module(name + "_sse2")
if module is not None:
return module

return importlib.import_module(name)


def fallback_import(
module: str,
name: str,
) -> Any:
"""
import library function and possibly fall back to a pure Python version
when no C++ implementation is available
"""
impl = os.environ.get("RAPIDFUZZ_IMPLEMENTATION")

py_mod = importlib.import_module(module + "_py")
py_func = getattr(py_mod, name)
if not py_func:
msg = f"cannot import name {name!r} from {py_mod.__name!r} ({py_mod.__file__})"
raise ImportError(msg)

if impl == "cpp":
cpp_mod = vectorized_import(module + "_cpp")
elif impl == "python":
return py_func
else:
try:
cpp_mod = vectorized_import(module + "_cpp")
except Exception:
return py_func

cpp_func = getattr(cpp_mod, name)
if not cpp_func:
msg = f"cannot import name {name!r} from {cpp_mod.__name!r} ({cpp_mod.__file__})"
raise ImportError(msg)

return cpp_func


default_distance_attribute: dict[str, Callable[..., dict[str, Any]]] = {"get_scorer_flags": _get_scorer_flags_distance}
default_similarity_attribute: dict[str, Callable[..., dict[str, Any]]] = {
"get_scorer_flags": _get_scorer_flags_similarity
Expand Down
4 changes: 2 additions & 2 deletions src/rapidfuzz/distance/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ function(create_cython_target _name)
VERBATIM
COMMAND
Python::Interpreter -m cython "${CMAKE_CURRENT_LIST_DIR}/${_name}.pyx"
--cplus -I "${CMAKE_CURRENT_LIST_DIR}/.."
--output-file "${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx")
--cplus -I "${CMAKE_CURRENT_LIST_DIR}/.." --output-file
"${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx")

set(${_name}
${CMAKE_CURRENT_BINARY_DIR}/${_name}.cxx
Expand Down
95 changes: 88 additions & 7 deletions src/rapidfuzz/distance/DamerauLevenshtein.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,92 @@
# SPDX-License-Identifier: MIT
# Copyright (C) 2022 Max Bachmann
# Copyright (C) 2025 Max Bachmann
from __future__ import annotations

from rapidfuzz._utils import fallback_import as _fallback_import
import contextlib
import os

_mod = "rapidfuzz.distance.metrics"
distance = _fallback_import(_mod, "damerau_levenshtein_distance")
similarity = _fallback_import(_mod, "damerau_levenshtein_similarity")
normalized_distance = _fallback_import(_mod, "damerau_levenshtein_normalized_distance")
normalized_similarity = _fallback_import(_mod, "damerau_levenshtein_normalized_similarity")
from rapidfuzz._feature_detector import AVX2, SSE2, supports

__all__ = ["distance", "normalized_distance", "normalized_similarity", "similarity"]

_impl = os.environ.get("RAPIDFUZZ_IMPLEMENTATION")
if _impl == "cpp":
imported = False
if supports(AVX2):
with contextlib.suppress(ImportError):
from rapidfuzz.distance.metrics_cpp_avx2 import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)

imported = True

if not imported and supports(SSE2):
with contextlib.suppress(ImportError):
from rapidfuzz.distance.metrics_cpp_sse2 import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)

imported = True

if not imported:
from rapidfuzz.distance.metrics_cpp import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)
elif _impl == "python":
from rapidfuzz.distance.metrics_py import (
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)
else:
imported = False
if supports(AVX2):
with contextlib.suppress(ImportError):
from rapidfuzz.distance.metrics_cpp_avx2 import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)

imported = True

if not imported and supports(SSE2):
with contextlib.suppress(ImportError):
from rapidfuzz.distance.metrics_cpp_sse2 import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)

imported = True

if not imported:
with contextlib.suppress(ImportError):
from rapidfuzz.distance.metrics_cpp import ( # pyright: ignore[reportMissingImports]
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)

imported = True

if not imported:
from rapidfuzz.distance.metrics_py import (
damerau_levenshtein_distance as distance,
damerau_levenshtein_normalized_distance as normalized_distance,
damerau_levenshtein_normalized_similarity as normalized_similarity,
damerau_levenshtein_similarity as similarity,
)
3 changes: 2 additions & 1 deletion src/rapidfuzz/distance/DamerauLevenshtein.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

from __future__ import annotations

from typing import Callable, Hashable, Sequence, TypeVar, overload
from collections.abc import Hashable, Sequence
from typing import Callable, TypeVar, overload

_UnprocessedType1 = TypeVar("_UnprocessedType1")
_UnprocessedType2 = TypeVar("_UnprocessedType2")
Expand Down
Loading

0 comments on commit 90811df

Please sign in to comment.