File: windows.py

package info (click to toggle)
python-pyshortcuts 1.9.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,632 kB
  • sloc: python: 1,097; makefile: 42
file content (158 lines) | stat: -rw-r--r-- 5,558 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/usr/bin/env python
"""
Create desktop shortcuts for Windows
"""
import os
import sys
import time
from pathlib import Path
from collections import namedtuple
import win32com.client
from win32com.shell import shell, shellcon

from .utils import get_pyexe, get_homedir

def get_conda_active_env():
    '''Return name of active conda environment or empty string'''
    c_env = None
    try:
        c_env = os.environ['CONDA_DEFAULT_ENV']
    except KeyError:
        print("No conda env active, defaulting to base")
        c_env = "base"
    return c_env

# batch file to activate the environment
# for Anaconda Python before running command.
conda_env = get_conda_active_env()
ENVRUNNER = r"""
@ECHO OFF
if exist "%~dp0..\Scripts\activate.bat" (
  call "%~dp0..\Scripts\activate.bat" {0}
) else (
   if exist "%~dp0..\condabin\conda.bat" (
      call "%~dp0..\condabin\conda.bat" activate {0}
   )
)
echo # run in conda environment "%CONDA_DEFAULT_ENV%":
echo # %*
%*
""".format(conda_env)


def get_desktop():
    '''Return user Desktop folder'''
    return shell.SHGetFolderPath(0, shellcon.CSIDL_DESKTOP, None, 0)

def get_startmenu():
    '''Return user Start Menu Programs folder
    note that we return CSIDL_PROGRAMS not CSIDL_COMMON_PROGRAMS
    '''
    return shell.SHGetFolderPath(0, shellcon.CSIDL_PROGRAMS, None, 0)

def get_folders():
    """get user-specific folders

    Returns:
    -------
    Named tuple with fields 'home', 'desktop', 'startmenu'

    Example:
    -------
    >>> from pyshortcuts import get_folders
    >>> folders = get_folders()
    >>> print("Home, Desktop, StartMenu ",
    ...       folders.home, folders.desktop, folders.startmenu)
    """
    UserFolders = namedtuple("UserFolders", ("home", "desktop", "startmenu"))
    return UserFolders(get_homedir(), get_desktop(), get_startmenu())


def make_shortcut(script, name=None, working_dir=None, description=None, icon=None,
                  folder=None, terminal=True, desktop=True,
                  startmenu=True, executable=None, noexe=False):
    """create shortcut

    Arguments:
    ---------
    script      (str) path to script, may include command-line arguments
    name        (str, None) name to display for shortcut [name of script]
    working_dir (str, None) directory where to run the script in
    description (str, None) longer description of script [`name`]
    icon        (str, None) path to icon file [python icon]
    folder      (str, None) subfolder of Desktop for shortcut [None] (See Note 1)
    terminal    (bool) whether to run in a Terminal [True]
    desktop     (bool) whether to add shortcut to Desktop [True]
    startmenu   (bool) whether to add shortcut to Start Menu [True] (See Note 2)
    executable  (str, None) name of executable to use [this Python] (see Note 3)
    noexe       (bool) whether to use no executable (script is entire command) [False]

    Notes:
    ------
    1. `folder` will place shortcut in a subfolder of Desktop and/or Start Menu
    2. Start Menu does not exist for Darwin / MacOSX
    3. executable defaults to the Python executable used to make shortcut.
    """
    from .shortcut import shortcut
    userfolders = get_folders()

    scut = shortcut(script, userfolders, name=name, description=description,
                    working_dir=working_dir, folder=folder, icon=icon)

    if noexe:
        full_script =scut.script
        executable = ''
    else:
        full_script =scut.full_script
        if executable is None:
            executable = get_pyexe()
        executable = Path(executable).resolve().as_posix()

        if Path(scut.full_script).resolve() == Path(executable).resolve():
            executable = ''

    # Check for other valid ways to run the script
    # try appending .exe if script itself not found
    if not Path(full_script).exists():
        tname = full_script + '.exe'
        if Path(tname).exists():
            executable = tname
            full_script = ''

    # If script is already executable use it directly instead of via pyexe
    ext = os.path.splitext(full_script)[1].lower()
    known_exes = [e.lower() for e in os.environ['PATHEXT'].split(os.pathsep)]
    if ext != '.py' and ext in known_exes:
        executable = full_script
        full_script = ''
    full_script = ' '.join((full_script, scut.arguments))

    # If we're on Anaconda Python, we need to wrap this
    # script in a batch file that activates an environment
    if Path(sys.prefix, 'conda-meta').exists():
        runnerbat = f'envrunner-{conda_env}.bat'
        runner = Path(sys.prefix, 'Scripts', runnerbat).resolve().as_posix()
        with open(runner, 'w') as fh:
            fh.write(ENVRUNNER)
        time.sleep(0.05)
        full_script = f"{executable} {full_script}".strip()
        executable = runner

    for (create, ofolder) in ((desktop, scut.desktop_dir),
                             (startmenu, scut.startmenu_dir)):
        if create:
            if not Path(ofolder).exists():
                os.makedirs(ofolder)
            dest = Path(ofolder, scut.target).resolve().as_posix()

            _WSHELL = win32com.client.Dispatch("Wscript.Shell")
            wscript = _WSHELL.CreateShortCut(dest)
            wscript.Targetpath = f'"{executable}"'
            wscript.Arguments = full_script
            wscript.WorkingDirectory = scut.working_dir or userfolders.home
            wscript.WindowStyle = 0
            wscript.Description = scut.description
            wscript.IconLocation = scut.icon
            wscript.save()

    return scut