Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ on:
- main
workflow_call:

# NOTE: Python 3.7 Testing Support
# Python 3.7 reached end-of-life in June 2023 and is no longer available
# in GitHub's ubuntu-latest runners. We use ubuntu-20.04 specifically for
# Python 3.7 testing to maintain backward compatibility. Consider removing
# Python 3.7 support in future major releases.

defaults:
run:
shell: bash
Expand Down Expand Up @@ -38,24 +44,35 @@ jobs:
test:
name: "Test"
needs: analyze
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
# Python 3.7 requires ubuntu-20.04 as it's no longer available on ubuntu-latest
- toxenv: "python3.7"
py: "3.7"
os: "ubuntu-20.04"
- toxenv: "python3.8"
py: "3.8"
os: "ubuntu-latest"
- toxenv: "python3.9"
py: "3.9"
os: "ubuntu-latest"
- toxenv: "python3.10"
py: "3.10"
os: "ubuntu-latest"
- toxenv: "python3.11"
py: "3.11"
os: "ubuntu-latest"
- toxenv: "python3.12"
py: "3.12"
os: "ubuntu-latest"
- toxenv: "python3.13"
py: "3.13"
os: "ubuntu-latest"
- toxenv: "python3.14"
py: "3.14"
os: "ubuntu-latest"
steps:
- uses: actions/checkout@v5
- name: Set up Python ${{ matrix.py }}
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ related to the project.

## Python version support

Currently, the package supports Python versions 3.8 and above. Once a new Python version is released, we will aim to
Currently, the package supports Python versions 3.7 and above. Once a new Python version is released, we will aim to
support it as soon as possible. If you encounter any issues with a new Python version, please create an issue in the
repository.

Expand Down
15 changes: 8 additions & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description = "A query string encoding and decoding library for Python. Ported f
readme = { file = "README.rst", content-type = "text/x-rst" }
license = "BSD-3-Clause"
license-files = ["LICENSE"]
requires-python = ">=3.8"
requires-python = ">=3.7"
authors = [
{ name = "Klemen Tusar", email = "techouse@gmail.com" },
]
Expand All @@ -25,6 +25,7 @@ classifiers = [
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand All @@ -51,10 +52,10 @@ PayPal = "https://paypal.me/ktusar"

[project.optional-dependencies]
dev = [
"pytest>=8.1.2",
"pytest-cov>=5.0.0",
"mypy>=1.10.0",
"toml>=0.10.2",
"pytest>=7.4.4",
"pytest-cov",
"mypy>=1.8.0",
"toml",
"tox",
"black",
"isort"
Expand All @@ -80,7 +81,7 @@ include = ["src/qs_codec/py.typed"]

[tool.black]
line-length = 120
target-version = ["py38", "py39", "py310", "py311", "py312", "py313", "py314"]
target-version = ["py37", "py38", "py39", "py310", "py311", "py312", "py313", "py314"]
include = '\.pyi?$'
exclude = '''
(
Expand Down Expand Up @@ -118,7 +119,7 @@ markers = []

[tool.mypy]
mypy_path = "src"
python_version = "3.8"
python_version = "3.7"
exclude = [
"tests",
"docs",
Expand Down
4 changes: 3 additions & 1 deletion src/qs_codec/encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ def _encode(

# Walk up the chain looking for `obj_wrapper`. If we see it at the same "step"
# again we've closed a loop.
while (tmp_sc := tmp_sc.get(_sentinel)) and not find_flag: # type: ignore [union-attr]
tmp_sc = tmp_sc.get(_sentinel) # type: ignore [union-attr]
while tmp_sc and not find_flag:
# Where `value` last appeared in the ref tree
pos: t.Optional[int] = tmp_sc.get(obj_wrapper)
step += 1
Expand All @@ -246,6 +247,7 @@ def _encode(
find_flag = True # Break while
if tmp_sc.get(_sentinel) is None:
step = 0
tmp_sc = tmp_sc.get(_sentinel) # type: ignore [union-attr]

# --- Pre-processing: filter & datetime handling ---------------------------------------
if callable(filter):
Expand Down
6 changes: 4 additions & 2 deletions src/qs_codec/utils/decode_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,11 @@ def unescape(cls, string: str) -> str:
return string

def replacer(match: t.Match[str]) -> str:
if (unicode_val := match.group("unicode")) is not None:
unicode_val = match.group("unicode")
if unicode_val is not None:
return chr(int(unicode_val, 16))
elif (hex_val := match.group("hex")) is not None:
hex_val = match.group("hex")
if hex_val is not None:
return chr(int(hex_val, 16))
return match.group(0)

Expand Down
5 changes: 3 additions & 2 deletions tests/unit/decode_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -974,10 +974,11 @@ def _decode(s: t.Optional[str], charset: t.Optional[Charset]) -> t.Any:

reg: re.Pattern = re.compile(r"%([0-9A-F]{2})", re.IGNORECASE)
result: t.List[int] = []
parts: t.Optional[re.Match]
while (parts := reg.search(s)) is not None:
parts: t.Optional[re.Match] = reg.search(s)
while parts is not None:
result.append(int(parts.group(1), 16))
s = s[parts.end() :]
parts = reg.search(s)
return bytes(result).decode("shift-jis")

assert decode("%8c%a7=%91%e5%8d%e3%95%7b", DecodeOptions(decoder=_decode)) == {"県": "大阪府"}
Expand Down
2 changes: 2 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[tox]
isolated_build = true
envlist =
python3.7,
python3.8,
python3.9,
python3.10,
Expand All @@ -15,6 +16,7 @@ skip_missing_interpreters = true

[gh-actions]
python =
3.7: python3.7
3.8: python3.8
3.9: python3.9
3.10: python3.10
Expand Down
Loading