From 49db877fbeecb57ca0fba32bf6d90eb40109eb02 Mon Sep 17 00:00:00 2001 From: Gautham <41098605+ahgamut@users.noreply.github.com> Date: Tue, 26 Oct 2021 02:34:04 +0530 Subject: [PATCH] Minimize Python startup imports (#292) * get_exports_list should return list * remove unintentional `CC=clang` in makefile * avoid importing sysconfig during startup site.py requires only a couple of functions from sysconfig, but needs to load the entirety of sysconfig to get those functions. This commit makes it such that sysconfig is imported only when sys.platform is darwin. * remove redundant constants from stat module The constants are only there in case the C implementation (ie the _stat module) is not available. With Cosmopolitan the _stat module is always available. The entire Lib/stat.py file can be removed if the Windows-based constants can be moved into the Modules/_stat.c. * minimal changes to os.py python checks os-based assumptions at startup, some of which can be bypassed since this is Cosmopolitan Python. --- dsp/core/core.mk | 3 - third_party/python/Lib/logging/handlers.py | 2 +- third_party/python/Lib/os.py | 19 +-- third_party/python/Lib/pathlib.py | 2 +- third_party/python/Lib/site.py | 44 +++++- third_party/python/Lib/stat.py | 153 +-------------------- third_party/python/Lib/test/test_stat.py | 7 - third_party/python/Modules/posixmodule.c | 2 + 8 files changed, 47 insertions(+), 185 deletions(-) diff --git a/dsp/core/core.mk b/dsp/core/core.mk index 37140ac7d..66bba02f2 100644 --- a/dsp/core/core.mk +++ b/dsp/core/core.mk @@ -51,9 +51,6 @@ o/$(MODE)/dsp/core/scalevolume.o: \ OVERRIDE_CFLAGS += \ $(MATHEMATICAL) -o/$(MODE)/dsp/core/alaw.o: \ - CC = clang - o/tiny/dsp/core/scalevolume.o: \ OVERRIDE_CFLAGS += \ -Os diff --git a/third_party/python/Lib/logging/handlers.py b/third_party/python/Lib/logging/handlers.py index 11ebcf124..aa9355c5e 100644 --- a/third_party/python/Lib/logging/handlers.py +++ b/third_party/python/Lib/logging/handlers.py @@ -24,7 +24,7 @@ To use, simply 'import logging.handlers' and log away! """ import logging, socket, os, pickle, struct, time, re -from stat import ST_DEV, ST_INO, ST_MTIME +from _stat import ST_DEV, ST_INO, ST_MTIME import queue try: import threading diff --git a/third_party/python/Lib/os.py b/third_party/python/Lib/os.py index e15133af6..76f62113b 100644 --- a/third_party/python/Lib/os.py +++ b/third_party/python/Lib/os.py @@ -38,24 +38,15 @@ def _exists(name): return name in globals() def _get_exports_list(module): - try: - return list(module.__all__) - except AttributeError: - return [n for n in dir(module) if n[0] != '_'] + return list(getattr(module, "__all__", (n for n in dir(module) if n[0] != '_'))) name = 'posix' linesep = '\n' from posix import * -try: - from posix import _exit - __all__.append('_exit') -except ImportError: - pass +from posix import _exit +__all__.append('_exit') import posixpath as path -try: - from posix import _have_functions -except ImportError: - pass +from posix import _have_functions import posix __all__.extend(_get_exports_list(posix)) del posix @@ -67,7 +58,7 @@ from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, del _names -if _exists("_have_functions"): +if True or _exists("_have_functions"): _globals = globals() def _add(str, fn): if (fn in _globals) and (str in _have_functions): diff --git a/third_party/python/Lib/pathlib.py b/third_party/python/Lib/pathlib.py index e90e51a9f..4c165200b 100644 --- a/third_party/python/Lib/pathlib.py +++ b/third_party/python/Lib/pathlib.py @@ -11,7 +11,7 @@ from collections.abc import Sequence from contextlib import contextmanager from errno import EINVAL, ENOENT, ENOTDIR from operator import attrgetter -from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO +from _stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO from urllib.parse import quote_from_bytes as urlquote_from_bytes from posix import _getfinalpathname diff --git a/third_party/python/Lib/site.py b/third_party/python/Lib/site.py index 7447d1d7a..40b0c865a 100644 --- a/third_party/python/Lib/site.py +++ b/third_party/python/Lib/site.py @@ -234,6 +234,35 @@ def check_enableusersite(): return True +def _getuserbase(): + env_base = os.environ.get("PYTHONUSERBASE", None) + + def joinuser(*args): + return os.path.expanduser(os.path.join(*args)) + + if os.name == "nt": + base = os.environ.get("APPDATA") or "~" + if env_base: + return env_base + else: + return joinuser(base, "Python") + + if sys.platform == "darwin": + from sysconfig import get_config_var + framework = get_config_var("PYTHONFRAMEWORK") + if framework: + if env_base: + return env_base + else: + return joinuser("~", "Library", framework, "%d.%d" % + sys.version_info[:2]) + + if env_base: + return env_base + else: + return joinuser("~", ".local") + + def getuserbase(): """Returns the `user base` directory path. @@ -244,8 +273,7 @@ def getuserbase(): global USER_BASE if USER_BASE is not None: return USER_BASE - from sysconfig import get_config_var - USER_BASE = get_config_var('userbase') + USER_BASE = _getuserbase() return USER_BASE def getusersitepackages(): @@ -255,20 +283,22 @@ def getusersitepackages(): function will also set it. """ global USER_SITE - user_base = getuserbase() # this will also set USER_BASE if USER_SITE is not None: return USER_SITE - from sysconfig import get_path - if sys.platform == 'darwin': - from sysconfig import get_config_var + from sysconfig import get_config_var, get_path if get_config_var('PYTHONFRAMEWORK'): USER_SITE = get_path('purelib', 'osx_framework_user') return USER_SITE - USER_SITE = get_path('purelib', '%s_user' % os.name) + user_base = getuserbase() # this will also set USER_BASE + purelib_map = { + "posix_user":'{userbase}/lib/python3.6/site-packages', + "nt_user": "{userbase}/Python36/site-packages", + } + USER_SITE = purelib_map.get('%s_user' % os.name).format(userbase=user_base) return USER_SITE def addusersitepackages(known_paths): diff --git a/third_party/python/Lib/stat.py b/third_party/python/Lib/stat.py index 92bc7ff25..94dc9c46d 100644 --- a/third_party/python/Lib/stat.py +++ b/third_party/python/Lib/stat.py @@ -3,151 +3,7 @@ Suggested usage: from stat import * """ -# Indices for stat struct members in the tuple returned by os.stat() - -ST_MODE = 0 -ST_INO = 1 -ST_DEV = 2 -ST_NLINK = 3 -ST_UID = 4 -ST_GID = 5 -ST_SIZE = 6 -ST_ATIME = 7 -ST_MTIME = 8 -ST_CTIME = 9 - -# Extract bits from the mode - -def S_IMODE(mode): - """Return the portion of the file's mode that can be set by - os.chmod(). - """ - return mode & 0o7777 - -def S_IFMT(mode): - """Return the portion of the file's mode that describes the - file type. - """ - return mode & 0o170000 - -# Constants used as S_IFMT() for various file types -# (not all are implemented on all systems) - -S_IFDIR = 0o040000 # directory -S_IFCHR = 0o020000 # character device -S_IFBLK = 0o060000 # block device -S_IFREG = 0o100000 # regular file -S_IFIFO = 0o010000 # fifo (named pipe) -S_IFLNK = 0o120000 # symbolic link -S_IFSOCK = 0o140000 # socket file - -# Functions to test for each file type - -def S_ISDIR(mode): - """Return True if mode is from a directory.""" - return S_IFMT(mode) == S_IFDIR - -def S_ISCHR(mode): - """Return True if mode is from a character special device file.""" - return S_IFMT(mode) == S_IFCHR - -def S_ISBLK(mode): - """Return True if mode is from a block special device file.""" - return S_IFMT(mode) == S_IFBLK - -def S_ISREG(mode): - """Return True if mode is from a regular file.""" - return S_IFMT(mode) == S_IFREG - -def S_ISFIFO(mode): - """Return True if mode is from a FIFO (named pipe).""" - return S_IFMT(mode) == S_IFIFO - -def S_ISLNK(mode): - """Return True if mode is from a symbolic link.""" - return S_IFMT(mode) == S_IFLNK - -def S_ISSOCK(mode): - """Return True if mode is from a socket.""" - return S_IFMT(mode) == S_IFSOCK - -# Names for permission bits - -S_ISUID = 0o4000 # set UID bit -S_ISGID = 0o2000 # set GID bit -S_ENFMT = S_ISGID # file locking enforcement -S_ISVTX = 0o1000 # sticky bit -S_IREAD = 0o0400 # Unix V7 synonym for S_IRUSR -S_IWRITE = 0o0200 # Unix V7 synonym for S_IWUSR -S_IEXEC = 0o0100 # Unix V7 synonym for S_IXUSR -S_IRWXU = 0o0700 # mask for owner permissions -S_IRUSR = 0o0400 # read by owner -S_IWUSR = 0o0200 # write by owner -S_IXUSR = 0o0100 # execute by owner -S_IRWXG = 0o0070 # mask for group permissions -S_IRGRP = 0o0040 # read by group -S_IWGRP = 0o0020 # write by group -S_IXGRP = 0o0010 # execute by group -S_IRWXO = 0o0007 # mask for others (not in group) permissions -S_IROTH = 0o0004 # read by others -S_IWOTH = 0o0002 # write by others -S_IXOTH = 0o0001 # execute by others - -# Names for file flags - -UF_NODUMP = 0x00000001 # do not dump file -UF_IMMUTABLE = 0x00000002 # file may not be changed -UF_APPEND = 0x00000004 # file may only be appended to -UF_OPAQUE = 0x00000008 # directory is opaque when viewed through a union stack -UF_NOUNLINK = 0x00000010 # file may not be renamed or deleted -UF_COMPRESSED = 0x00000020 # OS X: file is hfs-compressed -UF_HIDDEN = 0x00008000 # OS X: file should not be displayed -SF_ARCHIVED = 0x00010000 # file may be archived -SF_IMMUTABLE = 0x00020000 # file may not be changed -SF_APPEND = 0x00040000 # file may only be appended to -SF_NOUNLINK = 0x00100000 # file may not be renamed or deleted -SF_SNAPSHOT = 0x00200000 # file is a snapshot file - - -_filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((S_IRUSR, "r"),), - ((S_IWUSR, "w"),), - ((S_IXUSR|S_ISUID, "s"), - (S_ISUID, "S"), - (S_IXUSR, "x")), - - ((S_IRGRP, "r"),), - ((S_IWGRP, "w"),), - ((S_IXGRP|S_ISGID, "s"), - (S_ISGID, "S"), - (S_IXGRP, "x")), - - ((S_IROTH, "r"),), - ((S_IWOTH, "w"),), - ((S_IXOTH|S_ISVTX, "t"), - (S_ISVTX, "T"), - (S_IXOTH, "x")) -) - -def filemode(mode): - """Convert a file's mode to a string of the form '-rwxrwxrwx'.""" - perm = [] - for table in _filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) - +from _stat import * # Windows FILE_ATTRIBUTE constants for interpreting os.stat()'s # "st_file_attributes" member @@ -170,12 +26,5 @@ FILE_ATTRIBUTE_SYSTEM = 4 FILE_ATTRIBUTE_TEMPORARY = 256 FILE_ATTRIBUTE_VIRTUAL = 65536 - -# If available, use C implementation -try: - from _stat import * -except ImportError: - pass - if __name__ == 'PYOBJ.COM': import _stat diff --git a/third_party/python/Lib/test/test_stat.py b/third_party/python/Lib/test/test_stat.py index f2b5e28e3..02a44374c 100644 --- a/third_party/python/Lib/test/test_stat.py +++ b/third_party/python/Lib/test/test_stat.py @@ -4,10 +4,8 @@ import sys from test.support import TESTFN, import_fresh_module c_stat = import_fresh_module('stat', fresh=['_stat']) -py_stat = import_fresh_module('stat', blocked=['_stat']) assert c_stat -assert py_stat class TestFilemode: statmod = None @@ -228,11 +226,6 @@ class TestFilemodeCStat(TestFilemode, unittest.TestCase): format_funcs = TestFilemode.format_funcs | {'S_ISDOOR', 'S_ISPORT', 'S_ISWHT'} - -class TestFilemodePyStat(TestFilemode, unittest.TestCase): - statmod = py_stat - - if __name__ == '__main__': unittest.main() diff --git a/third_party/python/Modules/posixmodule.c b/third_party/python/Modules/posixmodule.c index 6a67f4c3d..2bb79f0cd 100644 --- a/third_party/python/Modules/posixmodule.c +++ b/third_party/python/Modules/posixmodule.c @@ -78,6 +78,8 @@ PYTHON_PROVIDE("posix"); PYTHON_PROVIDE("posix._getfinalpathname"); +PYTHON_PROVIDE("posix._exit"); +PYTHON_PROVIDE("posix._have_functions"); /* POSIX module implementation */