Compare commits

...

3 commits

Author SHA1 Message Date
470052c736
fix: run vendored test on package 2024-01-03 12:14:37 -06:00
082fe2d3f5
fix: use most recent tomli 2024-01-03 12:09:52 -06:00
30c756d3e7
feat: vendor packaging + add support for requires python check
This is a mostly small change albeit with addition of more embedded
code from pypa/packaging to simplify supporting a requires-python check
with PEP723 style syntax.
2024-01-03 12:01:28 -06:00
10 changed files with 1474 additions and 433 deletions

2
.gitignore vendored
View file

@ -176,3 +176,5 @@ docs/viv.py
docs/svgs docs/svgs
docs/public docs/public
/tests/.viv-cache /tests/.viv-cache
/scripts/tomli
/scripts/packaging

View file

@ -4,6 +4,6 @@ repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.10 rev: v0.1.10
hooks: hooks:
- id: ruff-format
- id: ruff - id: ruff
args: [ --fix ] args: [ --fix ]
- id: ruff-format

0
examples/stopwatch.py Executable file → Normal file
View file

View file

@ -58,4 +58,4 @@ def release(session):
@nox.session(python=["3.8", "3.9", "3.10", "3.11"]) @nox.session(python=["3.8", "3.9", "3.10", "3.11"])
def test(session): def test(session):
pdm_install(session, "test") pdm_install(session, "test")
session.run("pytest") session.run("pytest", "tests/")

View file

@ -5,7 +5,7 @@
groups = ["default", "dev", "docs", "test"] groups = ["default", "dev", "docs", "test"]
strategy = ["cross_platform"] strategy = ["cross_platform"]
lock_version = "4.4.1" lock_version = "4.4.1"
content_hash = "sha256:c9e5da8cc42f30380075c09b37765d5687a14daa61ee3323af51ee1aa73f57a5" content_hash = "sha256:67b99f093f433bb1a56dc393d51c615b65e94ea9ad397a5460c5a2a29a21cb22"
[[package]] [[package]]
name = "alabaster" name = "alabaster"
@ -17,6 +17,16 @@ files = [
{file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"},
] ]
[[package]]
name = "astor"
version = "0.8.1"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
summary = "Read/rewrite/write Python ASTs"
files = [
{file = "astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5"},
{file = "astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e"},
]
[[package]] [[package]]
name = "babel" name = "babel"
version = "2.14.0" version = "2.14.0"
@ -216,15 +226,15 @@ files = [
[[package]] [[package]]
name = "importlib-metadata" name = "importlib-metadata"
version = "7.0.0" version = "7.0.1"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Read metadata from Python packages" summary = "Read metadata from Python packages"
dependencies = [ dependencies = [
"zipp>=0.5", "zipp>=0.5",
] ]
files = [ files = [
{file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"},
{file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"},
] ]
[[package]] [[package]]
@ -360,7 +370,7 @@ files = [
[[package]] [[package]]
name = "mypy" name = "mypy"
version = "1.7.1" version = "1.8.0"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Optional static typing for Python" summary = "Optional static typing for Python"
dependencies = [ dependencies = [
@ -369,33 +379,33 @@ dependencies = [
"typing-extensions>=4.1.0", "typing-extensions>=4.1.0",
] ]
files = [ files = [
{file = "mypy-1.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12cce78e329838d70a204293e7b29af9faa3ab14899aec397798a4b41be7f340"}, {file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"},
{file = "mypy-1.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1484b8fa2c10adf4474f016e09d7a159602f3239075c7bf9f1627f5acf40ad49"}, {file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"},
{file = "mypy-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31902408f4bf54108bbfb2e35369877c01c95adc6192958684473658c322c8a5"}, {file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"},
{file = "mypy-1.7.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f2c2521a8e4d6d769e3234350ba7b65ff5d527137cdcde13ff4d99114b0c8e7d"}, {file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"},
{file = "mypy-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:fcd2572dd4519e8a6642b733cd3a8cfc1ef94bafd0c1ceed9c94fe736cb65b6a"}, {file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"},
{file = "mypy-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b901927f16224d0d143b925ce9a4e6b3a758010673eeded9b748f250cf4e8f7"}, {file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"},
{file = "mypy-1.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7f6985d05a4e3ce8255396df363046c28bea790e40617654e91ed580ca7c51"}, {file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"},
{file = "mypy-1.7.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:944bdc21ebd620eafefc090cdf83158393ec2b1391578359776c00de00e8907a"}, {file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"},
{file = "mypy-1.7.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9c7ac372232c928fff0645d85f273a726970c014749b924ce5710d7d89763a28"}, {file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"},
{file = "mypy-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:f6efc9bd72258f89a3816e3a98c09d36f079c223aa345c659622f056b760ab42"}, {file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"},
{file = "mypy-1.7.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6dbdec441c60699288adf051f51a5d512b0d818526d1dcfff5a41f8cd8b4aaf1"}, {file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"},
{file = "mypy-1.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4fc3d14ee80cd22367caaaf6e014494415bf440980a3045bf5045b525680ac33"}, {file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"},
{file = "mypy-1.7.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c6e4464ed5f01dc44dc9821caf67b60a4e5c3b04278286a85c067010653a0eb"}, {file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"},
{file = "mypy-1.7.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d9b338c19fa2412f76e17525c1b4f2c687a55b156320acb588df79f2e6fa9fea"}, {file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"},
{file = "mypy-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:204e0d6de5fd2317394a4eff62065614c4892d5a4d1a7ee55b765d7a3d9e3f82"}, {file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"},
{file = "mypy-1.7.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:84860e06ba363d9c0eeabd45ac0fde4b903ad7aa4f93cd8b648385a888e23200"}, {file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"},
{file = "mypy-1.7.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8c5091ebd294f7628eb25ea554852a52058ac81472c921150e3a61cdd68f75a7"}, {file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"},
{file = "mypy-1.7.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40716d1f821b89838589e5b3106ebbc23636ffdef5abc31f7cd0266db936067e"}, {file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"},
{file = "mypy-1.7.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cf3f0c5ac72139797953bd50bc6c95ac13075e62dbfcc923571180bebb662e9"}, {file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"},
{file = "mypy-1.7.1-cp38-cp38-win_amd64.whl", hash = "sha256:78e25b2fd6cbb55ddfb8058417df193f0129cad5f4ee75d1502248e588d9e0d7"}, {file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"},
{file = "mypy-1.7.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:75c4d2a6effd015786c87774e04331b6da863fc3fc4e8adfc3b40aa55ab516fe"}, {file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"},
{file = "mypy-1.7.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2643d145af5292ee956aa0a83c2ce1038a3bdb26e033dadeb2f7066fb0c9abce"}, {file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"},
{file = "mypy-1.7.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75aa828610b67462ffe3057d4d8a4112105ed211596b750b53cbfe182f44777a"}, {file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"},
{file = "mypy-1.7.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ee5d62d28b854eb61889cde4e1dbc10fbaa5560cb39780c3995f6737f7e82120"}, {file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"},
{file = "mypy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:72cf32ce7dd3562373f78bd751f73c96cfb441de147cc2448a92c1a308bd0ca6"}, {file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"},
{file = "mypy-1.7.1-py3-none-any.whl", hash = "sha256:f7c5d642db47376a0cc130f0de6d055056e010debdaf0707cd2b0fc7e7ef30ea"}, {file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"},
{file = "mypy-1.7.1.tar.gz", hash = "sha256:fcb6d9afb1b6208b4c712af0dafdc650f518836065df0d4fb1d800f5d6773db2"}, {file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"},
] ]
[[package]] [[package]]
@ -507,7 +517,7 @@ files = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "7.4.3" version = "7.4.4"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "pytest: simple powerful testing with Python" summary = "pytest: simple powerful testing with Python"
dependencies = [ dependencies = [
@ -519,8 +529,8 @@ dependencies = [
"tomli>=1.0.0; python_version < \"3.11\"", "tomli>=1.0.0; python_version < \"3.11\"",
] ]
files = [ files = [
{file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
{file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
] ]
[[package]] [[package]]
@ -624,25 +634,25 @@ files = [
[[package]] [[package]]
name = "setuptools" name = "setuptools"
version = "69.0.2" version = "69.0.3"
requires_python = ">=3.8" requires_python = ">=3.8"
summary = "Easily download, build, install, upgrade, and uninstall Python packages" summary = "Easily download, build, install, upgrade, and uninstall Python packages"
files = [ files = [
{file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"},
{file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"},
] ]
[[package]] [[package]]
name = "shibuya" name = "shibuya"
version = "2023.10.26" version = "2024.1.2"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "A clean, responsive, and customizable Sphinx documentation theme with light/dark mode." summary = "A clean, responsive, and customizable Sphinx documentation theme with light/dark mode."
dependencies = [ dependencies = [
"Sphinx", "Sphinx",
] ]
files = [ files = [
{file = "shibuya-2023.10.26-py3-none-any.whl", hash = "sha256:e8a8647005a410d929fe4fdd3af2b88c156efbca8582ce3803ebd7771d08cebb"}, {file = "shibuya-2024.1.2-py3-none-any.whl", hash = "sha256:27533d5ed93881c3de3eec9c9f3004fa2fb3120c73869ffc2c719fda65cc78ee"},
{file = "shibuya-2023.10.26.tar.gz", hash = "sha256:878f866a8720776c878ff1d9e17f7731cf8923859ff6fec77999b469477764a1"}, {file = "shibuya-2024.1.2.tar.gz", hash = "sha256:12937ad82c660db660a4ce196bd126630c9bd90d96a8593203eefd2ad255957e"},
] ]
[[package]] [[package]]

View file

@ -24,8 +24,9 @@ version = { source = "scm" }
[tool.pdm.dev-dependencies] [tool.pdm.dev-dependencies]
dev = [ dev = [
"pre-commit>=3", "pre-commit>=3",
"mypy>=0.991", "mypy>=0.991",
"astor>=0.8.1",
] ]
docs = [ docs = [
"sphinx", "sphinx",

View file

@ -1,87 +0,0 @@
import re
from pathlib import Path
FILES = (
("types", [[7, 11]]),
("re", [[14, 107]]),
("parser", [[20, 691]]),
)
TOMLI_DELIM = ("##### START VENDORED TOMLI #####", "##### END VENDORED TOMLI #####")
TOMLI_PREFACE = """
# MODIFIED FROM https://github.com/hukkin/tomli
# see below for original license
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
"""
VENDORED_IMPORTS = """
import string # noqa
from collections.abc import Iterable # noqa
from functools import lru_cache # noqa
from datetime import date, datetime, time, timedelta, timezone, tzinfo # noqa
from types import MappingProxyType # noqa
from typing import IO, Any, Callable, NamedTuple # noqa
"""
# REMOVE FOR ACTUAL VENDORED VERSION
tomli_text = VENDORED_IMPORTS
for f, slices in FILES:
text = Path(f"./tomli/src/tomli/_{f}.py").read_text()
for indices in slices:
tomli_text = "\n".join(
(
tomli_text,
# black can add back spaces if it wants
*[
line
for line in text.splitlines()[slice(*indices)]
if line.strip("\r\n")
],
)
)
IDENT_PATTERN = r"^(?P<ident>[A-Z_]*) ="
FUNC_PATTERN = r"^def (?P<function>[a-zA-Z_]+)\("
idents = re.findall(IDENT_PATTERN, tomli_text, re.MULTILINE)
funcs = re.findall(FUNC_PATTERN, tomli_text, re.MULTILINE)
# TODO: USE ONE LOOP?
for pat in idents + funcs:
tomli_text = re.sub(f"(?<!__tomli__){pat}", f"__tomli__{pat}", tomli_text)
# for func in funcs:
# tomli_text = re.sub(f"(?<!__tomli__){func}", f" __tomli__{func}", tomli_text)
# tomli_text += "\n# fmt:on\n"
tomli_text = "\n".join((TOMLI_PREFACE, tomli_text))
viv_src = Path("../src/viv/viv.py")
start, rest = re.split(TOMLI_DELIM[0], viv_src.read_text())
_, rest = re.split(TOMLI_DELIM[1], viv_src.read_text())
viv_src.write_text(
"\n".join(
(
start.strip(),
"\n",
TOMLI_DELIM[0],
tomli_text.strip(),
TOMLI_DELIM[1],
"\n",
rest.strip(),
)
)
)
# re.sub(
# r"""\n##### START VENDORED TOMLI #####\n*.*\n*##### END VENDORED TOMLI #####\n""",
# re.escape(tomli_text),
# viv_src.read_text(),
# re.MULTILINE,
# )
# )

221
scripts/vendor.py Executable file
View file

@ -0,0 +1,221 @@
#!/usr/bin/env python3
import ast
import re
import subprocess
import textwrap
from pathlib import Path
from typing import List
import astor
def remove_docs_and_comments(code):
parsed = ast.parse(code)
for node in ast.walk(parsed):
if isinstance(node, ast.Expr) and isinstance(node.value, ast.Str):
# set value to empty string which should be ignored by astor.to_source
node.value = ast.Constant(value="")
elif (
(isinstance(node, ast.FunctionDef) or isinstance(node, ast.ClassDef))
and len(node.body) == 1
and isinstance(node.body[0], ast.Expr)
and isinstance(node.body[0].value, ast.Constant)
):
# add pass to empty functions and class definition
node.body = [ast.Pass()]
formatted_code = astor.to_source(parsed)
pattern = r'^.*"""""".*$' # remove empty """"""
formatted_code = re.sub(pattern, "", formatted_code, flags=re.MULTILINE)
return formatted_code
class Package:
def __init__(
self,
name: str,
url: str,
files: List[tuple[str, List[List[int]]]],
rev: str,
basepath: Path,
imports: str = "",
prefix: str = "",
suffix: str = "",
indent: bool = False,
):
self.name = name
self.files = files
self.url = url
self.rev = rev
self.basepath = basepath
self.imports = imports
self.prefix = prefix
self.suffix = suffix
self.indent = indent
self.ensure()
self.generate_vendored_source()
self.replace_identifiers()
def ensure(self):
dir = Path(__file__).parent / self.name
if not dir.is_dir():
subprocess.run(["git", "clone", self.url, dir])
subprocess.run(["git", "-C", dir, "checkout", self.rev])
@property
def start_delim(self) -> str:
return f"#### START VENDORED {self.name.upper()} ####"
@property
def end_delim(self) -> str:
return f"#### END VENDORED {self.name.upper()} ####"
def generate_vendored_source(self):
self.src_text = ""
for f, slices in self.files:
og_text = (self.basepath / f"{f}.py").read_text()
for indices in slices:
self.src_text = "\n".join(
(
self.src_text,
*[
line
for line in og_text.splitlines()[slice(*indices)]
if line.strip("\r\n")
],
)
)
def replace_identifiers(self):
patterns = set.union(
*[
set(re.findall(regex, self.src_text, re.MULTILINE))
for regex in (
r"^class (?P<class>[a-zA-Z_]*)(?:\(.*\))?:",
r"^(?P<ident>[a-zA-Z_]*) =",
r"^def (?P<function>[a-zA-Z_]+)\(",
)
]
) - {
"Key",
} # prevent KeyError false positive by leaving Key alone
for pat in patterns:
self.src_text = re.sub(
r'(?P<lead>[\s("\[={])' + pat,
f"\g<lead>v_{self.name}_{pat}",
self.src_text,
)
def insert(self, base_text: str) -> str:
start, rest = re.split(self.start_delim, base_text)
_, rest = re.split(self.end_delim, base_text)
src = textwrap.indent(
remove_docs_and_comments(self.src_text.strip()),
prefix=" " * (4 if self.indent else 0),
)
return "\n".join(
(
start.strip(),
"\n",
self.start_delim,
self.prefix + self.imports + src + self.suffix,
self.end_delim,
"\n",
rest.strip(),
)
)
PACKAGES = [
Package(
name="packaging",
url="https://github.com/pypa/packaging.git",
rev="23.2",
files=(
("_structures", [[5, 61]]),
("version", [[17, 563]]),
("utils", [[54, 100]]),
("specifiers", [[28, 1030]]),
),
basepath=Path(__file__).parent / "packaging/src/packaging",
prefix="""
# MODIFIED FROM https://github.com/pypa/packaging
# see repo for original licenses
# This software is made available under the terms of *either* of the licenses
# found in LICENSE.APACHE or LICENSE.BSD. Contributions to this software is made
# under the terms of *both* these licenses.
""",
imports="""
import abc # noqa
import itertools # noqa
import re # noqa
from typing import ( # noqa
Any,
Callable,
Iterable,
Iterator,
List,
NamedTuple,
Optional,
Set,
SupportsInt,
Tuple,
TypeVar,
Union,
)
""",
suffix="""
Version = v_packaging_Version
SpecifierSet = v_packaging_SpecifierSet
""",
),
Package(
name="tomli",
url="https://github.com/hukkin/tomli.git",
# rev="2.0.1",
rev="a6138675bcca68eea5b8abec7c2ec06d57f965a0",
files=(
("_types", [[7, 11]]),
("_re", [[14, 107]]),
("_parser", [[20, 691]]),
),
prefix="""
if sys.version_info >= (3, 11):
from tomllib import loads as toml_loads
else:
# MODIFIED FROM https://github.com/hukkin/tomli
# see below for original license
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021 Taneli Hukkinen
# Licensed to PSF under a Contributor Agreement.
""",
imports="""
import string # noqa
from collections.abc import Iterable # noqa
from functools import lru_cache # noqa
from datetime import date, datetime, time, timedelta, timezone, tzinfo # noqa
from types import MappingProxyType # noqa
from typing import IO, Any, Callable, NamedTuple # noqa
""",
basepath=Path(__file__).parent / "tomli/src/tomli",
suffix="""
toml_loads = v_tomli_loads
""",
indent=True,
),
]
def main():
viv_source_path = Path(__file__).parent.parent / "src/viv/viv.py"
viv_source = viv_source_path.read_text()
for pkg in PACKAGES:
viv_source = pkg.insert(viv_source)
viv_source_path.write_text(viv_source)
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load diff

17
tests/test_vendored.py Normal file
View file

@ -0,0 +1,17 @@
from viv.viv import SpecifierSet, Version, toml_loads
def test_packaging():
assert Version("3.6") in SpecifierSet(">=3.6")
def test_tomli():
assert {"requires-python": ">3.6", "dependencies": ["rich", "typer"]} == toml_loads(
"""
requires-python = ">3.6"
dependencies = [
"rich",
"typer"
]
"""
)