From 377e9086b0794ddbff709c5310ed580d565bb91a Mon Sep 17 00:00:00 2001 From: Walter Doekes Date: Fri, 8 Jul 2022 09:15:14 +0200 Subject: [PATCH] Do not spawn uname(1) every time version info is needed On Unixes, there is a os.uname() call which provides the same info and we don't need to fork()+execve() to get it. That uname(1) call wastes resources and trips IDSes with its unexpected fork(). Before: $ strace -feexecve python3 -c "import os; import platform; __version__ = 'x'; print({'language': 'Python', 'version': __version__, 'language_version': platform.python_version(), 'os': platform.system(), 'os_version': platform.release()})" execve("/usr/bin/python3", ["python3", "-c", "import os; import platform; __ve"...], 0x7ffc828c5c38 /* 63 vars */) = 0 strace: Process 4112873 attached [pid 4112873] execve("/usr/local/sbin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = -1 ENOENT (No such file or directory) [pid 4112873] execve("/usr/local/bin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = -1 ENOENT (No such file or directory) [pid 4112873] execve("/usr/sbin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = -1 ENOENT (No such file or directory) [pid 4112873] execve("/usr/bin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = -1 ENOENT (No such file or directory) [pid 4112873] execve("/sbin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = -1 ENOENT (No such file or directory) [pid 4112873] execve("/bin/uname", ["uname", "-p"], 0x7fff0c485da8 /* 63 vars */) = 0 [pid 4112873] +++ exited with 0 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4112873, si_uid=1000, si_status=0, si_utime=0, si_stime=0} --- {'language': 'Python', 'version': 'x', 'language_version': '3.8.10', 'os': 'Linux', 'os_version': '5.4.0-109-generic'} +++ exited with 0 +++ After: $ strace -feexecve python3 -c "import os; import platform; __version__ = 'x'; print({'language': 'Python', 'version': __version__, 'language_version': platform.python_version(), 'os': (hasattr(os, 'uname') and os.uname().sysname or platform.system()), 'os_version': (hasattr(os, 'uname') and os.uname().release or platform.release())})" execve("/usr/bin/python3", ["python3", "-c", "import os; import platform; __ve"...], 0x7ffdf3b12e18 /* 63 vars */) = 0 {'language': 'Python', 'version': 'x', 'language_version': '3.8.10', 'os': 'Linux', 'os_version': '5.4.0-109-generic'} +++ exited with 0 +++ --- asana/client.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/asana/client.py b/asana/client.py index 46635fbd..3b00377c 100644 --- a/asana/client.py +++ b/asana/client.py @@ -1,6 +1,7 @@ from types import ModuleType import json import platform +import os import time import string import warnings @@ -324,12 +325,18 @@ def _version_header(self): def _version_values(self): """Generate the values to go in the client version header.""" + # Prefer os.uname() over platform.*() on systems that support + # it, as it does not call the uname(1) binary. + # Using [0] instead of .sysname and [2] instead of .release for + # python2 compatibility. return { 'language': 'Python', 'version': __version__, 'language_version': platform.python_version(), - 'os': platform.system(), - 'os_version': platform.release() + 'os': ( + hasattr(os, 'uname') and os.uname()[0] or platform.system()), + 'os_version': ( + hasattr(os, 'uname') and os.uname()[2] or platform.release()) } @classmethod