File: utils.py

package info (click to toggle)
python-pyshortcuts 1.9.5-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,632 kB
  • sloc: python: 1,097; makefile: 42
file content (177 lines) | stat: -rw-r--r-- 5,041 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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/usr/bin/env python
"""
utilities for pyshortcuts
"""
import os
import sys
from pathlib import Path
from datetime import datetime
from string import ascii_letters

try:
    from pwd import getpwnam
except ImportError:
    getpwnam = None

uname = "unknown"
scut_ext = "lnk"
ico_ext = ("ico",)

if sys.platform.startswith('lin'):
    uname = "linux"
    scut_ext = "desktop"
    ico_ext = ("ico", "png")
elif sys.platform.startswith('darwin'):
    uname = 'darwin'
    scut_ext = "app"
    ico_ext = ("icns",)
elif sys.platform.startswith('win')  or os.name.startswith('nt'):
    uname = "win"
    scut_ext = "lnk"
    ico_ext = ("ico",)

def get_homedir():
    "determine home directory"
    # for Unixes, allow for sudo case
    susername = os.environ.get("SUDO_USER", None)
    try:
        if susername is not None and getpwnam is not None:
            return Path(getpwnam(susername).pw_dir).resolve().as_posix()
    except KeyError:
        pass

    homedir = Path.home()

    # For Windows, ask for parent of Roaming 'Application Data' directory
    if homedir is None and os.name == 'nt':
        try:
            from win32com.shell import shellcon, shell
            homedir = Path(shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0))
        except ImportError:
            pass

    # try the HOME environmental variable
    if homedir is  None:
        test = os.path.expandvars('$HOME')
        if test not in (None, '$HOME'):
            homedir = Path(test)

    # finally, use current folder
    if homedir is None:
        homedir = Path('.')
    return homedir.resolve().as_posix()

def get_cwd():
    """get current working directory
    Note: os.getcwd() can fail with permission error.

    when that happens, this changes to the users `HOME` directory
    and returns that directory so that it always returns an existing
    and readable directory.
    """
    try:
        return Path('.').resolve().as_posix()
    except Exception:
        home = get_homedir()
        os.chdir(home)
        return home


def isotime(dtime=None, timespec='seconds', sep=' '):
    """return ISO format of current timestamp:
          2024-04-27 17:31:12
    """
    if dtime is None:
        dtime = datetime.now()
    elif isinstance(dtime, (float, int)):
        dtime = datetime.fromtimestamp(dtime)
    return datetime.isoformat(dtime, timespec=timespec, sep=sep)

BAD_FILECHARS = ';~,`!%$@$&^?*#:"/|\'\\\t\r\n(){}[]<>'
GOOD_FILECHARS = '_'*len(BAD_FILECHARS)
TRANS_FILE = str.maketrans(BAD_FILECHARS, GOOD_FILECHARS)

def fix_filename(filename, allow_spaces=False):
    """
    fix string to be a 'good' filename, with very few special
    characters and (optionally) no more than 1 '.'.

    More restrictive than most OSes, but avoids hard-to-deal with filenames

    argument `allow_spaces` [default is False] allows spaces in filenames.
    """
    fname = str(filename).translate(TRANS_FILE)
    if not allow_spaces:
        fname = fname.replace(' ', '_')
    if fname.count('.') > 1:
        words = fname.split('.')
        ext = words.pop()
        fname = f"{'_'.join(words)}.{ext}"
    while '__' in fname:
        fname = fname.replace('__', '_')
    return fname

def fix_varname(varname):
    """fix string to be a 'good' variable name."""
    vname = fix_filename(varname, allow_spaces=False)
    if vname[0] not in (ascii_letters+'_'):
        vname = f'_{vname}'
    for c in '=+-.':
        vname = vname.replace(c, '_')
    while '__' in vname:
        vname = vname.replace('__', '_')
    if vname.endswith('_'):
        vname = vname[:-1]
    return vname

def get_pyexe():
    "python executable"
    return Path(sys.executable).resolve().as_posix()

def new_filename(filename):
    """
    increment filename to be an unused filename
    """
    fpath = Path(filename)
    if fpath.exists():
        fstem = fpath.stem
        fsuffix = fpath.suffix
        if fsuffix.startswith('.'):
            fsuffix = fsuffix[1:]
        if len(fsuffix) == 0:
            fsuffix = 'txt'
        int_suffix = True
        fsint = 0
        try:
            fsint = int(fsuffix)
        except (ValueError, TypeError):
            int_suffix = False
        while fpath.exists():
            fsint += 1
            if int_suffix:
                fpath = Path(f"{fstem}.{fsint:03d}")
            else:
                if '_' in fstem:
                    w = fstem.split('_')
                    try:
                        fsint = int(w[-1])
                        fstem = '_'.join(w[:-1])
                    except (ValueError, TypeError):
                        pass
                fpath = Path(f"{fstem}_{fsint:03d}.{fsuffix}")

    return fpath.as_posix()

def bytes2str(s):
    'byte to string conversion'
    if isinstance(s, str):
        return s
    if isinstance(s, bytes):
        return s.decode(sys.stdout.encoding)
    return str(s, sys.stdout.encoding)

def str2bytes(s):
    'string to byte conversion'
    if isinstance(s, bytes):
        return s
    return bytes(s, sys.stdout.encoding)