Skip to content
Draft
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
24 changes: 12 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,32 @@ jobs:
- name: Set up uv
uses: astral-sh/setup-uv@v6
with:
cache-dependency-glob: |
setup.py
cache-suffix: ${{ matrix.python-version }}
enable-cache: true
version: "latest"

- name: Setup env
run: uv sync
- name: Invoke tests
run: |

# Propagate build matrix information.
./devtools/setup_ci.sh

# Bootstrap environment.
source bootstrap.sh


# Run linter.
uv run ruff check .

# Run type testing
uv run mypy

# Report about the test matrix slot.
echo "Invoking tests with CrateDB ${CRATEDB_VERSION}"

# Run linter.
poe lint
uv run coverage run -m pytest

# Run tests.
coverage run bin/test -vvv

# Set the stage for uploading the coverage report.
coverage xml
uv run coverage xml

# https://github.com/codecov/codecov-action
- name: Upload coverage results to Codecov
Expand Down
134 changes: 94 additions & 40 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
[build-system]
requires = ["hatchling >= 1.26"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/crate"]

[tool.hatch.version]
path = "src/crate/client/__init__.py"

[project]
name = "crate-python"
dynamic = ["version"]
description = "CrateDB Python Client"
authors = [{ name = "Crate.io", email = "office@crate.io" }]
requires-python = ">=3.10"
readme = "README.rst"
license = { file = "LICENSE"}
classifiers = [
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Topic :: Database",
]
dependencies = [
"orjson>=3.11.3",
"urllib3>=2.5.0",
]

[dependency-groups]
dev = [
"certifi>=2025.10.5",
"coverage>=7.11.0",
"mypy>=1.18.2",
"pytest>=8.4.2",
"pytz>=2025.2",
"ruff>=0.14.2",
"setuptools>=80.9.0",
"stopit>=1.1.2",
"verlib2>=0.3.1",
]


[tool.mypy]
mypy_path = "src"
packages = [
Expand All @@ -18,65 +70,67 @@ non_interactive = true
line-length = 80

extend-exclude = [
"/example_*",
"/example_*",
]

lint.select = [
# Builtins
"A",
# Bugbear
"B",
# comprehensions
"C4",
# Pycodestyle
"E",
# eradicate
"ERA",
# Pyflakes
"F",
# isort
"I",
# pandas-vet
"PD",
# return
"RET",
# Bandit
"S",
# print
"T20",
"W",
# flake8-2020
"YTT",
# Builtins
"A",
# Bugbear
"B",
# comprehensions
"C4",
# Pycodestyle
"E",
# eradicate
"ERA",
# Pyflakes
"F",
# isort
"I",
# pandas-vet
"PD",
# return
"RET",
# Bandit
"S",
# print
"T20",
"W",
# flake8-2020
"YTT",
]

lint.extend-ignore = [
# Unnecessary variable assignment before `return` statement
"RET504",
# Unnecessary `elif` after `return` statement
"RET505",
# Unnecessary variable assignment before `return` statement
"RET504",
# Unnecessary `elif` after `return` statement
"RET505",
]

lint.per-file-ignores."example_*" = [
"ERA001", # Found commented-out code
"T201", # Allow `print`
"ERA001", # Found commented-out code
"T201", # Allow `print`
]
lint.per-file-ignores."devtools/*" = [
"T201", # Allow `print`
"T201", # Allow `print`
]
lint.per-file-ignores."examples/*" = [
"ERA001", # Found commented-out code
"T201", # Allow `print`
"ERA001", # Found commented-out code
"T201", # Allow `print`
]
lint.per-file-ignores."tests/*" = [
"S106", # Possible hardcoded password assigned to argument: "password"
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
"S101", # Asserts.
"S105", # Possible hardcoded password assigned to: "password"
"S106", # Possible hardcoded password assigned to argument: "password"
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
]
lint.per-file-ignores."src/crate/client/{connection.py,http.py}" = [
"A004", # Import `ConnectionError` is shadowing a Python builtin
"A005", # Import `ConnectionError` is shadowing a Python builtin
"A004", # Import `ConnectionError` is shadowing a Python builtin
"A005", # Import `ConnectionError` is shadowing a Python builtin
]
lint.per-file-ignores."tests/client/test_http.py" = [
"A004", # Import `ConnectionError` is shadowing a Python builtin
"A004", # Import `ConnectionError` is shadowing a Python builtin
]


Expand Down
3 changes: 2 additions & 1 deletion src/crate/client/cursor.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ def _convert_rows(self):

# Process result rows with conversion.
for row in self._result["rows"]:
yield [convert(value) for convert, value in zip(converters, row)]
yield [convert(value) for convert, value
in zip(converters, row, strict=False)]

@property
def time_zone(self):
Expand Down
2 changes: 1 addition & 1 deletion src/crate/client/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def __init__(self, table, digest):
self.digest = digest

def __str__(self):
return "{table}/{digest}".format(table=self.table, digest=self.digest)
return f"{self.__class__.__qualname__}('{self.table}/{self.digest})'"


class DigestNotFoundException(BlobException):
Expand Down
5 changes: 4 additions & 1 deletion src/crate/client/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,10 @@ def _pool_kw_args(
return kw


def _remove_certs_for_non_https(server, kwargs):
def _remove_certs_for_non_https(server: str, kwargs: dict) -> dict:
"""
Removes certificates for http requests.
"""
if server.lower().startswith("https"):
return kwargs
used_ssl_args = SSL_ONLY_ARGS & set(kwargs.keys())
Expand Down
Loading