Merge pull request #529 from nix-community/remove-mach-nix-xs

Replace mach-nix-xs/fetchPip with pip/fetchPipMetadata
This commit is contained in:
DavHau 2023-06-20 17:22:52 +02:00 committed by GitHub
commit 0572dda8bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 922 additions and 939 deletions

View File

@ -1,52 +0,0 @@
{
config,
lib,
drv-parts,
name,
version,
...
}: let
l = lib // builtins;
fetchPip = import ../../../pkgs/fetchPip {
inherit lib;
inherit
(config.deps)
buildPackages
stdenv
python3 # only used for proxy script
;
};
in {
imports = [
./interface.nix
../lock
drv-parts.modules.drv-parts.mkDerivation
];
inherit name version;
package-func.outputs = ["out" "names"];
deps = {nixpkgs, ...}:
l.mapAttrs (_: l.mkDefault) {
inherit
(nixpkgs)
buildPackages
stdenv
python3 # only used for proxy script
;
python = nixpkgs.python3;
};
package-func.func = fetchPip;
package-func.args = l.mkForce (
config.fetch-pip
// {
inherit (config) name;
}
// lib.optionalAttrs (config.mkDerivation.nativeBuildInputs != null) {
inherit (config.mkDerivation) nativeBuildInputs;
}
);
}

View File

@ -1,92 +0,0 @@
{
config,
lib,
...
}: let
l = lib // builtins;
t = l.types;
in {
options.fetch-pip = {
hash = l.mkOption {
type = t.str;
description = ''
hash for the fixed output derivation
'';
};
pypiSnapshotDate = l.mkOption {
type = t.str;
description = ''
maximum release date for packages
Choose any date from the past.
'';
example = "2023-01-01";
};
nameSuffix = l.mkOption {
type = t.str;
default = "python-requirements";
description = ''
suffix of the fetcher derivation name
'';
};
noBinary = l.mkOption {
type = t.listOf t.str;
default = [];
description = ''
enforce source downloads for these package names
'';
};
onlyBinary = l.mkOption {
type = t.bool;
default = false;
description = ''
restrict to binary releases (.whl)
this allows buildPlatform independent fetching
'';
};
python = l.mkOption {
type = t.package;
default = config.deps.python;
description = ''
Specify the python version for which the packages should be downloaded.
Pip needs to be executed from that specific python version.
Pip accepts '--python-version', but this works only for wheel packages.
'';
};
pipFlags = l.mkOption {
type = t.listOf t.str;
description = ''
hash for the fixed output derivation
'';
default = [];
};
pipVersion = l.mkOption {
type = t.str;
default = "23.0";
description = ''
the pip version used for fetching
'';
example = "23.1";
};
requirementsList = l.mkOption {
type = t.listOf t.str;
default = [];
description = ''
list of strings of requirements.txt entries
'';
};
requirementsFiles = l.mkOption {
type = t.listOf t.path;
default = [];
description = ''
list of requirements.txt files
'';
};
writeMetaData = l.mkOption {
type = t.bool;
default = true;
description = ''
Write "metadata.json" to $out, documenting which package depends on which.
'';
};
};
}

View File

@ -1,250 +0,0 @@
{
config,
lib,
drv-parts,
...
}: let
l = lib // builtins;
python = config.deps.python;
cfg = config.mach-nix;
packageName = config.name;
# For a given name, return the path containing the downloaded file
getDistDir = name: "${cfg.pythonSources.names}/${name}";
# (IFD) Get the dist file for a given name by looking inside (pythonSources)
getDistFile = name: let
distDir = getDistDir name;
distFile = l.head (l.attrNames (builtins.readDir distDir));
in "${distDir}/${distFile}";
# Extract the version from a dist's file name
getVersion = file: let
base = l.pipe file [
(l.removeSuffix ".tgx")
(l.removeSuffix ".tar.gz")
(l.removeSuffix ".zip")
(l.removeSuffix ".whl")
];
version = l.last (l.splitString "-" base);
in
version;
# (IFD) For each dist we need to recall:
# - the type (wheel or sdist)
# - the version (only needed for sdist, so we can build a wheel)
getDistInfo = name: let
file = getDistFile name;
in
if l.hasSuffix ".whl" file
then "wheel"
else getVersion file;
preparedWheels = let
filterAttrs = l.flip l.filterAttrs;
mapAttrs = l.flip l.mapAttrs;
distInfos = config.eval-cache.content.mach-nix.dists;
# Validate Substitutions. Allow only names that we actually depend on.
unknownSubstitutions = l.attrNames (l.removeAttrs cfg.substitutions (l.attrNames distInfos));
substitutions =
if unknownSubstitutions == []
then cfg.substitutions
else
throw ''
${"\n"}The following substitutions for python derivation '${packageName}' will not have any effect. There are no dependencies with such names:
- ${lib.concatStringsSep "\n - " unknownSubstitutions}
'';
# separate 2 types of downloaded files: sdist, wheel
# key: name; val: {version or "wheel"}
wheelInfos = filterAttrs distInfos (name: ver: ver == "wheel");
sdistInfos = filterAttrs distInfos (name: ver: ! wheelInfos ? ${name});
# get the paths of all downloaded wheels
downloadedWheels = mapAttrs wheelInfos (name: ver: getDistDir name);
# Only build sdists which are not substituted via config.substitutions and which aren't the toplevel
# package.
sdistsToBuild = filterAttrs sdistInfos (name: ver: (! substitutions ? ${name}) && name != packageName);
builtWheels = mapAttrs sdistsToBuild (name: ver: mkWheelDist name ver (getDistDir name));
# Usually references to buildInputs would get lost in the dist output.
# Patch wheels to ensure build inputs remain dependencies of the `dist` output
# Those references are needed for the final autoPatchelfHook to find the required deps.
linkOutToDistOverride = old: {
linkOutToDist = "ln -s $out $dist/out";
postPhases = ["linkOutToDist"];
};
patchedWheels = mapAttrs substitutions (name: dist: dist.overridePythonAttrs linkOutToDistOverride);
in {inherit patchedWheels downloadedWheels builtWheels;};
# The final dists we want to install.
# A mix of:
# - downloaded wheels
# - downloaded sdists built into wheels (see above)
# - substitutions from nixpkgs patched for compat with autoPatchelfHook
finalDistsPaths =
preparedWheels.downloadedWheels // (l.mapAttrs (_: drv: drv.public.out.dist) config.mach-nix.drvs);
# build a wheel for a given sdist
mkWheelDist = name: version: distDir: let
manualSetupDeps =
lib.mapAttrs
(name: deps: map (dep: finalDistsPaths.${dep}) deps)
cfg.manualSetupDeps;
in
{config, ...}: {
imports = [
drv-parts.modules.drv-parts.mkDerivation
../buildPythonPackage
./interface.nix
../eval-cache
../nixpkgs-overrides
];
config = {
nixpkgs-overrides.enable = l.mkDefault true;
deps = {nixpkgs, ...}:
l.mapAttrs (_: l.mkDefault) {
inherit python;
inherit
(nixpkgs)
autoPatchelfHook
stdenv
unzip
;
};
inherit name version;
buildPythonPackage = {
format = l.mkDefault "setuptools";
pipInstallFlags =
(map (distDir: "--find-links ${distDir}") manualSetupDeps.${name} or [])
++ (
map (dep: "--find-links ${finalDistsPaths.${dep}}")
(getTransitiveDeps name)
);
};
mkDerivation = {
# distDir will contain a single file which is the src
preUnpack = ''export src="${distDir}"/*'';
nativeBuildInputs = [
config.deps.unzip
];
# ensure build inputs are propagated for autopPatchelfHook
postPhases = ["linkOutToDist"];
};
env.linkOutToDist = "ln -s $out $dist/out";
# TODO If setup deps have been specified manually, we need to remove the
# propagatedBuildInputs from nixpkgs to prevent collisions.
#// lib.optionalAttrs (manualSetupDeps ? ${name}) {
# propagatedBuildInputs = [];
#};
};
};
dependenciesFile = "${cfg.pythonSources}/metadata.json";
dependencyTree = l.fromJSON (l.readFile dependenciesFile);
getTransitiveDeps' = name: let
directDeps = dependencyTree.${name}.dependencies or [];
in
directDeps
++ (l.concatMap getTransitiveDeps' directDeps);
getTransitiveDeps = name: l.unique (getTransitiveDeps' name);
makeModuleFromDerivation = _name: drv:
drv-parts.lib.makeModule {
packageFunc = drv;
# TODO: if `overridePythonAttrs` is used here, the .dist output is missing
# Maybe a bug in drv-parts?
overrideFuncName = "overrideAttrs";
modules = [
{deps = {inherit (config.deps) stdenv;};}
];
};
in {
imports = [
drv-parts.modules.drv-parts.mkDerivation
../buildPythonPackage
./interface.nix
../eval-cache
../lock
];
config = {
# use lock file to manage hash for fetchPip
lock.fields.fetchPipHash = {
script =
config.lock.lib.computeFODHash
config.mach-nix.pythonSources;
default = l.fakeSha256;
};
mach-nix.drvs = (l.mapAttrs makeModuleFromDerivation preparedWheels.patchedWheels) // preparedWheels.builtWheels;
mach-nix.dists =
l.mapAttrs
(name: _: getDistInfo name)
(l.readDir cfg.pythonSources.names);
mach-nix.dependencyTree = dependencyTree;
mach-nix.pythonSources = {
imports = [../../drv-parts/fetch-pip];
deps.python = config.deps.python;
fetch-pip = {
hash = config.lock.content.fetchPipHash;
};
};
deps = {nixpkgs, ...}:
l.mapAttrs (_: l.mkDefault) {
inherit
(nixpkgs)
autoPatchelfHook
stdenv
;
manylinuxPackages = nixpkgs.pythonManylinuxPackages.manylinux1;
fetchPip = nixpkgs.callPackage ../../../pkgs/fetchPip {};
runCommand = nixpkgs.runCommand;
pip = nixpkgs.python3Packages.pip;
};
eval-cache.fields = {
mach-nix.dists = true;
mach-nix.dependencyTree = true;
};
eval-cache.invalidationFields = {
mach-nix.pythonSources = true;
};
buildPythonPackage = {
pipInstallFlags =
["--ignore-installed"]
++ (
map (distDir: "--find-links ${distDir}")
(l.attrValues finalDistsPaths)
);
};
mkDerivation = {
doCheck = false;
dontPatchELF = l.mkDefault true;
dontStrip = l.mkDefault true;
nativeBuildInputs =
l.optionals config.deps.stdenv.isLinux [config.deps.autoPatchelfHook];
buildInputs =
l.optionals config.deps.stdenv.isLinux [config.deps.manylinuxPackages];
passthru = {
inherit (config.mach-nix) pythonSources;
dists = finalDistsPaths;
};
};
};
}

View File

@ -1,83 +0,0 @@
{
config,
lib,
drv-parts,
packageSets,
...
}: let
l = lib // builtins;
t = l.types;
drvPartsTypes = import (drv-parts + /types) {
inherit lib;
specialArgs = {
inherit packageSets drv-parts;
inherit (config) name version;
};
};
in {
options.mach-nix = {
pythonSources = l.mkOption {
type = drvPartsTypes.drvPartOrPackage;
# if module given, convert to derivation
apply = val: val.public or val;
description = ''
A derivation or drv-part that outputs fetched python sources.
Each single python source must be located in a subdirectory named after the package name.
'';
};
substitutions = l.mkOption {
type = t.lazyAttrsOf t.package;
description = ''
Substitute individual python packages from nixpkgs.
'';
default = {};
};
manualSetupDeps = l.mkOption {
type = t.lazyAttrsOf (t.listOf t.str);
description = ''
Replace the default setup dependencies from nixpkgs for sdist based builds
'';
default = {};
example = {
vobject = [
"python-dateutil"
"six"
];
libsass = [
"six"
];
};
};
drvs = l.mkOption {
type = t.attrsOf (t.submoduleWith {
modules = [drv-parts.modules.drv-parts.core];
specialArgs = {inherit packageSets;};
});
description = "drv-parts modules that define python dependencies";
};
# INTERNAL
dists = l.mkOption {
type = t.lazyAttrsOf t.str;
description = ''
Attrs which depend on IFD and therefore should be cached
'';
internal = true;
readOnly = true;
};
dependencyTree = l.mkOption {
type = t.lazyAttrsOf t.anything;
description = ''
Dependency tree of the python environment
'';
internal = true;
readOnly = true;
};
};
}

View File

@ -9,7 +9,7 @@
nixpkgsAttrs = extractPythonAttrs python.pkgs.apache-airflow;
in {
imports = [
../../drv-parts/mach-nix-xs
../../drv-parts/pip
../../drv-parts/nixpkgs-overrides
];
@ -23,6 +23,7 @@ in {
git
fetchFromGitHub
;
python = nixpkgs.python3;
};
name = "apache-airflow";
@ -53,19 +54,30 @@ in {
;
};
mach-nix.pythonSources.fetch-pip = {
pip = {
pypiSnapshotDate = "2023-01-01";
requirementsList = [
"apache-airflow"
"setuptools-scm"
];
};
# Replace some python packages entirely with candidates from nixpkgs, because
# they are hard to fix
mach-nix.substitutions = {
cron-descriptor = python.pkgs.cron-descriptor;
python-nvd3 = python.pkgs.python-nvd3;
pendulum = python.pkgs.pendulum;
drvs = {
# We include fixes from nixpkgs for pendulum, but keep
# our dependencies to avoid version conflicts
pendulum.nixpkgs-overrides = {
enable = true;
exclude = ["propagatedBuildInputs"];
};
lazy-object-proxy.mkDerivation = {
# setuptools-scm is required by lazy-object-proxy,
# we include it in our requirements above instead of
# using the version from nixpkgs to ensure that
# transistive dependencies (i.e. typing-extensions) are
# compatible with the rest of our lock file.
buildInputs = [config.pip.drvs.setuptools-scm.public];
};
};
};
env = {

View File

@ -1,3 +1,899 @@
{
"fetchPipHash": "sha256-pAI3j43S4HedxsXIbe2+LQtpzcp1gjwlneohlD3V3LA="
"fetchPipMetadata": {
"alembic": {
"dependencies": [
"mako",
"sqlalchemy"
],
"sha256": "a9781ed0979a20341c2cbb56bd22bd8db4fc1913f955e705444bd3a97c59fa32",
"url": "https://files.pythonhosted.org/packages/67/8d/694d5c1de901de71cd6d5fb2d0e19cad29b5615c6b56dabcf0a4aaf34082/alembic-1.9.1-py3-none-any.whl",
"version": "1.9.1"
},
"anyio": {
"dependencies": [
"idna",
"sniffio"
],
"sha256": "fbbe32bd270d2a2ef3ed1c5d45041250284e31fc0a4df4a5a6071842051a51e3",
"url": "https://files.pythonhosted.org/packages/77/2b/b4c0b7a3f3d61adb1a1e0b78f90a94e2b6162a043880704b7437ef297cad/anyio-3.6.2-py3-none-any.whl",
"version": "3.6.2"
},
"apache-airflow": {
"dependencies": [
"alembic",
"apache-airflow-providers-common-sql",
"apache-airflow-providers-ftp",
"apache-airflow-providers-http",
"apache-airflow-providers-imap",
"apache-airflow-providers-sqlite",
"argcomplete",
"attrs",
"blinker",
"cattrs",
"colorlog",
"configupdater",
"connexion",
"cron-descriptor",
"croniter",
"cryptography",
"deprecated",
"dill",
"flask",
"flask-appbuilder",
"flask-caching",
"flask-login",
"flask-session",
"flask-wtf",
"graphviz",
"gunicorn",
"httpx",
"itsdangerous",
"jinja2",
"jsonschema",
"lazy-object-proxy",
"linkify-it-py",
"lockfile",
"markdown",
"markdown-it-py",
"markupsafe",
"marshmallow-oneofschema",
"mdit-py-plugins",
"packaging",
"pathspec",
"pendulum",
"pluggy",
"psutil",
"pygments",
"pyjwt",
"python-daemon",
"python-dateutil",
"python-nvd3",
"python-slugify",
"rich",
"setproctitle",
"sqlalchemy",
"sqlalchemy-jsonfield",
"tabulate",
"tenacity",
"termcolor",
"typing-extensions",
"unicodecsv",
"werkzeug"
],
"sha256": "fb2c2768e3a233e60b110431b907045256a224cffaf01fa475ccef3db8d6edd3",
"url": "https://files.pythonhosted.org/packages/94/3a/3d050e3decaf7c1064e6e0e5e06f5f9be6c7476b438f8d25e458421e2e13/apache_airflow-2.5.0-py3-none-any.whl",
"version": "2.5.0"
},
"apache-airflow-providers-common-sql": {
"dependencies": [
"sqlparse"
],
"sha256": "352e7303149083687635b1d8b401b0925bccaeb7c493a9dc1416b828d9891fc7",
"url": "https://files.pythonhosted.org/packages/9f/65/8127df3048051278b7f3f8a0ba834533ead54fc6a292ec498ec636268703/apache_airflow_providers_common_sql-1.3.1-py3-none-any.whl",
"version": "1.3.1"
},
"apache-airflow-providers-ftp": {
"dependencies": [],
"sha256": "b2eee640f7eaf0fff3ebeeacc83fe0c315aa297de8780a5a6aededfeeb7e11e0",
"url": "https://files.pythonhosted.org/packages/9b/cf/d4368604feca0b93dd29dce04c19ae4e5a62071ad44faf9d13210ace3a3c/apache_airflow_providers_ftp-3.2.0-py3-none-any.whl",
"version": "3.2.0"
},
"apache-airflow-providers-http": {
"dependencies": [
"requests",
"requests-toolbelt"
],
"sha256": "c424945876ba3d40ef108e73973aba646509336f589f9d0a11a44786e6dac2b7",
"url": "https://files.pythonhosted.org/packages/48/74/ec2dcbc3a8dc442b5d427658e516f8b7410bcc4823bb091c8be2823a4a67/apache_airflow_providers_http-4.1.0-py3-none-any.whl",
"version": "4.1.0"
},
"apache-airflow-providers-imap": {
"dependencies": [],
"sha256": "79da5956637788c19fd3a152bb20fb476c980fdad80724fec8ade02abe47834b",
"url": "https://files.pythonhosted.org/packages/63/41/bcf07b9be7802a8ff18b2ae6e1f8b5c3ae3aa119c5739b1f0aac8e865734/apache_airflow_providers_imap-3.1.0-py3-none-any.whl",
"version": "3.1.0"
},
"apache-airflow-providers-sqlite": {
"dependencies": [
"apache-airflow-providers-common-sql"
],
"sha256": "f282247f29a3130eae6c05d8c41cee012e1b7d482c6a7ed058deef01e9af1c43",
"url": "https://files.pythonhosted.org/packages/e3/cf/dcacb9649a4f0004871d040ddbce429404a6af82df18b964432790022f0a/apache_airflow_providers_sqlite-3.3.1-py3-none-any.whl",
"version": "3.3.1"
},
"apispec": {
"dependencies": [
"pyyaml"
],
"sha256": "a1df9ec6b2cd0edf45039ef025abd7f0660808fa2edf737d3ba1cf5ef1a4625b",
"url": "https://files.pythonhosted.org/packages/35/a2/80a82b22296c942a5298bb760e8e21c86ace3342de840ff3df8938af4272/apispec-3.3.2-py2.py3-none-any.whl",
"version": "3.3.2"
},
"argcomplete": {
"dependencies": [],
"sha256": "cffa11ea77999bb0dd27bb25ff6dc142a6796142f68d45b1a26b11f58724561e",
"url": "https://files.pythonhosted.org/packages/d3/e5/c5509683462e51b070df9e83e7f72c1ccfe3f733f328b4a0f06804c27278/argcomplete-2.0.0-py2.py3-none-any.whl",
"version": "2.0.0"
},
"attrs": {
"dependencies": [],
"sha256": "29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836",
"url": "https://files.pythonhosted.org/packages/fb/6e/6f83bf616d2becdf333a1640f1d463fef3150e2e926b7010cb0f81c95e88/attrs-22.2.0-py3-none-any.whl",
"version": "22.2.0"
},
"babel": {
"dependencies": [
"pytz"
],
"sha256": "1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe",
"url": "https://files.pythonhosted.org/packages/92/f7/86301a69926e11cd52f73396d169554d09b20b1723a040c2dcc1559ef588/Babel-2.11.0-py3-none-any.whl",
"version": "2.11.0"
},
"blinker": {
"dependencies": [],
"sha256": "1eb563df6fdbc39eeddc177d953203f99f097e9bf0e2b8f9f3cf18b6ca425e36",
"url": "https://files.pythonhosted.org/packages/30/41/caa5da2dbe6d26029dfe11d31dfa8132b4d6d30b6d6b61a24824075a5f06/blinker-1.5-py2.py3-none-any.whl",
"version": "1.5"
},
"cachelib": {
"dependencies": [],
"sha256": "811ceeb1209d2fe51cd2b62810bd1eccf70feba5c52641532498be5c675493b3",
"url": "https://files.pythonhosted.org/packages/93/70/58e525451478055b0fd2859b22226888a6985d404fe65e014fc4893d3b75/cachelib-0.9.0-py3-none-any.whl",
"version": "0.9.0"
},
"cattrs": {
"dependencies": [
"attrs",
"exceptiongroup"
],
"sha256": "bc12b1f0d000b9f9bee83335887d532a1d3e99a833d1bf0882151c97d3e68c21",
"url": "https://files.pythonhosted.org/packages/43/3b/1d34fc4449174dfd2bc5ad7047a23edb6558b2e4b5a41b25a8ad6655c6c7/cattrs-22.2.0-py3-none-any.whl",
"version": "22.2.0"
},
"certifi": {
"dependencies": [],
"sha256": "4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18",
"url": "https://files.pythonhosted.org/packages/71/4c/3db2b8021bd6f2f0ceb0e088d6b2d49147671f25832fb17970e9b583d742/certifi-2022.12.7-py3-none-any.whl",
"version": "2022.12.7"
},
"cffi": {
"dependencies": [
"pycparser"
],
"sha256": "dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4",
"url": "https://files.pythonhosted.org/packages/88/89/c34caf63029fb7628ec2ebd5c88ae0c9bd17db98c812e4065a4d020ca41f/cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "1.15.1"
},
"charset-normalizer": {
"dependencies": [],
"sha256": "83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f",
"url": "https://files.pythonhosted.org/packages/db/51/a507c856293ab05cdc1db77ff4bc1268ddd39f29e7dc4919aa497f0adbec/charset_normalizer-2.1.1-py3-none-any.whl",
"version": "2.1.1"
},
"click": {
"dependencies": [],
"sha256": "bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48",
"url": "https://files.pythonhosted.org/packages/c2/f1/df59e28c642d583f7dacffb1e0965d0e00b218e0186d7858ac5233dce840/click-8.1.3-py3-none-any.whl",
"version": "8.1.3"
},
"clickclick": {
"dependencies": [
"click",
"pyyaml"
],
"sha256": "c8f33e6d9ec83f68416dd2136a7950125bd256ec39ccc9a85c6e280a16be2bb5",
"url": "https://files.pythonhosted.org/packages/7a/7e/c08007d3fb2bbefb430437a3573373590abedc03566b785d7d6763b22480/clickclick-20.10.2-py2.py3-none-any.whl",
"version": "20.10.2"
},
"colorama": {
"dependencies": [],
"sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6",
"url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl",
"version": "0.4.6"
},
"colorlog": {
"dependencies": [],
"sha256": "3dd15cb27e8119a24c1a7b5c93f9f3b455855e0f73993b1c25921b2f646f1dcd",
"url": "https://files.pythonhosted.org/packages/51/62/61449c6bb74c2a3953c415b2cdb488e4f0518ac67b35e2b03a6d543035ca/colorlog-4.8.0-py2.py3-none-any.whl",
"version": "4.8.0"
},
"commonmark": {
"dependencies": [],
"sha256": "da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9",
"url": "https://files.pythonhosted.org/packages/b1/92/dfd892312d822f36c55366118b95d914e5f16de11044a27cf10a7d71bbbf/commonmark-0.9.1-py2.py3-none-any.whl",
"version": "0.9.1"
},
"configupdater": {
"dependencies": [],
"sha256": "805986dbeba317886c7a8d348b2e34986dc9e3128cd3761ecc35decbd372b286",
"url": "https://files.pythonhosted.org/packages/4d/13/6791bba527baf3648be8aabaf6d3775027c3ebbf4000f2ae16867911b879/ConfigUpdater-3.1.1-py2.py3-none-any.whl",
"version": "3.1.1"
},
"connexion": {
"dependencies": [
"clickclick",
"flask",
"inflection",
"itsdangerous",
"jsonschema",
"packaging",
"pyyaml",
"requests",
"swagger-ui-bundle",
"werkzeug"
],
"sha256": "f343717241b4c4802a694c38fee66fb1693c897fe4ea5a957fa9b3b07caf6394",
"url": "https://files.pythonhosted.org/packages/de/ce/1ed67157e4d5fae496be1a82e0c1003bcef944dad0f902c4f6c3fd1c8f4d/connexion-2.14.1-py2.py3-none-any.whl",
"version": "2.14.1"
},
"cron-descriptor": {
"dependencies": [],
"sha256": "a8554e91483f9977c3e5fa90a3c7a06fb97472ec9b160df6fe89f3114658236d",
"url": "https://files.pythonhosted.org/packages/7d/4f/fc70577320a99982006ab4ee11f5d5fb0f819aff2e5fff0b6bc54ff19c96/cron_descriptor-1.2.32.tar.gz",
"version": "1.2.32"
},
"croniter": {
"dependencies": [
"python-dateutil"
],
"sha256": "d6ed8386d5f4bbb29419dc1b65c4909c04a2322bd15ec0dc5b2877bfa1b75c7a",
"url": "https://files.pythonhosted.org/packages/0f/4d/0cc5a7f4bdcefecebdf8a95c8372606c13d3355e8536d9cd3e7070e94269/croniter-1.3.8-py2.py3-none-any.whl",
"version": "1.3.8"
},
"cryptography": {
"dependencies": [
"cffi"
],
"sha256": "ce127dd0a6a0811c251a6cddd014d292728484e530d80e872ad9806cfb1c5b3c",
"url": "https://files.pythonhosted.org/packages/26/f8/a81170a816679fca9ccd907b801992acfc03c33f952440421c921af2cc57/cryptography-38.0.4-cp36-abi3-manylinux_2_28_x86_64.whl",
"version": "38.0.4"
},
"deprecated": {
"dependencies": [
"wrapt"
],
"sha256": "64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d",
"url": "https://files.pythonhosted.org/packages/51/6a/c3a0408646408f7283b7bc550c30a32cc791181ec4618592eec13e066ce3/Deprecated-1.2.13-py2.py3-none-any.whl",
"version": "1.2.13"
},
"dill": {
"dependencies": [],
"sha256": "a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0",
"url": "https://files.pythonhosted.org/packages/be/e3/a84bf2e561beed15813080d693b4b27573262433fced9c1d1fea59e60553/dill-0.3.6-py3-none-any.whl",
"version": "0.3.6"
},
"dnspython": {
"dependencies": [],
"sha256": "a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f",
"url": "https://files.pythonhosted.org/packages/9b/ed/28fb14146c7033ba0e89decd92a4fa16b0b69b84471e2deab3cc4337cc35/dnspython-2.2.1-py3-none-any.whl",
"version": "2.2.1"
},
"docutils": {
"dependencies": [],
"sha256": "5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc",
"url": "https://files.pythonhosted.org/packages/93/69/e391bd51bc08ed9141ecd899a0ddb61ab6465309f1eb470905c0c8868081/docutils-0.19-py3-none-any.whl",
"version": "0.19"
},
"email-validator": {
"dependencies": [
"dnspython",
"idna"
],
"sha256": "816073f2a7cffef786b29928f58ec16cdac42710a53bb18aa94317e3e145ec5c",
"url": "https://files.pythonhosted.org/packages/e7/d3/88997ca4903c70fb6eec2e29501a35f84aaf34790f207febdf188e374377/email_validator-1.3.0-py2.py3-none-any.whl",
"version": "1.3.0"
},
"exceptiongroup": {
"dependencies": [],
"sha256": "327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e",
"url": "https://files.pythonhosted.org/packages/e8/14/9c6a7e5f12294ccd6975a45e02899ed25468cd7c2c86f3d9725f387f9f5f/exceptiongroup-1.1.0-py3-none-any.whl",
"version": "1.1.0"
},
"flask": {
"dependencies": [
"click",
"itsdangerous",
"jinja2",
"werkzeug"
],
"sha256": "b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526",
"url": "https://files.pythonhosted.org/packages/0f/43/15f4f9ab225b0b25352412e8daa3d0e3d135fcf5e127070c74c3632c8b4c/Flask-2.2.2-py3-none-any.whl",
"version": "2.2.2"
},
"flask-appbuilder": {
"dependencies": [
"apispec",
"click",
"colorama",
"email-validator",
"flask",
"flask-babel",
"flask-jwt-extended",
"flask-login",
"flask-sqlalchemy",
"flask-wtf",
"jsonschema",
"marshmallow",
"marshmallow-enum",
"marshmallow-sqlalchemy",
"prison",
"pyjwt",
"python-dateutil",
"sqlalchemy",
"sqlalchemy-utils",
"wtforms"
],
"sha256": "682e18fab43ccec8f4aac696f090ae45326b0ee1f3ad9608896111ff8405a7a4",
"url": "https://files.pythonhosted.org/packages/3b/28/9acebe45a02908193b28668867b8e948e747e37cb95937ee5f0281d71e27/Flask_AppBuilder-4.1.4-py3-none-any.whl",
"version": "4.1.4"
},
"flask-babel": {
"dependencies": [
"babel",
"flask",
"jinja2",
"pytz"
],
"sha256": "e6820a052a8d344e178cdd36dd4bb8aea09b4bda3d5f9fa9f008df2c7f2f5468",
"url": "https://files.pythonhosted.org/packages/ab/3e/02331179ffab8b79e0383606a028b6a60fb1b4419b84935edd43223406a0/Flask_Babel-2.0.0-py3-none-any.whl",
"version": "2.0.0"
},
"flask-caching": {
"dependencies": [
"cachelib",
"flask"
],
"sha256": "703df847cbe904d8ddffd5f5fb320e236a31cb7bebac4a93d6b1701dd16dbf37",
"url": "https://files.pythonhosted.org/packages/8b/3c/9b767cd054aa23283b55f45fca0bc6afc74c425ea15b67c8cd324ead9c06/Flask_Caching-2.0.1-py3-none-any.whl",
"version": "2.0.1"
},
"flask-jwt-extended": {
"dependencies": [
"flask",
"pyjwt",
"werkzeug"
],
"sha256": "a85eebfa17c339a7260c4643475af444784ba6de5588adda67406f0a75599553",
"url": "https://files.pythonhosted.org/packages/83/5a/f688f884d9bd10b0cf1b34373b5634ddc340f2b1a099d014bc3c997bf562/Flask_JWT_Extended-4.4.4-py2.py3-none-any.whl",
"version": "4.4.4"
},
"flask-login": {
"dependencies": [
"flask",
"werkzeug"
],
"sha256": "1ef79843f5eddd0f143c2cd994c1b05ac83c0401dc6234c143495af9a939613f",
"url": "https://files.pythonhosted.org/packages/a6/94/01b658bef1863a07f4738a322cce87d97be4362645255dc1182f7f5c075a/Flask_Login-0.6.2-py3-none-any.whl",
"version": "0.6.2"
},
"flask-session": {
"dependencies": [
"cachelib",
"flask"
],
"sha256": "1e3f8a317005db72c831f85d884a5a9d23145f256c730d80b325a3150a22c3db",
"url": "https://files.pythonhosted.org/packages/83/ae/13f06537405f8e04868f578295fa94bd46f0c1764431417a4059e2b54c91/Flask_Session-0.4.0-py2.py3-none-any.whl",
"version": "0.4.0"
},
"flask-sqlalchemy": {
"dependencies": [
"flask",
"sqlalchemy"
],
"sha256": "f12c3d4cc5cc7fdcc148b9527ea05671718c3ea45d50c7e732cceb33f574b390",
"url": "https://files.pythonhosted.org/packages/26/2c/9088b6bd95bca539230bbe9ad446737ed391aab9a83aff403e18dded3e75/Flask_SQLAlchemy-2.5.1-py2.py3-none-any.whl",
"version": "2.5.1"
},
"flask-wtf": {
"dependencies": [
"flask",
"itsdangerous",
"wtforms"
],
"sha256": "9d733658c80be551ce7d5bc13c7a7ac0d80df509be1e23827c847d9520f4359a",
"url": "https://files.pythonhosted.org/packages/3a/26/3803ee692eb9a8d21bf7ba1cecd649ce3a55899c65467bdfc1bad13ec50f/Flask_WTF-1.0.1-py3-none-any.whl",
"version": "1.0.1"
},
"graphviz": {
"dependencies": [],
"sha256": "587c58a223b51611c0cf461132da386edd896a029524ca61a1462b880bf97977",
"url": "https://files.pythonhosted.org/packages/de/5e/fcbb22c68208d39edff467809d06c9d81d7d27426460ebc598e55130c1aa/graphviz-0.20.1-py3-none-any.whl",
"version": "0.20.1"
},
"greenlet": {
"dependencies": [],
"sha256": "c140e7eb5ce47249668056edf3b7e9900c6a2e22fb0eaf0513f18a1b2c14e1da",
"url": "https://files.pythonhosted.org/packages/dd/5e/7309beef044bb4ceb0f052dc3797678a5f4eb6d07789787b2e4a15803b7a/greenlet-2.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "2.0.1"
},
"gunicorn": {
"dependencies": [
"setuptools"
],
"sha256": "9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e",
"url": "https://files.pythonhosted.org/packages/e4/dd/5b190393e6066286773a67dfcc2f9492058e9b57c4867a95f1ba5caf0a83/gunicorn-20.1.0-py3-none-any.whl",
"version": "20.1.0"
},
"h11": {
"dependencies": [],
"sha256": "e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761",
"url": "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl",
"version": "0.14.0"
},
"httpcore": {
"dependencies": [
"anyio",
"certifi",
"h11",
"sniffio"
],
"sha256": "da1fb708784a938aa084bde4feb8317056c55037247c787bd7e19eb2c2949dc0",
"url": "https://files.pythonhosted.org/packages/04/7e/ef97af4623024e8159993b3114ce208de4f677098ae058ec5882a1bf7605/httpcore-0.16.3-py3-none-any.whl",
"version": "0.16.3"
},
"httpx": {
"dependencies": [
"certifi",
"httpcore",
"rfc3986",
"sniffio"
],
"sha256": "0b9b1f0ee18b9978d637b0776bfd7f54e2ca278e063e3586d8f01cda89e042a8",
"url": "https://files.pythonhosted.org/packages/e1/74/cdce73069e021ad5913451b86c2707b027975cf302016ca557686d87eb41/httpx-0.23.1-py3-none-any.whl",
"version": "0.23.1"
},
"idna": {
"dependencies": [],
"sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2",
"url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl",
"version": "3.4"
},
"inflection": {
"dependencies": [],
"sha256": "f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2",
"url": "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl",
"version": "0.5.1"
},
"itsdangerous": {
"dependencies": [],
"sha256": "2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
"url": "https://files.pythonhosted.org/packages/68/5f/447e04e828f47465eeab35b5d408b7ebaaaee207f48b7136c5a7267a30ae/itsdangerous-2.1.2-py3-none-any.whl",
"version": "2.1.2"
},
"jinja2": {
"dependencies": [
"markupsafe"
],
"sha256": "6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61",
"url": "https://files.pythonhosted.org/packages/bc/c3/f068337a370801f372f2f8f6bad74a5c140f6fda3d9de154052708dd3c65/Jinja2-3.1.2-py3-none-any.whl",
"version": "3.1.2"
},
"jsonschema": {
"dependencies": [
"attrs",
"pyrsistent"
],
"sha256": "a870ad254da1a8ca84b6a2905cac29d265f805acc57af304784962a2aa6508f6",
"url": "https://files.pythonhosted.org/packages/c1/97/c698bd9350f307daad79dd740806e1a59becd693bd11443a0f531e3229b3/jsonschema-4.17.3-py3-none-any.whl",
"version": "4.17.3"
},
"lazy-object-proxy": {
"dependencies": [],
"sha256": "c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156",
"url": "https://files.pythonhosted.org/packages/74/37/591f89e8a09ae4574391bdf8a5eecd34a3dbe545917333e625c9de9a66b0/lazy-object-proxy-1.8.0.tar.gz",
"version": "1.8.0"
},
"linkify-it-py": {
"dependencies": [
"uc-micro-py"
],
"sha256": "1bff43823e24e507a099e328fc54696124423dd6320c75a9da45b4b754b748ad",
"url": "https://files.pythonhosted.org/packages/fa/1a/2280e2eb892162ef5c0480a131d1d176b61f5f24abdce8dd9862454f7d14/linkify_it_py-2.0.0-py3-none-any.whl",
"version": "2.0.0"
},
"lockfile": {
"dependencies": [],
"sha256": "6c3cb24f344923d30b2785d5ad75182c8ea7ac1b6171b08657258ec7429d50fa",
"url": "https://files.pythonhosted.org/packages/c8/22/9460e311f340cb62d26a38c419b1381b8593b0bb6b5d1f056938b086d362/lockfile-0.12.2-py2.py3-none-any.whl",
"version": "0.12.2"
},
"mako": {
"dependencies": [
"markupsafe"
],
"sha256": "c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818",
"url": "https://files.pythonhosted.org/packages/03/3b/68690a035ba7347860f1b8c0cde853230ba69ff41df5884ea7d89fe68cd3/Mako-1.2.4-py3-none-any.whl",
"version": "1.2.4"
},
"markdown": {
"dependencies": [],
"sha256": "08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186",
"url": "https://files.pythonhosted.org/packages/86/be/ad281f7a3686b38dd8a307fa33210cdf2130404dfef668a37a4166d737ca/Markdown-3.4.1-py3-none-any.whl",
"version": "3.4.1"
},
"markdown-it-py": {
"dependencies": [
"mdurl"
],
"sha256": "93de681e5c021a432c63147656fe21790bc01231e0cd2da73626f1aa3ac0fe27",
"url": "https://files.pythonhosted.org/packages/f9/3f/ecd1b708973b9a3e4574b43cffc1ce8eb98696da34f1a1c44a68c3c0d737/markdown_it_py-2.1.0-py3-none-any.whl",
"version": "2.1.0"
},
"markupsafe": {
"dependencies": [],
"sha256": "10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
"url": "https://files.pythonhosted.org/packages/9e/82/2e089c6f34e77c073aa5a67040d368aac0dfb9b8ccbb46d381452c26fc33/MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "2.1.1"
},
"marshmallow": {
"dependencies": [
"packaging"
],
"sha256": "93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b",
"url": "https://files.pythonhosted.org/packages/ae/53/980a20d789029329fdf1546c315f9c92bf862c7f3e7294e3667afcc464f5/marshmallow-3.19.0-py3-none-any.whl",
"version": "3.19.0"
},
"marshmallow-enum": {
"dependencies": [
"marshmallow"
],
"sha256": "57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072",
"url": "https://files.pythonhosted.org/packages/c6/59/ef3a3dc499be447098d4a89399beb869f813fee1b5a57d5d79dee2c1bf51/marshmallow_enum-1.5.1-py2.py3-none-any.whl",
"version": "1.5.1"
},
"marshmallow-oneofschema": {
"dependencies": [
"marshmallow"
],
"sha256": "bd29410a9f2f7457a2b428286e2a80ef76b8ddc3701527dc1f935a88914b02f2",
"url": "https://files.pythonhosted.org/packages/ca/eb/3f6d90ba82b2dd319c7d3534a90ba3f4bdf2e332e89c2399fdc818051589/marshmallow_oneofschema-3.0.1-py2.py3-none-any.whl",
"version": "3.0.1"
},
"marshmallow-sqlalchemy": {
"dependencies": [
"marshmallow",
"sqlalchemy"
],
"sha256": "ba7493eeb8669a3bf00d8f906b657feaa87a740ae9e4ecf829cfd6ddf763d276",
"url": "https://files.pythonhosted.org/packages/d1/84/1f4d7393d04f2ae0d4098791d1901a713f45ba70ff6f3c35ff2f7fd81f7b/marshmallow_sqlalchemy-0.26.1-py2.py3-none-any.whl",
"version": "0.26.1"
},
"mdit-py-plugins": {
"dependencies": [
"markdown-it-py"
],
"sha256": "36d08a29def19ec43acdcd8ba471d3ebab132e7879d442760d963f19913e04b9",
"url": "https://files.pythonhosted.org/packages/33/eb/c358112e8265f827cf8228eda36cf2a720ad933f5ca66f47f808edf4bb34/mdit_py_plugins-0.3.3-py3-none-any.whl",
"version": "0.3.3"
},
"mdurl": {
"dependencies": [],
"sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
"url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl",
"version": "0.1.2"
},
"packaging": {
"dependencies": [],
"sha256": "957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3",
"url": "https://files.pythonhosted.org/packages/8f/7b/42582927d281d7cb035609cd3a543ffac89b74f3f4ee8e1c50914bcb57eb/packaging-22.0-py3-none-any.whl",
"version": "22.0"
},
"pathspec": {
"dependencies": [],
"sha256": "7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a",
"url": "https://files.pythonhosted.org/packages/42/ba/a9d64c7bcbc7e3e8e5f93a52721b377e994c22d16196e2b0f1236774353a/pathspec-0.9.0-py2.py3-none-any.whl",
"version": "0.9.0"
},
"pendulum": {
"dependencies": [
"python-dateutil",
"pytzdata"
],
"sha256": "b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207",
"url": "https://files.pythonhosted.org/packages/db/15/6e89ae7cde7907118769ed3d2481566d05b5fd362724025198bb95faf599/pendulum-2.1.2.tar.gz",
"version": "2.1.2"
},
"pluggy": {
"dependencies": [],
"sha256": "74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3",
"url": "https://files.pythonhosted.org/packages/9e/01/f38e2ff29715251cf25532b9082a1589ab7e4f571ced434f98d0139336dc/pluggy-1.0.0-py2.py3-none-any.whl",
"version": "1.0.0"
},
"prison": {
"dependencies": [
"six"
],
"sha256": "f90bab63fca497aa0819a852f64fb21a4e181ed9f6114deaa5dc04001a7555c5",
"url": "https://files.pythonhosted.org/packages/f1/bd/e55e14cd213174100be0353824f2add41e8996c6f32081888897e8ec48b5/prison-0.2.1-py2.py3-none-any.whl",
"version": "0.2.1"
},
"psutil": {
"dependencies": [],
"sha256": "54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08",
"url": "https://files.pythonhosted.org/packages/6e/c8/784968329c1c67c28cce91991ef9af8a8913aa5a3399a6a8954b1380572f/psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "5.9.4"
},
"pycparser": {
"dependencies": [],
"sha256": "8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9",
"url": "https://files.pythonhosted.org/packages/62/d5/5f610ebe421e85889f2e55e33b7f9a6795bd982198517d912eb1c76e1a53/pycparser-2.21-py2.py3-none-any.whl",
"version": "2.21"
},
"pygments": {
"dependencies": [],
"sha256": "f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42",
"url": "https://files.pythonhosted.org/packages/4f/82/672cd382e5b39ab1cd422a672382f08a1fb3d08d9e0c0f3707f33a52063b/Pygments-2.13.0-py3-none-any.whl",
"version": "2.13.0"
},
"pyjwt": {
"dependencies": [],
"sha256": "d83c3d892a77bbb74d3e1a2cfa90afaadb60945205d1095d9221f04466f64c14",
"url": "https://files.pythonhosted.org/packages/40/46/505f0dd53c14096f01922bf93a7abb4e40e29a06f858abbaa791e6954324/PyJWT-2.6.0-py3-none-any.whl",
"version": "2.6.0"
},
"pyrsistent": {
"dependencies": [],
"sha256": "ccf0d6bd208f8111179f0c26fdf84ed7c3891982f2edaeae7422575f47e66b64",
"url": "https://files.pythonhosted.org/packages/64/de/375aa14daaee107f987da76ca32f7a907fea00fa8b8afb67dc09bec0de91/pyrsistent-0.19.3-py3-none-any.whl",
"version": "0.19.3"
},
"python-daemon": {
"dependencies": [
"docutils",
"lockfile",
"setuptools"
],
"sha256": "01d26358598f8c3f5fc6de553e2f3080ffc59cf89102d7ee8098f33c72b3c04c",
"url": "https://files.pythonhosted.org/packages/89/38/c223036ee8104ae95118d4481b5cacccf4547d7e5b8d1ee1c63d2cd57e5d/python_daemon-2.3.2-py3-none-any.whl",
"version": "2.3.2"
},
"python-dateutil": {
"dependencies": [
"six"
],
"sha256": "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9",
"url": "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl",
"version": "2.8.2"
},
"python-nvd3": {
"dependencies": [
"jinja2",
"python-slugify"
],
"sha256": "fbd75ff47e0ef255b4aa4f3a8b10dc8b4024aa5a9a7abed5b2406bd3cb817715",
"url": "https://files.pythonhosted.org/packages/0b/aa/97165daa6e319409c5c2582e62736a7353bda3c90d90fdcb0b11e116dd2d/python-nvd3-0.15.0.tar.gz",
"version": "0.15.0"
},
"python-slugify": {
"dependencies": [
"text-unidecode"
],
"sha256": "003aee64f9fd955d111549f96c4b58a3f40b9319383c70fad6277a4974bbf570",
"url": "https://files.pythonhosted.org/packages/63/65/d0d7c085964fdf0cb294299663b407c38e2c8e8dd13bafcf5681798c12db/python_slugify-7.0.0-py2.py3-none-any.whl",
"version": "7.0.0"
},
"pytz": {
"dependencies": [],
"sha256": "93007def75ae22f7cd991c84e02d434876818661f8df9ad5df9e950ff4e52cfd",
"url": "https://files.pythonhosted.org/packages/3d/19/4de17f0d5cf5a0d87aa67532d4c2fa75e6e7d8df13c27635ff40fa6f4b76/pytz-2022.7-py2.py3-none-any.whl",
"version": "2022.7"
},
"pytzdata": {
"dependencies": [],
"sha256": "e1e14750bcf95016381e4d472bad004eef710f2d6417240904070b3d6654485f",
"url": "https://files.pythonhosted.org/packages/e0/4f/4474bda990ee740a020cbc3eb271925ef7daa7c8444240d34ff62c8442a3/pytzdata-2020.1-py2.py3-none-any.whl",
"version": "2020.1"
},
"pyyaml": {
"dependencies": [],
"sha256": "f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5",
"url": "https://files.pythonhosted.org/packages/02/25/6ba9f6bb50a3d4fbe22c1a02554dc670682a07c8701d1716d19ddea2c940/PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl",
"version": "6.0"
},
"requests": {
"dependencies": [
"certifi",
"charset-normalizer",
"idna",
"urllib3"
],
"sha256": "8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349",
"url": "https://files.pythonhosted.org/packages/ca/91/6d9b8ccacd0412c08820f72cebaa4f0c0441b5cda699c90f618b6f8a1b42/requests-2.28.1-py3-none-any.whl",
"version": "2.28.1"
},
"requests-toolbelt": {
"dependencies": [
"requests"
],
"sha256": "18565aa58116d9951ac39baa288d3adb5b3ff975c4f25eee78555d89e8f247f7",
"url": "https://files.pythonhosted.org/packages/05/d3/bf87a36bff1cb88fd30a509fd366c70ec30676517ee791b2f77e0e29817a/requests_toolbelt-0.10.1-py2.py3-none-any.whl",
"version": "0.10.1"
},
"rfc3986": {
"dependencies": [
"idna"
],
"sha256": "a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97",
"url": "https://files.pythonhosted.org/packages/c4/e5/63ca2c4edf4e00657584608bee1001302bbf8c5f569340b78304f2f446cb/rfc3986-1.5.0-py2.py3-none-any.whl",
"version": "1.5.0"
},
"rich": {
"dependencies": [
"commonmark",
"pygments"
],
"sha256": "12b1d77ee7edf251b741531323f0d990f5f570a4e7c054d0bfb59fb7981ad977",
"url": "https://files.pythonhosted.org/packages/92/37/2732511fdd5c6e037af9e92b87dbb50049c02fd3a8c070bc75eed6c798b3/rich-13.0.0-py3-none-any.whl",
"version": "13.0.0"
},
"setproctitle": {
"dependencies": [],
"sha256": "e00c9d5c541a2713ba0e657e0303bf96ddddc412ef4761676adc35df35d7c246",
"url": "https://files.pythonhosted.org/packages/46/b6/d1a2fc143997d89dc2dd9b55646fddb702699624510d619e101c8e149bdf/setproctitle-1.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "1.3.2"
},
"setuptools": {
"dependencies": [],
"sha256": "57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54",
"url": "https://files.pythonhosted.org/packages/ef/e3/29d6e1a07e8d90ace4a522d9689d03e833b67b50d1588e693eec15f26251/setuptools-65.6.3-py3-none-any.whl",
"version": "65.6.3"
},
"setuptools-scm": {
"dependencies": [
"packaging",
"setuptools",
"tomli",
"typing-extensions"
],
"sha256": "73988b6d848709e2af142aa48c986ea29592bbcfca5375678064708205253d8e",
"url": "https://files.pythonhosted.org/packages/1d/66/8f42c941be949ef2b22fe905d850c794e7c170a526023612aad5f3a121ad/setuptools_scm-7.1.0-py3-none-any.whl",
"version": "7.1.0"
},
"six": {
"dependencies": [],
"sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254",
"url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl",
"version": "1.16.0"
},
"sniffio": {
"dependencies": [],
"sha256": "eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384",
"url": "https://files.pythonhosted.org/packages/c3/a0/5dba8ed157b0136607c7f2151db695885606968d1fae123dc3391e0cfdbf/sniffio-1.3.0-py3-none-any.whl",
"version": "1.3.0"
},
"sqlalchemy": {
"dependencies": [
"greenlet"
],
"sha256": "96821d806c0c90c68ce3f2ce6dd529c10e5d7587961f31dd5c30e3bfddc4545d",
"url": "https://files.pythonhosted.org/packages/16/ee/f9d05f6ef9794b754cf46fd46103b8a3e54dc2dbbe7a7bcd431725321e72/SQLAlchemy-1.4.45-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "1.4.45"
},
"sqlalchemy-jsonfield": {
"dependencies": [
"sqlalchemy"
],
"sha256": "d6f1e5ee329a3c0d9d164e40d81a2143ac8332e09988fbbaff84179dac5503d4",
"url": "https://files.pythonhosted.org/packages/38/1c/283e6216c21827fb1358f2f409432828f9df4e402182cf590a1cc5a8874f/SQLAlchemy_JSONField-1.0.1.post0-py3-none-any.whl",
"version": "1.0.1.post0"
},
"sqlalchemy-utils": {
"dependencies": [
"sqlalchemy"
],
"sha256": "9da26a9b20c6979167772ba5dc2a1d01265648f18c82995f082279a399ea308b",
"url": "https://files.pythonhosted.org/packages/12/c2/131e1c6ff887fde1783c1f21e9d132fb799b9c5680abb88c35f40a32a26c/SQLAlchemy_Utils-0.39.0-py3-none-any.whl",
"version": "0.39.0"
},
"sqlparse": {
"dependencies": [],
"sha256": "0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34",
"url": "https://files.pythonhosted.org/packages/97/d3/31dd2c3e48fc2060819f4acb0686248250a0f2326356306b38a42e059144/sqlparse-0.4.3-py3-none-any.whl",
"version": "0.4.3"
},
"swagger-ui-bundle": {
"dependencies": [
"jinja2"
],
"sha256": "cea116ed81147c345001027325c1ddc9ca78c1ee7319935c3c75d3669279d575",
"url": "https://files.pythonhosted.org/packages/f1/4e/920b2cece4bc0367a60a53dcdb63ad210ea8bfe1fcebb35c6e5f47a69259/swagger_ui_bundle-0.0.9-py3-none-any.whl",
"version": "0.0.9"
},
"tabulate": {
"dependencies": [],
"sha256": "024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f",
"url": "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl",
"version": "0.9.0"
},
"tenacity": {
"dependencies": [],
"sha256": "35525cd47f82830069f0d6b73f7eb83bc5b73ee2fff0437952cedf98b27653ac",
"url": "https://files.pythonhosted.org/packages/a5/94/933ce16d18450ccf518a6da5bd51418611e8776b992070b9f40b2f9cedff/tenacity-8.1.0-py3-none-any.whl",
"version": "8.1.0"
},
"termcolor": {
"dependencies": [],
"sha256": "fa852e957f97252205e105dd55bbc23b419a70fec0085708fc0515e399f304fd",
"url": "https://files.pythonhosted.org/packages/c3/23/16f4cdb09368524cd7cf47c2950663dd197a6c180cd5b6db01dcb65c5135/termcolor-2.1.1-py3-none-any.whl",
"version": "2.1.1"
},
"text-unidecode": {
"dependencies": [],
"sha256": "1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8",
"url": "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl",
"version": "1.3"
},
"tomli": {
"dependencies": [],
"sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
"url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl",
"version": "2.0.1"
},
"typing-extensions": {
"dependencies": [],
"sha256": "16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e",
"url": "https://files.pythonhosted.org/packages/0b/8e/f1a0a5a76cfef77e1eb6004cb49e5f8d72634da638420b9ea492ce8305e8/typing_extensions-4.4.0-py3-none-any.whl",
"version": "4.4.0"
},
"uc-micro-py": {
"dependencies": [],
"sha256": "316cfb8b6862a0f1d03540f0ae6e7b033ff1fa0ddbe60c12cbe0d4cec846a69f",
"url": "https://files.pythonhosted.org/packages/14/0e/738dbd15b1afe372d0d788e1e2112cfa67c9cf9e1c777360eaf9cd429caf/uc_micro_py-1.0.1-py3-none-any.whl",
"version": "1.0.1"
},
"unicodecsv": {
"dependencies": [],
"sha256": "018c08037d48649a0412063ff4eda26eaa81eff1546dbffa51fa5293276ff7fc",
"url": "https://files.pythonhosted.org/packages/6f/a4/691ab63b17505a26096608cc309960b5a6bdf39e4ba1a793d5f9b1a53270/unicodecsv-0.14.1.tar.gz",
"version": "0.14.1"
},
"urllib3": {
"dependencies": [],
"sha256": "47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc",
"url": "https://files.pythonhosted.org/packages/65/0c/cc6644eaa594585e5875f46f3c83ee8762b647b51fc5b0fb253a242df2dc/urllib3-1.26.13-py2.py3-none-any.whl",
"version": "1.26.13"
},
"werkzeug": {
"dependencies": [
"markupsafe"
],
"sha256": "f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5",
"url": "https://files.pythonhosted.org/packages/c8/27/be6ddbcf60115305205de79c29004a0c6bc53cec814f733467b1bb89386d/Werkzeug-2.2.2-py3-none-any.whl",
"version": "2.2.2"
},
"wrapt": {
"dependencies": [],
"sha256": "257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310",
"url": "https://files.pythonhosted.org/packages/fd/70/8a133c88a394394dd57159083b86a564247399440b63f2da0ad727593570/wrapt-1.14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"version": "1.14.1"
},
"wtforms": {
"dependencies": [
"markupsafe"
],
"sha256": "837f2f0e0ca79481b92884962b914eba4e72b7a2daaf1f939c890ed0124b834b",
"url": "https://files.pythonhosted.org/packages/eb/2e/199a0edf6577af771a68fbd950d98f0c1a16bb5fa956e45772005318c702/WTForms-3.0.1-py3-none-any.whl",
"version": "3.0.1"
}
}
}

View File

@ -1 +0,0 @@
import ./fetchPip.nix

View File

@ -1,211 +0,0 @@
# fetchPip downloads python packages specified by executing
# `pip download` on a source tree, or a list of requirements.
# This fetcher requires a maximum date 'pypiSnapshotDate' being specified.
# The result will be the same as if `pip download` would have been executed
# at the point in time specified by pypiSnapshotDate.
# This is ensured by putting pip behind a local proxy filtering the
# api responses from pypi.org to only contain files for which the
# release date is lower than the specified pypiSnapshotDate.
# TODO: ignore if packages are yanked
# TODO: for pypiSnapshotDate only allow timestamp or format 2023-01-01
# TODO: Error if pypiSnapshotDate points to the future
{
buildPackages,
lib,
stdenv,
# Use the nixpkgs default python version for the proxy script.
# The python version select by the user below might be too old for the
# dependencies required by the proxy
python3,
}: {
# Specify the python version for which the packages should be downloaded.
# Pip needs to be executed from that specific python version.
# Pip accepts '--python-version', but this works only for wheel packages.
python,
# hash for the fixed output derivation
hash,
# list of strings of requirements.txt entries
requirementsList ? [],
# list of requirements.txt files
requirementsFiles ? [],
# enforce source downloads for these package names
noBinary ? [],
# restrict to binary releases (.whl)
# this allows buildPlatform independent fetching
onlyBinary ? false,
# additional flags for `pip download`.
# for reference see: https://pip.pypa.io/en/stable/cli/pip_download/
pipFlags ? [],
name ? null,
nameSuffix ? "python-requirements",
nativeBuildInputs ? [],
# maximum release date for packages
pypiSnapshotDate ?
throw ''
'pypiSnapshotDate' must be specified for fetchPip.
Choose any date from the past.
Example value: "2023-01-01"
'',
# It's better to not refer to python.pkgs.pip directly, as we want to reduce
# the times we have to update the output hash
pipVersion ? "23.0.1",
# Write "metadata.json" to $out, including which package depends on which.
writeMetaData ? true,
}: let
# throws an error if pipDownload is executed with unsafe arguments
validateArgs = result:
# specifying `--platform` for pip download is only allowed in combination with `--only-binary :all:`
# therefore, if onlyBinary is disabled, we must enforce targetPlatform == buildPlatform to ensure reproducibility
if ! onlyBinary && stdenv.system != stdenv.buildPlatform.system
then
throw ''
fetchPip cannot fetch sdist packages for ${stdenv.system} on a ${stdenv.buildPlatform.system}.
Either build on a ${stdenv.system} or set `onlyBinary = true`.
''
else result;
# map nixos system strings to python platforms
sysToPlatforms = {
"x86_64-linux" = [
"manylinux1_x86_64"
"manylinux2010_x86_64"
"manylinux2014_x86_64"
"linux_x86_64"
];
"x86_64-darwin" =
lib.forEach (lib.range 0 15)
(minor: "macosx_10_${builtins.toString minor}_x86_64");
"aarch64-linux" = [
"manylinux1_aarch64"
"manylinux2010_aarch64"
"manylinux2014_aarch64"
"linux_aarch64"
];
};
platforms =
if sysToPlatforms ? "${stdenv.system}"
then sysToPlatforms."${stdenv.system}"
else throw errorNoBinaryFetchingForTarget;
errorNoBinaryFetchingForTarget = ''
'onlyBinary' fetching is currently not supported for target ${stdenv.system}.
You could set 'onlyBinary = false' and execute the build on a ${stdenv.system}.
'';
# We use nixpkgs python3 to run mitmproxy, see function parameters
pythonWithMitmproxy =
python3.withPackages
(ps: [ps.mitmproxy ps.dateutil]);
# We use the user-selected python to run pip and friends, this ensures
# that version-related markers are resolved correctly.
pythonWithPackaging =
python.withPackages
(ps: [ps.packaging ps.certifi ps.dateutil]);
pythonMajorAndMinorVer =
lib.concatStringsSep "."
(lib.sublist 0 2 (lib.splitString "." python.version));
invalidationHash = finalAttrs:
builtins.hashString "sha256" ''
# Ignore the python minor version. It should not affect resolution
${python.implementation}
${pythonMajorAndMinorVer}
${stdenv.system}
# All variables that might influence the output
${finalAttrs.pypiSnapshotDate}
${toString finalAttrs.noBinary}
${finalAttrs.onlyBinaryFlags}
${finalAttrs.pipVersion}
${finalAttrs.pipFlags}
${toString writeMetaData}
# Include requirements
# We hash the content, as store paths might change more often
${toString finalAttrs.requirementsList}
${toString finalAttrs.requirementsFiles}
# Only hash the content of the python scripts, as the store path
# changes with every nixpkgs commit
${builtins.readFile finalAttrs.filterPypiResponsesScript}
${builtins.readFile finalAttrs.buildScript}
'';
invalidationHashShort = finalAttrs:
lib.substring 0 10
(builtins.unsafeDiscardStringContext (invalidationHash finalAttrs));
namePrefix =
if name == null
then ""
else name + "-";
# A fixed output derivation containing all downloaded packages.
# each single file is located inside a directory named like the package.
# Example:
# "$out/werkzeug" will contain "Werkzeug-0.14.1-py2.py3-none-any.whl"
# Each directory only ever contains a single file
pipDownload = stdenv.mkDerivation (finalAttrs: {
# An invalidation hash is embedded into the `name`.
# This will prevent `forgot to update the hash` scenarios, as any change
# in the derivaiton name enforces a re-build.
name = "${namePrefix}${nameSuffix}-${invalidationHashShort finalAttrs}";
# setup FOD
outputHashMode = "recursive";
outputHashAlgo = "sha256";
outputHash = hash;
# Multiple outputs are not allowed in an FOD, therefore use passthru
# to export $dist and $names
passthru.dist = "${finalAttrs.finalPackage}/dist";
passthru.names = "${finalAttrs.finalPackage}/names";
# disable some phases
dontUnpack = true;
dontInstall = true;
dontFixup = true;
# build inputs
nativeBuildInputs = nativeBuildInputs ++ [pythonWithMitmproxy];
# python scripts
filterPypiResponsesScript = ./filter-pypi-responses.py;
buildScript = ./fetchPip.py;
# the python interpreter used to run the build script
inherit pythonWithPackaging;
# the python interpreter used to run the proxy script
inherit pythonWithMitmproxy;
# convert pypiSnapshotDate to string and integrate into finalAttrs
pypiSnapshotDate = builtins.toString pypiSnapshotDate;
# add some variables to the derivation to integrate them into finalAttrs
inherit
noBinary
pipVersion
requirementsFiles
requirementsList
writeMetaData
;
# prepare flags for `pip download`
pipFlags = lib.concatStringsSep " " pipFlags;
onlyBinaryFlags = lib.optionalString onlyBinary "--only-binary :all: ${
lib.concatStringsSep " " (lib.forEach platforms (pf: "--platform ${pf}"))
}";
# - Execute `pip download` through the filtering proxy.
# - optionally add a file to the FOD containing metadata of the packages involved
buildPhase = ''
$pythonWithPackaging/bin/python $buildScript
'';
});
in
validateArgs pipDownload

View File

@ -1,236 +0,0 @@
import os
import socket
import ssl
import subprocess
import time
import json
import dateutil.parser
import urllib.request
from pathlib import Path
import certifi
from packaging.requirements import Requirement
from packaging.utils import (
canonicalize_name,
parse_sdist_filename,
parse_wheel_filename,
)
HOME = Path(os.getcwd())
OUT = Path(os.getenv("out"))
PYTHON_WITH_PACKAGING = os.getenv("pythonWithPackaging")
PYTHON_WITH_MITM_PROXY = os.getenv("pythonWithMitmproxy")
FILTER_PYPI_RESPONSE_SCRIPTS = os.getenv("filterPypiResponsesScript")
PIP_VERSION = os.getenv("pipVersion")
PIP_FLAGS = os.getenv("pipFlags")
NO_BINARY = os.getenv("noBinary")
ONLY_BINARY_FLAGS = os.getenv("onlyBinaryFlags")
REQUIREMENTS_LIST = os.getenv("requirementsList")
REQUIREMENTS_FILES = os.getenv("requirementsFiles")
WRITE_METADATA = os.getenv("writeMetaData")
TMPDIR = os.getenv("TMPDIR")
def get_max_date():
try:
return int(os.getenv("pypiSnapshotDate"))
except ValueError:
return dateutil.parser.parse(os.getenv("pypiSnapshotDate"))
def get_free_port():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("", 0))
port = sock.getsockname()[1]
sock.close()
return port
def start_mitmproxy(port):
proc = subprocess.Popen(
[
f"{PYTHON_WITH_MITM_PROXY}/bin/mitmdump",
"--listen-port",
str(port),
"--anticache",
"--ignore-hosts",
".*files.pythonhosted.org.*",
"--script",
FILTER_PYPI_RESPONSE_SCRIPTS,
],
env={"pypiSnapshotDate": os.getenv("pypiSnapshotDate"), "HOME": HOME},
)
return proc
def wait_for_proxy(proxy_port, cafile):
timeout = time.time() + 10
req = urllib.request.Request("https://pypi.org")
req.set_proxy(f"127.0.0.1:{proxy_port}", "http")
req.set_proxy(f"127.0.0.1:{proxy_port}", "https")
context = ssl.create_default_context(cafile=cafile)
while time.time() < timeout:
try:
res = urllib.request.urlopen(req, None, 5, context=context)
if res.status < 400:
break
except urllib.error.URLError as e:
pass
finally:
time.sleep(1)
# as we only proxy *some* calls, we need to combine upstream
# ca certificates and the one from mitm proxy
def generate_ca_bundle(path):
proxy_cert = HOME / ".mitmproxy/mitmproxy-ca-cert.pem"
while not os.path.exists(proxy_cert):
time.sleep(0.1)
with open(proxy_cert, "r") as f:
mitmproxy_cacert = f.read()
with open(certifi.where(), "r") as f:
certifi_cacert = f.read()
with open(path, "w") as f:
f.write(mitmproxy_cacert)
f.write("\n")
f.write(certifi_cacert)
return path
def create_venv(path):
subprocess.run(
[f"{PYTHON_WITH_PACKAGING}/bin/python", "-m", "venv", path], check=True
)
def pip(venv_path, *args):
subprocess.run([f"{venv_path}/bin/pip", *args], check=True)
if __name__ == "__main__":
OUT.mkdir()
dist_path = OUT / "dist"
names_path = OUT / "names"
dist_path.mkdir()
names_path.mkdir()
cache_path = Path(f"{TMPDIR}/pip_cache")
cache_path.mkdir()
print(f"selected maximum release date for python packages: {get_max_date()}")
proxy_port = get_free_port()
proxy = start_mitmproxy(proxy_port)
venv_path = Path(".venv").absolute()
create_venv(venv_path)
cafile = generate_ca_bundle(HOME / ".ca-cert.pem")
wait_for_proxy(proxy_port, cafile)
pip(
venv_path,
"install",
"--upgrade",
f"pip=={PIP_VERSION}",
)
# some legacy setup.py based packages require wheel in order to be inspected
pip(
venv_path,
"install",
"--proxy",
f"https://localhost:{proxy_port}",
"--cert",
cafile,
"--upgrade",
f"wheel",
)
flags = [
PIP_FLAGS,
ONLY_BINARY_FLAGS,
"--proxy",
f"https://localhost:{proxy_port}",
"--progress-bar",
"off",
"--cert",
cafile,
"--cache-dir",
cache_path,
]
if NO_BINARY:
optional_flags += ["--no-binary " + " --no-binary ".join(NO_BINARY.split())]
if WRITE_METADATA:
metadata_flags = ["--report", f"{TMPDIR}/report.json"]
for req in REQUIREMENTS_LIST.split(" "):
if req:
flags.append(req)
for req in REQUIREMENTS_FILES.split(" "):
if req:
flags += ["-r", req]
flags = " ".join(map(str, filter(None, flags))).split(" ")
pip(
venv_path,
"install",
"--dry-run",
"--ignore-installed",
*metadata_flags,
*flags,
)
pip(
venv_path,
"download",
"--dest",
dist_path,
*flags,
)
proxy.kill()
for dist_file in dist_path.iterdir():
if dist_file.suffix == ".whl":
name = parse_wheel_filename(dist_file.name)[0]
else:
name = parse_sdist_filename(dist_file.name)[0]
pname = canonicalize_name(name)
name_path = names_path / pname
print(f"creating link {name_path} -> {dist_file}")
name_path.mkdir()
(name_path / dist_file.name).symlink_to(f"../../dist/{dist_file.name}")
if WRITE_METADATA:
packages = dict()
with open(f"{TMPDIR}/report.json", "r") as f:
report = json.load(f)
for install in report["install"]:
metadata = install["metadata"]
name = canonicalize_name(metadata["name"])
download_info = install["download_info"]
file = download_info["url"].split("/")[-1]
hash = download_info.get("archive_info", {}).get("hashes", {}).get("sha256")
requirements = [
Requirement(req) for req in metadata.get("requires_dist", [])
]
extras = ""
dependencies = sorted(
[
canonicalize_name(req.name)
for req in requirements
if not req.marker or req.marker.evaluate({"extra": extras})
]
)
packages[name] = dict(
version=metadata["version"],
dependencies=dependencies,
file=file,
hash=hash,
)
with open(OUT / "metadata.json", "w") as f:
json.dump(packages, f, indent=2)

View File

@ -1,4 +1,4 @@
# fetchPip downloads python packages specified by executing
# fetchPipMetadata downloads python packages specified by executing
# `pip download` on a source tree, or a list of requirements.
# This fetcher requires a maximum date 'pypiSnapshotDate' being specified.
# The result will be the same as if `pip download` would have been executed
@ -34,7 +34,7 @@
# maximum release date for packages
pypiSnapshotDate ?
throw ''
'pypiSnapshotDate' must be specified for fetchPip.
'pypiSnapshotDate' must be specified for fetchPipMetadata.
Choose any date from the past.
Example value: "2023-01-01"
'',
@ -57,7 +57,7 @@
};
args = writeText "pip-args" (builtins.toJSON {
filterPypiResponsesScript = ../fetchPip/filter-pypi-responses.py;
filterPypiResponsesScript = ./filter-pypi-responses.py;
# the python interpreter used to run the proxy script
mitmProxy = "${pythonWithMitmproxy}/bin/mitmdump";

View File

@ -1,5 +1,5 @@
"""
This script is part of fetchPip
This script is part of fetchPipMetadata
It is meant to be used with mitmproxy via `--script`
It will filter api repsonses from the pypi.org api (used by pip),
to only contain files with release date < pypiSnapshotDate