I'm very new to NIX so maybe this is something simple but I haven't managed to find a fix yet.
I have this python script (resource.py) that I have nixified. When I run the script from within it's own directory (./resource.py), everything runs fine. Nix gets all the packages needed and runs the script without any errors. But when I try to call the script from a different folder, then I get this error:
error: cannot auto-call a function that has an argument without a
default value ('pkgs')
What I am aiming for is being able to call the script directly from any folder, ie call "/home/.../resource.py" from anywhere.
Here is my default.nix file:
{ pkgs }:
pkgs.poetry2nix.mkPoetryApplication {
projectDir = ./.;
}
my shell.nix:
{
pkgs ? (import (builtins.fetchTarball {
# Release '22.05' is a tag which points to ce6aa13369b667ac2542593170993504932eb836
url = "https://github.com/nixos/nixpkgs/tarball/22.05";
# This hash is git-agnostic so nix can detect if the git-tag changes
sha256 = "0d643wp3l77hv2pmg2fi7vyxn4rwy0iyr8djcw1h5x72315ck9ik";
}) {}),
allthepoetrystuff ? import ./default.nix { inherit pkgs; }
}:
pkgs.mkShell {
buildInputs = [
pkgs.python3
pkgs.poetry
allthepoetrystuff # This assumes lockfile is present
];
}
and the main script (resource.py):
#! /usr/bin/env nix-shell
#! nix-shell --pure -i "python3"
import resourcehandler
if __name__ == "__main__":
resourcehandler.ResourceHandler()
Any help/tips/suggestions are highly appreciated!
I'm trying to package a python application for Nix, but I'm finding that the majority of the documentation assumes that I want to package a library.
In order to do this, I looked at Rednotebook example (not for any particular reason other than I happened to know it was written in python), which can be found in python-packages, but as that file is so huge, here is the relevant part:
redNotebook = buildPythonPackage rec {
name = "rednotebook-1.8.1";
src = pkgs.fetchurl {
url = "mirror://sourceforge/rednotebook/${name}.tar.gz";
sha256 = "00b7s4xpqpxsbzjvjx9qsx5d84m9pvn383c5di1nsfh35pig0rzn";
};
# no tests available
doCheck = false;
propagatedBuildInputs = with self; [ pygtk pywebkitgtk pyyaml chardet ];
meta = {
homepage = http://rednotebook.sourceforge.net/index.html;
description = "A modern journal that includes a calendar navigation, customizable templates, export functionality and word clouds";
license = licenses.gpl2;
maintainers = with maintainers; [ tstrobel ];
};
};
My derivation looks like this:
{ pkgs ? import <nixpkgs> {} }:
let
requirements = import ./nix/requirements.nix { inherit pkgs; };
in
pkgs.python35Packages.buildPythonPackage rec {
name = "package-name";
version = "1.0.0";
namePrefix = "";
src = ./.;
doCheck = false;
propagatedBuildInputs = builtins.attrValues requirements.packages;
}
requirements.nix was the output of pypi2nix and requirements.packages has type "list of derivations". Despite this when I cd into the resulting store path for Rednotebook there is a /bin directory with some wrapper scripts. The store path for my app there is just a lib an no /bin
How do I tell Nixpkgs that I have an application?
There are buildPythonPackage and buildPythonApplication functions, but at the end of the day, they both call mkPythonDerivation.
A Python application with a simple Nix package you can reference is Ranger; which uses buildPythonApplication. The resulting derivation contains a wrapper in /nix/store/PACKAGE/bin/
Was experimenting with building and installing a sample service written in Python.
Ended up using buildPythonApplication in my installer
Important points
If you are leveraging setuptools to distribute your app you need to have the entry_points value in your setup call:
from distutils.core import setup
setup(
...
entry_points = {
'console_scripts': ['sample_module = src.app:main']
}
src - source code folder
app - entry point module name
main - name of the entry point function
My whole build configuration was:
# sample.nix
with (import <nixpkgs> {});
python37.pkgs.buildPythonApplication rec {
pname = "sample_service";
version = "0.0.3";
src = ./sample_package;
meta = with lib; {
homepage = "https://www.example.com";
description = "Sample Python Service";
};
}
sample_package was the folder that contained 'src' folder and 'setup.py' located at the same level as above 'sample.nix' file.
At this point, if you run nix-build sample.nix it will build and install the package for you. However, to make it available on the path you will need to capture the resulting path in the nix store and run:
nix-env -i <nix_store_path>
buildPythonPackage is to be used for libraries, that is, when you want it to expose its modules in site-packages. buildPythonApplication is for applications that just happen to be written in Python. In that case, when you include such a derivation in another derivation, you don't want to expose the libraries.
This separation is important because it may happen that a Python 3 environment calls a tool that is written in Python 2 and vice versa.
Note that at the time of writing this issue hasn't been completely solved yet, but at least python.buildEnv or python.withPackages will not include applications along with their dependencies.
I actually tried following this guide, but it did not work for me(I believe it's only for python 2 since I got a ton of errors and tried fixing them but it wasn't working still, I'm trying to do this for python 3)
set file permissions in setup.py file
So basically I have a folder in lets say
/usr/lib/python3.6/site_packages/XYZ
I want to give XYZ read & write permissions, since the current permissions only give root user write access. In my documentation I can require each user that installs my program through pip to chmod the directory themselves, but I'm looking for a more convenient way so no one has to do that.
Here's my setup.py incase anyone wants to see it
from distutils.core import setup
setup(
name = 'graphite-analytics',
packages = ['graphite'],
package_data={
'graphite' : ['graphite.py', 'capture.j3', 'templates/css/styles.css', 'templates/js/Chart.PieceLabel.js', 'templates/html/render.html', 'templates/fonts/Antro_Vectra.otf', 'templates/images/Calendar-icon.png'],
},
version = '0.1.2.13',
description = 'Create a print-out template for your google analytics data',
author = 'NAME REDACTED',
author_email = 'EMAIL REDACTED',
url = 'https://github.com/ARM-open/Graphite',
include_package_data=True,
zip_safe=True,
classifiers = [],
keywords = ['Google analytics', 'analytics', 'templates'],
install_requires=['Click', 'google-api-python-client', 'jinja2'],
entry_points={'console_scripts': [
'graphite-analytics = graphite.graphite:main'
]}
)
How to pass commands to gcc through cx_Freeze 'disutils.core.setup()' arguments?
Specifically, i want my .exe file to use relative paths in traceback messages, rather than the path where i build .exe file
Here is my setup.py file:
setup(
name="test",
packages=['test'],
package_data={'': ['*.py', '*.txt', '*.sample', '*.mo', 'README.rst']},
options={"build_exe": {
"icon": r"test\resources\test.ico",
"compressed": True,
"create_shared_zip": True,
"copy_dependent_files": True,
"include_files": [
('test/i18n/', 'i18n/'),
('test/resources/', 'resources/'),
('test/client.conf.sample', 'client.conf.sample'),
],
"excludes": [
'urllib.sys',
'urllib._sre',
'urllib.array',
'urllib._locale',
'urllib.datetime',
'urllib._functools',
]
}
},
executables=Executable(script=script),)
You need to add one additional option to the ones you already have:
replace_paths = [("*", "")]
That will replace all paths with relative paths. You can also do more interesting things like:
replace_paths = [
("/path/to/python/lib", "<Python>"),
("/path/to/my/script", "<Script>")
]
In essence, the first element of the tuple is the part of the path which is to be replaced with the value in the second element of the tuple. A value of * in the search value results in all paths being replaced with the replacement value.
I've created my setup.py file as instructed but I don't actually.. understand what to do next. Typing "python setup.py build" into the command line just gets a syntax error.
So, what do I do?
setup.py:
from cx_Freeze import setup, Executable
setup(
name = "On Dijkstra's Algorithm",
version = "3.1",
description = "A Dijkstra's Algorithm help tool.",
exectuables = [Executable(script = "Main.py", base = "Win32GUI")])
Add import sys as the new topline
You misspelled "executables" on the last line.
Remove script = on last line.
The code should now look like:
import sys
from cx_Freeze import setup, Executable
setup(
name = "On Dijkstra's Algorithm",
version = "3.1",
description = "A Dijkstra's Algorithm help tool.",
executables = [Executable("Main.py", base = "Win32GUI")])
Use the command prompt (cmd) to run python setup.py build. (Run this command from the folder containing setup.py.) Notice the build parameter we added at the end of the script call.
I'm really not sure what you're doing to get that error, it looks like you're trying to run cx_Freeze on its own, without arguments. So here is a short step-by-step guide on how to do it in windows (Your screenshot looks rather like the windows command line, so I'm assuming that's your platform)
Write your setup.py file. Your script above looks correct so it should work, assuming that your script exists.
Open the command line (Start -> Run -> "cmd")
Go to the location of your setup.py file and run python setup.py build
Notes:
There may be a problem with the name of your script. "Main.py" contains upper case letters, which might cause confusion since windows' file names are not case sensitive, but python is. My approach is to always use lower case for scripts to avoid any conflicts.
Make sure that python is on your PATH (read http://docs.python.org/using/windows.html)1
Make sure are are looking at the new cx_Freeze documentation. Google often seems to bring up the old docs.
I ran into a similar issue. I solved it by setting the Executable options in a variable and then simply calling the variable. Below is a sample setup.py that I use:
from cx_Freeze import setup, Executable
import sys
productName = "ProductName"
if 'bdist_msi' in sys.argv:
sys.argv += ['--initial-target-dir', 'C:\InstallDir\\' + productName]
sys.argv += ['--install-script', 'install.py']
exe = Executable(
script="main.py",
base="Win32GUI",
targetName="Product.exe"
)
setup(
name="Product.exe",
version="1.0",
author="Me",
description="Copyright 2012",
executables=[exe],
scripts=[
'install.py'
]
)
You can change the setup.py code to this:
from cx_freeze import setup, Executable
setup( name = "foo",
version = "1.1",
description = "Description of the app here.",
executables = [Executable("foo.py")]
)
I am sure it will work. I have tried it on both windows 7 as well as ubuntu 12.04
find the cxfreeze script and run it. It will be in the same path as your other python helper scripts, such as pip.
cxfreeze Main.py --target-dir dist
read more at:
http://cx-freeze.readthedocs.org/en/latest/script.html#script
I usually put the calling setup.py command into .bat file to easy recall.
Here is simple code in COMPILE.BAT file:
python setup.py build
#ECHO:
#ECHO . : ` . * F I N I S H E D * . ` : .
#ECHO:
#Pause
And the setup.py is organized to easy customizable parameters that let you set icon, add importe module library:
APP_NAME = "Meme Studio"; ## < Your App's name
Python_File = "app.py"; ## < Main Python file to run
Icon_Path = "./res/iconApp48.ico"; ## < Icon
UseFile = ["LANGUAGE.TXT","THEME.TXT"];
UseAllFolder = True; ## Auto scan folder which is same level with Python_File and append to UseFile.
Import = ["infi","time","webbrowser", "cv2","numpy","PIL","tkinter","math","random","datetime","threading","pathlib","os","sys"]; ## < Your Imported modules (cv2,numpy,PIL,...)
Import+=["pkg_resources","xml","email","urllib","ctypes", "json","logging"]
################################### CX_FREEZE IGNITER ###################################
from os import walk
def dirFolder(folderPath="./"): return next(walk(folderPath), (None, None, []))[1]; # [ Folder ]
def dirFile(folderPath="./"): return next(walk(folderPath), (None, None, []))[2]; # [ File ]
if UseAllFolder: UseFile += dirFolder();
import sys, pkgutil;
from cx_Freeze import setup, Executable;
BasicPackages=["collections","encodings","importlib"] + Import;
def AllPackage(): return [i.name for i in list(pkgutil.iter_modules()) if i.ispkg]; # Return name of all package
#Z=AllPackage();Z.sort();print(Z);
#while True:pass;
def notFound(A,v): # Check if v outside A
try: A.index(v); return False;
except: return True;
build_msi_options = {
'add_to_path': False,
"upgrade_code": "{22a35bac-14af-4159-7e77-3afcc7e2ad2c}",
"target_name": APP_NAME,
"install_icon": Icon_Path,
'initial_target_dir': r'[ProgramFilesFolder]\%s\%s' % ("Picox", APP_NAME)
}
build_exe_options = {
"includes": BasicPackages,
"excludes": [i for i in AllPackage() if notFound(BasicPackages,i)],
"include_files":UseFile,
"zip_include_packages": ["encodings"] ##
}
setup( name = APP_NAME,
options = {"build_exe": build_exe_options},#"bdist_msi": build_msi_options},#,
executables = [Executable(
Python_File,
base='Win32GUI',#Win64GUI
icon=Icon_Path,
targetName=APP_NAME,
copyright="Copyright (C) 2900AD Muc",
)]
);
The modules library list in the code above is minimum for workable opencv + pillow + win32 application.
Example of my project file organize:
========== U P D A T E ==========
Although cx_Freeze is a good way to create setup file. It's really consume disk space if you build multiple different software project that use large library module like opencv, torch, ai... Sometimes, users download installer, and receive false positive virus alert about your .exe file after install.
Thus, you should consider use SFX archive (.exe) your app package and SFX python package separate to share between app project instead.
You can create .bat that launch .py file and then convert .bat file to .exe with microsoft IExpress.exe.
Next, you can change .exe icon to your own icon with Resource Hacker: http://www.angusj.com/resourcehacker/
And then, create SFX archive of your package with PeaZip: https://peazip.github.io/
Finally change the icon.
The Python Package can be pack to .exe and the PATH register can made with .bat that also convertable to .exe.
If you learn more about command in .bat file and make experiments with Resource Hacker & self extract ARC in PeaZip & IExpress, you can group both your app project, python package into one .exe file only. It'll auto install what it need on user machine. Although this way more complex and harder, but then you can custom many install experiences included create desktop shorcut, and install UI, and add to app & feature list, and uninstall ability, and portable app, and serial key require, and custom license agreement, and fast window run box, and many more,..... but the important features you get is non virus false positive block, reduce 200MB to many GB when user install many your python graphic applications.