macOS listener support on apps where `sys.executable` is not a python interpreter
Right now the macOS listener invokes a subprocess with args (sys.executable, "-c", cmd); this assumes that sys.executable is a python interpreter or at least exposes -c. That is not necessarily the case when running from something like a pyinstaller build, which bundles the interpreter and other files into a binary executable which does not expose -c.
This is undocumented, though that is fixed by: https://github.com/albertosottile/darkdetect/pull/32
Right now the listener will silently fail; it would be nice to change this. One possible solution is to check that Path(sys.executable).name.startsWith("python") and fail with an exception; though then python interpreter hardlinks to different names might not work; this is why the problem is non-trivial. There would need to be some way to determine if sys.executable is a python interpreter to fail more loudly; or we could maybe wait on the subprocess for a few moments to see if it dies immediately? How exactly would need to be decided.
EDIT:
A hacky fix for pyinstaller specifically is to prefix cmd with from multiprocessing.resource_tracker import main;; as pyinstaller supports -c for any command prefixed by that string.
Perhaps the macOS listener should subprocess.Process an osascript that does the same the presently-python subprocess does; since macOS should have osascript where as subprocessing on sys.executable with -c won't always work.
Putting this here in case someone else considers it: we could use the built-in python at /System/Library/Frameworks/Python or something. This would require making the required function / file work without any non-default libraries though, which means the setup.py of this would likely have to subproces.run("/usr/bin/python -m pip install pyobjc-framework-Cocoa --target=(path_to_darkdetect + "/pyobjc") which the listener subprocess could then load. Unless there is a way to create an observer which doesn't require subclassing an NSObject (which as far as I'm aware requires a native component provided via pyobjc's pip). Although that might have to be done at runtime for anything pre-built for many OS versions. So this isn't a great solution either.
For pyinstaller specifically: It seems pyinstaller supports -c as the second to last argument as long as the command starts with from multiprocessing.resource_tracker import main. So a hacky fix for pyinstaller might be to have our command be -c from multiprocessing.resource_tracker import main; import _mac_detect as m; m._listen_child()
For
pyinstallerspecifically: It seemspyinstallersupports-cas the second to last argument as long as the command starts withfrom multiprocessing.resource_tracker import main. So a hacky fix for pyinstaller might be to have our command be-cfrom multiprocessing.resource_tracker import main; import _mac_detect as m; m._listen_child()
Sorry but this command is used in the command line of pyinstaller or write in the python script that pyinstaller is going to pack?
A tool build via piainstaller suports -c if the command following -c starts with from multiprocessing.resource_tracker import main;. For an example, see this fork: https://github.com/zwimer/darkdetect
Thanks, I'll try this.
Thanks, I'll try this.
It's presently on pypi as darkdetect-angr. Once this PR is merged in though the fork will likely go away in lieu of the original.
Thanks, I'll try this.
It's presently on pypi as darkdetect-angr. Once this PR is merged in though the fork will likely go away in lieu of the original.
Thanks for your work. For me another option is to use darkdetect.theme + timer to achieve same "listener" feature on macOS.
Also I found that darkdetect fails to behave under sudo mode. See issue #37 .