Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use USERBASE based package installation into local directory #249

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

laundmo
Copy link

@laundmo laundmo commented Aug 13, 2022

This PR sets and uses USERBASE for pip installations. This has the advantage of never interacting with the systems python installation and should prevent bugs which might happend due to wrong versions of pip (shimmed by conda)

This also localises the dependencies within the addons folder to make sure permission errors don't happen.

This is after i deletd both py-slvs and pip from any python packages directories blender can see, and clicking the "install from pip" button once:
image

closes: #243

also i formatted the files i touched with black, which is in line with #248 so i hope its fine even before that is closed.

TODO:

  • [] test how well this works with .whl installation

@laundmo laundmo marked this pull request as draft August 13, 2022 18:03
@laundmo laundmo changed the title Use blender or usersite pip installation, not system Use USERBASE based package installation into local directory Aug 14, 2022
@laundmo laundmo marked this pull request as ready for review August 14, 2022 02:09
Copy link
Owner

@hlorus hlorus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This did work on my end and installed the module into CAD_Sketcher/lib/python3.10/site-packages.
For some reason it cannot find the module in the same session, i had to restart blender.
Also this added a bin folder which should also be ignored by git.

def install_pip():
import ensurepip

ret_val = ensurepip._bootstrap()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why the protected function is called and not just bootstrap itself?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh i actually had that commented in a previous version but it must've gotten lost somewhere. The bootstrap function itself doesn't do anything but call _bootstrap - but it hides the exit code of the process. will add comment.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the docs, they do warn about environment changes when using this function.

Note The bootstrapping process has side effects on both sys.path and os.environ. Invoking the command line interface in a subprocess instead allows these side effects to be avoided.

-- https://docs.python.org/3/library/ensurepip.html#ensurepip.bootstrap

This was initially achieved when using the cmd tool as before

    cmd = [global_data.PYPATH, "-m", "ensurepip", "--upgrade"]
    return not subprocess.call(cmd)

My question being: Do we absolutely need to keep it in this process in order to maintain the environment variables such as PYTHONUSERBASE ? The warning message could hint at future environment-related bugs.


Alternatively, I would suggest using subprocess.call as done before or subprocess.run() where you can also pass environment variables using env=env_vars in case the environment inheritance is somehow compromised.

If env is not None, it must be a mapping that defines the environment variables for the new process; these are used instead of the default behavior of inheriting the current process’ environment. It is passed directly to Popen.

@laundmo
Copy link
Author

laundmo commented Aug 14, 2022

This did work on my end and installed the module into CAD_Sketcher/lib/python3.10/site-packages. For some reason it cannot find the module in the same session, i had to restart blender. Also this added a bin folder which should also be ignored by git.

I'll have to add those, the folder names depend on what Python does for different OSs so we have to gitignore all versions - i forgot it only uses the Python3x folder scheme on windows. Maybe it's better to add another folder to USERBASE so that we can gitignore that without caring about OS specifics.

As for the finding the module: I'm not sure why that's failing - I'll have to boot into my linux install to test. wierd.

@hlorus
Copy link
Owner

hlorus commented Aug 15, 2022

Well path and user_base seems to be right:
sys.path: ['/home/yoga/Dropbox/blend/addons/CAD_Sketcher/lib/python3.10/site-packages', '/usr/share/blender/3.2/scripts/startup', '/usr/share/blender/3.2/scripts/modules', '/usr/lib/python310.zip', '/usr/lib/python3.10', '/usr/lib/python3.10/lib-dynload', '/usr/lib/python3.10/site-packages', '/usr/share/blender/3.2/scripts/freestyle/modules', '/usr/share/blender/3.2/scripts/addons/modules', '/home/yoga/.config/blender/3.2/scripts/addons/modules', '/usr/share/blender/3.2/scripts/addons', '/home/yoga/.config/blender/3.2/scripts/addons', '/home/yoga/Dropbox/blend/addons', '/usr/share/blender/3.2/scripts/addons_contrib']

site.USER_BASE: /home/yoga/Dropbox/blend/addons/CAD_Sketcher

@hlorus
Copy link
Owner

hlorus commented Aug 15, 2022

Calling importlib.invalidate_caches seems to do the trick on my end.

Copy link
Collaborator

@amrsoll amrsoll left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes do not seem applicable to my platform (linux). Restarting Blender doesn't fix the issue either

Comment on lines +40 to +42
if subprocess.call(cmd, env=global_data.env_vars) == 0:
return True
return False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if subprocess.call(cmd, env=global_data.env_vars) == 0:
return True
return False
return subprocess.call(cmd, env=global_data.env_vars) == 0

Copy link
Collaborator

@amrsoll amrsoll Aug 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this doesn't seem to function. In the terminal stdout/err I get No module named pip but the return value is 0. Which is very strange because it should return 1 in that case. In turn, it doesn't want to install pip.

# Running with the debugger, and tried this right before executing line 40.
>>> subprocess.run(cmd, env=global_data.env_vars, capture_output=True)
CompletedProcess(args=['/usr/bin/python3.10', '-m', 'pip', '--version'], returncode=0, stdout=b'', stderr=b'No module named pip\n')

I do run on Linux. Given the difference for our platforms, I will try to investigate myself

Copy link
Collaborator

@amrsoll amrsoll Aug 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a fix, I would recommend to always use ensurepip as it will, at most, update pip to the latest version in case pip is already present.

python -m ensurepip

This invocation will install pip if it is not already installed, but otherwise does nothing.

def install_pip():
import ensurepip

ret_val = ensurepip._bootstrap()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the docs, they do warn about environment changes when using this function.

Note The bootstrapping process has side effects on both sys.path and os.environ. Invoking the command line interface in a subprocess instead allows these side effects to be avoided.

-- https://docs.python.org/3/library/ensurepip.html#ensurepip.bootstrap

This was initially achieved when using the cmd tool as before

    cmd = [global_data.PYPATH, "-m", "ensurepip", "--upgrade"]
    return not subprocess.call(cmd)

My question being: Do we absolutely need to keep it in this process in order to maintain the environment variables such as PYTHONUSERBASE ? The warning message could hint at future environment-related bugs.


Alternatively, I would suggest using subprocess.call as done before or subprocess.run() where you can also pass environment variables using env=env_vars in case the environment inheritance is somehow compromised.

If env is not None, it must be a mapping that defines the environment variables for the new process; these are used instead of the default behavior of inheriting the current process’ environment. It is passed directly to Popen.

if no_deps:
cmd += ["--no-deps"]

cmd = cmd + package.split(" ")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't strictly your change, but the .split(" ") will break file paths containing spaces. If we are parsing some input value, it should be done at the source View3D_OT_slvs_install_package.execute()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and you can expect file paths if we are installing .whl wheels from a different folder.

Comment on lines +31 to +32
# code which is needed for the currect error messages.
ret_val = ensurepip._bootstrap()
Copy link
Collaborator

@amrsoll amrsoll Aug 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo + link to ref

Suggested change
# code which is needed for the currect error messages.
ret_val = ensurepip._bootstrap()
# code which is needed for the correct error messages.
# https://github.com/python/cpython/blob/f4c03484da59049eb62a9bf7777b963e2267d187/Lib/ensurepip/__init__.py#L115-127
ret_val = ensurepip._bootstrap()

@Cheaterman
Copy link
Collaborator

The Linux issues here are fairly interesting, and indeed need to be solved ; thankfully I'm on Linux too, but I'll need someone to take a look at my fixed version later on other platforms, to make sure I didn't break anything. :-)

@alexfanqi
Copy link

alexfanqi commented Mar 16, 2023

The linux issue might be py_slv 1.0.5 wheel package's problem. realthunder/slvs_py#7
somehow, this specific version installs module files into wrong location. The 1.0.3 wheel version works fine even without this pr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants