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
|
# Copyright (c) 2017-2026 Juancarlo AƱez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
from __future__ import annotations
import datetime
import keyword
import os
import os.path
from pathlib import Path
from typing import Any
def startscript() -> str:
import __main__ as main
if main.__package__:
return main.__package__
elif isinstance(main.__file__, str):
return Path(main.__file__).name
else:
return 'unknown'
def is_posix() -> bool:
return os.name == 'posix'
def identity(*args: Any) -> Any:
if len(args) == 1:
return args[0]
return args
def format_if(fmt, values):
return fmt % values if values else ''
def timestamp():
return '.'.join(
'%2.2d' % t for t in datetime.datetime.now(datetime.UTC).utctimetuple()[:-2]
)
try:
import psutil
except ImportError:
def memory_use():
return 0
else:
def memory_use(): # pyright: ignore[reportRedeclaration]
process = psutil.Process(os.getpid())
return process.memory_info().rss
def try_read(filename):
if isinstance(filename, Path):
filename = str(filename)
for e in ['utf-16', 'utf-8', 'latin-1', 'cp1252', 'ascii']:
try:
return Path(filename).read_text(encoding=e)
except UnicodeError:
pass
raise ValueError(f"cannot find the encoding for '{filename}'")
def filelist_from_patterns(patterns, ignore=None, base='.', sizesort=False):
ignore = ignore or ()
base = Path(base or '.').expanduser()
filenames = set()
for pattern in patterns or []:
path = base / pattern
if path.is_file():
filenames.add(path)
continue
if path.is_dir():
path += '/*'
parts = path.parts[1:] if path.is_absolute() else path.parts
joined_pattern = str(Path().joinpath(*parts))
filenames.update(
p for p in Path(path.root).glob(joined_pattern) if not p.is_dir()
)
filenames = list(filenames)
def excluded(path):
if any(path.match(ex) for ex in ignore):
return True
return any(
any(Path(part).match(ex) for ex in ignore or ()) for part in path.parts
)
if ignore:
filenames = [path for path in filenames if not excluded(path)]
if sizesort:
filenames.sort(key=lambda f: f.stat().st_size)
return filenames
def short_relative_path(path: str | Path, base: str | Path = '.') -> Path:
path = Path(path)
base = Path(base)
common = Path(os.path.commonpath([base.resolve(), path.resolve()]))
if common == path.root:
return path
elif common == Path.home():
up = Path('~')
elif common == base:
up = Path()
else:
n = len(base.parts) - len(common.parts)
up = Path('../' * n)
rel = up / path.resolve().relative_to(common)
if len(str(rel)) < len(str(path)):
return rel
else:
return path
def fqn(obj: Any) -> str:
# by [apalala@gmail.com](https://github.com/apalala)
# by Gemini (2026-01-30)
"""Helper to safely retrieve the fully qualified name of a callable."""
module = getattr(obj, "__module__", None)
qualname = getattr(obj, "__qualname__", None)
if module and qualname and module != "builtins":
return f"{module}.{qualname}"
return qualname or str(obj)
def is_reserved(name) -> bool:
return (
keyword.iskeyword(name)
or keyword.issoftkeyword(name)
or name in {'type', 'list', 'dict', 'set'}
)
def typename(obj: Any) -> str:
return type(obj).__name__
|