Confused with installing per-user in Windows

eryk sun eryksun at gmail.com
Mon Nov 7 03:09:08 EST 2016


On Mon, Nov 7, 2016 at 1:11 AM, ddbug <pavel.aronsky at gmail.com> wrote:
>
> In Windows, the user-local directory for scripts is %APPDATA%\Python\Scripts. It is not in
> PATH by default and finding it is hard (because Microsoft made it hidden in their infinite
> wisdom).

POSIX "~/.local" is hidden as well, by convention, so I don't see how
the directory's being hidden is relevant.

In Windows 10, showing hidden files and folders in Explorer takes just
two clicks -- three if the ribbon is collapsed. It's not much harder
in Windows 7, but you have to know how to set folder options. Or enter
%appdata% in the location bar, or shell:appdata:

    http://www.winhelponline.com/blog/shell-commands-to-access-the-special-folders

In cmd use "dir /a" to list all files or "dir /ad" to list all
directories. You can use set "DIRCMD=/a" if you prefer to always list
all files. (FYI, /a doesn't mean [a]ll; it's an [a]ttribute filter; an
empty filter yields all files and directories.)

In PowerShell it's "gci -fo" or "gci -fo -ad". To be verbose, the
latter is "Get-ChildItem -Force -Attributes Directory".

I do think using %APPDATA% is a mistake, but not because it's hidden.
A --user install should be using %LOCALAPPDATA%, which is excluded
from the user's roaming profile. It was also a mistake to dump
everything into a common "Scripts" directory, since the Python version
number isn't appended to script names. This was fixed in 3.5, which
instead uses "%APPDATA%\Python\Python35\Scripts".

> 1. would it be good if python interpreter could JUST find user-local scripts - by default or by some
> easy configuration option?

That would be surprising behavior if it were enabled by default.

It was already suggested that you add the user scripts directory to
PATH and run the .py file directly. However, calling ShellExecuteEx to
run a file by association isn't always an option. That's why pip and
setuptools create EXE wrappers for script entry points when installing
source and wheel distributions.

Consider packaging your scripts in a wheel that defines entry points.
For example:

spam_scripts\spam.py:

    import sys

    def main():
        print('spam%d%d' % sys.version_info[:2])
        return 42

    # unused classic entry point
    if __name__ == '__main__':
        sys.exit(main())

setup.py:

    from setuptools import setup

    setup(name='spam_scripts',
          version='1.0',
          description='...',
          url='...',
          author='...',
          author_email='...',
          license='...',
          packages=['spam_scripts'],
          entry_points = {
              'console_scripts': ['spam=spam_scripts.spam:main'],
          })

build:

    > python setup.py bdist_wheel --universal
    > cd dist

installation (3.5.2 on this system):

    > pip install --user spam_scripts-1.0-py2.py3-none-any.whl

installation (latest 2.x):

    > py -2 -m pip install --user spam_scripts-1.0-py2.py3-none-any.whl

Usage:

    >%APPDATA%\Python\Python35\Scripts\spam.exe
    spam35
    >echo %errorlevel%
    42

    >%APPDATA%\Python\Scripts\spam.exe
    spam27
    >echo %errorlevel%
    42



More information about the Python-list mailing list