diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5fc192b..c8a348d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,7 +25,7 @@ jobs: DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7.0.1 - name: Install uv uses: astral-sh/setup-uv@v10.2.0 diff --git a/Dockerfile b/Dockerfile index 901f47b..3f07089 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -# syntax=docker/dockerfile:1.21.0 +# syntax=docker/dockerfile:1.27.0 # ---- builder: install Python deps into an isolated venv via uv ---- FROM python:3.13-slim AS builder -COPY --from=ghcr.io/astral-sh/uv:0.12.1 /uv /uvx /usr/local/bin/ +COPY --from=ghcr.io/astral-sh/uv:0.12.19 /uv /uvx /usr/local/bin/ ENV UV_LINK_MODE=copy \ UV_PROJECT_ENVIRONMENT=/opt/venv \ diff --git a/mise.toml b/mise.toml index 8911f2a..d0daeac 100644 --- a/mise.toml +++ b/mise.toml @@ -1,4 +1,4 @@ [tools] python = "3.13" -task = "3.50.0" -uv = "0.12.1" +task = "3.53.1" +uv = "0.12.19" diff --git a/pyproject.toml b/pyproject.toml index a3f43f9..bd82add 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,44 +4,44 @@ version = "0.1.0" description = "Python Ireland website (python.ie / pycon.ie), built with Django and Wagtail CMS" requires-python = "==3.13.*" dependencies = [ - "boto3", - "colander", - "defusedxml", - "delorean", - "dj-database-url", - "dj-static", - "django<6.1", # pinned to the 6.0.x branch, matches the currently deployed version - "django-compressor", - "django-extensions", - "django-libsass", - "django-modelcluster", - "django-storages", - "django-taggit", - "gunicorn", - "pandas", - "psycopg[binary]", - "pydantic", - "python-dateutil", - "pytz", - "redis", - "requests>=2.32.5", - "wagtail>=7.3.2,<7.4", - "whitenoise", - "willow", + "boto3>=1.43.102", + "colander>=2.0", + "defusedxml>=0.7.1", + "delorean>=2.0.0", + "dj-database-url>=3.1.2", + "dj-static>=0.0.6", + "django>=6.0.8,<6.1", # pinned to the 6.0.x branch, matches the currently deployed version + "django-compressor>=4.6.0", + "django-extensions>=4.1", + "django-libsass>=0.9", + "django-modelcluster>=6.5", + "django-storages>=1.14.6", + "django-taggit>=6.1.0", + "gunicorn>=26.2.0", + "pandas>=3.0.6", + "psycopg[binary]>=3.3.6", + "pydantic>=2.13.5", + "python-dateutil>=2.9.0.post0", + "pytz>=2026.4", + "redis>=8.1.0", + "requests>=2.34.2", + "wagtail>=7.3.4,<7.4", + "whitenoise>=6.12.0", + "willow>=1.12.0", ] [dependency-groups] dev = [ - "coverage", - "django-debug-toolbar", - "fakeredis", - "isort", - "model_mommy", - "pip-audit", - "pipdeptree", - "ruff==0.15.16", # pinned: 0.16 changes the default lint rule set - "uv", - "wagtail-factories", + "coverage>=7.16.1", + "django-debug-toolbar>=8.0.0", + "fakeredis>=2.38.0", + "isort>=9.0.1", + "model_mommy>=2.0.0", + "pip-audit>=2.10.1", + "pipdeptree>=4.2.5", + "ruff==0.16.9", # pinned: ruff minor releases change the default lint rule set + "uv>=0.12.19", + "wagtail-factories>=4.5.0", ] [tool.uv] @@ -50,6 +50,11 @@ package = false [tool.ruff] target-version = "py313" +[tool.ruff.lint] +# RUF012 flags the Django/Wagtail class-attribute idioms (Meta, migrations +# operations/dependencies, content_panels) that are never mutated. +extend-ignore = ["RUF012"] + [tool.coverage.run] branch = true source = ["pythonie"] diff --git a/pythonie/core/factories.py b/pythonie/core/factories.py index 1c57d2d..996fe38 100644 --- a/pythonie/core/factories.py +++ b/pythonie/core/factories.py @@ -1,12 +1,12 @@ import factory +import wagtail_factories from django.utils import timezone from factory.django import DjangoModelFactory -import wagtail_factories - -from core.models import HomePage, SimplePage from meetups.models import Meetup from sponsors.models import SponsorshipLevel +from core.models import HomePage, SimplePage + class SponsorshipLevelFactory(DjangoModelFactory): class Meta: diff --git a/pythonie/core/migrations/0001_initial.py b/pythonie/core/migrations/0001_initial.py index cd69e01..68ed801 100644 --- a/pythonie/core/migrations/0001_initial.py +++ b/pythonie/core/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import modelcluster.fields import wagtail.fields from django.db import migrations, models diff --git a/pythonie/core/migrations/0002_simplepage.py b/pythonie/core/migrations/0002_simplepage.py index 3656081..579ec5a 100644 --- a/pythonie/core/migrations/0002_simplepage.py +++ b/pythonie/core/migrations/0002_simplepage.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import wagtail.blocks import wagtail.fields import wagtail.images.blocks diff --git a/pythonie/core/migrations/0003_media_in_simple_page.py b/pythonie/core/migrations/0003_media_in_simple_page.py index 265ef9b..eb03e2b 100644 --- a/pythonie/core/migrations/0003_media_in_simple_page.py +++ b/pythonie/core/migrations/0003_media_in_simple_page.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import wagtail.blocks import wagtail.embeds.blocks import wagtail.fields diff --git a/pythonie/core/migrations/0004_auto_20150708_1416.py b/pythonie/core/migrations/0004_auto_20150708_1416.py index a4b2b5d..482a3fd 100644 --- a/pythonie/core/migrations/0004_auto_20150708_1416.py +++ b/pythonie/core/migrations/0004_auto_20150708_1416.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import wagtail.blocks import wagtail.embeds.blocks import wagtail.fields diff --git a/pythonie/core/migrations/0005_auto_20150726_1416.py b/pythonie/core/migrations/0005_auto_20150726_1416.py index 658a02a..6da9bc5 100644 --- a/pythonie/core/migrations/0005_auto_20150726_1416.py +++ b/pythonie/core/migrations/0005_auto_20150726_1416.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/core/migrations/0006_homepagesponsorrelationship.py b/pythonie/core/migrations/0006_homepagesponsorrelationship.py index a3b4e43..649d745 100644 --- a/pythonie/core/migrations/0006_homepagesponsorrelationship.py +++ b/pythonie/core/migrations/0006_homepagesponsorrelationship.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/core/migrations/0007_homepage_sponsors.py b/pythonie/core/migrations/0007_homepage_sponsors.py index 0c9022f..77ae1d1 100644 --- a/pythonie/core/migrations/0007_homepage_sponsors.py +++ b/pythonie/core/migrations/0007_homepage_sponsors.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/core/migrations/0008_auto_20150821_2230.py b/pythonie/core/migrations/0008_auto_20150821_2230.py index c3f927f..d9b42ea 100644 --- a/pythonie/core/migrations/0008_auto_20150821_2230.py +++ b/pythonie/core/migrations/0008_auto_20150821_2230.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import wagtail.blocks import wagtail.embeds.blocks import wagtail.fields diff --git a/pythonie/core/migrations/0009_auto_20160703_0857.py b/pythonie/core/migrations/0009_auto_20160703_0857.py index e068472..c4b08c5 100644 --- a/pythonie/core/migrations/0009_auto_20160703_0857.py +++ b/pythonie/core/migrations/0009_auto_20160703_0857.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-07-03 08:57 -from __future__ import unicode_literals from django.db import migrations, models diff --git a/pythonie/core/models.py b/pythonie/core/models.py index 77b92fe..f38bf47 100644 --- a/pythonie/core/models.py +++ b/pythonie/core/models.py @@ -1,5 +1,3 @@ -from __future__ import unicode_literals - import logging from django.db import models @@ -62,7 +60,7 @@ class PageSegment(models.Model): ] def __str__(self): - return "{!s} on {!s}".format(self.title, self.homepage_segments.first()) + return f"{self.title!s} on {self.homepage_segments.first()!s}" class HomePageSegment(Orderable, models.Model): @@ -84,7 +82,7 @@ class Meta: ] def __str__(self): - return "{!s} Segment".format(self.homepage) + return f"{self.homepage!s} Segment" class HomePageSponsorRelationship(models.Model): @@ -97,9 +95,7 @@ class HomePageSponsorRelationship(models.Model): level = models.ForeignKey(SponsorshipLevel, on_delete=models.CASCADE) def __repr__(self): - return "{} {} {}".format( - self.sponsor.name, self.homepage.title, self.level.name - ) + return f"{self.sponsor.name} {self.homepage.title} {self.level.name}" class HomePage(Page, MeetupMixin, SponsorMixin): diff --git a/pythonie/meetups/migrations/0001_initial.py b/pythonie/meetups/migrations/0001_initial.py index 770973b..c034ba2 100644 --- a/pythonie/meetups/migrations/0001_initial.py +++ b/pythonie/meetups/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/meetups/migrations/0002_add_meetup_sponsor_relationship.py b/pythonie/meetups/migrations/0002_add_meetup_sponsor_relationship.py index f6516cf..f61a9ac 100644 --- a/pythonie/meetups/migrations/0002_add_meetup_sponsor_relationship.py +++ b/pythonie/meetups/migrations/0002_add_meetup_sponsor_relationship.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/meetups/migrations/0003_remove_meetup_announced.py b/pythonie/meetups/migrations/0003_remove_meetup_announced.py index 670368c..01ad1ec 100644 --- a/pythonie/meetups/migrations/0003_remove_meetup_announced.py +++ b/pythonie/meetups/migrations/0003_remove_meetup_announced.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations diff --git a/pythonie/meetups/migrations/0004_auto_20150705_1641.py b/pythonie/meetups/migrations/0004_auto_20150705_1641.py index 95a709c..5103813 100644 --- a/pythonie/meetups/migrations/0004_auto_20150705_1641.py +++ b/pythonie/meetups/migrations/0004_auto_20150705_1641.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - import datetime from django.db import migrations, models @@ -16,9 +13,7 @@ class Migration(migrations.Migration): model_name="meetup", name="updated", field=models.DateTimeField( - default=datetime.datetime( - 1970, 1, 1, 0, 0, tzinfo=datetime.timezone.utc - ) + default=datetime.datetime(1970, 1, 1, 0, 0, tzinfo=datetime.UTC) ), preserve_default=True, ), diff --git a/pythonie/meetups/migrations/0005_delete_meetupupdate.py b/pythonie/meetups/migrations/0005_delete_meetupupdate.py index d046bd8..f516e5e 100644 --- a/pythonie/meetups/migrations/0005_delete_meetupupdate.py +++ b/pythonie/meetups/migrations/0005_delete_meetupupdate.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations diff --git a/pythonie/meetups/migrations/0006_auto_20160703_0857.py b/pythonie/meetups/migrations/0006_auto_20160703_0857.py index f52facb..579805f 100644 --- a/pythonie/meetups/migrations/0006_auto_20160703_0857.py +++ b/pythonie/meetups/migrations/0006_auto_20160703_0857.py @@ -1,6 +1,4 @@ -# -*- coding: utf-8 -*- # Generated by Django 1.9.7 on 2016-07-03 08:57 -from __future__ import unicode_literals from django.db import migrations, models diff --git a/pythonie/meetups/models.py b/pythonie/meetups/models.py index 42af7e3..7cb7d77 100644 --- a/pythonie/meetups/models.py +++ b/pythonie/meetups/models.py @@ -1,9 +1,9 @@ import logging -from datetime import datetime +from datetime import UTC, datetime from dateutil.relativedelta import relativedelta -from delorean import Delorean from django.db import models +from django.utils import timezone from sponsors.models import Sponsor from wagtail.snippets.models import register_snippet @@ -38,9 +38,7 @@ class Meetup(models.Model): ) time = models.DateTimeField() created = models.DateTimeField() - updated = models.DateTimeField( - default=Delorean(datetime(1970, 1, 1), timezone="UTC").datetime - ) + updated = models.DateTimeField(default=datetime(1970, 1, 1, tzinfo=UTC)) rsvps = models.IntegerField(default=0) maybe_rsvps = models.IntegerField(default=0) @@ -57,7 +55,7 @@ def __str__(self): @classmethod def future_events(cls): - today = datetime.now() + today = timezone.now() return cls.objects.filter(time__gt=today).filter( time__lt=next_n_months(today, 3) ) diff --git a/pythonie/meetups/schema.py b/pythonie/meetups/schema.py index 94ae813..5888e0a 100644 --- a/pythonie/meetups/schema.py +++ b/pythonie/meetups/schema.py @@ -1,12 +1,12 @@ -from datetime import datetime +from datetime import UTC, datetime import colander from delorean import Delorean def int_to_datetime(value): - time = datetime.utcfromtimestamp(value / 1000) - return Delorean(time, timezone="UTC").shift("Europe/Dublin").datetime + time = datetime.fromtimestamp(value / 1000, tz=UTC) + return Delorean(time).shift("Europe/Dublin").datetime class Meetups(colander.MappingSchema): diff --git a/pythonie/meetups/test_meetups.py b/pythonie/meetups/test_meetups.py index bde8da8..ee6bd72 100644 --- a/pythonie/meetups/test_meetups.py +++ b/pythonie/meetups/test_meetups.py @@ -37,12 +37,12 @@ def test_create_meetup(self): self.assertIsNotNone(meetup.visibility) def test_next_n_months(self): - september = datetime(year=2015, month=9, day=1, hour=1, minute=00) - expected = datetime(year=2015, month=12, day=1, hour=1, minute=00) + september = datetime(year=2015, month=9, day=1, hour=1, minute=00, tzinfo=UTC) + expected = datetime(year=2015, month=12, day=1, hour=1, minute=00, tzinfo=UTC) actual = next_n_months(september, 3) self.assertEqual(expected, actual) - november = datetime(year=2015, month=10, day=1, hour=1, minute=00) - expected = datetime(year=2016, month=1, day=1, hour=1, minute=00) + november = datetime(year=2015, month=10, day=1, hour=1, minute=00, tzinfo=UTC) + expected = datetime(year=2016, month=1, day=1, hour=1, minute=00, tzinfo=UTC) actual = next_n_months(november, 3) self.assertEqual(expected, actual) diff --git a/pythonie/meetups/utils.py b/pythonie/meetups/utils.py index 4b67386..651ff1b 100644 --- a/pythonie/meetups/utils.py +++ b/pythonie/meetups/utils.py @@ -9,10 +9,10 @@ def get_content(url, params=None): response = requests.get(url, params=params, timeout=3) - log.info("Response from meetups request: {0}".format(response)) + log.info(f"Response from meetups request: {response}") if not response: return [] - log.debug("Retrieved {} from {}".format(response.json(), url)) + log.debug(f"Retrieved {response.json()} from {url}") return response.json() @@ -24,7 +24,7 @@ def update(): params={"group_urlname": "pythonireland", "text_format": "html", "time": ",3m"}, ) if not meetup_data: - log.warn("No meetup data returned from API") + log.warning("No meetup data returned from API") return log.info(meetup_data) meetups = schema.Meetups() @@ -40,7 +40,7 @@ def update(): meetup.waitlist_count = result.get("waitlist_count") if result["updated"] <= meetup.updated: - log.info("Existing meetup:{!r} RSVPs updated".format(meetup)) + log.info(f"Existing meetup:{meetup!r} RSVPs updated") meetup.save() continue @@ -55,4 +55,4 @@ def update(): meetup.status = result.get("status") meetup.visibility = result.get("visibility") meetup.save() - log.info("Existing meetup:{!r} fully updated".format(meetup)) + log.info(f"Existing meetup:{meetup!r} fully updated") diff --git a/pythonie/pythonie/settings/configure.py b/pythonie/pythonie/settings/configure.py index a0c6cc1..8e38deb 100644 --- a/pythonie/pythonie/settings/configure.py +++ b/pythonie/pythonie/settings/configure.py @@ -16,7 +16,7 @@ def configure_redis(redis_url, test=False): import redis url = urlparse(redis_url) - log.info("Redis configured with redis_url: %s" % redis_url) + log.info("Redis configured with redis_url: %s", redis_url) return redis.Redis(host=url.hostname, port=url.port, password=url.password) - log.warn("Redis not configured") + log.warning("Redis not configured") diff --git a/pythonie/sponsors/migrations/0001_initial.py b/pythonie/sponsors/migrations/0001_initial.py index 04a9a7b..f92ef5e 100644 --- a/pythonie/sponsors/migrations/0001_initial.py +++ b/pythonie/sponsors/migrations/0001_initial.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/sponsors/migrations/0002_restructure_sponsor.py b/pythonie/sponsors/migrations/0002_restructure_sponsor.py index 0e0788e..2e4c613 100644 --- a/pythonie/sponsors/migrations/0002_restructure_sponsor.py +++ b/pythonie/sponsors/migrations/0002_restructure_sponsor.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/sponsors/migrations/0003_sponsorshiplevel.py b/pythonie/sponsors/migrations/0003_sponsorshiplevel.py index 05c8c49..a081c85 100644 --- a/pythonie/sponsors/migrations/0003_sponsorshiplevel.py +++ b/pythonie/sponsors/migrations/0003_sponsorshiplevel.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations, models diff --git a/pythonie/sponsors/migrations/0004_auto_20150726_1412.py b/pythonie/sponsors/migrations/0004_auto_20150726_1412.py index 3ed8b10..0d17166 100644 --- a/pythonie/sponsors/migrations/0004_auto_20150726_1412.py +++ b/pythonie/sponsors/migrations/0004_auto_20150726_1412.py @@ -1,6 +1,3 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - from django.db import migrations diff --git a/uv.lock b/uv.lock index 1406cf8..8021321 100644 --- a/uv.lock +++ b/uv.lock @@ -1187,44 +1187,44 @@ dev = [ [package.metadata] requires-dist = [ - { name = "boto3" }, - { name = "colander" }, - { name = "defusedxml" }, - { name = "delorean" }, - { name = "dj-database-url" }, - { name = "dj-static" }, - { name = "django", specifier = "<6.1" }, - { name = "django-compressor" }, - { name = "django-extensions" }, - { name = "django-libsass" }, - { name = "django-modelcluster" }, - { name = "django-storages" }, - { name = "django-taggit" }, - { name = "gunicorn" }, - { name = "pandas" }, - { name = "psycopg", extras = ["binary"] }, - { name = "pydantic" }, - { name = "python-dateutil" }, - { name = "pytz" }, - { name = "redis" }, - { name = "requests", specifier = ">=2.32.5" }, - { name = "wagtail", specifier = ">=7.3.2,<7.4" }, - { name = "whitenoise" }, - { name = "willow" }, + { name = "boto3", specifier = ">=1.43.102" }, + { name = "colander", specifier = ">=2.0" }, + { name = "defusedxml", specifier = ">=0.7.1" }, + { name = "delorean", specifier = ">=2.0.0" }, + { name = "dj-database-url", specifier = ">=3.1.2" }, + { name = "dj-static", specifier = ">=0.0.6" }, + { name = "django", specifier = ">=6.0.8,<6.1" }, + { name = "django-compressor", specifier = ">=4.6.0" }, + { name = "django-extensions", specifier = ">=4.1" }, + { name = "django-libsass", specifier = ">=0.9" }, + { name = "django-modelcluster", specifier = ">=6.5" }, + { name = "django-storages", specifier = ">=1.14.6" }, + { name = "django-taggit", specifier = ">=6.1.0" }, + { name = "gunicorn", specifier = ">=26.2.0" }, + { name = "pandas", specifier = ">=3.0.6" }, + { name = "psycopg", extras = ["binary"], specifier = ">=3.3.6" }, + { name = "pydantic", specifier = ">=2.13.5" }, + { name = "python-dateutil", specifier = ">=2.9.0.post0" }, + { name = "pytz", specifier = ">=2026.4" }, + { name = "redis", specifier = ">=8.1.0" }, + { name = "requests", specifier = ">=2.34.2" }, + { name = "wagtail", specifier = ">=7.3.4,<7.4" }, + { name = "whitenoise", specifier = ">=6.12.0" }, + { name = "willow", specifier = ">=1.12.0" }, ] [package.metadata.requires-dev] dev = [ - { name = "coverage" }, - { name = "django-debug-toolbar" }, - { name = "fakeredis" }, - { name = "isort" }, - { name = "model-mommy" }, - { name = "pip-audit" }, - { name = "pipdeptree" }, - { name = "ruff", specifier = "==0.15.16" }, - { name = "uv" }, - { name = "wagtail-factories" }, + { name = "coverage", specifier = ">=7.16.1" }, + { name = "django-debug-toolbar", specifier = ">=8.0.0" }, + { name = "fakeredis", specifier = ">=2.38.0" }, + { name = "isort", specifier = ">=9.0.1" }, + { name = "model-mommy", specifier = ">=2.0.0" }, + { name = "pip-audit", specifier = ">=2.10.1" }, + { name = "pipdeptree", specifier = ">=4.2.5" }, + { name = "ruff", specifier = "==0.16.9" }, + { name = "uv", specifier = ">=0.12.19" }, + { name = "wagtail-factories", specifier = ">=4.5.0" }, ] [[package]] @@ -1315,27 +1315,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.16" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/5f7ec371001337d8fa61701c186ff8b613ecac1651848c5950f4c4d5f2e9/ruff-0.15.16.tar.gz", hash = "sha256:d05e78d38c78caf020b03789e25106c93017db5a0cb6e2819885018c61343b78", size = 4714267, upload-time = "2026-06-04T16:33:09.974Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/42/53ef1c3953f157956db9bf7861e3bc50b9b887ce93300aa48cdba8336fe6/ruff-0.15.16-py3-none-linux_armv6l.whl", hash = "sha256:6ac3c0b3969cc6cf6b158c4e2f8f682acb58e7d700d8a44b65ecdc72d66ab0b2", size = 10709025, upload-time = "2026-06-04T16:32:51.935Z" }, - { url = "https://files.pythonhosted.org/packages/93/9a/a79159346f19134a956607754e57d8d128f7a4c00f4ad2f7514d224c172c/ruff-0.15.16-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:197c207ed75ffba54a0dec23db4aa939a27a3053073e085e0042433cbdc58e4a", size = 11063550, upload-time = "2026-06-04T16:32:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/bc/72/3ce2ac000a5299ec238e01f51397b3b653c93b077d9b1bfe8715bb895f20/ruff-0.15.16-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a39fec45ab316cc23e7558f23fea4a70403ddb5648ea9a4a3854a16973d0071", size = 10421345, upload-time = "2026-06-04T16:32:37.251Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c2/cc7fad3ec9169373f5b6a18f1917b91080feec40c3f9658334a1d28e2f03/ruff-0.15.16-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba93191d79003116b95128c9d306e045200fdbd0bccb782b110f3cd1d4abc5cf", size = 10757217, upload-time = "2026-06-04T16:32:54.722Z" }, - { url = "https://files.pythonhosted.org/packages/69/d2/3474009eaa0a65b31fa7152a2fad5e2f050c640ceb1e6b02ee6922e94c82/ruff-0.15.16-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c6ee4b90520630120ef032aa5cc10db483852dff950e78b1d717e2993a61ac8d", size = 10507035, upload-time = "2026-06-04T16:33:05.343Z" }, - { url = "https://files.pythonhosted.org/packages/ca/81/b7ae6ccbd11f0c8dc3d5d67fc4be9b57ff57ca86ba56152021378e1277f2/ruff-0.15.16-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e4215bc938bc3c8215c1472c1aa437e310fee20cd427335fec9d7e609563628", size = 11255291, upload-time = "2026-06-04T16:32:49.49Z" }, - { url = "https://files.pythonhosted.org/packages/d9/e1/46e526f1a7cc90857ce6ddf25fbb77eb6568651ac38d71b033af07076dd5/ruff-0.15.16-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c8d26be963b090f10e29abc8b3e74a2a321f6fa34e02424e30b5af89350ecbb", size = 12124922, upload-time = "2026-06-04T16:33:07.821Z" }, - { url = "https://files.pythonhosted.org/packages/1a/da/5c791b088b596b24d0deb967fa28ae02ad751a140c0b9ea81c5ab915d6c0/ruff-0.15.16-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f198cf4123602a2280ed46c307bcbafe41758d6fee5b456b6b6058ca1514b3b4", size = 11332186, upload-time = "2026-06-04T16:33:02.971Z" }, - { url = "https://files.pythonhosted.org/packages/72/11/5da87abe20047c8962361473923ebb2f62b595250126aadfad8c20649c1e/ruff-0.15.16-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb27515fa6240fb586ae82b901a59e67d24acff86f2190b433dc542fe0435aeb", size = 11373541, upload-time = "2026-06-04T16:32:47.007Z" }, - { url = "https://files.pythonhosted.org/packages/fe/2a/8554754c23a854ae3fd6b507e36ad61ddb121e298c6d5d617dec94ed0f14/ruff-0.15.16-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a267c46ba1593fc26b8eecbea050b39d40c0b6bb7781ee11c90a02cd10032951", size = 11353014, upload-time = "2026-06-04T16:32:34.795Z" }, - { url = "https://files.pythonhosted.org/packages/62/25/62ea41529ec89f742ea3fed9cb1059c72877ec7cf9b9e99ac9cf3294d1d9/ruff-0.15.16-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:528c68f39a91498a8d50e91ff5985df3d105782bab49cc378e73ac26bff083e8", size = 10737467, upload-time = "2026-06-04T16:32:26.348Z" }, - { url = "https://files.pythonhosted.org/packages/90/17/334d3ad9de4d40f9dd58fdd09e35ce64553bb501e2f19a839e2fb6be14fc/ruff-0.15.16-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:7ed55c58950df60589a9a7a5d2f8fa5f54ebd287163be805adfe6ee95a9de123", size = 10521910, upload-time = "2026-06-04T16:32:32.54Z" }, - { url = "https://files.pythonhosted.org/packages/4d/bd/3ac7c6ae77a885c1004b3dda2446ea401768d24f851c14b4ad4b24f6639c/ruff-0.15.16-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d482feaf51512b50f9790ceb417a56a61dd1e9d9bf967662b9ed27c01b34f53a", size = 10979190, upload-time = "2026-06-04T16:32:57.492Z" }, - { url = "https://files.pythonhosted.org/packages/33/d7/609546e6a413c3f216fbf2a50c928f97c80939154f6a0503114094a86191/ruff-0.15.16-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1e15bc8c94513dae2a40cc9ef07c94fdd4ecc9e29dabebeebe170f952322c9e3", size = 11477014, upload-time = "2026-06-04T16:32:44.687Z" }, - { url = "https://files.pythonhosted.org/packages/74/0d/f2cd247ad32633a5c36e97141a2c21b11c6279f7957bc2ff360b1e08fddd/ruff-0.15.16-py3-none-win32.whl", hash = "sha256:580378f7bd4aa25f72e74aa54948a9622f142b1e509521dd10902e886681cc1e", size = 10735541, upload-time = "2026-06-04T16:32:30.145Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/02e845ef151b1dee585e55c4739f8e1734ae1d9f1221dff65761c162208b/ruff-0.15.16-py3-none-win_amd64.whl", hash = "sha256:408256017284eddf98fff77b29aa4fb30f586042d535b2d9befc6512f400aaec", size = 11843403, upload-time = "2026-06-04T16:32:39.76Z" }, - { url = "https://files.pythonhosted.org/packages/15/19/016553f86f207450aebebc2b2b5088d086b901cc8186c02ac4284db3bd88/ruff-0.15.16-py3-none-win_arm64.whl", hash = "sha256:8cd61783afb39638a7133ef0d2dfb1e91277593962f81b5a8423eb0b888a6121", size = 11134555, upload-time = "2026-06-04T16:33:00.136Z" }, +version = "0.16.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/bf/c935ca98e73fe8ce65b87ef08a280c0c1e85295d569228c15e87d8fdfaf1/ruff-0.16.9.tar.gz", hash = "sha256:12b625c6cfba78d285d9f48eda5f053374f1e53cb10ef17342a383750db99161", size = 4948764, upload-time = "2026-09-24T20:37:49.416Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/26/df51322b52ee1ada7eff2d071ea09d11d5c2d1dcc9f02594f5785c4d1635/ruff-0.16.9-py3-none-linux_armv6l.whl", hash = "sha256:95e6f022090368ab3b824c36276839c53b2adf1a3f4c09fefc33dfc400f6da96", size = 10082922, upload-time = "2026-09-24T20:37:13.045Z" }, + { url = "https://files.pythonhosted.org/packages/a5/27/7bf51f5a7aa375e9f339280a303aab44ca75dc1525f1cdc5991761685b0f/ruff-0.16.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a5f27be168556594a86d2f415db0cf43f5291917849318f873c7e2791f7a8c67", size = 10236360, upload-time = "2026-09-24T20:37:16.049Z" }, + { url = "https://files.pythonhosted.org/packages/b6/63/09659283f92f02dff45809da194a70da2f688d87c55d8875c4fae3536072/ruff-0.16.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1632eb1d6197f33bd00b1acbc5b71009e89a8895c158e2d2b03a834fac964ab6", size = 9892940, upload-time = "2026-09-24T20:37:17.957Z" }, + { url = "https://files.pythonhosted.org/packages/24/58/98de1b72ec172f5f8f1731236fe21585b3998bf7dfe9fcc44ae9ba626012/ruff-0.16.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3f951b14d865d5952c89d40a5ca07e87abe24fa5453299878411e127748fb1c", size = 10032114, upload-time = "2026-09-24T20:37:19.942Z" }, + { url = "https://files.pythonhosted.org/packages/c8/7d/f1e17c54ab59d4bad1dce8ee3e22a7a1d0ef4745240decacdcf3832b5bb2/ruff-0.16.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:447fc07e1573afff7cb02803462b12b6c8ece7cf10e2cd78565fa6d7a1c0bf8d", size = 9910227, upload-time = "2026-09-24T20:37:21.872Z" }, + { url = "https://files.pythonhosted.org/packages/34/19/436f647a65075bbd3bab2668b3bdaa5120559b294694018cdcefabbbf30b/ruff-0.16.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a3e039a6a40ed976c491722b60e0ae4a4aa1a86057f540ee7a37a5d19ae9120", size = 10547484, upload-time = "2026-09-24T20:37:24.229Z" }, + { url = "https://files.pythonhosted.org/packages/03/59/38430a6bc2f6d8095447ac39625cf8b6e9344a47e6c26225c8ba1bff3ffb/ruff-0.16.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4684dded7db60aa57cb118fa158630f5feade4af5782903b6053484bdf9bd129", size = 11412367, upload-time = "2026-09-24T20:37:26.307Z" }, + { url = "https://files.pythonhosted.org/packages/c8/bd/bbb6d7fc7f208c8b8c50dd5dc8206e4cfdb1e7a8fb852606a3adf370c880/ruff-0.16.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d29c934357e45642fda2f34c0b1f4025b4a6c01e15e4bf0016879d60078a142c", size = 10869787, upload-time = "2026-09-24T20:37:28.35Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b8/9c543074918061abbefc3bd139bee22de35abedb00dde0f2d27288838962/ruff-0.16.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a21713e629d3e5bdb2f5c2def1cc7f04f47fa8e1a7eb0571b4a28e1da64bc728", size = 10406494, upload-time = "2026-09-24T20:37:30.624Z" }, + { url = "https://files.pythonhosted.org/packages/35/7a/5a8851bd146e7ccf8fd4b003f6c75c11f8fbdb0e60673b45097986b6bf41/ruff-0.16.9-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:7baa24ef5fc8e77aa93879e1d3f43754a01ae488e869f1ae30cf431afd4d2452", size = 10590083, upload-time = "2026-09-24T20:37:32.439Z" }, + { url = "https://files.pythonhosted.org/packages/87/f0/4c3467188f23f806960b46fa76575a7cd0514c9ba90562650b71efc96980/ruff-0.16.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a41aac6230aadfaa133bdfa1614488531ffa3e0837567ae04c0da2058a9c0f9e", size = 10119151, upload-time = "2026-09-24T20:37:34.581Z" }, + { url = "https://files.pythonhosted.org/packages/15/34/5a4def5adea572ce6aea0bb64f21f928ee317b80e0db747d7979b01d7261/ruff-0.16.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:c2529fb5896d49115b0e9aa8f887490b34bbe76baf879ec2264ac59406869ce7", size = 9911544, upload-time = "2026-09-24T20:37:36.796Z" }, + { url = "https://files.pythonhosted.org/packages/62/5d/d15ebea7499eef9373318c0ee6ca127832927c6529731f6d48e18dce7ca9/ruff-0.16.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:41e3870277694177429b56406d65dfbdb2c2802c52b715edaf6a0b829c69d4ee", size = 10269884, upload-time = "2026-09-24T20:37:38.857Z" }, + { url = "https://files.pythonhosted.org/packages/d1/56/c5d3cd119ded7a3c7aba0e961b69cb3df701c91662c98ad694467d060ce1/ruff-0.16.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:8adbe4e58af167f767d7b2ba5e83c42e878350796cf78c2f5e14ab9903a92588", size = 10749366, upload-time = "2026-09-24T20:37:41.042Z" }, + { url = "https://files.pythonhosted.org/packages/ac/fe/734ec7527029ac757ecf821f143c9f3fcf69149c21f53a044a899b430f5a/ruff-0.16.9-py3-none-win32.whl", hash = "sha256:0e1dbc2073624dee6618d41d0098690a7244654af746704b64759e12b6b6b385", size = 10152355, upload-time = "2026-09-24T20:37:43.025Z" }, + { url = "https://files.pythonhosted.org/packages/14/21/26e4643629b3ebb44f0a06f9c9a53058d63d989415f63a9a3c28e2ee7f22/ruff-0.16.9-py3-none-win_amd64.whl", hash = "sha256:6bd40fec8cd4c8a3d4dd589bd8ad4e6320c13c29234159bfd959a40d529d597b", size = 10592965, upload-time = "2026-09-24T20:37:44.944Z" }, + { url = "https://files.pythonhosted.org/packages/51/60/5fb1a39dbb5ae314d5f59bc7348a63c1d5c20f3cd83914c4b5cb0be31d2d/ruff-0.16.9-py3-none-win_arm64.whl", hash = "sha256:ed1a252039200f57a59eebc063b54beabea67bfbaaca0eeaa7f54b5fbcda2284", size = 10458649, upload-time = "2026-09-24T20:37:46.882Z" }, ] [[package]]