Skip to content

Commit

Permalink
v0.14.0 - Add support for Python 3.8
Browse files Browse the repository at this point in the history
  • Loading branch information
atomflunder committed Jul 29, 2022
1 parent 649c143 commit 813de46
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10"]
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,11 @@ coverage.*
/dist/
/*.egg-info/
/*.eggs/
/wheelhouse/
/wheelhouse/

# Tox stuff
/.tox/

# Bytecode stuff
*.pyd
*.so
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

This is a broad overview of the changes that have been made over the lifespan of this library.

## v0.14.0 - 2022-07-29

- Added support for Python 3.8
- Support for 3.7 and below is unlikely since we make some use of the walrus operator
- 3.6 and below are EoL anyways and 3.7 is due to follow in 2023

## v0.13.0 - 2022-07-25

- Removed Levenshtein as a dependency and replaced it with RapidFuzz
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ What makes stringmatch special compared to other libraries with similar function

## Requirements

- Python 3.9 or later.
- The packages described in [`requirements.txt`](/requirements.txt), pip will usually handle these for you.
- Python 3.8 or later.
- The packages in [`requirements.txt`](/requirements.txt), pip will handle these for you.

## Installation

Expand Down
11 changes: 10 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,13 @@ line_length=88
profile="black"

[tool.cibuildwheel]
skip="pp*"
skip="pp*"

[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py310, py39, py38
[testenv]
deps = pytest
"""
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
ext_modules=mypycify(all_files), # type: ignore
version=version,
install_requires=required_packages,
python_requires=">=3.9",
python_requires=">=3.8",
setup_requires=["pytest-runner"],
tests_require=["pytest"],
test_suite="tests",
Expand All @@ -49,6 +49,7 @@
"License :: OSI Approved :: MIT License",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
],
Expand Down
2 changes: 1 addition & 1 deletion stringmatch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from stringmatch.strings import Strings

__title__ = "stringmatch"
__version__ = "0.13.0"
__version__ = "0.14.0"
__all__ = (
"Distance",
"Match",
Expand Down
10 changes: 5 additions & 5 deletions stringmatch/distance.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Optional

from rapidfuzz.distance.Levenshtein import distance

Expand Down Expand Up @@ -30,19 +30,19 @@ def distance(self, string1: str, string2: str) -> Optional[int]:
"""
return distance(string1, string2) if string1 and string2 else None

def distance_list(self, string: str, string_list: list[str]) -> list[Optional[int]]:
def distance_list(self, string: str, string_list: List[str]) -> List[Optional[int]]:
"""Returns the levenshtein distance for a string and a list of strings.
Parameters
----------
string : str
The string to compare.
string_list : list[str]
The list of strings to compare to.
string_list : List[str]
The List of strings to compare to.
Returns
-------
list[Optional[int]]
List[Optional[int]]
The levenshtein distances between the two strings.
Examples
Expand Down
50 changes: 25 additions & 25 deletions stringmatch/match.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Optional
from typing import List, Optional, Tuple, Type

from stringmatch.ratio import Ratio
from stringmatch.scorer import BaseScorer, LevenshteinScorer
Expand All @@ -10,7 +10,7 @@ class Match:
def __init__(
self,
*,
scorer: type[BaseScorer] = LevenshteinScorer,
scorer: Type[BaseScorer] = LevenshteinScorer,
latinise: bool = False,
ignore_case: bool = True,
remove_punctuation: bool = False,
Expand All @@ -21,7 +21,7 @@ def __init__(
Parameters
----------
scorer : type[BaseScorer], optional
scorer : Type[BaseScorer], optional
The scoring algorithm to use, by default LevenshteinScorer
Available scorers: LevenshteinScorer, JaroScorer, JaroWinklerScorer.
latinise : bool, optional
Expand All @@ -44,7 +44,7 @@ def __init__(
--------
>>> Match(latninise=True, scorer=JaroScorer, include_partial=True)
"""
self.scorer: type[BaseScorer] = scorer
self.scorer: Type[BaseScorer] = scorer
self.latinise: bool = latinise
self.ignore_case: bool = ignore_case
self.remove_punctuation: bool = remove_punctuation
Expand Down Expand Up @@ -79,7 +79,7 @@ def match(self, string1: str, string2: str, *, score: int = 70) -> bool:

def match_with_ratio(
self, string1: str, string2: str, *, score: int = 70
) -> tuple[bool, int]:
) -> Tuple[bool, int]:
"""Same as match, but returns the boolean in a tuple, together with the score.
Parameters
Expand All @@ -93,7 +93,7 @@ def match_with_ratio(
Returns
-------
tuple[bool, int]
Tuple[bool, int]
If the strings are similar and their score.
Examples
Expand All @@ -115,16 +115,16 @@ def match_with_ratio(
return (r >= score, r)

def get_best_match(
self, string: str, string_list: list[str], *, score: int = 70
self, string: str, string_list: List[str], *, score: int = 70
) -> Optional[str]:
"""Returns the best match from a list of strings.
Parameters
----------
string : str
The string to compare.
string_list : list[str]
The list of strings to compare to.
string_list : List[str]
The List of strings to compare to.
score : int, optional
The cutoff for the score, by default 70.
Expand All @@ -138,23 +138,23 @@ def get_best_match(
>>> get_best_match("stringmatch", ["strmatch", "test", "something else"])
'strmatch'
"""
match: Optional[tuple[str, int]] = self.get_best_match_with_ratio(
match: Optional[Tuple[str, int]] = self.get_best_match_with_ratio(
string, string_list, score=score
)

return match[0] if match else None

def get_best_match_with_ratio(
self, string: str, string_list: list[str], *, score: int = 70
) -> Optional[tuple[str, int]]:
self, string: str, string_list: List[str], *, score: int = 70
) -> Optional[Tuple[str, int]]:
"""Same as get_best_match, but returns a tuple with the best match and its score.
Parameters
----------
string : str
The string to compare.
string_list : list[str]
The list of strings to compare to.
string_list : List[str]
The List of strings to compare to.
score : int, optional
The cutoff for the score, by default 70.
Expand All @@ -177,7 +177,7 @@ def get_best_match_with_ratio(
include_partial=self.include_partial,
)

matches: list[tuple[str, int]] = sorted(
matches: List[Tuple[str, int]] = sorted(
# We only add the entry to the list if the ratio is above the cutoff score.
[(s, r) for s in string_list if (r := ratio.ratio(string, s)) >= score],
key=lambda x: (
Expand All @@ -201,11 +201,11 @@ def get_best_match_with_ratio(
def get_best_matches(
self,
string: str,
string_list: list[str],
string_list: List[str],
*,
score: int = 70,
limit: Optional[int] = 5,
) -> list[str]:
) -> List[str]:
"""Matches a string to a list of strings, returns the strings found that are similar.
If there are more than `limit` matches,
only the `limit` best matches are returned, sorted by score.
Expand All @@ -215,8 +215,8 @@ def get_best_matches(
----------
string : str
The string to compare.
string_list : list[str]
The list of strings to compare to.
string_list : List[str]
The List of strings to compare to.
score : int, optional
The cutoff for the score, by default 70.
limit : int, optional
Expand All @@ -225,7 +225,7 @@ def get_best_matches(
Returns
-------
list[str]
List[str]
All of the matches found.
Examples
Expand All @@ -248,19 +248,19 @@ def get_best_matches(
def get_best_matches_with_ratio(
self,
string: str,
string_list: list[str],
string_list: List[str],
*,
score: int = 70,
limit: Optional[int] = 5,
) -> list[tuple[str, int]]:
) -> List[Tuple[str, int]]:
"""Same as get_best_matches, but returns a list of tuples with the best matches and their score.
Parameters
----------
string : str
The string to compare.
string_list : list[str]
The list of strings to compare to.
string_list : List[str]
The List of strings to compare to.
score : int, optional
The cutoff for the score, by default 70.
limit : int, optional
Expand All @@ -269,7 +269,7 @@ def get_best_matches_with_ratio(
Returns
-------
list[tuple[str, int]]
List[tuple[str, int]]
All of the matches found.
Examples
Expand Down
22 changes: 12 additions & 10 deletions stringmatch/ratio.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List, Tuple, Type

from rapidfuzz.distance import Levenshtein, MatchingBlock

from stringmatch.scorer import BaseScorer, LevenshteinScorer
Expand All @@ -10,7 +12,7 @@ class Ratio:
def __init__(
self,
*,
scorer: type[BaseScorer] = LevenshteinScorer,
scorer: Type[BaseScorer] = LevenshteinScorer,
latinise: bool = False,
ignore_case: bool = True,
remove_punctuation: bool = False,
Expand All @@ -21,7 +23,7 @@ def __init__(
Parameters
----------
scorer : type[BaseScorer], optional
scorer : Type[BaseScorer], optional
The scoring algorithm to use, by default LevenshteinScorer
Available scorers: LevenshteinScorer, JaroScorer, JaroWinklerScorer.
latinise : bool, optional
Expand All @@ -44,14 +46,14 @@ def __init__(
--------
>>> Ratio(latninise=True, scorer=JaroScorer, include_partial=True)
"""
self.scorer: type[BaseScorer] = scorer
self.scorer: Type[BaseScorer] = scorer
self.latinise: bool = latinise
self.ignore_case: bool = ignore_case
self.remove_punctuation: bool = remove_punctuation
self.alphanumeric: bool = alphanumeric
self.include_partial: bool = include_partial

def _prepare_strings(self, string1: str, string2: str) -> tuple[str, str]:
def _prepare_strings(self, string1: str, string2: str) -> Tuple[str, str]:
"""Modifies the strings to be ready for comparison, according to the settings.
Only meant for internal usage, but feel free to use it for something else.
Expand All @@ -64,7 +66,7 @@ def _prepare_strings(self, string1: str, string2: str) -> tuple[str, str]:
Returns
-------
tuple[str, str]
Tuple[str, str]
The two modified strings.
Examples
Expand Down Expand Up @@ -130,19 +132,19 @@ def ratio(self, string1: str, string2: str) -> int:

return round(self.scorer().score(string1, string2))

def ratio_list(self, string: str, string_list: list[str]) -> list[int]:
def ratio_list(self, string: str, string_list: List[str]) -> List[int]:
"""Returns the similarity score between a string and a list of strings.
Parameters
----------
string : str
The string to compare.
string_list : list[str]
string_list : List[str]
The list of strings to compare to.
Returns
-------
list[int]
List[int]
The scores between 0 and 100.
Examples
Expand Down Expand Up @@ -188,7 +190,7 @@ def partial_ratio(self, string1: str, string2: str) -> int:
else:
longer_string, shorter_string = string2, string1

blocks: list[MatchingBlock] = [
blocks: List[MatchingBlock] = [
block
for block in Levenshtein.editops(
longer_string, shorter_string
Expand All @@ -215,7 +217,7 @@ def partial_ratio(self, string1: str, string2: str) -> int:
# We want to reserve a score of 100 for perfect matches.
multiplier = 0.95

scores: list[int] = []
scores: List[int] = []

for block in blocks:
start: int = max((block.a - block.b), 0)
Expand Down

0 comments on commit 813de46

Please sign in to comment.