This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new 806ca1d Add check result caching and apply to license checks
806ca1d is described below
commit 806ca1db6fe2f26718d21dda21c87c6d46d3ea14
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Dec 22 15:16:30 2025 +0000
Add check result caching and apply to license checks
---
.pre-commit-config.yaml | 2 +-
atr/models/sql.py | 1 +
atr/tasks/checks/__init__.py | 66 ++++++++++++++++++++++++-
atr/tasks/checks/license.py | 4 ++
atr/tasks/checks/rat.py | 4 ++
migrations/versions/0031_2025.12.22_0f049a07.py | 29 +++++++++++
pyproject.toml | 1 +
uv.lock | 48 +++++++++++++++---
8 files changed, 146 insertions(+), 9 deletions(-)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 9b72a39..b3f0e96 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -102,7 +102,7 @@ repos:
hooks:
- id: pip-audit
- repo: https://github.com/oxc-project/mirrors-oxlint
- rev: v1.34.0
+ rev: v1.35.0
hooks:
- id: oxlint
name: lint JS files with Oxlint
diff --git a/atr/models/sql.py b/atr/models/sql.py
index 2892d86..5b21220 100644
--- a/atr/models/sql.py
+++ b/atr/models/sql.py
@@ -857,6 +857,7 @@ class CheckResult(sqlmodel.SQLModel, table=True):
data: Any = sqlmodel.Field(
sa_column=sqlalchemy.Column(sqlalchemy.JSON), **example({"expected":
"...", "found": "..."})
)
+ input_hash: str | None = sqlmodel.Field(default=None, index=True,
**example("blake3:7f83b1657ff1fc..."))
class CheckResultIgnore(sqlmodel.SQLModel, table=True):
diff --git a/atr/tasks/checks/__init__.py b/atr/tasks/checks/__init__.py
index 574c9ab..97b7c29 100644
--- a/atr/tasks/checks/__init__.py
+++ b/atr/tasks/checks/__init__.py
@@ -21,8 +21,11 @@ import dataclasses
import datetime
import functools
import pathlib
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING, Any, Final
+import aiofiles
+import aiofiles.os
+import blake3
import sqlmodel
if TYPE_CHECKING:
@@ -34,6 +37,8 @@ import atr.db as db
import atr.models.sql as sql
import atr.util as util
+_HASH_CHUNK_SIZE: Final[int] = 4 * 1024 * 1024
+
# Pydantic does not like Callable types, so we use a dataclass instead
# It says: "you should define `Callable`, then call
`FunctionArguments.model_rebuild()`"
@@ -57,6 +62,8 @@ class Recorder:
member_rel_path: str | None
revision: str
afresh: bool
+ __cached: bool
+ __input_hash: str | None
def __init__(
self,
@@ -76,6 +83,8 @@ class Recorder:
self.afresh = afresh
self.constructed = False
self.member_problems: dict[sql.CheckResultStatus, int] = {}
+ self.__cached = False
+ self.__input_hash = None
self.project_name = project_name
self.version_name = version_name
@@ -129,6 +138,7 @@ class Recorder:
status=status,
message=message,
data=data,
+ input_hash=self.__input_hash,
)
# It would be more efficient to keep a session open
@@ -186,6 +196,48 @@ class Recorder:
abs_path = await self.abs_path()
return matches(str(abs_path))
+ @property
+ def cached(self) -> bool:
+ return self.__cached
+
+ async def check_cache(self, path: pathlib.Path) -> bool:
+ if not await aiofiles.os.path.isfile(path):
+ return False
+
+ self.__input_hash = await _compute_file_hash(path)
+
+ async with db.session() as data:
+ stmt = (
+ sqlmodel.select(sql.CheckResult)
+ .where(sql.CheckResult.checker == self.checker)
+ .where(sql.CheckResult.input_hash == self.__input_hash)
+ .where(sql.CheckResult.primary_rel_path ==
self.primary_rel_path)
+ )
+ results = await data.execute(stmt)
+ cached_results = results.scalars().all()
+
+ if not cached_results:
+ return False
+
+ for cached in cached_results:
+ new_result = sql.CheckResult(
+ release_name=self.release_name,
+ revision_number=self.revision_number,
+ checker=self.checker,
+ primary_rel_path=self.primary_rel_path,
+ member_rel_path=cached.member_rel_path,
+ created=datetime.datetime.now(datetime.UTC),
+ status=cached.status,
+ message=cached.message,
+ data=cached.data,
+ input_hash=self.__input_hash,
+ )
+ data.add(new_result)
+ await data.commit()
+
+ self.__cached = True
+ return True
+
async def clear(self, primary_rel_path: str | None = None,
member_rel_path: str | None = None) -> None:
async with db.session() as data:
stmt = sqlmodel.delete(sql.CheckResult).where(
@@ -198,6 +250,10 @@ class Recorder:
await data.execute(stmt)
await data.commit()
+ @property
+ def input_hash(self) -> str | None:
+ return self.__input_hash
+
async def exception(
self, message: str, data: Any, primary_rel_path: str | None = None,
member_rel_path: str | None = None
) -> sql.CheckResult:
@@ -259,3 +315,11 @@ def with_model(cls: type[schema.Strict]) ->
Callable[[Callable[..., Any]], Calla
return wrapper
return decorator
+
+
+async def _compute_file_hash(path: pathlib.Path) -> str:
+ hasher = blake3.blake3()
+ async with aiofiles.open(path, "rb") as f:
+ while chunk := await f.read(_HASH_CHUNK_SIZE):
+ hasher.update(chunk)
+ return f"blake3:{hasher.hexdigest()}"
diff --git a/atr/tasks/checks/license.py b/atr/tasks/checks/license.py
index f8be11b..d4f9ce4 100644
--- a/atr/tasks/checks/license.py
+++ b/atr/tasks/checks/license.py
@@ -158,6 +158,10 @@ async def headers(args: checks.FunctionArguments) ->
results.Results | None:
if await recorder.primary_path_is_binary():
return None
+ if await recorder.check_cache(artifact_abs_path):
+ log.info(f"Using cached license headers result for {artifact_abs_path}
(rel: {args.primary_rel_path})")
+ return None
+
log.info(f"Checking license headers for {artifact_abs_path} (rel:
{args.primary_rel_path})")
async with db.session() as data:
diff --git a/atr/tasks/checks/rat.py b/atr/tasks/checks/rat.py
index 1e87da0..fadae35 100644
--- a/atr/tasks/checks/rat.py
+++ b/atr/tasks/checks/rat.py
@@ -53,6 +53,10 @@ async def check(args: checks.FunctionArguments) ->
results.Results | None:
log.info(f"Skipping RAT check for binary artifact {artifact_abs_path}
(rel: {args.primary_rel_path})")
return None
+ if await recorder.check_cache(artifact_abs_path):
+ log.info(f"Using cached RAT result for {artifact_abs_path} (rel:
{args.primary_rel_path})")
+ return None
+
log.info(f"Checking RAT licenses for {artifact_abs_path} (rel:
{args.primary_rel_path})")
try:
diff --git a/migrations/versions/0031_2025.12.22_0f049a07.py
b/migrations/versions/0031_2025.12.22_0f049a07.py
new file mode 100644
index 0000000..a77fe74
--- /dev/null
+++ b/migrations/versions/0031_2025.12.22_0f049a07.py
@@ -0,0 +1,29 @@
+"""Add an input hash field for check caching
+
+Revision ID: 0031_2025.12.22_0f049a07
+Revises: 0030_2025.12.05_211a31e3
+Create Date: 2025-12-22 14:59:17.175444+00:00
+"""
+
+from collections.abc import Sequence
+
+import sqlalchemy as sa
+from alembic import op
+
+# Revision identifiers, used by Alembic
+revision: str = "0031_2025.12.22_0f049a07"
+down_revision: str | None = "0030_2025.12.05_211a31e3"
+branch_labels: str | Sequence[str] | None = None
+depends_on: str | Sequence[str] | None = None
+
+
+def upgrade() -> None:
+ with op.batch_alter_table("checkresult", schema=None) as batch_op:
+ batch_op.add_column(sa.Column("input_hash", sa.String(),
nullable=True))
+ batch_op.create_index(batch_op.f("ix_checkresult_input_hash"),
["input_hash"], unique=False)
+
+
+def downgrade() -> None:
+ with op.batch_alter_table("checkresult", schema=None) as batch_op:
+ batch_op.drop_index(batch_op.f("ix_checkresult_input_hash"))
+ batch_op.drop_column("input_hash")
diff --git a/pyproject.toml b/pyproject.toml
index a1263df..e183ff8 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,6 +18,7 @@ dependencies = [
"alembic~=1.14",
"asfquart @ git+https://github.com/apache/infrastructure-asfquart.git@main",
"asyncssh>=2.20.0,<3.0.0",
+ "blake3>=1.0.8",
"blockbuster>=1.5.23,<2.0.0",
"cmarkgfm>=2024.11.20",
"cryptography~=44.0",
diff --git a/uv.lock b/uv.lock
index 8b73407..9e12959 100644
--- a/uv.lock
+++ b/uv.lock
@@ -3,7 +3,7 @@ revision = 3
requires-python = "==3.13.*"
[options]
-exclude-newer = "2025-12-19T17:04:05Z"
+exclude-newer = "2025-12-22T14:59:46Z"
[[package]]
name = "aiofiles"
@@ -191,15 +191,15 @@ dependencies = [
[[package]]
name = "asyncssh"
-version = "2.21.1"
+version = "2.22.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cryptography" },
{ name = "typing-extensions" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/6b/b8/065c20bb5c9b8991648c0f25b13e445b4f51556cc3fdd0ad13ce4787c156/asyncssh-2.21.1.tar.gz",
hash =
"sha256:9943802955e2131536c2b1e71aacc68f56973a399937ed0b725086d7461c990c", size
= 540515, upload-time = "2025-09-28T16:36:19.468Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/fc/d5/957886c316466349d55c4de6a688a10a98295c0b4429deb8db1a17f3eb19/asyncssh-2.22.0.tar.gz",
hash =
"sha256:c3ce72b01be4f97b40e62844dd384227e5ff5a401a3793007c42f86a5c8eb537", size
= 540523, upload-time = "2025-12-21T23:38:30.5Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/0e/89/4a9a61bc120ca68bce92b0ea176ddc0e550e58c60ab820603bd5246e7261/asyncssh-2.21.1-py3-none-any.whl",
hash =
"sha256:f218f9f303c78df6627d0646835e04039a156d15e174ad63c058d62de61e1968", size
= 375529, upload-time = "2025-09-28T16:36:17.68Z" },
+ { url =
"https://files.pythonhosted.org/packages/ed/ae/0da2f2214fc183338af1afe5a103a2052fd03464e8eafbd827abff58a4d0/asyncssh-2.22.0-py3-none-any.whl",
hash =
"sha256:d16465ccdf1ed20eba1131b14415b155e047f6f5be0d19f39c2e0b61331ee0e7", size
= 374938, upload-time = "2025-12-21T23:38:28.976Z" },
]
[[package]]
@@ -211,6 +211,38 @@ wheels = [
{ url =
"https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl",
hash =
"sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size
= 67615, upload-time = "2025-10-06T13:54:43.17Z" },
]
+[[package]]
+name = "blake3"
+version = "1.0.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url =
"https://files.pythonhosted.org/packages/75/aa/abcd75e9600987a0bc6cfe9b6b2ff3f0e2cb08c170addc6e76035b5c4cb3/blake3-1.0.8.tar.gz",
hash =
"sha256:513cc7f0f5a7c035812604c2c852a0c1468311345573de647e310aca4ab165ba", size
= 117308, upload-time = "2025-10-14T06:47:48.83Z" }
+wheels = [
+ { url =
"https://files.pythonhosted.org/packages/55/b8/11de9528c257f7f1633f957ccaff253b706838d22c5d2908e4735798ec01/blake3-1.0.8-cp313-cp313-macosx_10_12_x86_64.whl",
hash =
"sha256:46dc20976bd6c235959ef0246ec73420d1063c3da2839a9c87ca395cf1fd7943", size
= 347771, upload-time = "2025-10-14T06:46:04.248Z" },
+ { url =
"https://files.pythonhosted.org/packages/50/26/f7668be55c909678b001ecacff11ad7016cd9b4e9c7cc87b5971d638c5a9/blake3-1.0.8-cp313-cp313-macosx_11_0_arm64.whl",
hash =
"sha256:d17eb6382634b3a5bc0c0e0454d5265b0becaeeadb6801ed25150b39a999d0cc", size
= 325431, upload-time = "2025-10-14T06:46:06.136Z" },
+ { url =
"https://files.pythonhosted.org/packages/77/57/e8a85fa261894bf7ce7af928ff3408aab60287ab8d58b55d13a3f700b619/blake3-1.0.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:19fc6f2b7edab8acff6895fc6e38c19bd79f4c089e21153020c75dfc7397d52d", size
= 370994, upload-time = "2025-10-14T06:46:07.398Z" },
+ { url =
"https://files.pythonhosted.org/packages/62/cd/765b76bb48b8b294fea94c9008b0d82b4cfa0fa2f3c6008d840d01a597e4/blake3-1.0.8-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:4f54cff7f15d91dc78a63a2dd02a3dccdc932946f271e2adb4130e0b4cf608ba", size
= 374372, upload-time = "2025-10-14T06:46:08.698Z" },
+ { url =
"https://files.pythonhosted.org/packages/36/7a/32084eadbb28592bb07298f0de316d2da586c62f31500a6b1339a7e7b29b/blake3-1.0.8-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:e7e12a777f6b798eb8d06f875d6e108e3008bd658d274d8c676dcf98e0f10537", size
= 447627, upload-time = "2025-10-14T06:46:10.002Z" },
+ { url =
"https://files.pythonhosted.org/packages/a7/f4/3788a1d86e17425eea147e28d7195d7053565fc279236a9fd278c2ec495e/blake3-1.0.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:ddfc59b0176fb31168f08d5dd536e69b1f4f13b5a0f4b0c3be1003efd47f9308", size
= 507536, upload-time = "2025-10-14T06:46:11.614Z" },
+ { url =
"https://files.pythonhosted.org/packages/fe/01/4639cba48513b94192681b4da472cdec843d3001c5344d7051ee5eaef606/blake3-1.0.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:a2336d5b2a801a7256da21150348f41610a6c21dae885a3acb1ebbd7333d88d8", size
= 394105, upload-time = "2025-10-14T06:46:12.808Z" },
+ { url =
"https://files.pythonhosted.org/packages/21/ae/6e55c19c8460fada86cd1306a390a09b0c5a2e2e424f9317d2edacea439f/blake3-1.0.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:e4072196547484c95a5a09adbb952e9bb501949f03f9e2a85e7249ef85faaba8", size
= 386928, upload-time = "2025-10-14T06:46:16.284Z" },
+ { url =
"https://files.pythonhosted.org/packages/ee/6c/05b7a5a907df1be53a8f19e7828986fc6b608a44119641ef9c0804fbef15/blake3-1.0.8-cp313-cp313-musllinux_1_1_aarch64.whl",
hash =
"sha256:0eab3318ec02f8e16fe549244791ace2ada2c259332f0c77ab22cf94dfff7130", size
= 550003, upload-time = "2025-10-14T06:46:17.791Z" },
+ { url =
"https://files.pythonhosted.org/packages/b4/03/f0ea4adfedc1717623be6460b3710fcb725ca38082c14274369803f727e1/blake3-1.0.8-cp313-cp313-musllinux_1_1_x86_64.whl",
hash =
"sha256:a33b9a1fb6d1d559a8e0d04b041e99419a6bb771311c774f6ff57ed7119c70ed", size
= 553857, upload-time = "2025-10-14T06:46:19.088Z" },
+ { url =
"https://files.pythonhosted.org/packages/cc/6f/e5410d2e2a30c8aba8389ffc1c0061356916bf5ecd0a210344e7b69b62ab/blake3-1.0.8-cp313-cp313-win32.whl",
hash =
"sha256:e171b169cb7ea618e362a4dddb7a4d4c173bbc08b9ba41ea3086dd1265530d4f", size
= 228315, upload-time = "2025-10-14T06:46:20.391Z" },
+ { url =
"https://files.pythonhosted.org/packages/79/ef/d9c297956dfecd893f29f59e7b22445aba5b47b7f6815d9ba5dcd73fcae6/blake3-1.0.8-cp313-cp313-win_amd64.whl",
hash =
"sha256:3168c457255b5d2a2fc356ba696996fcaff5d38284f968210d54376312107662", size
= 215477, upload-time = "2025-10-14T06:46:21.542Z" },
+ { url =
"https://files.pythonhosted.org/packages/20/ba/eaa7723d66dd8ab762a3e85e139bb9c46167b751df6e950ad287adb8fb61/blake3-1.0.8-cp313-cp313t-macosx_10_12_x86_64.whl",
hash =
"sha256:b4d672c24dc15ec617d212a338a4ca14b449829b6072d09c96c63b6e6b621aed", size
= 347289, upload-time = "2025-10-14T06:46:22.772Z" },
+ { url =
"https://files.pythonhosted.org/packages/47/b3/6957f6ee27f0d5b8c4efdfda68a1298926a88c099f4dd89c711049d16526/blake3-1.0.8-cp313-cp313t-macosx_11_0_arm64.whl",
hash =
"sha256:1af0e5a29aa56d4fba904452ae784740997440afd477a15e583c38338e641f41", size
= 324444, upload-time = "2025-10-14T06:46:24.729Z" },
+ { url =
"https://files.pythonhosted.org/packages/13/da/722cebca11238f3b24d3cefd2361c9c9ea47cfa0ad9288eeb4d1e0b7cf93/blake3-1.0.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:ef153c5860d5bf1cc71aece69b28097d2a392913eb323d6b52555c875d0439fc", size
= 370441, upload-time = "2025-10-14T06:46:26.29Z" },
+ { url =
"https://files.pythonhosted.org/packages/2e/d5/2f7440c8e41c0af995bad3a159e042af0f4ed1994710af5b4766ca918f65/blake3-1.0.8-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:e8ae3689f0c7bfa6ce6ae45cab110e4c3442125c4c23b28f1f097856de26e4d1", size
= 374312, upload-time = "2025-10-14T06:46:27.451Z" },
+ { url =
"https://files.pythonhosted.org/packages/a6/6c/fb6a7812e60ce3e110bcbbb11f167caf3e975c589572c41e1271f35f2c41/blake3-1.0.8-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:3fb83532f7456ddeb68dae1b36e1f7c52f9cb72852ac01159bbcb1a12b0f8be0", size
= 447007, upload-time = "2025-10-14T06:46:29.056Z" },
+ { url =
"https://files.pythonhosted.org/packages/13/3b/c99b43fae5047276ea9d944077c190fc1e5f22f57528b9794e21f7adedc6/blake3-1.0.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:6ae7754c7d96e92a70a52e07c732d594cf9924d780f49fffd3a1e9235e0f5ba7", size
= 507323, upload-time = "2025-10-14T06:46:30.661Z" },
+ { url =
"https://files.pythonhosted.org/packages/fc/bb/ba90eddd592f8c074a0694cb0a744b6bd76bfe67a14c2b490c8bdfca3119/blake3-1.0.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:4bacaae75e98dee3b7da6c5ee3b81ee21a3352dd2477d6f1d1dbfd38cdbf158a", size
= 393449, upload-time = "2025-10-14T06:46:31.805Z" },
+ { url =
"https://files.pythonhosted.org/packages/25/ed/58a2acd0b9e14459cdaef4344db414d4a36e329b9720921b442a454dd443/blake3-1.0.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:9456c829601d72852d8ba0af8dae0610f7def1d59f5942efde1e2ef93e8a8b57", size
= 386844, upload-time = "2025-10-14T06:46:33.195Z" },
+ { url =
"https://files.pythonhosted.org/packages/4a/04/fed09845b18d90862100c8e48308261e2f663aab25d3c71a6a0bdda6618b/blake3-1.0.8-cp313-cp313t-musllinux_1_1_aarch64.whl",
hash =
"sha256:497ef8096ec4ac1ffba9a66152cee3992337cebf8ea434331d8fd9ce5423d227", size
= 549550, upload-time = "2025-10-14T06:46:35.23Z" },
+ { url =
"https://files.pythonhosted.org/packages/d6/65/1859fddfabc1cc72548c2269d988819aad96d854e25eae00531517925901/blake3-1.0.8-cp313-cp313t-musllinux_1_1_x86_64.whl",
hash =
"sha256:511133bab85ff60ed143424ce484d08c60894ff7323f685d7a6095f43f0c85c3", size
= 553805, upload-time = "2025-10-14T06:46:36.532Z" },
+ { url =
"https://files.pythonhosted.org/packages/c1/c7/2969352017f62378e388bb07bb2191bc9a953f818dc1cd6b9dd5c24916e1/blake3-1.0.8-cp313-cp313t-win32.whl",
hash =
"sha256:9c9fbdacfdeb68f7ca53bb5a7a5a593ec996eaf21155ad5b08d35e6f97e60877", size
= 228068, upload-time = "2025-10-14T06:46:37.826Z" },
+ { url =
"https://files.pythonhosted.org/packages/d8/fc/923e25ac9cadfff1cd20038bcc0854d0f98061eb6bc78e42c43615f5982d/blake3-1.0.8-cp313-cp313t-win_amd64.whl",
hash =
"sha256:3cec94ed5676821cf371e9c9d25a41b4f3ebdb5724719b31b2749653b7cc1dfa", size
= 215369, upload-time = "2025-10-14T06:46:39.054Z" },
+]
+
[[package]]
name = "blinker"
version = "1.9.0"
@@ -986,11 +1018,11 @@ sdist = { url =
"https://files.pythonhosted.org/packages/a6/91/86a6eac449ddfae23
[[package]]
name = "nodeenv"
-version = "1.9.1"
+version = "1.10.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url =
"https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz",
hash =
"sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size
= 47437, upload-time = "2024-06-04T18:44:11.171Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz",
hash =
"sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size
= 55611, upload-time = "2025-12-20T14:08:54.006Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl",
hash =
"sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size
= 22314, upload-time = "2024-06-04T18:44:08.352Z" },
+ { url =
"https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl",
hash =
"sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size
= 23438, upload-time = "2025-12-20T14:08:52.782Z" },
]
[[package]]
@@ -1778,6 +1810,7 @@ dependencies = [
{ name = "alembic" },
{ name = "asfquart" },
{ name = "asyncssh" },
+ { name = "blake3" },
{ name = "blockbuster" },
{ name = "cmarkgfm" },
{ name = "cryptography" },
@@ -1836,6 +1869,7 @@ requires-dist = [
{ name = "alembic", specifier = "~=1.14" },
{ name = "asfquart", git =
"https://github.com/apache/infrastructure-asfquart.git?rev=main" },
{ name = "asyncssh", specifier = ">=2.20.0,<3.0.0" },
+ { name = "blake3", specifier = ">=1.0.8" },
{ name = "blockbuster", specifier = ">=1.5.23,<2.0.0" },
{ name = "cmarkgfm", specifier = ">=2024.11.20" },
{ name = "cryptography", specifier = "~=44.0" },
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]