Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various minor updates #14

Merged
merged 9 commits into from
Sep 16, 2024
Merged
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
6 changes: 0 additions & 6 deletions .flake8

This file was deleted.

2 changes: 1 addition & 1 deletion .github/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def main():
}
)

print(json.dumps(actions_matrix))
print(json.dumps(actions_matrix)) # noqa:T201


if __name__ == "__main__":
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ concurrency:
jobs:
matrix:
name: Build test matrix
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -15,20 +15,20 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
python-version: '3.12'
cache: 'pip'
cache-dependency-path: 'requirements/*.txt'
- name: Run tox
id: matrix
run: |
pip install $(grep "^tox==" requirements/local.txt)
pip install $(grep -E "^(tox|tox-uv)==" requirements/local.txt)
echo "tox_matrix=$(tox -l | fgrep -v coverage | python .github/matrix.py)" >> $GITHUB_OUTPUT
outputs:
tox_matrix: ${{ steps.matrix.outputs.tox_matrix }}

test:
name: Test -- ${{ matrix.tox_env }}
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
needs: matrix
strategy:
matrix:
Expand All @@ -53,11 +53,11 @@ jobs:
TOX_OVERRIDE: "testenv.passenv=PG*"
PYTHON_VERSION: ${{ matrix.python }}
run: |
pip install $(grep "^tox==" requirements/local.txt)
pip install $(grep -E "^(tox|tox-uv)==" requirements/local.txt)
tox -e ${{ matrix.tox_env }}
services:
postgres:
image: postgres:15-alpine
image: postgres:16-alpine
env:
POSTGRES_PASSWORD: password
ports:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2019-2023, Developer Society Limited
Copyright (c) 2019-2024, Developer Society Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without
Expand Down
39 changes: 17 additions & 22 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ check: ## Check for any obvious errors in the project's setup.
check: pipdeptree-check

format: ## Run this project's code formatters.
format: black-format isort-format
format: ruff-format

lint: ## Lint the project.
lint: black-lint isort-lint flake8-lint
lint: ruff-lint

test: ## Run unit and integration tests.
test: django-test

test-report: ## Run and report on unit and integration tests.
test-report: coverage-clean test coverage-report

test-lowest: ## Run tox with lowest (oldest) package dependencies.
test-lowest: tox-test-lowest

dist: ## Builds source and wheel package
dist: clean build-dist

Expand Down Expand Up @@ -104,19 +107,6 @@ pip-install-local: venv-check
pip install -r requirements/local.txt


# ISort
isort-lint:
isort --check-only --diff postgres_lock tests

isort-format:
isort postgres_lock tests


# Flake8
flake8-lint:
flake8 postgres_lock


# Coverage
coverage-report: coverage-combine coverage-html coverage-xml
coverage report --show-missing
Expand All @@ -136,23 +126,28 @@ coverage-clean:
rm -f .coverage


# Black
black-lint:
black --check postgres_lock tests setup.py
# ruff
ruff-lint:
ruff check
ruff format --check

black-format:
black postgres_lock tests setup.py
ruff-format:
ruff check --fix-only
ruff format


#pipdeptree
# pipdeptree
pipdeptree-check:
@pipdeptree --warn fail > /dev/null
pipdeptree --warn fail >/dev/null


# Project testing
django-test:
PYTHONWARNINGS=all coverage run $$(which django-admin) test --pythonpath $$(pwd) --settings tests.settings tests

tox-test-lowest:
tox --recreate --override testenv.uv_resolution=lowest


# Help
help-display:
Expand Down
17 changes: 7 additions & 10 deletions postgres_lock/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,22 @@ def __init__(self, name=None, try_=False, shared=False, using=DEFAULT_DB_ALIAS):
else:
shared_str = ""

self.lock_function = "pg{try_str}_advisory_lock{shared_str}".format(
try_str=try_str, shared_str=shared_str
)
self.unlock_function = "pg_advisory_unlock{shared_str}".format(shared_str=shared_str)
self.lock_function = f"pg{try_str}_advisory_lock{shared_str}"
self.unlock_function = f"pg_advisory_unlock{shared_str}"

def get_lock_id(self, name):
"""
Generate an integer suitable for Postgres advisory locks.
"""
# Python 3 crc32 returns an unsigned integer, so we need to ensure we return a signed
# integer instead.
lock_id = crc32(name.encode()) & 0xFFFFFFFF
return lock_id
return crc32(name.encode()) & 0xFFFFFFFF

def lock(self):
self.cursor = self.database_connection.cursor()
self.cursor.execute(
"SELECT {lock_function}(%(lock_id)s)".format(lock_function=self.lock_function),
{"lock_function": self.lock_function, "lock_id": self.lock_id},
f"SELECT {self.lock_function}(%(lock_id)s)",
{"lock_id": self.lock_id},
)

if self.try_lock:
Expand All @@ -56,8 +53,8 @@ def lock(self):

def release(self):
self.cursor.execute(
"SELECT {unlock_function}(%(lock_id)s)".format(unlock_function=self.unlock_function),
{"unlock_function": self.unlock_function, "lock_id": self.lock_id},
f"SELECT {self.unlock_function}(%(lock_id)s)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's safe here - but would it be best practice (?) to use the psycopg2.sql functions for string building?

from psycopg2 import sql
Suggested change
f"SELECT {self.unlock_function}(%(lock_id)s)",
sql.SQL("SELECT {}(%(lock_id)s)").format(self.unlock_function)),

where self.unlock_function would be a sql.Identifier() rather than a plain string?
?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One to ponder on - seems like a good idea.

Only slight downside is that this package would then technically require psycopg2 or psycopg directly (which currently we don't!)

{"lock_id": self.lock_id},
)
self.cursor.close()

Expand Down
2 changes: 1 addition & 1 deletion postgres_lock/management/commands/command_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def execute(self, *args, **options):
using=options["database"],
) as acquired:
if acquired:
completed = subprocess.run(options["command"])
completed = subprocess.run(options["command"]) # noqa:S603
# Raise the return code of the child process if an error occurs
if completed.returncode != 0:
sys.exit(completed.returncode)
Expand Down
42 changes: 29 additions & 13 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
[tool.black]
[tool.ruff]
line-length = 99
target-version = ['py37']
exclude = '/migrations/'
target-version = 'py38'

[tool.isort]
combine_as_imports = true
sections = ['FUTURE','STDLIB','DJANGO','THIRDPARTY','FIRSTPARTY','LOCALFOLDER']
known_django = 'django'
include_trailing_comma = true
float_to_top = true
force_grid_wrap = 0
line_length = 99
multi_line_output = 3
skip_glob = '*/migrations/*.py'
[tool.ruff.lint]
select = [
'F', # pyflakes
'E', # pycodestyle
'W', # pycodestyle
'I', # isort
'N', # pep8-naming
'UP', # pyupgrade
'S', # flake8-bandit
'BLE', # flake8-blind-except
'C4', # flake8-comprehensions
'EM', # flake8-errmsg
'T20', # flake8-print
'RET', # flake8-return
'RUF', # ruff
]
ignore = [
'EM101', # flake8-errmsg: raw-string-in-exception
]

[tool.ruff.lint.isort]
combine-as-imports = true

[tool.ruff.lint.pep8-naming]
extend-ignore-names = [
'assert*',
]
7 changes: 4 additions & 3 deletions requirements/local.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

bump2version==1.0.1
Django>=4.2,<5.0
psycopg2==2.9.6
tox==4.6.0
twine==4.0.2
psycopg==3.2.1
tox==4.18.1
tox-uv==1.11.3
twine==5.1.1
8 changes: 3 additions & 5 deletions requirements/testing.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
black==24.3.0 ; python_version >= '3.8'
coverage==7.2.7
flake8==6.0.0 ; python_version >= '3.8'
isort==5.12.0 ; python_version >= '3.8'
pipdeptree==2.9.0
coverage==7.6.1
pipdeptree==2.23.3
ruff==0.6.5
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ def read(filename):
platforms=["any"],
packages=find_packages(exclude=["tests"]),
include_package_data=True,
python_requires=">=3.7",
python_requires=">=3.8",
install_requires=["Django>=2.2"],
classifiers=[
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"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",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Framework :: Django",
"Framework :: Django :: 2.2",
"Framework :: Django :: 3.2",
Expand Down
2 changes: 1 addition & 1 deletion tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@

USE_TZ = True

SECRET_KEY = "postgres_lock"
SECRET_KEY = "postgres_lock" # noqa:S105

INSTALLED_APPS = ["postgres_lock", "tests"]
20 changes: 9 additions & 11 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
envlist =
check
lint
{py37,py38,py39}-django2.2
{py37,py38,py39,py310}-django3.2
{py38,py39,py310,py311}-django4.2
py{38,39}-django2.2
py{38,39,310}-django3.2
py{38,39,310,311,312}-django4.2
coverage
no_package = true

Expand All @@ -15,22 +15,20 @@ deps =
django3.2: Django>=3.2,<4.0
django4.2: Django>=4.2,<5.0
django2.2: psycopg2>=2.8,<2.9
django3.2,django4.2: psycopg2>=2.9,<2.10
django3.2: psycopg2>=2.9,<2.10
django4.2: psycopg<3.3
allowlist_externals = make
commands = make test
usedevelop = true
package = editable

[testenv:check]
basepython = python3.11
basepython = python3.12
commands = make check
skip_install = true

[testenv:lint]
basepython = python3.11
basepython = python3.12
commands = make lint
skip_install = true

[testenv:coverage]
basepython = python3.11
basepython = python3.12
commands = make coverage-report
skip_install = true