wip: assets

main
teutat3s 2023-05-20 23:36:21 +02:00
parent 5a181bbd83
commit 9781db320c
Signed by: teutat3s
GPG Key ID: 4FA1D3FA524F22C1
19 changed files with 472 additions and 293 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
result

20
erpnext-package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "erpnext",
"version": "v14.24.3",
"description": "Open Source ERP System powered by the Frappe Framework",
"repository": {
"type": "git",
"url": "git+https://github.com/frappe/erpnext.git"
},
"homepage": "https://erpnext.com",
"author": "Frappe Technologies Pvt. Ltd.",
"license": "GPL-3.0",
"bugs": {
"url": "https://github.com/frappe/erpnext/issues"
},
"devDependencies": {},
"dependencies": {
"html2canvas": "^1.1.4",
"onscan.js": "^1.5.2"
}
}

27
erpnext-yarn.lock Normal file
View File

@ -0,0 +1,27 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
base64-arraybuffer@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz#4b944fac0191aa5907afe2d8c999ccc57ce80f45"
integrity sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==
css-line-break@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/css-line-break/-/css-line-break-1.1.1.tgz#d5e9bdd297840099eb0503c7310fd34927a026ef"
integrity sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==
dependencies:
base64-arraybuffer "^0.2.0"
html2canvas@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/html2canvas/-/html2canvas-1.1.4.tgz#53ae91cd26e9e9e623c56533cccb2e3f57c8124c"
integrity sha512-uHgQDwrXsRmFdnlOVFvHin9R7mdjjZvoBoXxicPR+NnucngkaLa5zIDW9fzMkiip0jSffyTyWedE8iVogYOeWg==
dependencies:
css-line-break "1.1.1"
onscan.js@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/onscan.js/-/onscan.js-1.5.2.tgz#14ed636e5f4c3f0a78bacbf9a505dad3140ee341"
integrity sha512-9oGYy2gXYRjvXO9GYqqVca0VuCTAmWhbmX3egBSBP13rXiMNb+dKPJzKFEeECGqPBpf0m40Zoo+GUQ7eCackdw==

View File

@ -16,29 +16,28 @@
pkgs = import nixpkgs { inherit system;
config.allowBroken = true;
};
attrsets = pkgs.lib.attrsets;
overrideFiles = (attrsets.filterAttrs (f: type: type == "regular") (builtins.readDir ./python));
overridePackageNames = attrsets.mapAttrsToList (f: _: builtins.replaceStrings [".nix"] [""] f) overrideFiles;
python3 = pkgs.python3.override ({
packageOverrides = pself: psuper:
attrsets.genAttrs overridePackageNames (o: pself.callPackage ./python/${o}.nix {});
});
newversion = python3.pkgs.newversion.overrideAttrs(old: {
propagatedBuildInputs = old.propagatedBuildInputs ++ [python3.pkgs.setuptools];
});
#attrsets = pkgs.lib.attrsets;
#overrideFiles = (attrsets.filterAttrs (f: type: type == "regular") (builtins.readDir ./python));
#overridePackageNames = attrsets.mapAttrsToList (f: _: builtins.replaceStrings [".nix"] [""] f) overrideFiles;
py = pkgs.callPackage ./python.nix { inherit pkgs; };
# packageOverrides = pself: psuper:
# attrsets.genAttrs overridePackageNames (o: pself.callPackage ./python/${o}.nix {});
#});
#newversion = python3.pkgs.newversion.overrideAttrs(old: {
# propagatedBuildInputs = old.propagatedBuildInputs ++ [python3.pkgs.setuptools];
#});
in rec {
packages = {
devEnv = pkgs.buildEnv {
name = "erpnext-nix-dev-env";
paths = [
newversion
pkgs.dasel
];
};
inherit pkgs;
pip2nix = import "${pip2nix}/default.nix" { inherit pkgs; pythonPackages = "python310Packages"; };
erpnext = python3.pkgs.erpnext;
pythonPkgs = python3.pkgs;
erpnext = py.pkgs.erpnext;
pythonPkgs = py.pkgs;
};
});
}

86
frappe-package.json Normal file
View File

@ -0,0 +1,86 @@
{
"name": "frappe-framework",
"version": "14.36.1",
"scripts": {
"build": "node esbuild",
"production": "node esbuild --production",
"watch": "node esbuild --watch",
"coverage:report": "npx nyc report --reporter=clover",
"prepare": "npm run snyk-protect",
"snyk-protect": "snyk-protect"
},
"repository": {
"type": "git",
"url": "git+https://github.com/frappe/frappe.git"
},
"author": "Frappe Technologies Pvt. Ltd.",
"license": "MIT",
"bugs": {
"url": "https://github.com/frappe/frappe/issues"
},
"engines": {
"node": ">=14"
},
"homepage": "https://frappeframework.com",
"dependencies": {
"@editorjs/editorjs": "^2.26.3",
"@frappe/esbuild-plugin-postcss2": "^0.1.3",
"@snyk/protect": "^1.1107.0",
"@vue/component-compiler": "^4.2.4",
"ace-builds": "^1.4.8",
"air-datepicker": "github:frappe/air-datepicker",
"autoprefixer": "10",
"awesomplete": "^1.1.5",
"bootstrap": "4.5.0",
"chalk": "^2.3.2",
"cliui": "^7.0.4",
"cookie": "^0.4.0",
"cropperjs": "^1.5.12",
"cssnano": "^5.0.0",
"driver.js": "^0.9.8",
"editorjs-undo": "0.1.6",
"esbuild": "^0.14.29",
"esbuild-vue": "^1.2.1",
"fast-deep-equal": "^2.0.1",
"fast-glob": "^3.2.5",
"frappe-charts": "2.0.0-rc22",
"frappe-datatable": "^1.16.4",
"frappe-gantt": "^0.6.0",
"highlight.js": "^10.4.1",
"html5-qrcode": "^2.0.11",
"jquery": "3.6.0",
"js-sha256": "^0.9.0",
"jsbarcode": "^3.9.0",
"launch-editor": "^2.2.1",
"localforage": "^1.9.0",
"md5": "^2.3.0",
"moment": "^2.29.4",
"moment-timezone": "^0.5.28",
"plyr": "^3.7.2",
"popper.js": "^1.16.0",
"postcss": "8",
"quill": "2.0.0-dev.4",
"quill-image-resize": "^3.0.9",
"quill-magic-url": "^3.0.0",
"qz-tray": "^2.0.8",
"redis": "^3.1.1",
"rtlcss": "^3.2.1",
"sass": "^1.53.0",
"showdown": "^2.1.0",
"socket.io": "^4.5.1",
"socket.io-client": "^4.5.1",
"sortablejs": "1.9.0",
"superagent": "^3.8.2",
"touch": "^3.1.0",
"vue": "2.6.14",
"vue-router": "^2.0.0",
"vue-template-compiler": "2.6.14",
"vuedraggable": "^2.24.3",
"vuex": "3",
"yargs": "^17.5.1"
},
"snyk": true,
"nyc": {
"report-dir": ".cypress-coverage"
}
}

125
python.nix Normal file
View File

@ -0,0 +1,125 @@
{ pkgs }:
pkgs.python3.override {
packageOverrides = self: super: {
erpnext = self.callPackage ./python/erpnext.nix {};
frappe = self.callPackage ./python/frappe.nix {};
email-reply-parser = self.callPackage ./python/email-reply-parser.nix {};
git-url-parse = self.callPackage ./python/git-url-parse.nix {};
gocardless-pro = self.callPackage ./python/gocardless-pro.nix {};
jsonobject = self.callPackage ./python/jsonobject.nix {};
maxminddb-geolite2 = self.callPackage ./python/maxminddb-geolite2.nix {};
posthog = self.callPackage ./python/posthog.nix {};
psycopg2-binary = self.callPackage ./python/psycopg2-binary.nix {};
pypdf2 = self.callPackage ./python/pypdf2.nix {};
pypika = self.callPackage ./python/pypika.nix {};
python-youtube = self.callPackage ./python/python-youtube.nix {};
rauth = self.callPackage ./python/rauth.nix {};
redisearch = self.callPackage ./python/redisearch.nix {};
rejson = self.callPackage ./python/rejson.nix {};
taxjar = self.callPackage ./python/taxjar.nix {};
traceback-with-variables = self.callPackage ./python/traceback-with-variables.nix {};
barcodenumber = super.barcodenumber.overridePythonAttrs (oldAttrs: (rec {
version = "0.5.0";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-VZfHLwSF9aDoy5L1x4O2mu8/f2ijYKgyjCrQ1KKY5Ho=";
};
}));
bleach = super.bleach.overridePythonAttrs (oldAttrs: (rec {
version = "3.3.1";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-MGSDpal5VHQWCtV/zj3dG1BVHpge7Y4VpYLTTO8oqvo=";
};
}));
phonenumbers = super.phonenumbers.overridePythonAttrs (oldAttrs: (rec {
version = "8.12.40";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-APKVWkVrRY+barDSQykEnD5zWMRN/Bl5/kkIztQPHrg=";
};
}));
plaid-python = super.plaid-python.overridePythonAttrs (oldAttrs: (rec {
version = "7.2.1";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-ryrTJug3fIyG2XGE9gwL5BzXH1B1IB39szMcyF1N5RM=";
};
propagatedBuildInputs = [ super.requests ];
checkInputs = [ super.pytest ];
# Integration tests require API keys and internet access
checkPhase = "py.test -rxs ./tests/unit";
}));
pycountry = super.pycountry.overridePythonAttrs (oldAttrs: (rec {
version = "20.7.3";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-gQhKU9NFQ0TAKS3uvCD80KFIjBNtSQAxLL1GXPVSy0I=";
};
}));
pymysql = super.pymysql.overridePythonAttrs (oldAttrs: (rec {
version = "1.0.3";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-PdqUPvNpQGinXWnQcXVdvsrO4a35ofxbIGgw0rZ9Jeg=";
};
format = "pyproject";
buildInputs = [super.setuptools];
}));
pypng = super.pypng.overridePythonAttrs (oldAttrs: (rec {
version = "0.20220715.0";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-c5xDO6lvB4MV3lTA25da7lN8vD4dCuTtmqsMoeQn4sE=";
};
}));
pytz = super.pytz.overridePythonAttrs (oldAttrs: (rec {
version = "2022.1";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-HnYOL+aoFjvAs9mhnE+ENCr6Cir/6/qoSwG5eKAuyqc=";
};
}));
redis = super.redis.overridePythonAttrs (oldAttrs: (rec {
version = "3.5.3";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-Dn4M/KhmDeqLfVzYxPbF4p4R8xFYwLCukaOX8A5aBaI=";
};
pythonImportsCheck = [];
# tests require a running redis
doCheck = false;
}));
tweepy = super.tweepy.overridePythonAttrs (oldAttrs: (rec {
version = "3.10.0";
src = super.fetchPypi {
inherit version;
inherit (oldAttrs) pname;
sha256 = "sha256-duaVS4BspHDdqHf1fbh5L/8GoL66DtQ+/DgFdx458Go=";
};
doCheck = false;
pythonImportsCheck = [];
}));
unidecode = super.unidecode.overridePythonAttrs (oldAttrs: (rec {
version = "1.2.0";
src = super.fetchPypi {
inherit version;
pname = "Unidecode";
sha256 = "sha256-jXOpfTh6lWkiNE9rdCQ8LGdxWUZZd4dEstvarY9rcn0=";
};
}));
};
}

View File

@ -1,19 +0,0 @@
{
buildPythonPackage,
fetchPypi,
python-stdnum
}:
buildPythonPackage rec {
pname = "barcodenumber";
version = "0.5.0";
format = "wheel";
src = fetchPypi {
inherit pname version format;
sha256 = "sha256-VZfHLwSF9aDoy5L1x4O2mu8/f2ijYKgyjCrQ1KKY5Ho=";
python = "py3";
dist = "py3";
};
buildInputs = [
python-stdnum
];
}

View File

@ -1,20 +0,0 @@
{ buildPythonPackage
, fetchPypi
, six
, packaging
, webencodings
}:
buildPythonPackage rec {
pname = "bleach";
version = "3.3.1";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-MGSDpal5VHQWCtV/zj3dG1BVHpge7Y4VpYLTTO8oqvo=";
};
propagatedBuildInputs = [
packaging
six
webencodings
];
doCheck = false;
}

View File

@ -1,28 +1,34 @@
{
buildPythonPackage,
fetchFromGitHub,
{ lib
, buildPythonPackage
, fetchFromGitHub
, fetchYarnDeps
, mkYarnPackage
taxjar,
gocardless-pro,
plaid-python,
unidecode,
pycountry,
python-youtube,
tweepy,
redisearch,
googlemaps,
python-stdnum,
frappe
, taxjar
, gocardless-pro
, plaid-python
, unidecode
, pycountry
, python-youtube
, tweepy
, redisearch
, googlemaps
, python-stdnum
, frappe
}:
let
frappe-version = "14.36.1";
erpnext-version = "14.24.3";
in
buildPythonPackage rec {
pname = "erpnext";
version = "14.24.1";
version = erpnext-version;
format = "flit";
src = fetchFromGitHub {
owner = "frappe";
repo = pname;
rev = "v${version}";
sha256 = "sha256-djux5iwbwXQBMOg7R79hjy0szgFxd6L9nobsLVS7kEg=";
rev = "v${erpnext-version}";
sha256 = "sha256-zovdbpTp9fTpY7kAs4J8EiPh+EjqUOtVUk+rDYMfYDk=";
};
buildInputs = [
taxjar
@ -37,4 +43,104 @@ buildPythonPackage rec {
python-stdnum
frappe
];
frappe-assets = mkYarnPackage {
pname = "frappe-assets";
version = frappe-version;
src = fetchFromGitHub {
owner = "frappe";
repo = "frappe";
rev = "v${frappe-version}";
hash = "sha256-eee6IS/Ep/DSDCPdnyrqBea/ag0kNnN5Id3YQMNz5js=";
};
packageJSON = ../frappe-package.json;
yarnFlags = [ "--production" ];
offlineCache = fetchYarnDeps {
yarnLock = src + "/yarn.lock";
hash = "sha256-PBdMUz9gJIoQaqQYbdk+xnd8CyZPmdeyz/9WznCb4Ss=";
};
buildPhase = ''
runHook preBuild
# Yarn writes cache directories etc to $HOME.
export HOME=$PWD/yarn_home
# The upstream build script reads sites/apps.txt to define what assets to build
# A list of assets is written to sites/assets/assets.json
mkdir -p apps sites/assets
echo -e "erpnext\nfrappe\n" > sites/apps.txt
cp -r ${src} apps/erpnext
chmod u+rw apps/erpnext
cp -r ${erpnext-modules}/node_modules apps/erpnext/node_modules
chmod u+rw apps/erpnext
#ln -s ${frappe-assets.src} apps/frappe
yarn --offline production
mv sites deps/
runHook postBuild
'';
# Do not attempt generating a tarball
doDist = false;
meta = with lib; {
description = "Assets for frappe";
homepage = "https://github.com/frappe/frappe";
license = licenses.mit;
maintainers = with maintainers; [ axeman teutat3s ];
};
};
erpnext-modules = mkYarnPackage {
pname = "erpnext-modules";
version = erpnext-version;
src = fetchFromGitHub {
owner = "frappe";
repo = "erpnext";
rev = "v${erpnext-version}";
hash = "sha256-zovdbpTp9fTpY7kAs4J8EiPh+EjqUOtVUk+rDYMfYDk=";
};
packageJSON = ../erpnext-package.json;
yarnFlags = [ "--production" ];
offlineCache = fetchYarnDeps {
yarnLock = ../erpnext-yarn.lock;
hash = "sha256-Vho4BSbxcsVYExLvUaeoc3xIpbXoCUP/4jw4RwGnWGY=";
};
configurePhase = ''
ln -s $node_modules node_modules
'';
installPhase = ''
ls -alh
mkdir $out
cp -r node_modules $out/
ls -alh $out/
'';
# We only need node_modules
dontBuild = true;
# Do not attempt generating a tarball
doDist = false;
meta = with lib; {
description = "Node modules for erpnext";
homepage = "https://github.com/frappe/erpnext";
license = licenses.mit;
maintainers = with maintainers; [ axeman teutat3s ];
};
};
postInstall = ''
mkdir -p $out/test/frappe $out/test/erpnext
ln -s ${frappe-assets} $out/test/frappe
ln -s ${erpnext-modules} $out/test/erpnext
'';
}

View File

@ -1,83 +1,83 @@
{
buildPythonPackage,
fetchPypi,
fetchFromGitHub,
{ lib
, buildPythonPackage
, fetchPypi
, fetchFromGitHub
# core dependencies
babel,
click,
filelock,
gitpython,
jinja2,
pillow,
pyjwt,
pymysql,
pypdf2,
pypika,
pyqrcode,
pyyaml,
restrictedpython,
weasyprint,
werkzeug,
whoosh,
beautifulsoup4,
bleach-allowlist,
bleach,
cairocffi,
chardet,
croniter,
cryptography,
email-reply-parser,
git-url-parse,
gitdb,
gunicorn,
html5lib,
ipython,
ldap3,
markdown2,
markupsafe,
maxminddb-geolite2,
num2words,
oauthlib,
openpyxl,
passlib,
pdfkit,
phonenumbers,
premailer,
psutil,
psycopg2-binary,
pyasn1,
pyopenssl,
pycryptodome,
pyotp,
pypng,
python-dateutil,
pytz,
rauth,
redis,
hiredis,
requests-oauthlib,
requests,
rq,
rsa,
semantic-version,
sqlparse,
tenacity,
terminaltables,
traceback-with-variables,
urllib3,
xlrd,
zxcvbn,
markdownify,
# core dependencies
, babel
, click
, filelock
, gitpython
, jinja2
, pillow
, pyjwt
, pymysql
, pypdf2
, pypika
, pyqrcode
, pyyaml
, restrictedpython
, weasyprint
, werkzeug
, whoosh
, beautifulsoup4
, bleach-allowlist
, bleach
, cairocffi
, chardet
, croniter
, cryptography
, email-reply-parser
, git-url-parse
, gitdb
, gunicorn
, html5lib
, ipython
, ldap3
, markdown2
, markupsafe
, maxminddb-geolite2
, num2words
, oauthlib
, openpyxl
, passlib
, pdfkit
, phonenumbers
, premailer
, psutil
, psycopg2-binary
, pyasn1
, pyopenssl
, pycryptodome
, pyotp
, pypng
, python-dateutil
, pytz
, rauth
, redis
, hiredis
, requests-oauthlib
, requests
, rq
, rsa
, semantic-version
, sqlparse
, tenacity
, terminaltables
, traceback-with-variables
, urllib3
, xlrd
, zxcvbn
, markdownify
# integration dependencies
boto3,
dropbox,
google-api-python-client,
google-auth-httplib2,
google-auth-oauthlib,
google-auth,
posthog,
# integration dependencie
, boto3
, dropbox
, google-api-python-client
, google-auth-httplib2
, google-auth-oauthlib
, google-auth
, posthog
}:
buildPythonPackage rec {
pname = "frappe";

View File

@ -1,13 +0,0 @@
{
buildPythonPackage,
fetchPypi,
}:
buildPythonPackage rec {
pname = "phonenumbers";
version = "8.12.40";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-APKVWkVrRY+barDSQykEnD5zWMRN/Bl5/kkIztQPHrg=";
};
propagatedBuildInputs = [];
}

View File

@ -1,18 +0,0 @@
{
buildPythonPackage,
fetchPypi,
requests,
}:
buildPythonPackage rec {
pname = "plaid-python";
version = "7.2.1";
format = "setuptools";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-ryrTJug3fIyG2XGE9gwL5BzXH1B1IB39szMcyF1N5RM=";
};
doCheck = false;
propagatedBuildInputs = [
requests
];
}

View File

@ -1,13 +0,0 @@
{
buildPythonPackage,
fetchPypi,
}:
buildPythonPackage rec {
pname = "pycountry";
version = "20.7.3";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-gQhKU9NFQ0TAKS3uvCD80KFIjBNtSQAxLL1GXPVSy0I=";
};
propagatedBuildInputs = [];
}

View File

@ -1,22 +0,0 @@
{
buildPythonPackage,
fetchPypi,
cryptography,
setuptools
}:
buildPythonPackage rec {
pname = "pymysql";
version = "1.0.3";
format = "pyproject";
src = fetchPypi {
pname = "PyMySQL";
inherit version;
sha256 = "sha256-PdqUPvNpQGinXWnQcXVdvsrO4a35ofxbIGgw0rZ9Jeg=";
};
buildInputs = [setuptools];
propagatedBuildInputs = [cryptography];
# Wants to connect to MySQL
doCheck = false;
}

View File

@ -1,16 +0,0 @@
{
buildPythonPackage,
fetchPypi,
setuptools
}:
buildPythonPackage rec {
pname = "pypng";
version = "0.20220715.0";
format = "pyproject";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-c5xDO6lvB4MV3lTA25da7lN8vD4dCuTtmqsMoeQn4sE=";
};
buildInputs = [setuptools];
propagatedBuildInputs = [];
}

View File

@ -1,13 +0,0 @@
{
buildPythonPackage,
fetchPypi,
}:
buildPythonPackage rec {
pname = "pytz";
version = "2022.1";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-HnYOL+aoFjvAs9mhnE+ENCr6Cir/6/qoSwG5eKAuyqc=";
};
propagatedBuildInputs = [];
}

View File

@ -1,14 +0,0 @@
{
buildPythonPackage,
fetchPypi,
}:
buildPythonPackage rec {
pname = "redis";
version = "3.5.3";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-Dn4M/KhmDeqLfVzYxPbF4p4R8xFYwLCukaOX8A5aBaI=";
};
doCheck = false;
propagatedBuildInputs = [];
}

View File

@ -1,23 +0,0 @@
{
buildPythonPackage,
fetchPypi,
requests-oauthlib,
six,
}:
buildPythonPackage rec {
pname = "tweepy";
version = "3.10.0";
src = fetchPypi {
inherit pname version;
sha256 = "sha256-duaVS4BspHDdqHf1fbh5L/8GoL66DtQ+/DgFdx458Go=";
};
# ModuleNotFoundError: No module named 'tests'
doCheck = false;
propagatedBuildInputs = [
requests-oauthlib
six
];
}

View File

@ -1,14 +0,0 @@
{
buildPythonPackage,
fetchPypi,
}:
buildPythonPackage rec {
pname = "unidecode";
version = "1.2.0";
src = fetchPypi {
pname = "Unidecode";
inherit version;
sha256 = "sha256-jXOpfTh6lWkiNE9rdCQ8LGdxWUZZd4dEstvarY9rcn0=";
};
propagatedBuildInputs = [];
}