poetry2nix: drop

The in-tree version has been broken for a while, so now is probably a good time to rip off the band-aid.
This commit is contained in:
K900 2023-10-25 12:25:39 +03:00
parent 3f2deb9e98
commit b6958acdab
35 changed files with 1 additions and 27714 deletions

1
.github/CODEOWNERS vendored
View File

@ -116,7 +116,6 @@
/maintainers/scripts/update-python-libraries @FRidh
/pkgs/development/interpreters/python @FRidh
/doc/languages-frameworks/python.section.md @FRidh @mweinelt
/pkgs/development/tools/poetry2nix @adisbladis
/pkgs/development/interpreters/python/hooks @FRidh @jonringer
# Haskell

View File

@ -1,6 +0,0 @@
Dont change these files here, they are maintained at https://github.com/nix-community/poetry2nix
The update procedure is as-follows:
1. Send your change to the upstream poetry2nix repository
2. Get it approved with tests passing
3. Run the update script in pkgs/development/tools/poetry2nix

View File

@ -1,157 +0,0 @@
#!/usr/bin/env python
from concurrent.futures import ThreadPoolExecutor
import subprocess
import textwrap
import argparse
import toml
import json
import sys
from typing import Dict, Any, Tuple, List
class Package:
def __init__(self, attrs: Dict[str, Any]) -> None:
self.attrs = attrs
self.name = attrs["name"]
self.source = self.attrs["source"]
def fetch(self) -> Tuple["Package", subprocess.CompletedProcess]:
raise NotImplementedError()
def expression(self, output: str) -> str:
raise NotImplementedError()
class UrlPackage(Package):
def fetch(self) -> Tuple[Package, subprocess.CompletedProcess]:
return (
self,
subprocess.run(
[
"nix-prefetch-url",
"--unpack",
self.source["url"],
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
),
)
def expression(self, output: str) -> str:
sha256 = output.rstrip()
return textwrap.dedent("""
%s = super.%s.overridePythonAttrs (
_: {
src = pkgs.fetchzip {
url = "%s";
sha256 = "%s";
};
}
);""" % (self.name, self.name, self.source["url"], sha256))
class GitPackage(Package):
def fetch(self) -> Tuple[Package, subprocess.CompletedProcess]:
reference = self.source.get("resolved_reference", self.source["reference"])
return (
self,
subprocess.run(
[
"nix-prefetch-git",
"--fetch-submodules",
"--url",
self.source["url"],
"--rev",
reference,
],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
),
)
def expression(self, output: str) -> str:
meta = json.loads(output)
return textwrap.dedent("""
%s = super.%s.overridePythonAttrs (
_: {
src = pkgs.fetchgit {
url = "%s";
rev = "%s";
sha256 = "%s";
};
}
);""" % (self.name, self.name, meta["url"], meta["rev"], meta["sha256"]))
def parse_args() -> argparse.Namespace:
argparser = argparse.ArgumentParser(description="Poetry2nix CLI")
subparsers = argparser.add_subparsers(dest="subcommand")
subparsers.required = True
parser_lock = subparsers.add_parser("lock", help="Generate overrides for git hashes",)
parser_lock.add_argument(
"--lock", default="poetry.lock", help="Path to input poetry.lock",
)
parser_lock.add_argument(
"--out", default="poetry-git-overlay.nix", help="Output file",
)
return argparser.parse_args()
def indent(expr: str, spaces: int = 2) -> str:
i = " " * spaces
return "\n".join([(i if l != "" else "") + l for l in expr.split("\n")])
def main() -> None:
args = parse_args()
with open(args.lock) as lockf:
lock = toml.load(lockf)
pkgs: List[Package] = []
for pkg in lock["package"]:
if "source" in pkg:
source_type = pkg["source"]["type"]
if source_type == "git":
pkgs.append(GitPackage(pkg))
elif source_type == "url":
pkgs.append(UrlPackage(pkg))
with ThreadPoolExecutor() as e:
futures = []
for pkg in pkgs:
futures.append(e.submit(pkg.fetch))
lines = [
"{ pkgs }:",
"self: super: {",
]
for f in futures:
package, p = f.result()
if p.returncode != 0:
sys.stderr.write(p.stderr)
sys.stderr.flush()
exit(p.returncode)
expr = package.expression(p.stdout)
lines.append(indent(expr))
lines.extend(["", "}", ""])
expr = "\n".join(lines)
with open(args.out, "w") as fout:
fout.write(expr)
print(f"Wrote {args.out}")
if __name__ == "__main__":
main()

View File

@ -1,49 +0,0 @@
{ pkgs ? import <nixpkgs> { }
, lib ? pkgs.lib
, version
}:
let
inherit (pkgs) python3;
in
pkgs.stdenv.mkDerivation {
pname = "poetry2nix";
inherit version;
buildInputs = [
(python3.withPackages (ps: [ ps.toml ]))
];
nativeBuildInputs = [
pkgs.makeWrapper
];
src = ./bin;
dontConfigure = true;
buildPhase = ''
runHook preBuild
patchShebangs poetry2nix
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/bin
mv poetry2nix $out/bin
wrapProgram $out/bin/poetry2nix --prefix PATH ":" ${lib.makeBinPath [
pkgs.nix-prefetch-git
]}
runHook postInstall
'';
meta = {
homepage = "https://github.com/nix-community/poetry2nix";
description = "CLI to supplement sha256 hashes for git dependencies";
license = lib.licenses.mit;
maintainers = [ lib.maintainers.adisbladis ];
};
}

View File

@ -1,531 +0,0 @@
{ pkgs ? import <nixpkgs> { }
, lib ? pkgs.lib
, poetryLib ? import ./lib.nix { inherit lib pkgs; stdenv = pkgs.stdenv; }
}:
let
# Poetry2nix version
version = "1.42.1";
inherit (poetryLib) isCompatible readTOML normalizePackageName normalizePackageSet;
# Map SPDX identifiers to license names
spdxLicenses = lib.listToAttrs (lib.filter (pair: pair.name != null) (builtins.map (v: { name = if lib.hasAttr "spdxId" v then v.spdxId else null; value = v; }) (lib.attrValues lib.licenses)));
# Get license by id falling back to input string
getLicenseBySpdxId = spdxId: spdxLicenses.${spdxId} or spdxId;
# Experimental withPlugins functionality
toPluginAble = (import ./plugins.nix { inherit pkgs lib; }).toPluginAble;
# List of known build systems that are passed through from nixpkgs unmodified
knownBuildSystems = builtins.fromJSON (builtins.readFile ./known-build-systems.json);
nixpkgsBuildSystems = lib.subtractLists [ "poetry" "poetry-core" ] knownBuildSystems;
mkInputAttrs =
{ py
, pyProject
, attrs
, includeBuildSystem ? true
, groups ? [ ]
, checkGroups ? [ "dev" ]
, extras ? [ "*" ] # * means all extras, otherwise include the dependencies for a given extra
}:
let
getInputs = attr: attrs.${attr} or [ ];
# Get dependencies and filter out depending on interpreter version
getDeps = depSet:
let
compat = isCompatible (poetryLib.getPythonVersion py);
depAttrs = builtins.map (d: lib.toLower d) (builtins.attrNames depSet);
in
(
builtins.map
(
dep:
let
pkg = py.pkgs."${normalizePackageName dep}";
constraints = depSet.${dep}.python or "";
isCompat = compat constraints;
in
if isCompat then pkg else null
)
depAttrs
);
buildSystemPkgs = poetryLib.getBuildSystemPkgs {
inherit pyProject;
pythonPackages = py.pkgs;
};
mkInput = attr: extraInputs: getInputs attr ++ extraInputs;
rawDeps = pyProject.tool.poetry."dependencies" or { };
rawRequiredDeps = lib.filterAttrs (_: v: !(v.optional or false)) rawDeps;
desiredExtrasDeps = lib.unique
(lib.concatMap (extra: pyProject.tool.poetry.extras.${extra}) extras);
allRawDeps =
if extras == [ "*" ] then
rawDeps
else
rawRequiredDeps // lib.getAttrs desiredExtrasDeps rawDeps;
checkInputs' = getDeps (pyProject.tool.poetry."dev-dependencies" or { }) # <poetry-1.2.0
# >=poetry-1.2.0 dependency groups
++ lib.flatten (map (g: getDeps (pyProject.tool.poetry.group.${g}.dependencies or { })) checkGroups);
in
{
buildInputs = mkInput "buildInputs" (if includeBuildSystem then buildSystemPkgs else [ ]);
propagatedBuildInputs = mkInput "propagatedBuildInputs" (
getDeps allRawDeps ++ (
# >=poetry-1.2.0 dependency groups
if pyProject.tool.poetry.group or { } != { }
then lib.flatten (map (g: getDeps pyProject.tool.poetry.group.${g}.dependencies) groups)
else [ ]
)
);
nativeBuildInputs = mkInput "nativeBuildInputs" [ ];
checkInputs = mkInput "checkInputs" checkInputs';
nativeCheckInputs = mkInput "nativeCheckInputs" checkInputs';
};
in
lib.makeScope pkgs.newScope (self: {
inherit version;
/* Returns a package of editable sources whose changes will be available without needing to restart the
nix-shell.
In editablePackageSources you can pass a mapping from package name to source directory to have
those packages available in the resulting environment, whose source changes are immediately available.
*/
mkPoetryEditablePackage =
{ projectDir ? null
, pyproject ? projectDir + "/pyproject.toml"
, python ? pkgs.python3
, pyProject ? readTOML pyproject
# Example: { my-app = ./src; }
, editablePackageSources
}:
assert editablePackageSources != { };
import ./editable.nix {
inherit pyProject python pkgs lib poetryLib editablePackageSources;
};
/* Returns a package containing scripts defined in tool.poetry.scripts.
*/
mkPoetryScriptsPackage =
{ projectDir ? null
, pyproject ? projectDir + "/pyproject.toml"
, python ? pkgs.python3
, pyProject ? readTOML pyproject
, scripts ? pyProject.tool.poetry.scripts
}:
assert scripts != { };
import ./shell-scripts.nix {
inherit lib python scripts;
};
/*
Returns an attrset { python, poetryPackages, pyProject, poetryLock } for the given pyproject/lockfile.
*/
mkPoetryPackages =
{ projectDir ? null
, pyproject ? projectDir + "/pyproject.toml"
, poetrylock ? projectDir + "/poetry.lock"
, poetrylockPos ? { file = toString poetrylock; line = 0; column = 0; }
, overrides ? self.defaultPoetryOverrides
, python ? pkgs.python3
, pwd ? projectDir
, preferWheels ? false
# Example: { my-app = ./src; }
, editablePackageSources ? { }
, pyProject ? readTOML pyproject
, groups ? [ ]
, checkGroups ? [ "dev" ]
, extras ? [ "*" ]
}:
let
/* The default list of poetry2nix override overlays */
mkEvalPep508 = import ./pep508.nix {
inherit lib poetryLib;
inherit (python) stdenv;
};
getFunctorFn = fn: if builtins.typeOf fn == "set" then fn.__functor else fn;
poetryPkg = pkgs.callPackage ./pkgs/poetry { inherit python; poetry2nix = self; };
scripts = pyProject.tool.poetry.scripts or { };
hasScripts = scripts != { };
scriptsPackage = self.mkPoetryScriptsPackage {
inherit python scripts;
};
editablePackageSources' = lib.filterAttrs (name: path: path != null) editablePackageSources;
hasEditable = editablePackageSources' != { };
editablePackage = self.mkPoetryEditablePackage {
inherit pyProject python;
editablePackageSources = editablePackageSources';
};
poetryLock = readTOML poetrylock;
# Lock file version 1.1 files
lockFiles =
let
lockfiles = lib.getAttrFromPath [ "metadata" "files" ] poetryLock;
in
lib.listToAttrs (lib.mapAttrsToList (n: v: { name = normalizePackageName n; value = v; }) lockfiles);
evalPep508 = mkEvalPep508 python;
# Filter packages by their PEP508 markers & pyproject interpreter version
partitions =
let
supportsPythonVersion = pkgMeta: if pkgMeta ? marker then (evalPep508 pkgMeta.marker) else true && isCompatible (poetryLib.getPythonVersion python) pkgMeta.python-versions;
in
lib.partition supportsPythonVersion poetryLock.package;
compatible = partitions.right;
incompatible = partitions.wrong;
# Create an overridden version of pythonPackages
#
# We need to avoid mixing multiple versions of pythonPackages in the same
# closure as python can only ever have one version of a dependency
baseOverlay = self: super:
let
lockPkgs = builtins.listToAttrs (
builtins.map
(
pkgMeta:
let normalizedName = normalizePackageName pkgMeta.name; in
{
name = normalizedName;
value = self.mkPoetryDep (
pkgMeta // {
inherit pwd preferWheels;
pos = poetrylockPos;
source = pkgMeta.source or null;
# Default to files from lock file version 2.0 and fall back to 1.1
files = pkgMeta.files or lockFiles.${normalizedName};
pythonPackages = self;
sourceSpec = (
(normalizePackageSet pyProject.tool.poetry.dependencies or { }).${normalizedName}
or (normalizePackageSet pyProject.tool.poetry.dev-dependencies or { }).${normalizedName}
or (normalizePackageSet pyProject.tool.poetry.group.dev.dependencies or { }).${normalizedName} # Poetry 1.2.0+
or { }
);
}
);
}
)
(lib.reverseList compatible)
);
buildSystems = builtins.listToAttrs (builtins.map (x: { name = x; value = super.${x}; }) nixpkgsBuildSystems);
in
lockPkgs // buildSystems // {
# Create a dummy null package for the current project in case any dependencies depend on the root project (issue #307)
${pyProject.tool.poetry.name} = null;
};
overlays = builtins.map
getFunctorFn
(
[
# Remove Python packages aliases with non-normalized names to avoid issues with infinite recursion (issue #750).
(self: super: {
# Upstream nixpkgs uses non canonical names
async-generator = super.async-generator or super.async_generator or null;
})
(self: super: lib.attrsets.mapAttrs
(
name: value:
if lib.isDerivation value && self.hasPythonModule value && (normalizePackageName name) != name
then null
else value
)
super)
(
self: super:
{
mkPoetryDep = self.callPackage ./mk-poetry-dep.nix {
inherit lib python poetryLib evalPep508;
};
# # Use poetry-core from the poetry build (pep517/518 build-system)
poetry-core = poetryPkg.passthru.python.pkgs.poetry-core;
poetry = poetryPkg;
__toPluginAble = toPluginAble self;
} // lib.optionalAttrs (! super ? setuptools-scm) {
# The canonical name is setuptools-scm
setuptools-scm = super.setuptools_scm;
}
)
# Fix infinite recursion in a lot of packages because of checkInputs
(self: super: lib.mapAttrs
(name: value: (
if lib.isDerivation value && lib.hasAttr "overridePythonAttrs" value
then value.overridePythonAttrs (_: { doCheck = false; })
else value
))
super)
# Null out any filtered packages, we don't want python.pkgs from nixpkgs
(self: super: builtins.listToAttrs (builtins.map (x: { name = normalizePackageName x.name; value = null; }) incompatible))
# Create poetry2nix layer
baseOverlay
] ++ # User provided overrides
(if builtins.typeOf overrides == "list" then overrides else [ overrides ])
);
packageOverrides = lib.foldr lib.composeExtensions (self: super: { }) overlays;
py = python.override { inherit packageOverrides; self = py; };
inputAttrs = mkInputAttrs { inherit py pyProject groups checkGroups extras; attrs = { }; includeBuildSystem = false; };
requiredPythonModules = python.pkgs.requiredPythonModules;
/* Include all the nested dependencies which are required for each package.
This guarantees that using the "poetryPackages" attribute will return
complete list of dependencies for the poetry project to be portable.
*/
storePackages = requiredPythonModules (builtins.foldl' (acc: v: acc ++ v) [ ] (lib.attrValues inputAttrs));
in
{
python = py;
poetryPackages = storePackages
++ lib.optional hasScripts scriptsPackage
++ lib.optional hasEditable editablePackage;
poetryLock = poetryLock;
inherit pyProject;
};
/* Returns a package with a python interpreter and all packages specified in the poetry.lock lock file.
In editablePackageSources you can pass a mapping from package name to source directory to have
those packages available in the resulting environment, whose source changes are immediately available.
Example:
poetry2nix.mkPoetryEnv { poetrylock = ./poetry.lock; python = python3; }
*/
mkPoetryEnv =
{ projectDir ? null
, pyproject ? projectDir + "/pyproject.toml"
, poetrylock ? projectDir + "/poetry.lock"
, overrides ? self.defaultPoetryOverrides
, pwd ? projectDir
, python ? pkgs.python3
, preferWheels ? false
, editablePackageSources ? { }
, extraPackages ? ps: [ ]
, groups ? [ "dev" ]
, checkGroups ? [ "dev" ]
, extras ? [ "*" ]
}:
let
inherit (lib) hasAttr;
pyProject = readTOML pyproject;
# Automatically add dependencies with develop = true as editable packages, but only if path dependencies
getEditableDeps = set: lib.mapAttrs
(name: value: projectDir + "/${value.path}")
(lib.filterAttrs (name: dep: dep.develop or false && hasAttr "path" dep) set);
excludedEditablePackageNames = builtins.filter
(pkg: editablePackageSources."${pkg}" == null)
(builtins.attrNames editablePackageSources);
allEditablePackageSources = (
(getEditableDeps (pyProject.tool.poetry."dependencies" or { }))
// (getEditableDeps (pyProject.tool.poetry."dev-dependencies" or { }))
// (
# Poetry>=1.2.0
if pyProject.tool.poetry.group or { } != { } then
builtins.foldl' (acc: g: acc // getEditableDeps pyProject.tool.poetry.group.${g}.dependencies) { } groups
else { }
)
// editablePackageSources
);
editablePackageSources' = builtins.removeAttrs
allEditablePackageSources
excludedEditablePackageNames;
poetryPython = self.mkPoetryPackages {
inherit pyproject poetrylock overrides python pwd preferWheels pyProject groups checkGroups extras;
editablePackageSources = editablePackageSources';
};
inherit (poetryPython) poetryPackages;
# Don't add editable sources to the environment since they will sometimes fail to build and are not useful in the development env
editableAttrs = lib.attrNames editablePackageSources';
envPkgs = builtins.filter (drv: ! lib.elem (drv.pname or drv.name or "") editableAttrs) poetryPackages;
in
poetryPython.python.withPackages (ps: envPkgs ++ (extraPackages ps));
/* Creates a Python application from pyproject.toml and poetry.lock
The result also contains a .dependencyEnv attribute which is a python
environment of all dependencies and this apps modules. This is useful if
you rely on dependencies to invoke your modules for deployment: e.g. this
allows `gunicorn my-module:app`.
*/
mkPoetryApplication =
{ projectDir ? null
, src ? (
# Assume that a project which is the result of a derivation is already adequately filtered
if lib.isDerivation projectDir then projectDir else self.cleanPythonSources { src = projectDir; }
)
, pyproject ? projectDir + "/pyproject.toml"
, poetrylock ? projectDir + "/poetry.lock"
, overrides ? self.defaultPoetryOverrides
, meta ? { }
, python ? pkgs.python3
, pwd ? projectDir
, preferWheels ? false
, groups ? [ ]
, checkGroups ? [ "dev" ]
, extras ? [ "*" ]
, ...
}@attrs:
let
poetryPython = self.mkPoetryPackages {
inherit pyproject poetrylock overrides python pwd preferWheels groups checkGroups extras;
};
py = poetryPython.python;
hooks = py.pkgs.callPackage ./hooks { };
inherit (poetryPython) pyProject;
specialAttrs = [
"overrides"
"poetrylock"
"projectDir"
"pwd"
"pyproject"
"preferWheels"
];
passedAttrs = builtins.removeAttrs attrs specialAttrs;
inputAttrs = mkInputAttrs { inherit py pyProject attrs groups checkGroups extras; };
app = py.pkgs.buildPythonPackage (
passedAttrs // inputAttrs // {
nativeBuildInputs = inputAttrs.nativeBuildInputs ++ [
hooks.removePathDependenciesHook
hooks.removeGitDependenciesHook
];
} // {
pname = normalizePackageName pyProject.tool.poetry.name;
version = pyProject.tool.poetry.version;
inherit src;
format = "pyproject";
# Like buildPythonApplication, but without the toPythonModule part
# Meaning this ends up looking like an application but it also
# provides python modules
namePrefix = "";
passthru = {
python = py;
dependencyEnv = (
lib.makeOverridable ({ app, ... }@attrs:
let
args = builtins.removeAttrs attrs [ "app" ] // {
extraLibs = [ app ];
};
in
py.buildEnv.override args)
) { inherit app; };
};
# Extract position from explicitly passed attrs so meta.position won't point to poetry2nix internals
pos = builtins.unsafeGetAttrPos (lib.elemAt (lib.attrNames attrs) 0) attrs;
meta = lib.optionalAttrs (lib.hasAttr "description" pyProject.tool.poetry)
{
inherit (pyProject.tool.poetry) description;
} // lib.optionalAttrs (lib.hasAttr "homepage" pyProject.tool.poetry) {
inherit (pyProject.tool.poetry) homepage;
} // {
inherit (py.meta) platforms;
license = getLicenseBySpdxId (pyProject.tool.poetry.license or "unknown");
} // meta;
}
);
in
app;
/* Poetry2nix CLI used to supplement SHA-256 hashes for git dependencies */
cli = import ./cli.nix {
inherit pkgs lib;
inherit (self) version;
};
# inherit mkPoetryEnv mkPoetryApplication mkPoetryPackages;
inherit (poetryLib) cleanPythonSources;
/*
Create a new default set of overrides with the same structure as the built-in ones
*/
mkDefaultPoetryOverrides = defaults: {
__functor = defaults;
extend = overlay:
let
composed = lib.foldr lib.composeExtensions overlay [ defaults ];
in
self.mkDefaultPoetryOverrides composed;
overrideOverlay = fn:
let
overlay = self: super:
let
defaultSet = defaults self super;
customSet = fn self super;
in
defaultSet // customSet;
in
self.mkDefaultPoetryOverrides overlay;
};
/*
The default list of poetry2nix override overlays
Can be overriden by calling defaultPoetryOverrides.overrideOverlay which takes an overlay function
*/
defaultPoetryOverrides = self.mkDefaultPoetryOverrides (import ./overrides { inherit pkgs lib; });
/*
Convenience functions for specifying overlays with or without the poerty2nix default overrides
*/
overrides = {
/*
Returns the specified overlay in a list
*/
withoutDefaults = overlay: [
overlay
];
/*
Returns the specified overlay and returns a list
combining it with poetry2nix default overrides
*/
withDefaults = overlay: [
overlay
self.defaultPoetryOverrides
];
};
})

View File

@ -1,55 +0,0 @@
{ pkgs
, lib
, poetryLib
, pyProject
, python
, editablePackageSources
}:
let
name = poetryLib.normalizePackageName pyProject.tool.poetry.name;
# Just enough standard PKG-INFO fields for an editable installation
pkgInfoFields = {
Metadata-Version = "2.1";
Name = name;
# While the pyproject.toml could contain arbitrary version strings, for
# simplicity we just use the same one for PKG-INFO, even though that
# should follow follow PEP 440: https://www.python.org/dev/peps/pep-0345/#version
# This is how poetry transforms it: https://github.com/python-poetry/poetry/blob/6cd3645d889f47c10425961661b8193b23f0ed79/poetry/version/version.py
Version = pyProject.tool.poetry.version;
Summary = pyProject.tool.poetry.description;
};
pkgInfoFile = builtins.toFile "${name}-PKG-INFO"
(lib.concatStringsSep "\n" (lib.mapAttrsToList (key: value: "${key}: ${value}") pkgInfoFields));
entryPointsFile = builtins.toFile "${name}-entry_points.txt"
(lib.generators.toINI { } pyProject.tool.poetry.plugins);
# A python package that contains simple .egg-info and .pth files for an editable installation
editablePackage = python.pkgs.toPythonModule (pkgs.runCommand "${name}-editable"
{ } ''
mkdir -p "$out/${python.sitePackages}"
cd "$out/${python.sitePackages}"
# See https://docs.python.org/3.8/library/site.html for info on such .pth files
# These add another site package path for each line
touch poetry2nix-editable.pth
${lib.concatMapStringsSep "\n"
(src: ''
echo "${toString src}" >> poetry2nix-editable.pth
'')
(lib.attrValues editablePackageSources)}
# Create a very simple egg so pkg_resources can find this package
# See https://setuptools.readthedocs.io/en/latest/formats.html for more info on the egg format
mkdir "${name}.egg-info"
cd "${name}.egg-info"
ln -s ${pkgInfoFile} PKG-INFO
${lib.optionalString (pyProject.tool.poetry ? plugins) ''
ln -s ${entryPointsFile} entry_points.txt
''}
''
);
in
editablePackage

View File

@ -1,15 +0,0 @@
[
"egg",
"tar",
"tar.bz2",
"tar.gz",
"tar.lz",
"tar.lzma",
"tar.xz",
"tbz",
"tgz",
"tlz",
"txz",
"whl",
"zip"
]

View File

@ -1,24 +0,0 @@
source $stdenv/setup
set -euo pipefail
curl="curl \
--location \
--max-redirs 20 \
--retry 2 \
--disable-epsv \
--cookie-jar cookies \
--insecure \
--speed-time 5 \
--progress-bar \
--fail \
$curlOpts \
$NIX_CURL_FLAGS"
echo "Trying to fetch with predicted URL: $predictedURL"
$curl $predictedURL --output $out && exit 0
echo "Predicted URL '$predictedURL' failed, querying pypi.org"
$curl "https://pypi.org/pypi/$pname/json" | jq -r ".releases.\"$version\"[] | select(.filename == \"$file\") | .url" > url
url=$(cat url)
$curl -k $url --output $out

View File

@ -1,134 +0,0 @@
# Some repositories (such as Devpi) expose the Pypi legacy API
# (https://warehouse.pypa.io/api-reference/legacy.html).
#
# Note it is not possible to use pip
# https://discuss.python.org/t/pip-download-just-the-source-packages-no-building-no-metadata-etc/4651/12
import os
import sys
import netrc
from urllib.parse import urlparse, urlunparse
from html.parser import HTMLParser
import urllib.request
import shutil
import ssl
from os.path import normpath
# Parse the legacy index page to extract the href and package names
class Pep503(HTMLParser):
def __init__(self):
super().__init__()
self.sources = {}
self.url = None
self.name = None
def handle_data(self, data):
if self.url is not None:
self.name = data
def handle_starttag(self, tag, attrs):
if tag == "a":
for name, value in attrs:
if name == "href":
self.url = value
def handle_endtag(self, tag):
if self.url is not None:
self.sources[self.name] = self.url
self.url = None
url = sys.argv[1]
package_name = sys.argv[2]
index_url = url + "/" + package_name + "/"
package_filename = sys.argv[3]
# Parse username and password for this host from the netrc file if given.
username, password = None, None
if os.environ["NETRC"]:
netrc_obj = netrc.netrc(os.environ["NETRC"])
host = urlparse(index_url).netloc
# Strip port number if present
if ":" in host:
host = host.split(":")[0]
username, _, password = netrc_obj.authenticators(host)
print("Reading index %s" % index_url)
context = ssl.create_default_context()
context.check_hostname = False
context.verify_mode = ssl.CERT_NONE
# Extract out username/password from index_url, if present.
parsed_url = urlparse(index_url)
username = parsed_url.username or username
password = parsed_url.password or password
index_url = parsed_url._replace(netloc=parsed_url.netloc.rpartition("@")[-1]).geturl()
req = urllib.request.Request(index_url)
if username and password:
import base64
password_b64 = base64.b64encode(":".join((username, password)).encode()).decode(
"utf-8"
)
req.add_header("Authorization", "Basic {}".format(password_b64))
response = urllib.request.urlopen(req, context=context)
index = response.read()
parser = Pep503()
parser.feed(str(index, "utf-8"))
if package_filename not in parser.sources:
print(
"The file %s has not be found in the index %s" % (package_filename, index_url)
)
exit(1)
package_file = open(package_filename, "wb")
# Sometimes the href is a relative or absolute path within the index's domain.
indicated_url = urlparse(parser.sources[package_filename])
if indicated_url.netloc == "":
parsed_url = urlparse(index_url)
if indicated_url.path.startswith("/"):
# An absolute path within the index's domain.
path = parser.sources[package_filename]
else:
# A relative path.
path = parsed_url.path + "/" + parser.sources[package_filename]
package_url = urlunparse(
(
parsed_url.scheme,
parsed_url.netloc,
path,
None,
None,
None,
)
)
else:
package_url = parser.sources[package_filename]
# Handle urls containing "../"
parsed_url = urlparse(package_url)
real_package_url = urlunparse(
(
parsed_url.scheme,
parsed_url.netloc,
normpath(parsed_url.path),
parsed_url.params,
parsed_url.query,
parsed_url.fragment,
)
)
print("Downloading %s" % real_package_url)
req = urllib.request.Request(real_package_url)
if username and password:
req.add_unredirected_header("Authorization", "Basic {}".format(password_b64))
response = urllib.request.urlopen(req, context=context)
with response as r:
shutil.copyfileobj(r, package_file)

View File

@ -1,132 +0,0 @@
{ python
, stdenv
, buildPackages
, makeSetupHook
, wheel
, pip
, pkgs
, lib
}:
let
inherit (python.pythonForBuild.pkgs) callPackage;
pythonInterpreter = python.pythonForBuild.interpreter;
pythonSitePackages = python.sitePackages;
nonOverlayedPython = pkgs.python3.pythonForBuild.withPackages (ps: [ ps.tomlkit ]);
makeRemoveSpecialDependenciesHook = { fields, kind }:
nonOverlayedPython.pkgs.callPackage
(
_:
makeSetupHook
{
name = "remove-path-dependencies.sh";
substitutions = {
# NOTE: We have to use a non-overlayed Python here because otherwise we run into an infinite recursion
# because building of tomlkit and its dependencies also use these hooks.
pythonPath = nonOverlayedPython.pkgs.makePythonPath [ nonOverlayedPython ];
pythonInterpreter = nonOverlayedPython.interpreter;
pyprojectPatchScript = "${./pyproject-without-special-deps.py}";
inherit fields;
inherit kind;
};
} ./remove-special-dependencies.sh
)
{ };
makeSetupHookArgs = deps:
if lib.elem "propagatedBuildInputs" (builtins.attrNames (builtins.functionArgs makeSetupHook)) then
{ propagatedBuildInputs = deps; }
else
{ inherit deps; };
in
{
removePathDependenciesHook = makeRemoveSpecialDependenciesHook {
fields = [ "path" ];
kind = "path";
};
removeGitDependenciesHook = makeRemoveSpecialDependenciesHook {
fields = [ "git" "branch" "rev" "tag" ];
kind = "git";
};
pipBuildHook = callPackage
(
{ pip, wheel }:
makeSetupHook
({
name = "pip-build-hook.sh";
substitutions = {
inherit pythonInterpreter pythonSitePackages;
};
} // (makeSetupHookArgs [ pip wheel ])) ./pip-build-hook.sh
)
{ };
poetry2nixFixupHook = callPackage
(
_:
makeSetupHook
{
name = "fixup-hook.sh";
substitutions = {
inherit pythonSitePackages;
filenames = builtins.concatStringsSep " " [
"pyproject.toml"
"README.md"
"LICENSE"
];
};
} ./fixup-hook.sh
)
{ };
# As of 2023-03 a newer version of packaging introduced a new behaviour where python-requires
# cannot contain version wildcards. This behaviour is complaint with PEP440
#
# The wildcards are a no-op anyway so we can work around this issue by just dropping the precision down to the last known number.
poetry2nixPythonRequiresPatchHook = callPackage
(
_:
let
# Python pre 3.9 does not contain the ast.unparse method.
# We can extract this from Python 3.8 for any
unparser = stdenv.mkDerivation {
name = "${python.name}-astunparse";
inherit (python) src;
dontConfigure = true;
dontBuild = true;
installPhase = ''
mkdir -p $out/poetry2nix_astunparse
cp ./Tools/parser/unparse.py $out/poetry2nix_astunparse/__init__.py
'';
};
pythonPath =
[ ]
++ lib.optional (lib.versionOlder python.version "3.9") unparser;
in
makeSetupHook
{
name = "require-python-patch-hook.sh";
substitutions = {
inherit pythonInterpreter pythonPath;
patchScript = ./python-requires-patch-hook.py;
};
} ./python-requires-patch-hook.sh
)
{ };
# When the "wheel" package itself is a wheel the nixpkgs hook (which pulls in "wheel") leads to infinite recursion
# It doesn't _really_ depend on wheel though, it just copies the wheel.
wheelUnpackHook = callPackage
(_:
makeSetupHook
{
name = "wheel-unpack-hook.sh";
} ./wheel-unpack-hook.sh
)
{ };
}

View File

@ -1,20 +0,0 @@
poetry2nix-fixup-hook() {
# Including tests in the output is a common mistake
if [ -z "${dontFixupTests-}" ]; then
rm -rf $out/@pythonSitePackages@/tests
fi
# Including files in site-packages is a common packaging mistake
#
# While we cannot remove all normal files dumped in site-packages
# we can clean up some common mistakes
if [ -z "${dontFixupSitePackages-}" ]; then
for f in @filenames@; do
rm -f $out/@pythonSitePackages@/$f
done
fi
}
postFixupHooks+=(poetry2nix-fixup-hook)

View File

@ -1,42 +0,0 @@
# Setup hook to use for pip projects
echo "Sourcing pip-build-hook"
pipBuildPhase() {
echo "Executing pipBuildPhase"
runHook preBuild
mkdir -p dist
echo "Creating a wheel..."
@pythonInterpreter@ -m pip wheel --verbose --no-index --no-deps --no-clean --no-build-isolation --wheel-dir dist .
echo "Finished creating a wheel..."
runHook postBuild
echo "Finished executing pipBuildPhase"
}
pipShellHook() {
echo "Executing pipShellHook"
runHook preShellHook
# Long-term setup.py should be dropped.
if [ -e pyproject.toml ]; then
tmp_path=$(mktemp -d)
export PATH="$tmp_path/bin:$PATH"
export PYTHONPATH="$tmp_path/@pythonSitePackages@:$PYTHONPATH"
mkdir -p "$tmp_path/@pythonSitePackages@"
@pythonInterpreter@ -m pip install -e . --prefix "$tmp_path" >&2
fi
runHook postShellHook
echo "Finished executing pipShellHook"
}
if [ -z "${dontUsePipBuild-}" ] && [ -z "${buildPhase-}" ]; then
echo "Using pipBuildPhase"
buildPhase=pipBuildPhase
fi
if [ -z "${shellHook-}" ]; then
echo "Using pipShellHook"
shellHook=pipShellHook
fi

View File

@ -1,54 +0,0 @@
#!/usr/bin/env python
# Patch out special dependencies (git and path) from a pyproject.toml file
import argparse
import sys
import tomlkit
def main(input, output, fields_to_remove):
data = tomlkit.loads(input.read())
try:
deps = data["tool"]["poetry"]["dependencies"]
except KeyError:
pass
else:
for dep in deps.values():
if isinstance(dep, dict):
any_removed = False
for field in fields_to_remove:
any_removed |= dep.pop(field, None) is not None
if any_removed:
dep["version"] = "*"
dep.pop("develop", None)
output.write(tomlkit.dumps(data))
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument(
"-i",
"--input",
type=argparse.FileType("r"),
default=sys.stdin,
help="Location from which to read input TOML",
)
p.add_argument(
"-o",
"--output",
type=argparse.FileType("w"),
default=sys.stdout,
help="Location to write output TOML",
)
p.add_argument(
"-f",
"--fields-to-remove",
nargs="+",
help="The fields to remove from the dependency's TOML",
)
args = p.parse_args()
main(args.input, args.output, args.fields_to_remove)

View File

@ -1,79 +0,0 @@
#!/usr/bin/env python
import ast
import sys
import io
# Python2 compat
if sys.version_info[0] < 3:
FileNotFoundError = IOError
# Python <= 3.8 compat
def astunparse(tree):
# Use bundled unparse by default
if hasattr(ast, "unparse"):
return ast.unparse(tree)
# Use example tool from Python sources for older interpreter versions
from poetry2nix_astunparse import Unparser
buf = io.StringIO()
up = Unparser(tree, buf)
return buf.getvalue()
class Rewriter(ast.NodeVisitor):
def __init__(self, *args, **kwargs):
super(Rewriter, self).__init__(*args, **kwargs)
self.modified = False
def visit_Call(self, node):
function_name = ""
if isinstance(node.func, ast.Name):
function_name = node.func.id
elif isinstance(node.func, ast.Attribute):
function_name = node.func.attr
else:
return
if function_name != "setup":
return
for kw in node.keywords:
if kw.arg != "python_requires":
continue
value = kw.value
if not isinstance(value, ast.Constant):
return
# Rewrite version constraints without wildcard characters.
#
# Only rewrite the file if the modified value actually differs, as we lose whitespace and comments when rewriting
# with the AST module.
python_requires = ", ".join(
[v.strip().rstrip(".*") for v in value.value.split(",")]
)
if value.value != python_requires:
value.value = python_requires
self.modified = True
if __name__ == "__main__":
sys.path.extend(sys.argv[1:])
try:
with open("setup.py", encoding="utf-8-sig") as f:
tree = ast.parse(f.read())
except FileNotFoundError:
exit(0)
r = Rewriter()
r.visit(tree)
if r.modified:
with open("setup.py", "w") as f:
f.write(astunparse(tree))

View File

@ -1,7 +0,0 @@
poetry2nix-python-requires-patch-hook() {
if [ -z "${dontFixupPythonRequires-}" ]; then
@pythonInterpreter@ @patchScript@ @pythonPath@
fi
}
postPatchHooks+=(poetry2nix-python-requires-patch-hook)

View File

@ -1,23 +0,0 @@
remove-@kind@-dependencies-hook() {
# Tell poetry not to resolve special dependencies. Any version is fine!
if ! test -f pyproject.toml; then
return
fi
echo "Removing @kind@ dependencies"
# NOTE: We have to reset PYTHONPATH to avoid having propagatedBuildInputs
# from the currently building derivation leaking into our unrelated Python
# environment.
PYTHONPATH=@pythonPath@ \
@pythonInterpreter@ \
@pyprojectPatchScript@ \
--fields-to-remove @fields@ < pyproject.toml > pyproject.formatted.toml
mv pyproject.formatted.toml pyproject.toml
echo "Finished removing @kind@ dependencies"
}
postPatchHooks+=(remove-@kind@-dependencies-hook)

View File

@ -1,18 +0,0 @@
# Setup hook to use in case a wheel is fetched
echo "Sourcing wheel setup hook"
wheelUnpackPhase(){
echo "Executing wheelUnpackPhase"
runHook preUnpack
mkdir -p dist
cp "$src" "dist/$(stripHash "$src")"
# runHook postUnpack # Calls find...?
echo "Finished executing wheelUnpackPhase"
}
if [ -z "${dontUseWheelUnpack-}" ] && [ -z "${unpackPhase-}" ]; then
echo "Using wheelUnpackPhase"
unpackPhase=wheelUnpackPhase
fi

View File

@ -1,12 +0,0 @@
[
"poetry",
"poetry-core",
"flit",
"flit-core",
"pbr",
"cython",
"hatchling",
"hatch-vcs",
"setuptools",
"setuptools-scm"
]

View File

@ -1,250 +0,0 @@
{ lib, pkgs, stdenv }:
let
inherit (import ./semver.nix { inherit lib ireplace; }) satisfiesSemver;
inherit (builtins) genList length;
# Replace a list entry at defined index with set value
ireplace = idx: value: list: (
genList (i: if i == idx then value else (builtins.elemAt list i)) (length list)
);
# Normalize package names as per PEP 503
normalizePackageName = name:
let
parts = builtins.split "[-_.]+" name;
partsWithoutSeparator = builtins.filter (x: builtins.typeOf x == "string") parts;
in
lib.strings.toLower (lib.strings.concatStringsSep "-" partsWithoutSeparator);
# Normalize an entire attrset of packages
normalizePackageSet = lib.attrsets.mapAttrs' (name: value: lib.attrsets.nameValuePair (normalizePackageName name) value);
# Get a full semver pythonVersion from a python derivation
getPythonVersion = python:
let
pyVer = lib.splitVersion python.pythonVersion ++ [ "0" ];
ver = lib.splitVersion python.version;
major = l: lib.elemAt l 0;
minor = l: lib.elemAt l 1;
joinVersion = v: lib.concatStringsSep "." v;
in
joinVersion (if major pyVer == major ver && minor pyVer == minor ver then ver else pyVer);
# Compare a semver expression with a version
isCompatible = version:
let
operators = {
"||" = cond1: cond2: cond1 || cond2;
"," = cond1: cond2: cond1 && cond2; # , means &&
"&&" = cond1: cond2: cond1 && cond2;
};
splitRe = "(" + (builtins.concatStringsSep "|" (builtins.map (x: lib.replaceStrings [ "|" ] [ "\\|" ] x) (lib.attrNames operators))) + ")";
in
expr:
let
tokens = builtins.filter (x: x != "") (builtins.split splitRe expr);
combine = acc: v:
let
isOperator = builtins.typeOf v == "list";
operator = if isOperator then (builtins.elemAt v 0) else acc.operator;
in
if isOperator then (acc // { inherit operator; }) else {
inherit operator;
state = operators."${operator}" acc.state (satisfiesSemver version v);
};
initial = { operator = "&&"; state = true; };
in
if expr == "" then true else (builtins.foldl' combine initial tokens).state;
fromTOML = builtins.fromTOML or
(
toml: builtins.fromJSON (
builtins.readFile (
pkgs.runCommand "from-toml"
{
inherit toml;
allowSubstitutes = false;
preferLocalBuild = true;
}
''
${pkgs.remarshal}/bin/remarshal \
-if toml \
-i <(echo "$toml") \
-of json \
-o $out
''
)
)
);
readTOML = path: fromTOML (builtins.readFile path);
#
# Returns the appropriate manylinux dependencies and string representation for the file specified
#
getManyLinuxDeps = f:
let
ml = pkgs.pythonManylinuxPackages;
in
if lib.strings.hasInfix "manylinux1" f then { pkg = [ ml.manylinux1 ]; str = "1"; }
else if lib.strings.hasInfix "manylinux2010" f then { pkg = [ ml.manylinux2010 ]; str = "2010"; }
else if lib.strings.hasInfix "manylinux2014" f then { pkg = [ ml.manylinux2014 ]; str = "2014"; }
else if lib.strings.hasInfix "manylinux_" f then { pkg = [ ml.manylinux2014 ]; str = "pep600"; }
else { pkg = [ ]; str = null; };
# Predict URL from the PyPI index.
# Args:
# pname: package name
# file: filename including extension
# hash: SRI hash
# kind: Language implementation and version tag
predictURLFromPypi = lib.makeOverridable (
{ pname, file, hash, kind }:
"https://files.pythonhosted.org/packages/${kind}/${lib.toLower (builtins.substring 0 1 file)}/${pname}/${file}"
);
# Fetch from the PyPI index.
# At first we try to fetch the predicated URL but if that fails we
# will use the Pypi API to determine the correct URL.
# Args:
# pname: package name
# file: filename including extension
# version: the version string of the dependency
# hash: SRI hash
# kind: Language implementation and version tag
fetchFromPypi = lib.makeOverridable (
{ pname, file, version, hash, kind, curlOpts ? "" }:
let
predictedURL = predictURLFromPypi { inherit pname file hash kind; };
in
(pkgs.stdenvNoCC.mkDerivation {
name = file;
nativeBuildInputs = [
pkgs.buildPackages.curl
pkgs.buildPackages.jq
];
isWheel = lib.strings.hasSuffix "whl" file;
system = "builtin";
preferLocalBuild = true;
impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [
"NIX_CURL_FLAGS"
];
inherit pname file version curlOpts predictedURL;
builder = ./fetch-from-pypi.sh;
outputHashMode = "flat";
outputHashAlgo = "sha256";
outputHash = hash;
passthru = {
urls = [ predictedURL ]; # retain compatibility with nixpkgs' fetchurl
};
})
);
fetchFromLegacy = lib.makeOverridable (
{ python, pname, url, file, hash }:
let
pathParts =
(builtins.filter
({ prefix, path }: "NETRC" == prefix)
builtins.nixPath);
netrc_file = if (pathParts != [ ]) then (builtins.head pathParts).path else "";
in
pkgs.runCommand file
{
nativeBuildInputs = [ python ];
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
outputHashMode = "flat";
outputHashAlgo = "sha256";
outputHash = hash;
NETRC = netrc_file;
passthru.isWheel = lib.strings.hasSuffix "whl" file;
} ''
python ${./fetch_from_legacy.py} ${url} ${pname} ${file}
mv ${file} $out
''
);
getBuildSystemPkgs =
{ pythonPackages
, pyProject
}:
let
missingBuildBackendError = "No build-system.build-backend section in pyproject.toml. "
+ "Add such a section as described in https://python-poetry.org/docs/pyproject/#poetry-and-pep-517";
requires = lib.attrByPath [ "build-system" "requires" ] (throw missingBuildBackendError) pyProject;
requiredPkgs = builtins.map (n: lib.elemAt (builtins.match "([^!=<>~[]+).*" n) 0) requires;
in
builtins.map (drvAttr: pythonPackages.${drvAttr} or (throw "unsupported build system requirement ${drvAttr}")) requiredPkgs;
# Find gitignore files recursively in parent directory stopping with .git
findGitIgnores = path:
let
parent = path + "/..";
gitIgnore = path + "/.gitignore";
isGitRoot = builtins.pathExists (path + "/.git");
hasGitIgnore = builtins.pathExists gitIgnore;
gitIgnores = if hasGitIgnore then [ gitIgnore ] else [ ];
in
lib.optionals (builtins.pathExists path && builtins.toString path != "/" && ! isGitRoot) (findGitIgnores parent) ++ gitIgnores;
/*
Provides a source filtering mechanism that:
- Filters gitignore's
- Filters pycache/pyc files
- Uses cleanSourceFilter to filter out .git/.hg, .o/.so, editor backup files & nix result symlinks
*/
cleanPythonSources = { src }:
let
gitIgnores = findGitIgnores src;
pycacheFilter = name: type:
(type == "directory" && ! lib.strings.hasInfix "__pycache__" name)
|| (type == "regular" && ! lib.strings.hasSuffix ".pyc" name)
;
in
lib.cleanSourceWith {
filter = lib.cleanSourceFilter;
src = lib.cleanSourceWith {
filter = pkgs.nix-gitignore.gitignoreFilterPure pycacheFilter gitIgnores src;
inherit src;
};
};
# Maps Nixpkgs CPU values to target machines known to be supported for manylinux* wheels.
# (a.k.a. `uname -m` output from CentOS 7)
#
# This is current as of manylinux2014 (PEP-0599), and is a superset of manylinux2010 / manylinux1.
# s390x is not supported in Nixpkgs, so we don't map it.
manyLinuxTargetMachines = {
x86_64 = "x86_64";
i686 = "i686";
aarch64 = "aarch64";
armv7l = "armv7l";
powerpc64 = "ppc64";
powerpc64le = "ppc64le";
};
# Machine tag for our target platform (if available)
getTargetMachine = stdenv: manyLinuxTargetMachines.${stdenv.targetPlatform.parsed.cpu.name} or null;
in
{
inherit
fetchFromPypi
fetchFromLegacy
getManyLinuxDeps
isCompatible
readTOML
getBuildSystemPkgs
satisfiesSemver
cleanPythonSources
normalizePackageName
normalizePackageSet
getPythonVersion
getTargetMachine
;
}

View File

@ -1,220 +0,0 @@
{ autoPatchelfHook
, lib
, python
, buildPythonPackage
, poetryLib
, evalPep508
}:
{ name
, version
, pos ? __curPos
, files
, source
, dependencies ? { }
, pythonPackages
, python-versions
, pwd
, sourceSpec
, supportedExtensions ? lib.importJSON ./extensions.json
, preferWheels ? false
, ...
}:
pythonPackages.callPackage
(
{ preferWheel ? preferWheels
, ...
}@args:
let
inherit (python) stdenv;
inherit (poetryLib) isCompatible getManyLinuxDeps fetchFromLegacy fetchFromPypi normalizePackageName;
inherit (import ./pep425.nix {
inherit lib poetryLib python stdenv;
}) selectWheel
;
fileCandidates =
let
supportedRegex = ("^.*(" + builtins.concatStringsSep "|" supportedExtensions + ")");
matchesVersion = fname: builtins.match ("^.*" + builtins.replaceStrings [ "." "+" ] [ "\\." "\\+" ] version + ".*$") fname != null;
hasSupportedExtension = fname: builtins.match supportedRegex fname != null;
isCompatibleEgg = fname: ! lib.strings.hasSuffix ".egg" fname || lib.strings.hasSuffix "py${python.pythonVersion}.egg" fname;
in
builtins.filter (f: matchesVersion f.file && hasSupportedExtension f.file && isCompatibleEgg f.file) files;
toPath = s: pwd + "/${s}";
isLocked = lib.length fileCandidates > 0;
isSource = source != null;
isGit = isSource && source.type == "git";
isUrl = isSource && source.type == "url";
isWheelUrl = isSource && source.type == "url" && lib.strings.hasSuffix ".whl" source.url;
isDirectory = isSource && source.type == "directory";
isFile = isSource && source.type == "file";
isLegacy = isSource && source.type == "legacy";
localDepPath = toPath source.url;
buildSystemPkgs =
let
pyProjectPath = localDepPath + "/pyproject.toml";
pyProject = poetryLib.readTOML pyProjectPath;
in
if builtins.pathExists pyProjectPath then
poetryLib.getBuildSystemPkgs
{
inherit pythonPackages pyProject;
} else [ ];
pname = normalizePackageName name;
preferWheel' = preferWheel && pname != "wheel";
fileInfo =
let
isBdist = f: lib.strings.hasSuffix "whl" f.file;
isSdist = f: ! isBdist f && ! isEgg f;
isEgg = f: lib.strings.hasSuffix ".egg" f.file;
binaryDist = selectWheel fileCandidates;
sourceDist = builtins.filter isSdist fileCandidates;
eggs = builtins.filter isEgg fileCandidates;
# the `wheel` package cannot be built from a wheel, since that requires the wheel package
# this causes a circular dependency so we special-case ignore its `preferWheel` attribute value
entries = (if preferWheel' then binaryDist ++ sourceDist else sourceDist ++ binaryDist) ++ eggs;
lockFileEntry = (
if lib.length entries > 0 then builtins.head entries
else throw "Missing suitable source/wheel file entry for ${name}"
);
_isEgg = isEgg lockFileEntry;
in
rec {
inherit (lockFileEntry) file hash;
name = file;
format =
if _isEgg then "egg"
else if lib.strings.hasSuffix ".whl" name then "wheel"
else "pyproject";
kind =
if _isEgg then python.pythonVersion
else if format == "pyproject" then "source"
else (builtins.elemAt (lib.strings.splitString "-" name) 2);
};
format = if isWheelUrl then "wheel" else if isDirectory || isGit || isUrl then "pyproject" else fileInfo.format;
hooks = python.pkgs.callPackage ./hooks { };
in
buildPythonPackage {
inherit pname version;
# Circumvent output separation (https://github.com/NixOS/nixpkgs/pull/190487)
format = if format == "pyproject" then "poetry2nix" else format;
doCheck = false; # We never get development deps
# Stripping pre-built wheels lead to `ELF load command address/offset not properly aligned`
dontStrip = format == "wheel";
nativeBuildInputs = [
hooks.poetry2nixFixupHook
]
++ lib.optional (!pythonPackages.isPy27) hooks.poetry2nixPythonRequiresPatchHook
++ lib.optional (isLocked && (getManyLinuxDeps fileInfo.name).str != null) autoPatchelfHook
++ lib.optionals (format == "wheel") [
hooks.wheelUnpackHook
pythonPackages.pipInstallHook
pythonPackages.setuptools
]
++ lib.optionals (format == "pyproject") [
hooks.removePathDependenciesHook
hooks.removeGitDependenciesHook
hooks.pipBuildHook
];
buildInputs = (
lib.optional (isLocked) (getManyLinuxDeps fileInfo.name).pkg
++ lib.optional isDirectory buildSystemPkgs
++ lib.optional (stdenv.buildPlatform != stdenv.hostPlatform) pythonPackages.setuptools
);
propagatedBuildInputs =
let
compat = isCompatible (poetryLib.getPythonVersion python);
deps = lib.filterAttrs
(n: v: v)
(
lib.mapAttrs
(
n: v:
let
constraints = v.python or "";
pep508Markers = v.markers or "";
in
compat constraints && evalPep508 pep508Markers
)
dependencies
);
depAttrs = lib.attrNames deps;
in
builtins.map (n: pythonPackages.${normalizePackageName n}) depAttrs;
inherit pos;
meta = {
broken = ! isCompatible (poetryLib.getPythonVersion python) python-versions;
license = [ ];
inherit (python.meta) platforms;
};
passthru = {
inherit args;
preferWheel = preferWheel';
};
# We need to retrieve kind from the interpreter and the filename of the package
# Interpreters should declare what wheel types they're compatible with (python type + ABI)
# Here we can then choose a file based on that info.
src =
if isGit then
(
builtins.fetchGit ({
inherit (source) url;
rev = source.resolved_reference or source.reference;
ref = sourceSpec.branch or (if sourceSpec ? tag then "refs/tags/${sourceSpec.tag}" else "HEAD");
} // (
lib.optionalAttrs ((sourceSpec ? rev) && (lib.versionAtLeast builtins.nixVersion "2.4")) {
allRefs = true;
}) // (
lib.optionalAttrs (lib.versionAtLeast builtins.nixVersion "2.4") {
submodules = true;
})
)
)
else if isWheelUrl then
builtins.fetchurl
{
inherit (source) url;
sha256 = fileInfo.hash;
}
else if isUrl then
builtins.fetchTarball
{
inherit (source) url;
sha256 = fileInfo.hash;
}
else if isDirectory then
(poetryLib.cleanPythonSources { src = localDepPath; })
else if isFile then
localDepPath
else if isLegacy then
fetchFromLegacy
{
pname = name;
inherit python;
inherit (fileInfo) file hash;
inherit (source) url;
}
else
fetchFromPypi {
pname = name;
inherit (fileInfo) file hash kind;
inherit version;
};
}
)
{ }

View File

@ -1,46 +0,0 @@
"""
Rewrite libc/library path references to Nix store paths
Nixpkgs uses a normal patch for this but we need to be less
sensitive to changes between versions.
"""
from textwrap import dedent
import sys
import ast
import os
with open(sys.argv[1]) as f:
mod = ast.parse(f.read(), "geos.py")
class LibTransformer(ast.NodeTransformer):
_lgeos_replaced = False
def visit_If(self, node):
if ast.unparse(node).startswith("if sys.platform.startswith('linux')"):
return ast.parse(
dedent(
"""
free = CDLL(%s).free
free.argtypes = [c_void_p]
free.restype = None
"""
)
% (lambda x: "'" + x + "'" if x else None)(os.environ.get("GEOS_LIBC"))
)
return node
def visit_Assign(self, node):
_target = node.targets[0]
if (
not self._lgeos_replaced
and isinstance(_target, ast.Name)
and _target.id == "_lgeos"
):
self._lgeos_replaced = True
return ast.parse("_lgeos = CDLL('%s')" % os.environ["GEOS_LIBRARY_PATH"])
return node
with open(sys.argv[1], "w") as f:
f.write(ast.unparse(LibTransformer().visit(mod)))

View File

@ -1,133 +0,0 @@
{ lib, stdenv, poetryLib, python, isLinux ? stdenv.isLinux }:
let
inherit (lib.strings) escapeRegex hasPrefix hasSuffix hasInfix splitString removePrefix removeSuffix;
targetMachine = poetryLib.getTargetMachine stdenv;
pythonVer =
let
ver = builtins.splitVersion python.version;
major = builtins.elemAt ver 0;
minor = builtins.elemAt ver 1;
tags = [ "cp" "py" ];
in
{ inherit major minor tags; };
abiTag = "cp${pythonVer.major}${pythonVer.minor}m";
#
# Parses wheel file returning an attribute set
#
toWheelAttrs = str:
let
entries' = splitString "-" str;
el = builtins.length entries';
entryAt = builtins.elemAt entries';
# Hack: Remove version "suffixes" like 2.11.4-1
entries =
if el == 6 then [
(entryAt 0) # name
(entryAt 1) # version
# build tag is skipped
(entryAt (el - 3)) # python version
(entryAt (el - 2)) # abi
(entryAt (el - 1)) # platform
] else entries';
p = removeSuffix ".whl" (builtins.elemAt entries 4);
in
{
pkgName = builtins.elemAt entries 0;
pkgVer = builtins.elemAt entries 1;
pyVer = builtins.elemAt entries 2;
abi = builtins.elemAt entries 3;
platform = p;
};
#
# Builds list of acceptable osx wheel files
#
# <versions> accepted versions in descending order of preference
# <candidates> list of wheel files to select from
findBestMatches = versions: candidates:
let
v = lib.lists.head versions;
vs = lib.lists.tail versions;
in
if (builtins.length versions == 0)
then [ ]
else (builtins.filter (x: hasInfix v x.file) candidates) ++ (findBestMatches vs candidates);
# x = "cpXX" | "py2" | "py3" | "py2.py3"
isPyVersionCompatible = pyver@{ major, minor, tags }: x:
let
isCompat = m:
builtins.elem m.tag tags
&& m.major == major
&& builtins.compareVersions minor m.minor >= 0;
parseMarker = v:
let
tag = builtins.substring 0 2 v;
major = builtins.substring 2 1 v;
end = builtins.substring 3 3 v;
minor = if builtins.stringLength end > 0 then end else "0";
in
{ inherit major minor tag; };
markers = splitString "." x;
in
lib.lists.any isCompat (map parseMarker markers);
#
# Selects the best matching wheel file from a list of files
#
selectWheel = files:
let
filesWithoutSources = (builtins.filter (x: hasSuffix ".whl" x.file) files);
isPyAbiCompatible = pyabi: x: x == "none" || hasPrefix pyabi x || hasPrefix x pyabi || (
# The CPython stable ABI is abi3 as in the shared library suffix.
python.passthru.implementation == "cpython" &&
builtins.elemAt (lib.splitString "." python.version) 0 == "3" &&
x == "abi3"
);
withPython = ver: abi: x: (isPyVersionCompatible ver x.pyVer) && (isPyAbiCompatible abi x.abi);
withPlatform =
if isLinux
then
if targetMachine != null
then
# See PEP 600 for details.
(p:
builtins.match "any|manylinux(1|2010|2014)_${escapeRegex targetMachine}|manylinux_[0-9]+_[0-9]+_${escapeRegex targetMachine}" p != null
)
else
(p: p == "any")
else
if stdenv.isDarwin
then
if stdenv.targetPlatform.isAarch64
then (p: p == "any" || (hasInfix "macosx" p && lib.lists.any (e: hasSuffix e p) [ "arm64" "aarch64" ]))
else (p: p == "any" || (hasInfix "macosx" p && hasSuffix "x86_64" p))
else (p: p == "any");
withPlatforms = x: lib.lists.any withPlatform (splitString "." x.platform);
filterWheel = x:
let
f = toWheelAttrs x.file;
in
(withPython pythonVer abiTag f) && (withPlatforms f);
filtered = builtins.filter filterWheel filesWithoutSources;
choose = files:
let
osxMatches = [ "12_0" "11_0" "10_15" "10_14" "10_12" "10_11" "10_10" "10_9" "10_8" "10_7" "any" ];
linuxMatches = [ "manylinux1_" "manylinux2010_" "manylinux2014_" "manylinux_" "any" ];
chooseLinux = x: lib.take 1 (findBestMatches linuxMatches x);
chooseOSX = x: lib.take 1 (findBestMatches osxMatches x);
in
if isLinux
then chooseLinux files
else chooseOSX files;
in
if (builtins.length filtered == 0)
then [ ]
else choose (filtered);
in
{
inherit selectWheel toWheelAttrs isPyVersionCompatible;
}

View File

@ -1,258 +0,0 @@
{ lib, stdenv, poetryLib }: python:
let
inherit (poetryLib) ireplace;
targetMachine = poetryLib.getTargetMachine stdenv;
# Like builtins.substring but with stop being offset instead of length
substr = start: stop: s: builtins.substring start (stop - start) s;
# Strip leading/trailing whitespace from string
stripStr = s: lib.elemAt (builtins.split "^ *" (lib.elemAt (builtins.split " *$" s) 0)) 2;
findSubExpressionsFun = acc: c: (
if c == "(" then
(
let
posNew = acc.pos + 1;
isOpen = acc.openP == 0;
startPos = if isOpen then posNew else acc.startPos;
in
acc // {
inherit startPos;
exprs = acc.exprs ++ [ (substr acc.exprPos (acc.pos - 1) acc.expr) ];
pos = posNew;
openP = acc.openP + 1;
}
) else if c == ")" then
(
let
openP = acc.openP - 1;
exprs = findSubExpressions (substr acc.startPos acc.pos acc.expr);
in
acc // {
inherit openP;
pos = acc.pos + 1;
exprs = if openP == 0 then acc.exprs ++ [ exprs ] else acc.exprs;
exprPos = if openP == 0 then acc.pos + 1 else acc.exprPos;
}
) else acc // { pos = acc.pos + 1; }
);
# Make a tree out of expression groups (parens)
findSubExpressions = expr':
let
expr = " " + expr';
acc = builtins.foldl'
findSubExpressionsFun
{
exprs = [ ];
expr = expr;
pos = 0;
openP = 0;
exprPos = 0;
startPos = 0;
}
(lib.stringToCharacters expr);
tailExpr = (substr acc.exprPos acc.pos expr);
tailExprs = if tailExpr != "" then [ tailExpr ] else [ ];
in
acc.exprs ++ tailExprs;
parseExpressions = exprs:
let
splitCond = (
s: builtins.map
(x: stripStr (if builtins.typeOf x == "list" then (builtins.elemAt x 0) else x))
(builtins.split " (and|or) " (s + " "))
);
mapfn = expr: (
if (builtins.match "^ ?$" expr != null) then null # Filter empty
else if (builtins.elem expr [ "and" "or" ]) then {
type = "bool";
value = expr;
}
else {
type = "expr";
value = expr;
}
);
parse = expr: builtins.filter (x: x != null) (builtins.map mapfn (splitCond expr));
in
builtins.foldl'
(
acc: v: acc ++ (if builtins.typeOf v == "string" then parse v else [ (parseExpressions v) ])
) [ ]
exprs;
# Transform individual expressions to structured expressions
# This function also performs variable substitution, replacing environment markers with their explicit values
transformExpressions = exprs:
let
variables = {
os_name = (
if python.pname == "jython" then "java"
else "posix"
);
sys_platform = (
if stdenv.isLinux then "linux"
else if stdenv.isDarwin then "darwin"
else throw "Unsupported platform"
);
platform_machine = targetMachine;
platform_python_implementation =
let
impl = python.passthru.implementation;
in
(
if impl == "cpython" then "CPython"
else if impl == "pypy" then "PyPy"
else throw "Unsupported implementation ${impl}"
);
platform_release = ""; # Field not reproducible
platform_system = (
if stdenv.isLinux then "Linux"
else if stdenv.isDarwin then "Darwin"
else throw "Unsupported platform"
);
platform_version = ""; # Field not reproducible
python_version = python.passthru.pythonVersion;
python_full_version = python.version;
implementation_name = python.implementation;
implementation_version = python.version;
# extra = "";
};
substituteVar = value: if builtins.hasAttr value variables then (builtins.toJSON variables."${value}") else value;
processVar = value: builtins.foldl' (acc: v: v acc) value [
stripStr
substituteVar
];
in
if builtins.typeOf exprs == "set" then
(
if exprs.type == "expr" then
(
let
mVal = ''[a-zA-Z0-9\'"_\. \-]+'';
mOp = "in|[!=<>]+";
e = stripStr exprs.value;
m' = builtins.match ''^(${mVal}) +(${mOp}) *(${mVal})$'' e;
m = builtins.map stripStr (if m' != null then m' else builtins.match ''^(${mVal}) +(${mOp}) *(${mVal})$'' e);
m0 = processVar (builtins.elemAt m 0);
m2 = processVar (builtins.elemAt m 2);
in
{
type = "expr";
value = {
# HACK: We don't know extra at eval time, so we assume the expression is always true
op = if m0 == "extra" then "true" else builtins.elemAt m 1;
values = [ m0 m2 ];
};
}
) else exprs
) else builtins.map transformExpressions exprs;
# Recursively eval all expressions
evalExpressions = exprs:
let
unmarshal = v: (
# TODO: Handle single quoted values
if v == "True" then true
else if v == "False" then false
else builtins.fromJSON v
);
hasElem = needle: haystack: builtins.elem needle (builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " haystack));
op = {
"true" = x: y: true;
"<=" = x: y: op.">=" y x;
"<" = x: y: lib.versionOlder (unmarshal x) (unmarshal y);
"!=" = x: y: x != y;
"==" = x: y: x == y;
">=" = x: y: lib.versionAtLeast (unmarshal x) (unmarshal y);
">" = x: y: op."<" y x;
"~=" = v: c:
let
parts = builtins.splitVersion c;
pruned = lib.take ((builtins.length parts) - 1) parts;
upper = builtins.toString (
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1
);
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned);
in
op.">=" v c && op."<" v upperConstraint;
"===" = x: y: x == y;
"in" = x: y:
let
values = builtins.filter (x: builtins.typeOf x == "string") (builtins.split " " (unmarshal y));
in
builtins.elem (unmarshal x) values;
};
in
if builtins.typeOf exprs == "set" then
(
if exprs.type == "expr" then
(
let
expr = exprs;
result = (op."${expr.value.op}") (builtins.elemAt expr.value.values 0) (builtins.elemAt expr.value.values 1);
in
{
type = "value";
value = result;
}
) else exprs
) else builtins.map evalExpressions exprs;
# Now that we have performed an eval all that's left to do is to concat the graph into a single bool
reduceExpressions = exprs:
let
cond = {
"and" = x: y: x && y;
"or" = x: y: x || y;
};
reduceExpressionsFun = acc: v: (
if builtins.typeOf v == "set" then
(
if v.type == "value" then
(
acc // {
value = cond."${acc.cond}" acc.value v.value;
}
) else if v.type == "bool" then
(
acc // {
cond = v.value;
}
) else throw "Unsupported type"
) else if builtins.typeOf v == "list" then
(
let
ret = builtins.foldl'
reduceExpressionsFun
{
value = true;
cond = "and";
}
v;
in
acc // {
value = cond."${acc.cond}" acc.value ret.value;
}
) else throw "Unsupported type"
);
in
(
builtins.foldl'
reduceExpressionsFun
{
value = true;
cond = "and";
}
exprs
).value;
in
e: builtins.foldl' (acc: v: v acc) e [
findSubExpressions
parseExpressions
transformExpressions
evalExpressions
reduceExpressions
]

View File

@ -1,82 +0,0 @@
{ lib
, poetry2nix
, python
, fetchFromGitHub
, projectDir ? ./.
, pyproject ? projectDir + "/pyproject.toml"
, poetrylock ? projectDir + "/poetry.lock"
}:
poetry2nix.mkPoetryApplication {
inherit python;
inherit projectDir pyproject poetrylock;
src = fetchFromGitHub (lib.importJSON ./src.json);
# "Vendor" dependencies (for build-system support)
postPatch = ''
# Figure out the location of poetry.core
# As poetry.core is using the same root import name as the poetry package and the python module system wont look for the root
# in the separate second location we need to link poetry.core to poetry
POETRY_CORE=$(python -c 'import poetry.core; import os.path; print(os.path.dirname(poetry.core.__file__))')
echo "import sys" >> src/poetry/__init__.py
for path in $propagatedBuildInputs; do
echo "sys.path.insert(0, \"$path\")" >> src/poetry/__init__.py
done
'';
postInstall = ''
ln -s $POETRY_CORE $out/${python.sitePackages}/poetry/core
mkdir -p "$out/share/bash-completion/completions"
"$out/bin/poetry" completions bash > "$out/share/bash-completion/completions/poetry"
mkdir -p "$out/share/zsh/site-functions"
"$out/bin/poetry" completions zsh > "$out/share/zsh/site-functions/_poetry"
mkdir -p "$out/share/fish/vendor_completions.d"
"$out/bin/poetry" completions fish > "$out/share/fish/vendor_completions.d/poetry.fish"
'';
# Propagating dependencies leads to issues downstream
# We've already patched poetry to prefer "vendored" dependencies
postFixup = ''
rm $out/nix-support/propagated-build-inputs
'';
# Fails because of impurities (network, git etc etc)
doCheck = false;
overrides = [
poetry2nix.defaultPoetryOverrides
(self: super: {
cryptography = super.cryptography.overridePythonAttrs (old: {
meta = old.meta // {
knownVulnerabilities = old.meta.knownVulnerabilities or [ ]
++ lib.optionals (lib.versionOlder old.version "41.0.0") [
"CVE-2023-2650"
"CVE-2023-2975"
"CVE-2023-3446"
"CVE-2023-3817"
"CVE-2023-38325"
];
};
});
requests = super.requests.overridePythonAttrs (old: {
meta = old.meta // {
knownVulnerabilities = old.meta.knownVulnerabilities or [ ]
++ lib.optionals (lib.versionOlder old.version "2.31.0") [
"CVE-2023-32681"
];
};
});
})
];
meta = with lib; {
inherit (python.meta) platforms;
maintainers = with maintainers; [ adisbladis jakewaksbaum ];
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,198 +0,0 @@
[tool.poetry]
name = "poetry"
version = "1.3.2"
description = "Python dependency management and packaging made easy."
authors = [
"Sébastien Eustace <sebastien@eustace.io>",
]
maintainers = [
"Arun Babu Neelicattu <arun.neelicattu@gmail.com>",
"Bjorn Neergaard <bjorn@neersighted.com>",
"Branch Vincent <branchevincent@gmail.com>",
"Bryce Drennan <github@accounts.brycedrennan.com>",
"Daniel Eades <danieleades@hotmail.com>",
"Randy Döring <radoering.poetry@gmail.com>",
"Steph Samson <hello@stephsamson.com>",
"finswimmer <finswimmer77@gmail.com>",
]
license = "MIT"
readme = "README.md"
packages = [
{ include = "poetry", from = "src" }
]
include = [
{ path = "tests", format = "sdist" }
]
homepage = "https://python-poetry.org/"
repository = "https://github.com/python-poetry/poetry"
documentation = "https://python-poetry.org/docs"
keywords = ["packaging", "dependency", "poetry"]
classifiers = [
"Topic :: Software Development :: Build Tools",
"Topic :: Software Development :: Libraries :: Python Modules"
]
[tool.poetry.urls]
Changelog = "https://python-poetry.org/history/"
[tool.poetry.build]
generate-setup-file = false
# Requirements
[tool.poetry.dependencies]
python = "^3.7"
poetry-core = "1.4.0"
poetry-plugin-export = "^1.2.0"
"backports.cached-property" = { version = "^1.0.2", python = "<3.8" }
cachecontrol = { version = "^0.12.9", extras = ["filecache"] }
cleo = "^2.0.0"
crashtest = "^0.4.1"
dulwich = "^0.20.46"
filelock = "^3.8.0"
html5lib = "^1.0"
importlib-metadata = { version = "^4.4", python = "<3.10" }
jsonschema = "^4.10.0"
keyring = "^23.9.0"
# packaging uses calver, so version is unclamped
packaging = ">=20.4"
pexpect = "^4.7.0"
pkginfo = "^1.5"
platformdirs = "^2.5.2"
requests = "^2.18"
requests-toolbelt = ">=0.9.1,<0.11.0"
shellingham = "^1.5"
tomli = { version = "^2.0.1", python = "<3.11" }
# exclude 0.11.2 and 0.11.3 due to https://github.com/sdispater/tomlkit/issues/225
tomlkit = ">=0.11.1,<1.0.0,!=0.11.2,!=0.11.3"
# trove-classifiers uses calver, so version is unclamped
trove-classifiers = ">=2022.5.19"
# exclude 20.4.5 - 20.4.6 due to https://github.com/pypa/pip/issues/9953
virtualenv = [
{ version = "^20.4.3,!=20.4.5,!=20.4.6", markers = "sys_platform != 'win32' or python_version != '3.9'" },
# see https://github.com/python-poetry/poetry/pull/6950 for details
{ version = "^20.4.3,!=20.4.5,!=20.4.6,<20.16.6", markers = "sys_platform == 'win32' and python_version == '3.9'" },
]
xattr = { version = "^0.10.0", markers = "sys_platform == 'darwin'" }
urllib3 = "^1.26.0"
[tool.poetry.group.dev.dependencies]
pre-commit = "^2.6"
[tool.poetry.group.test.dependencies]
# Cachy frozen to test backwards compatibility for `poetry.utils.cache`.
cachy = "0.3.0"
deepdiff = "^5.0"
flatdict = "^4.0.1"
httpretty = "^1.0"
pytest = "^7.1"
pytest-cov = "^4.0"
pytest-mock = "^3.9"
pytest-randomly = "^3.12"
pytest-xdist = { version = "^2.5", extras = ["psutil"] }
zipp = { version = "^3.4", python = "<3.8" }
[tool.poetry.group.typing.dependencies]
mypy = ">=0.990"
types-html5lib = ">=1.1.9"
types-jsonschema = ">=4.9.0"
types-requests = ">=2.28.8"
typing-extensions = { version = "^4.0.0", python = "<3.8" }
# only used in github actions
[tool.poetry.group.github-actions]
optional = true
[tool.poetry.group.github-actions.dependencies]
pytest-github-actions-annotate-failures = "^0.1.7"
[tool.poetry.scripts]
poetry = "poetry.console.application:main"
[build-system]
requires = ["poetry-core>=1.1.0"]
build-backend = "poetry.core.masonry.api"
[tool.isort]
py_version = 37
profile = "black"
force_single_line = true
combine_as_imports = true
lines_between_types = 1
lines_after_imports = 2
src_paths = ["src", "tests"]
extend_skip = ["setup.py"]
known_third_party = ["poetry.core"]
[tool.black]
target-version = ['py37']
preview = true
force-exclude = '''
.*/setup\.py$
'''
[tool.mypy]
files = "src"
mypy_path = "src"
namespace_packages = true
explicit_package_bases = true
show_error_codes = true
strict = true
enable_error_code = [
"ignore-without-code",
"redundant-expr",
"truthy-bool",
]
# use of importlib-metadata backport at python3.7 makes it impossible to
# satisfy mypy without some ignores: but we get a different set of ignores at
# different python versions.
#
# <https://github.com/python/mypy/issues/8823>, meanwhile suppress that
# warning.
[[tool.mypy.overrides]]
module = [
'poetry.console.commands.self.show.plugins',
'poetry.installation.executor',
'poetry.mixology.version_solver',
'poetry.plugins.plugin_manager',
'poetry.repositories.installed_repository',
'poetry.utils.env',
]
warn_unused_ignores = false
[[tool.mypy.overrides]]
module = [
'cachecontrol.*',
'lockfile.*',
'pexpect.*',
'pkginfo.*',
'requests_toolbelt.*',
'shellingham.*',
'virtualenv.*',
'xattr.*',
]
ignore_missing_imports = true
[tool.pytest.ini_options]
addopts = "-n auto"
testpaths = [
"tests"
]
[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"if TYPE_CHECKING:"
]

View File

@ -1,8 +0,0 @@
{
"owner": "python-poetry",
"repo": "poetry",
"rev": "1.3.0",
"sha256": "16ng59ykm7zkjizmwb482y0hawpjjr5mvl0ahjd790xzxcc2bbbv",
"fetchSubmodules": true
}

View File

@ -1,70 +0,0 @@
{ pkgs, lib }:
let
inherit (pkgs) stdenv;
mkPluginDrv =
{ self
, plugins
, drv
, postInstall ? ""
, nativeBuildInputs ? [ ]
, buildInputs ? [ ]
}:
let
env = self.python.withPackages (ps: plugins);
in
stdenv.mkDerivation {
pname = drv.pname + "-with-plugins";
inherit (drv) src version meta;
buildInputs = drv.buildInputs ++ drv.propagatedBuildInputs ++ buildInputs;
nativeBuildInputs = builtins.filter (x: x.name != "python-output-dist-hook") (drv.nativeBuildInputs ++ nativeBuildInputs);
dontConfigure = true;
dontBuild = true;
dontUsePythonRecompileBytecode = true;
passthru = {
inherit (drv.passthru) withPlugins;
inherit plugins;
};
# Link bin/ from environment, but only if it's in a plugin
installPhase = ''
runHook preInstall
mkdir -p $out/bin
for bindir in ${lib.concatStringsSep " " (map (d: "${lib.getBin d}/bin") plugins)}; do
for bin in $bindir/*; do
ln -s ${env}/bin/$(basename $bin) $out/bin/
done
done
runHook postInstall
'';
inherit postInstall;
};
in
{
# Provide the `withPlugins` function
toPluginAble = self: { drv
, finalDrv
, postInstall ? ""
, nativeBuildInputs ? [ ]
, buildInputs ? [ ]
}: drv.overridePythonAttrs (old: {
passthru = old.passthru // {
withPlugins = pluginFn: mkPluginDrv {
plugins = [ finalDrv ] ++ pluginFn self;
inherit self postInstall nativeBuildInputs buildInputs;
drv = finalDrv;
};
};
});
}

View File

@ -1,87 +0,0 @@
{ lib, ireplace }:
let
inherit (builtins) elemAt match;
operators =
let
matchWildCard = s: match "([^*])(\\.[*])" s;
mkComparison = ret: version: v: builtins.compareVersions version v == ret;
mkIdxComparison = idx: version: v:
let
ver = builtins.splitVersion v;
minor = builtins.toString (lib.toInt (elemAt ver idx) + 1);
upper = builtins.concatStringsSep "." (ireplace idx minor ver);
in
operators.">=" version v && operators."<" version upper;
dropWildcardPrecision = f: version: constraint:
let
m = matchWildCard constraint;
hasWildcard = m != null;
c = if hasWildcard then (elemAt m 0) else constraint;
v =
if hasWildcard then (builtins.substring 0 (builtins.stringLength c) version)
else version;
in
f v c;
in
{
# Prefix operators
"==" = dropWildcardPrecision (mkComparison 0);
">" = dropWildcardPrecision (mkComparison 1);
"<" = dropWildcardPrecision (mkComparison (-1));
"!=" = v: c: ! operators."==" v c;
">=" = v: c: operators."==" v c || operators.">" v c;
"<=" = v: c: operators."==" v c || operators."<" v c;
# Semver specific operators
"~" = mkIdxComparison 1;
"^" = mkIdxComparison 0;
"~=" = v: c:
let
# Prune constraint
parts = builtins.splitVersion c;
pruned = lib.take ((builtins.length parts) - 1) parts;
upper = builtins.toString (
(lib.toInt (builtins.elemAt pruned (builtins.length pruned - 1))) + 1
);
upperConstraint = builtins.concatStringsSep "." (ireplace (builtins.length pruned - 1) upper pruned);
in
operators.">=" v c && operators."<" v upperConstraint;
# Infix operators
"-" = version: v: operators.">=" version v.vl && operators."<=" version v.vu;
# Arbitrary equality clause, just run simple comparison
"===" = v: c: v == c;
#
};
re = {
operators = "([=><!~^]+)";
version = "([0-9.*x]+)";
};
parseConstraint = constraint:
let
constraintStr = builtins.replaceStrings [ " " ] [ "" ] constraint;
# The common prefix operators
mPre = match "${re.operators} *${re.version}" constraintStr;
# There is also an infix operator to match ranges
mIn = match "${re.version} *(-) *${re.version}" constraintStr;
in
(
if mPre != null then {
op = elemAt mPre 0;
v = elemAt mPre 1;
}
# Infix operators are range matches
else if mIn != null then {
op = elemAt mIn 1;
v = {
vl = (elemAt mIn 0);
vu = (elemAt mIn 2);
};
}
else throw "Constraint \"${constraintStr}\" could not be parsed"
);
satisfiesSemver = version: constraint:
let
inherit (parseConstraint constraint) op v;
in
if constraint == "*" then true else operators."${op}" version v;
in
{ inherit satisfiesSemver; }

View File

@ -1,43 +0,0 @@
{ lib
, scripts
, python
}:
let
mkScript = bin: entrypoint:
let
elem = builtins.elemAt (builtins.split ":" entrypoint);
module = elem 0;
fn = elem 2;
in
''
cat << EOF >> $out/bin/${bin}
#!${python.interpreter}
import sys
import re
# Insert "" to add CWD to import path
sys.path.insert(0, "")
from ${module} import ${fn}
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', "", sys.argv[0])
sys.exit(${fn}())
EOF
chmod +x $out/bin/${bin}
'';
in
python.pkgs.buildPythonPackage {
name = "poetry2nix-env-scripts";
dontUnpack = true;
dontUseSetuptoolsBuild = true;
dontConfigure = true;
dontUseSetuptoolsCheck = true;
format = "poetry2nix";
installPhase = ''
mkdir -p $out/bin
${lib.concatStringsSep "\n" (lib.mapAttrsToList mkScript scripts)}
'';
}

View File

@ -1,32 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
pwd=$(pwd)
workdir=$(mktemp -d)
function cleanup {
cd "$pwd"
rm -rf $workdir
}
trap cleanup EXIT
cd "$workdir"
curl -L -s https://github.com/nix-community/poetry2nix/archive/master.tar.gz | tar -xz
mv poetry2nix-master/* .
mkdir build
cp *.* build/
cp -r overrides pkgs hooks bin build/
rm build/shell.nix build/generate.py build/overlay.nix build/flake.* build/check-fmt.nix build/pkgs/poetry/update*
cat > build/README.md << EOF
Dont change these files here, they are maintained at https://github.com/nix-community/poetry2nix
The update procedure is as-follows:
1. Send your change to the upstream poetry2nix repository
2. Get it approved with tests passing
3. Run the update script in pkgs/development/tools/poetry2nix
EOF
rm -rf "$pwd/poetry2nix"
mv build "$pwd/poetry2nix"

View File

@ -697,6 +697,7 @@ mapAliases ({
pinentry_gtk2 = throw "'pinentry_gtk2' has been renamed to/replaced by 'pinentry-gtk2'"; # Converted to throw 2023-09-10
pinentry_qt = throw "'pinentry_qt' has been renamed to/replaced by 'pinentry-qt'"; # Converted to throw 2023-09-10
pinentry_qt5 = pinentry-qt; # Added 2020-02-11
poetry2nix = throw "poetry2nix is now maintained out-of-tree. Please use https://github.com/nix-community/poetry2nix/"; # Added 2023-10-26
probe-rs-cli = throw "probe-rs-cli is now part of the probe-rs package"; # Added 2023-07-03
processing3 = throw "'processing3' has been renamed to/replaced by 'processing'"; # Converted to throw 2023-09-10
prometheus-dmarc-exporter = dmarc-metrics-exporter; # added 2022-05-31

View File

@ -17980,10 +17980,6 @@ with pkgs;
poetryPlugins = recurseIntoAttrs poetry.plugins;
poetry2nix = callPackage ../development/tools/poetry2nix/poetry2nix {
inherit pkgs lib;
};
poetry2conda = callPackage ../tools/package-management/poetry2conda { };
pip-audit = callPackage ../development/tools/pip-audit { };