Skip to content

Commit 10946df

Browse files
committed
add python 2.7 support
1 parent a780018 commit 10946df

File tree

14 files changed

+239
-229
lines changed

14 files changed

+239
-229
lines changed

.github/workflows/pythonbuild.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
runs-on: ubuntu-latest
1414
strategy:
1515
matrix:
16-
python-version: [3.5, 3.6, 3.7, 3.8]
16+
python-version: [2.7, 3.5, 3.6, 3.7, 3.8]
1717

1818
steps:
1919
- uses: actions/checkout@v2
@@ -34,9 +34,9 @@ jobs:
3434
run: |
3535
pip install flake8
3636
# stop the build if there are Python syntax errors or undefined names
37-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
37+
flake8 src --count --select=E9,F63,F7,F82 --show-source --statistics
3838
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
39-
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
39+
flake8 src --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
4040
4141
- name: Run Unit Tests
4242
run: |
@@ -53,7 +53,7 @@ jobs:
5353
matrix:
5454
os: [ubuntu-18.04, windows-latest, macos-latest]
5555
env:
56-
CIBW_SKIP: cp27-* pp27-*
56+
CIBW_SKIP: cp27-win* pp27-win*
5757

5858
steps:
5959
- uses: actions/checkout@v1

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,6 @@ recursive-include src/rapidfuzz-cpp/extern/nonstd *
1111

1212
recursive-include extern/variant *
1313
include src/py_utils.hpp
14+
include src/py2_utils.hpp
15+
include src/py3_utils.hpp
1416
include src/rapidfuzz-cpp/LICENSE

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.10.0
1+
0.11.0

setup.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import sys
44

55
from os import path
6+
from io import open
7+
68
this_dir = path.abspath(path.dirname(__file__))
79
with open(path.join(this_dir, "VERSION"), encoding='utf-8') as version_file:
810
version = version_file.read().strip()
@@ -76,6 +78,8 @@ def build_extensions(self):
7678
include_package_data=True,
7779
zip_safe=False,
7880
classifiers=[
81+
"Programming Language :: Python :: 2",
82+
"Programming Language :: Python :: 2.7",
7983
"Programming Language :: Python :: 3",
8084
"Programming Language :: Python :: 3.5",
8185
"Programming Language :: Python :: 3.6",
@@ -84,5 +88,5 @@ def build_extensions(self):
8488
"Programming Language :: Python :: 3.9",
8589
"License :: OSI Approved :: MIT License",
8690
],
87-
python_requires=">=3.5",
91+
python_requires=">=2.7",
8892
)

src/py2_utils.hpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* Copyright © 2020 Max Bachmann */
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
#include <nonstd/string_view.hpp>
7+
#include <variant/variant.hpp>
8+
9+
bool valid_str(PyObject* str, const char* name) {
10+
if (!PyObject_TypeCheck(str, &PyString_Type)
11+
&& !PyObject_TypeCheck(str, &PyUnicode_Type))
12+
{
13+
PyErr_Format(PyExc_TypeError, "%s must be a String, Unicode or None", name);
14+
return false;
15+
}
16+
return true;
17+
}
18+
19+
#define PY_INIT_MOD(name, doc, methods) \
20+
PyMODINIT_FUNC init##name(void) { \
21+
Py_InitModule3(#name, methods, doc); \
22+
}
23+
24+
using python_string_view = mpark::variant<
25+
nonstd::basic_string_view<uint8_t>,
26+
nonstd::basic_string_view<Py_UNICODE>
27+
>;
28+
29+
python_string_view decode_python_string(PyObject* py_str) {
30+
if (PyObject_TypeCheck(py_str, &PyString_Type)) {
31+
Py_ssize_t len = PyString_GET_SIZE(py_str);
32+
uint8_t* str = reinterpret_cast<uint8_t*>(PyString_AS_STRING(py_str));
33+
return nonstd::basic_string_view<uint8_t>(str, len);
34+
35+
} else {
36+
Py_ssize_t len = PyUnicode_GET_SIZE(py_str);
37+
Py_UNICODE* str = PyUnicode_AS_UNICODE(py_str);
38+
return nonstd::basic_string_view<Py_UNICODE>(str, len);
39+
}
40+
}

src/py3_utils.hpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/* SPDX-License-Identifier: MIT */
2+
/* Copyright © 2020 Max Bachmann */
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
#include <nonstd/string_view.hpp>
7+
#include <variant/variant.hpp>
8+
9+
#if PY_VERSION_HEX < 0x030C0000
10+
#define PY_BELOW_3_12
11+
#endif
12+
13+
bool valid_str(PyObject* str, const char* name) {
14+
if (!PyUnicode_Check(str)) {
15+
PyErr_Format(PyExc_TypeError, "%s must be a String or None", name);
16+
return false;
17+
}
18+
19+
// PyUnicode_READY deprecated in Python 3.10 removed in Python 3.12
20+
#ifdef PY_BELOW_3_12
21+
if (PyUnicode_READY(str)) {
22+
return false;
23+
}
24+
#endif
25+
26+
return true;
27+
}
28+
29+
#define PY_INIT_MOD(name, doc, methods) \
30+
static struct PyModuleDef moduledef = { \
31+
PyModuleDef_HEAD_INIT, #name, doc, -1, methods, NULL, NULL, NULL, NULL}; \
32+
PyMODINIT_FUNC PyInit_##name(void) { \
33+
return PyModule_Create(&moduledef); \
34+
}
35+
36+
using python_string_view = mpark::variant<
37+
nonstd::basic_string_view<uint8_t>,
38+
nonstd::basic_string_view<uint16_t>,
39+
nonstd::basic_string_view<uint32_t>
40+
>;
41+
42+
python_string_view decode_python_string(PyObject* py_str) {
43+
Py_ssize_t len = PyUnicode_GET_LENGTH(py_str);
44+
void* str = PyUnicode_DATA(py_str);
45+
46+
int str_kind = PyUnicode_KIND(py_str);
47+
48+
switch (str_kind) {
49+
case PyUnicode_1BYTE_KIND:
50+
return nonstd::basic_string_view<uint8_t>(static_cast<uint8_t*>(str), len);
51+
case PyUnicode_2BYTE_KIND:
52+
return nonstd::basic_string_view<uint16_t>(static_cast<uint16_t*>(str), len);
53+
default:
54+
return nonstd::basic_string_view<uint32_t>(static_cast<uint32_t*>(str), len);
55+
}
56+
}

0 commit comments

Comments
 (0)