From 5b7ba490791f6b021e3c8569c2c7bb6264d7250d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 4 Dec 2023 14:30:50 -0600 Subject: [PATCH 01/29] Merge in upstream/beta --- .gitignore | 44 ++++++++- .pylintrc | 1 + .vscode/launch.json | 16 ++++ .vscode/settings.json | 3 +- python3-PySide6-Addons.json | 17 ++++ python3-PySide6-Essentials.json | 33 +++++++ python3-numpy.json | 14 +++ python3-psutil.json | 14 +++ python3-python-dateutil.json | 14 +++ python3-requests.json | 34 +++++++ python3-shiboken6.json | 14 +++ python3-suntime.json | 19 ++++ python3-systemd-python.json | 14 +++ runner.sh | 2 + sh.oskar.yin-yang.json | 45 +++++++++ yin_yang/daemon_handler.py | 5 +- yin_yang/helpers.py | 43 +++++++++ yin_yang/plugins/_plugin.py | 5 +- yin_yang/plugins/colors.py | 8 +- yin_yang/plugins/custom.py | 11 +-- yin_yang/plugins/firefox.py | 2 +- yin_yang/plugins/konsole.py | 156 +++++++++++++++++--------------- yin_yang/plugins/system.py | 4 +- yin_yang/plugins/wallpaper.py | 3 +- 24 files changed, 423 insertions(+), 98 deletions(-) create mode 100644 .pylintrc create mode 100644 .vscode/launch.json create mode 100644 python3-PySide6-Addons.json create mode 100644 python3-PySide6-Essentials.json create mode 100644 python3-numpy.json create mode 100644 python3-psutil.json create mode 100644 python3-python-dateutil.json create mode 100644 python3-requests.json create mode 100644 python3-shiboken6.json create mode 100644 python3-suntime.json create mode 100644 python3-systemd-python.json create mode 100644 runner.sh create mode 100644 sh.oskar.yin-yang.json create mode 100644 yin_yang/helpers.py diff --git a/.gitignore b/.gitignore index 4990b28b..6898446e 100755 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,19 @@ +# Created by https://www.toptal.com/developers/gitignore/api/flatpak,python,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=flatpak,python,visualstudiocode +*~ __pycache__ build-test* build-ui-* yin_yang/build.py -c_cpp_properties.json +setup.py -# Taken from https://github.com/github/gitignore/blob/main/Python.gitignore -# 12/18/2023 +### Flatpak ### +.flatpak-builder +build +build-dir +repo +### Python ### # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] @@ -167,3 +174,34 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# End of https://www.toptal.com/developers/gitignore/api/flatpak,python,visualstudiocode diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..e749d6bf --- /dev/null +++ b/.pylintrc @@ -0,0 +1 @@ +extension-pkg-whitelist=PyQt5 \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ae58ed4d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Main", + "type": "python", + "request": "launch", + "console": "integratedTerminal", + "module": "yin_yang", + "justMyCode": true + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 7a73a41b..0967ef42 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,2 +1 @@ -{ -} \ No newline at end of file +{} diff --git a/python3-PySide6-Addons.json b/python3-PySide6-Addons.json new file mode 100644 index 00000000..3fd9c85a --- /dev/null +++ b/python3-PySide6-Addons.json @@ -0,0 +1,17 @@ +{ + "name": "pyside6-addons", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_addons --no-build-isolation" + ], + "only-arches": [ + "x86_64" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/b1/c5/85ddc6e502ab88727ec3316c38f65830f82bfc66175f00349488a6431258/PySide6_Addons-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", + "sha256": "e5bc1fa95351182dc2c003e07320d5509218ccc0840d10197d7d452aa5de5d2e" + } + ] +} \ No newline at end of file diff --git a/python3-PySide6-Essentials.json b/python3-PySide6-Essentials.json new file mode 100644 index 00000000..b5328a66 --- /dev/null +++ b/python3-PySide6-Essentials.json @@ -0,0 +1,33 @@ +{ + "name": "pyside6-essentials", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_essentials --no-build-isolation" + ], + "only-arches": [ + "x86_64" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/e5/93/98f660dde373e2fba01caea8bbb2c986f94f02e32afab7b577df03ef744f/PySide6_Essentials-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", + "sha256": "45580138be91f5fdcefb4d28dadb56d3640eb658575af97b49057e10c22a024d" + } + ], + "modules": [ + { + "name": "shiboken6", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} shiboken6 --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/55/b4/370f7a1dd3c02150b60073f7a46418fa2932f8d3b864bc58883154c6a423/shiboken6-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", + "sha256": "4cdda98df511243c40f1dd4d9eac25a7191c2583ac673147ecdae0ffa3b9223f" + } + ] + } + ] +} \ No newline at end of file diff --git a/python3-numpy.json b/python3-numpy.json new file mode 100644 index 00000000..a8e3490c --- /dev/null +++ b/python3-numpy.json @@ -0,0 +1,14 @@ +{ + "name": "python3-numpy", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"numpy\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/e4/a9/6704bb5e1d1d778d3a6ee1278a8d8134f0db160e09d52863a24edb58eab5/numpy-1.24.2.tar.gz", + "sha256": "003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22" + } + ] +} \ No newline at end of file diff --git a/python3-psutil.json b/python3-psutil.json new file mode 100644 index 00000000..34836d47 --- /dev/null +++ b/python3-psutil.json @@ -0,0 +1,14 @@ +{ + "name": "python3-psutil", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/3d/7d/d05864a69e452f003c0d77e728e155a89a2a26b09e64860ddd70ad64fb26/psutil-5.9.4.tar.gz", + "sha256": "3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62" + } + ] +} \ No newline at end of file diff --git a/python3-python-dateutil.json b/python3-python-dateutil.json new file mode 100644 index 00000000..befceb70 --- /dev/null +++ b/python3-python-dateutil.json @@ -0,0 +1,14 @@ +{ + "name": "python3-python-dateutil", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-dateutil\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", + "sha256": "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + } + ] +} \ No newline at end of file diff --git a/python3-requests.json b/python3-requests.json new file mode 100644 index 00000000..c5cfb9d7 --- /dev/null +++ b/python3-requests.json @@ -0,0 +1,34 @@ +{ + "name": "python3-requests", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl", + "sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz", + "sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl", + "sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", + "sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/8a/03/ad9306a50d05c166e3456fe810f33cee2b8b2a7a6818ec5d4908c4ec6b36/urllib3-2.0.3-py3-none-any.whl", + "sha256": "48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1" + } + ] +} \ No newline at end of file diff --git a/python3-shiboken6.json b/python3-shiboken6.json new file mode 100644 index 00000000..7488be78 --- /dev/null +++ b/python3-shiboken6.json @@ -0,0 +1,14 @@ +{ + "name": "python3-shiboken6", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"shiboken6==6.4.1\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/72/ec/6bef61f5b07be13fd8255fdc5c66d8a097581cc58163457cc219ea3afe7b/shiboken6-6.4.1-cp37-abi3-manylinux_2_28_x86_64.whl", + "sha256": "41e67b67f65626bdd909f9c5fd5f80231ee6ae43418b331590ba225b3cfabd5b" + } + ] +} \ No newline at end of file diff --git a/python3-suntime.json b/python3-suntime.json new file mode 100644 index 00000000..f14f0ba0 --- /dev/null +++ b/python3-suntime.json @@ -0,0 +1,19 @@ +{ + "name": "python3-suntime", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"suntime\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", + "sha256": "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/93/95/a4eec0b36daeda6fa84b804da308211141d4a6ada13da228ecdf49600434/suntime-1.2.5-py3-none-any.whl", + "sha256": "d957e9ca786ab3cd80bf624b007fed7d07f07c6fa33f3ccc5ec34c9bb0c380c6" + } + ] +} \ No newline at end of file diff --git a/python3-systemd-python.json b/python3-systemd-python.json new file mode 100644 index 00000000..08b99dac --- /dev/null +++ b/python3-systemd-python.json @@ -0,0 +1,14 @@ +{ + "name": "python3-systemd-python", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"systemd-python\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", + "sha256": "4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a" + } + ] +} \ No newline at end of file diff --git a/runner.sh b/runner.sh new file mode 100644 index 00000000..53bccfea --- /dev/null +++ b/runner.sh @@ -0,0 +1,2 @@ +#!/bin/sh +python3 -m yin_yang \ No newline at end of file diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json new file mode 100644 index 00000000..3c446a3d --- /dev/null +++ b/sh.oskar.yin-yang.json @@ -0,0 +1,45 @@ +{ + "id": "sh.oskar.yin-yang", + "runtime": "org.kde.Platform", + "runtime-version": "5.15-22.08", + "sdk": "org.kde.Sdk", + "command": "runner.sh", + "finish-args": [ + "--share=network", + "--socket=x11", + "--socket=wayland", + "--socket=system-bus", + "--socket=session-bus", + "--share=ipc", + "--device=dri", + "--filesystem=host:rw", + "--filesystem=~/.mozilla:rw" + ], + "modules": [ + "python3-numpy.json", + "python3-psutil.json", + "python3-python-dateutil.json", + "python3-suntime.json", + "python3-PySide6-Essentials.json", + "python3-PySide6-Addons.json", + "python3-systemd-python.json", + "python3-requests.json", + { + "name": "yin-yang", + "buildsystem": "simple", + "build-commands": [ + "install -D yin_yang/__main__.py /app/__main__.py", + "cp -r yin_yang /app/yin_yang", + "cp -r resources /app/resources", + "install -D runner.sh /app/bin/runner.sh", + "sed -i 's|/bin/env python3|/app/bin/python3|' /app/__main__.py" + ], + "sources": [ + { + "type": "dir", + "path": "." + } + ] + } + ] +} \ No newline at end of file diff --git a/yin_yang/daemon_handler.py b/yin_yang/daemon_handler.py index 6b845bf8..7ee39ac2 100644 --- a/yin_yang/daemon_handler.py +++ b/yin_yang/daemon_handler.py @@ -4,6 +4,7 @@ from enum import Enum, auto from pathlib import Path +from yin_yang import helpers from .config import ConfigWatcher, config from .meta import ConfigEvent, Modes @@ -24,7 +25,7 @@ def create_files(): def run_command(command, **kwargs): - return subprocess.run(['systemctl', '--user', command, 'yin_yang.timer'], **kwargs) + return helpers.run(['systemctl', '--user', command, 'yin_yang.timer'], **kwargs) def update_times(): @@ -48,7 +49,7 @@ def update_times(): with TIMER_PATH.open('w') as file: file.writelines(lines) - subprocess.run(['systemctl', '--user', 'daemon-reload']) + helpers.run(['systemctl', '--user', 'daemon-reload']) run_command('start') diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py new file mode 100644 index 00000000..998d1990 --- /dev/null +++ b/yin_yang/helpers.py @@ -0,0 +1,43 @@ +import subprocess + + +"""Check output of a command. + +This is a helper method which will change how we check output depending on if +The application is running in a flatpak or not. +""" + + +def check_output(args, universal_newlines=False) -> bytes: + try: + output = subprocess.check_output( + args=args, universal_newlines=universal_newlines + ) + return output + except FileNotFoundError: + flatpak_args = ["flatpak-spawn", "--host"] + args + return subprocess.check_output( + args=flatpak_args, universal_newlines=universal_newlines + ) + + +def check_call(command, stdout=None) -> int: + try: + return subprocess.check_call(command, stdout=stdout) + except FileNotFoundError: + flatpak_args = ["flatpak-spawn", "--host"] + command + return subprocess.check_call(flatpak_args, stdout=stdout) + + +def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProcess[str]: + try: + if len(kwargs) == 0: + return subprocess.run(command) + else: + return subprocess.run(command, **kwargs) + except FileNotFoundError: + flatpak_args = ["flatpak-spawn", "--host"] + command + if len(kwargs) == 0: + return subprocess.run(flatpak_args) + else: + return subprocess.run(flatpak_args, **kwargs) diff --git a/yin_yang/plugins/_plugin.py b/yin_yang/plugins/_plugin.py index d7469d25..fc77f863 100644 --- a/yin_yang/plugins/_plugin.py +++ b/yin_yang/plugins/_plugin.py @@ -10,6 +10,7 @@ from PySide6.QtGui import QColor, QRgba64 from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLineEdit, QComboBox +from yin_yang import helpers from ..meta import UnsupportedDesktopError, FileFormat logger = logging.getLogger(__name__) @@ -138,7 +139,7 @@ def set_theme(self, theme: str): # insert theme in command and run it command = self.insert_theme(theme) - subprocess.check_call(command) + helpers.check_call(command) def insert_theme(self, theme: str) -> list: command = self.command.copy() @@ -152,7 +153,7 @@ def insert_theme(self, theme: str) -> list: def check_command(command) -> bool: # Returns true if command execution succeeds try: - subprocess.check_call(command, stdout=subprocess.DEVNULL) + helpers.check_call(command, stdout=subprocess.DEVNULL) return True except FileNotFoundError: # if no such command is available, the plugin is not available diff --git a/yin_yang/plugins/colors.py b/yin_yang/plugins/colors.py index 5796d57d..c2f818ad 100644 --- a/yin_yang/plugins/colors.py +++ b/yin_yang/plugins/colors.py @@ -1,5 +1,5 @@ -import subprocess import re +from yin_yang import helpers from ..meta import Desktop from ._plugin import Plugin, PluginDesktopDependent, PluginCommandline @@ -30,9 +30,9 @@ def available_themes(self) -> dict: if self.translations: return self.translations - colors = subprocess.check_output(['plasma-apply-colorscheme', '--list-schemes'], - universal_newlines=True) - + colors = str(helpers.check_output(['plasma-apply-colorscheme', '--list-schemes'], + universal_newlines=True)) + print(colors) colors = colors.splitlines() del colors[0] diff --git a/yin_yang/plugins/custom.py b/yin_yang/plugins/custom.py index 2f5547ce..7e1e87f7 100644 --- a/yin_yang/plugins/custom.py +++ b/yin_yang/plugins/custom.py @@ -1,7 +1,6 @@ -import subprocess - from PySide6.QtWidgets import QLineEdit +from yin_yang import helpers from ._plugin import PluginCommandline @@ -18,13 +17,13 @@ def available(self) -> bool: def get_input(self, widget): inputs: list[QLineEdit | QLineEdit] = super().get_input(widget) - inputs[0].setPlaceholderText('Light script') - inputs[1].setPlaceholderText('Dark script') + inputs[0].setPlaceholderText("Light script") + inputs[1].setPlaceholderText("Dark script") return inputs def set_theme(self, theme: str): if not theme: - raise ValueError(f'Theme \"{theme}\" is invalid') + raise ValueError(f'Theme "{theme}" is invalid') if not (self.available and self.enabled): return @@ -32,4 +31,4 @@ def set_theme(self, theme: str): # insert theme in command and run it command = self.insert_theme(theme) # set shell=True to avoid having to separate between arguments - subprocess.check_call(command, shell=True) + helpers.check_call(command, shell=True) diff --git a/yin_yang/plugins/firefox.py b/yin_yang/plugins/firefox.py index 8407e0c4..2cd47769 100755 --- a/yin_yang/plugins/firefox.py +++ b/yin_yang/plugins/firefox.py @@ -48,7 +48,7 @@ def available_themes(self) -> dict: logger.warning(f'Firefox profile has no extensions installed: {path}') continue - assert themes != {}, 'No themes found!' + # assert themes != {}, 'No themes found!' return themes @property diff --git a/yin_yang/plugins/konsole.py b/yin_yang/plugins/konsole.py index 194f3c6d..8a9a3a03 100644 --- a/yin_yang/plugins/konsole.py +++ b/yin_yang/plugins/konsole.py @@ -10,6 +10,8 @@ import psutil from PySide6.QtDBus import QDBusConnection, QDBusMessage +from yin_yang import helpers + from ._plugin import Plugin logger = logging.getLogger(__name__) @@ -21,17 +23,18 @@ class Konsole(Plugin): create a new profile or edit one to use the desired color scheme. This is necessary to allow live theme changes. """ - global_path = Path('/usr/share/konsole') - config_path = Path.home() / '.config/konsolerc' + + global_path = Path("/usr/share/konsole") + config_path = Path.home() / ".config/konsolerc" @property def user_path(self) -> Path: - return Path.home() / '.local/share/konsole' + return Path.home() / ".local/share/konsole" def __init__(self): super().__init__() - self._theme_light = 'BlackOnWhite' - self._theme_dark = 'Breeze' + self._theme_light = "BlackOnWhite" + self._theme_dark = "Breeze" @property def theme_light(self): @@ -56,42 +59,43 @@ def set_mode(self, dark: bool) -> bool: if not super().set_mode(dark): return False - profile = 'Dark' if dark else 'Light' + profile = "Dark" if dark else "Light" # update default profile, if application is started afterward - self.default_profile = profile + '.profile' + self.default_profile = profile + ".profile" # Set Konsole profile for all sessions # Get the process IDs of all running Konsole instances owned by the current user process_ids = [ - proc.pid for proc in psutil.process_iter() - if proc.name() == 'konsole' and proc.username() == os.getlogin() + proc.pid + for proc in psutil.process_iter() + if proc.name() == "konsole" and proc.username() == os.getlogin() ] # loop: console processes for proc_id in process_ids: - logger.debug(f'Changing profile in konsole session {proc_id}') - set_profile(f'org.kde.konsole-{proc_id}', profile) - set_profile(f'org.kde.konsole-{proc_id}', profile, set_default_profile=True) + logger.debug(f"Changing profile in konsole session {proc_id}") + set_profile(f"org.kde.konsole-{proc_id}", profile) + set_profile(f"org.kde.konsole-{proc_id}", profile, set_default_profile=True) # konsole may don't have session dbus like above - set_profile('org.kde.konsole', profile) - set_profile('org.kde.yakuake', profile) - set_profile('org.kde.konsole', profile, set_default_profile=True) - set_profile('org.kde.yakuake', profile, set_default_profile=True) + set_profile("org.kde.konsole", profile) + set_profile("org.kde.yakuake", profile) + set_profile("org.kde.konsole", profile, set_default_profile=True) + set_profile("org.kde.yakuake", profile, set_default_profile=True) process_ids = [ - proc.pid for proc in psutil.process_iter() - if proc.name() == 'dolphin' and proc.username() == os.getlogin() + proc.pid + for proc in psutil.process_iter() + if proc.name() == "dolphin" and proc.username() == os.getlogin() ] # loop: dolphin processes for proc_id in process_ids: - logger.debug(f'Changing profile in dolphin session {proc_id}') - set_profile(f'org.kde.dolphin-{proc_id}', profile) - set_profile(f'org.kde.dolphin-{proc_id}', - profile, set_default_profile=True) + logger.debug(f"Changing profile in dolphin session {proc_id}") + set_profile(f"org.kde.dolphin-{proc_id}", profile) + set_profile(f"org.kde.dolphin-{proc_id}", profile, set_default_profile=True) return True @@ -104,21 +108,25 @@ def available_themes(self) -> dict: if not self.available: return {} - themes = dict(sorted([ - (p.with_suffix('').name, p) - for p in chain(self.global_path.iterdir(), self.user_path.iterdir()) - if p.is_file() and p.suffix == '.colorscheme' - ])) + themes = dict( + sorted( + [ + (p.with_suffix("").name, p) + for p in chain(self.global_path.iterdir(), self.user_path.iterdir()) + if p.is_file() and p.suffix == ".colorscheme" + ] + ) + ) themes_dict = {} config_parser = ConfigParser() for theme, theme_path in themes.items(): config_parser.read(theme_path) - theme_name = config_parser['General']['Description'] + theme_name = config_parser["General"]["Description"] themes_dict[theme] = theme_name - assert themes_dict != {}, 'No themes found!' + assert themes_dict != {}, "No themes found!" return themes_dict @property @@ -129,10 +137,10 @@ def available(self) -> bool: def default_profile(self): value = None # cant use config parser because of weird file structure - with self.config_path.open('r') as file: + with self.config_path.open("r") as file: for line in file: # Search for the pattern "DefaultProfile=*" - match = re.search(r'DefaultProfile=(.*)', line) + match = re.search(r"DefaultProfile=(.*)", line) # If a match is found, return the content of the wildcard '*' if match: @@ -143,11 +151,11 @@ def default_profile(self): if value is None: # use the first found profile for file in self.user_path.iterdir(): - if file.suffix == '.profile': + if file.suffix == ".profile": value = file.name break if value is not None: - logger.warning(f'No default profile found, using {value} instead.') + logger.warning(f"No default profile found, using {value} instead.") if value is None: # create a custom profile manually @@ -160,44 +168,44 @@ def default_profile(self): Parent=FALLBACK/ """ - with (self.user_path / 'Default.profile').open('w') as file: + with (self.user_path / "Default.profile").open("w") as file: file.writelines(file_content) - self.default_profile = 'Default.profile' + self.default_profile = "Default.profile" - return 'Default.profile' + return "Default.profile" return value @default_profile.setter def default_profile(self, value: str): - assert value.endswith('.profile') + assert value.endswith(".profile") - with self.config_path.open('r') as file: + with self.config_path.open("r") as file: lines = file.readlines() for i, line in enumerate(lines): # Search for the pattern "DefaultProfile=*" - match = re.search(r'DefaultProfile=(.*)', line) + match = re.search(r"DefaultProfile=(.*)", line) # If a match is found, return the content of the wildcard '*' if match: - logger.debug(f'Changing default profile to {value}') - lines[i] = f'DefaultProfile={value}\n' + logger.debug(f"Changing default profile to {value}") + lines[i] = f"DefaultProfile={value}\n" break else: - logger.debug('No default profile found') - with self.config_path.open('w') as file: + logger.debug("No default profile found") + with self.config_path.open("w") as file: file.writelines(lines) def update_profile(self, dark: bool, theme: str): - if not self.available or theme == '': + if not self.available or theme == "": # theme is empty string on super init return # update the color scheme setting in either dark or light profile - logger.debug('Updating konsole profile') + logger.debug("Updating konsole profile") - file_path = self.user_path / ('Dark.profile' if dark else 'Light.profile') + file_path = self.user_path / ("Dark.profile" if dark else "Light.profile") if not file_path.exists(): self.create_profiles() @@ -206,19 +214,21 @@ def update_profile(self, dark: bool, theme: str): profile_config.read(file_path) try: - profile_config['Appearance']['ColorScheme'] = theme + profile_config["Appearance"]["ColorScheme"] = theme except KeyError: - profile_config.add_section('Appearance') - profile_config['Appearance']['ColorScheme'] = theme + profile_config.add_section("Appearance") + profile_config["Appearance"]["ColorScheme"] = theme - with open(file_path, 'w') as file: + with open(file_path, "w") as file: profile_config.write(file) def create_profiles(self): - logger.debug('Creating new profiles for live-switching between light and dark themes.') + logger.debug( + "Creating new profiles for live-switching between light and dark themes." + ) # copy default profile to create theme profiles - light_profile = self.user_path / 'Light.profile' - dark_profile = self.user_path / 'Dark.profile' + light_profile = self.user_path / "Light.profile" + dark_profile = self.user_path / "Dark.profile" # TODO there is a parent profile section in the profile file, maybe we can use that (in a later version)? copyfile(self.user_path / self.default_profile, light_profile) copyfile(self.user_path / self.default_profile, dark_profile) @@ -228,15 +238,15 @@ def create_profiles(self): profile_config.optionxform = str profile_config.read(light_profile) - profile_config['General']['Name'] = light_profile.stem + profile_config["General"]["Name"] = light_profile.stem - with open(light_profile, 'w') as file: + with open(light_profile, "w") as file: profile_config.write(file) profile_config.read(dark_profile) - profile_config['General']['Name'] = dark_profile.stem + profile_config["General"]["Name"] = dark_profile.stem - with open(dark_profile, 'w') as file: + with open(dark_profile, "w") as file: profile_config.write(file) @@ -244,42 +254,38 @@ def set_profile(service: str, profile: str, set_default_profile: bool = False): # connect to the session bus connection = QDBusConnection.sessionBus() if set_default_profile: - path = 'Sessions/' - interface = 'org.kde.konsole.Session' - method = 'setProfile' + path = "Sessions/" + interface = "org.kde.konsole.Session" + method = "setProfile" else: - path = 'Windows/' - interface = 'org.kde.konsole.Window' - method = 'setDefaultProfile' + path = "Windows/" + interface = "org.kde.konsole.Window" + method = "setDefaultProfile" # maybe it's possible with pyside6 dbus packages, but this was simpler and worked try: - sessions = subprocess.check_output( - f'qdbus {service} | grep "{path}"', shell=True) + sessions = helpers.check_output(f'qdbus {service} | grep "{path}"') except subprocess.CalledProcessError: try: sessions = subprocess.check_output( f'qdbus org.kde.konsole | grep "{path}"', shell=True ) - logger.debug(f'Found org.kde.konsole, use that instead') + logger.debug(f"Found org.kde.konsole, use that instead") service = "org.kde.konsole" except subprocess.CalledProcessError: # happens when dolphins konsole is not opened logger.debug( - f'No Konsole sessions available in service {service}, skipping') + f"No Konsole sessions available in service {service}, skipping" + ) return - sessions = sessions.decode('utf-8').removesuffix('\n').split('\n') + sessions = sessions.decode("utf-8").removesuffix("\n").split("\n") # loop: process sessions for session in sessions: logger.debug( - f'Changing {"default" if set_default_profile else ""} profile of session {session} to {profile}') - # set profile - message = QDBusMessage.createMethodCall( - service, - session, - interface, - method + f'Changing {"default" if set_default_profile else ""} profile of session {session} to {profile}' ) + # set profile + message = QDBusMessage.createMethodCall(service, session, interface, method) message.setArguments([profile]) connection.call(message) diff --git a/yin_yang/plugins/system.py b/yin_yang/plugins/system.py index c58bb14f..b5ba0381 100644 --- a/yin_yang/plugins/system.py +++ b/yin_yang/plugins/system.py @@ -1,12 +1,12 @@ import json import logging -import subprocess import pwd import os from configparser import ConfigParser from pathlib import Path from PySide6.QtCore import QLocale +from yin_yang import helpers from ..meta import Desktop from ._plugin import PluginDesktopDependent, PluginCommandline @@ -132,7 +132,7 @@ def available_themes(self) -> dict: # asks the system what themes are available # noinspection SpellCheckingInspection - long_names = subprocess.check_output(["lookandfeeltool", "-l"], universal_newlines=True) + long_names = helpers.check_output(["lookandfeeltool", "-l"], universal_newlines=True) long_names = long_names.splitlines() long_names.sort() diff --git a/yin_yang/plugins/wallpaper.py b/yin_yang/plugins/wallpaper.py index bc5d0587..eb3885e2 100755 --- a/yin_yang/plugins/wallpaper.py +++ b/yin_yang/plugins/wallpaper.py @@ -4,6 +4,7 @@ from PySide6.QtWidgets import QDialogButtonBox, QVBoxLayout, QWidget, QLineEdit from PySide6.QtDBus import QDBusMessage +from yin_yang import helpers from ..meta import Desktop from ._plugin import PluginDesktopDependent, PluginCommandline, DBusPlugin @@ -139,7 +140,7 @@ def create_message(self, theme: str) -> QDBusMessage: class _Xfce(PluginCommandline): def __init__(self): # first, get all monitors - properties = str(subprocess.check_output(['xfconf-query', '-c', 'xfce4-desktop', '-l'])) + properties = str(helpers.check_output(['xfconf-query', '-c', 'xfce4-desktop', '-l'])) monitor = next(p for p in properties.split('\\n') if p.endswith('/workspace0/last-image')) super().__init__(['xfconf-query', '-c', 'xfce4-desktop', '-p', monitor, '-s', '{theme}']) From b4f869c15ef62622cdd9ad2319d4e88daa64b7f4 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 4 Dec 2023 14:31:28 -0600 Subject: [PATCH 02/29] Pass through arguments to flatpak app --- runner.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runner.sh b/runner.sh index 53bccfea..992fbf60 100644 --- a/runner.sh +++ b/runner.sh @@ -1,2 +1,2 @@ #!/bin/sh -python3 -m yin_yang \ No newline at end of file +python3 -m yin_yang $@ From 890c7550108ad0efa0654407e222f779334ba3ed Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 4 Dec 2023 14:31:54 -0600 Subject: [PATCH 03/29] add is_flatpak() check --- yin_yang/helpers.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 998d1990..29b83e78 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -29,6 +29,13 @@ def check_call(command, stdout=None) -> int: return subprocess.check_call(flatpak_args, stdout=stdout) +def is_flatpak() -> bool: + try: + subprocess.run('lookandfeeltool') + return False + except FileNotFoundError: + return True + def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProcess[str]: try: if len(kwargs) == 0: From 2e6ed1defa4e5741930d42d8e88b6840351510f5 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 4 Dec 2023 14:32:29 -0600 Subject: [PATCH 04/29] Fix notifications crashing application When notify-send is not available, the application would crash --- yin_yang/NotificationHandler.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/yin_yang/NotificationHandler.py b/yin_yang/NotificationHandler.py index 1751a827..0f184f9d 100644 --- a/yin_yang/NotificationHandler.py +++ b/yin_yang/NotificationHandler.py @@ -1,9 +1,14 @@ +import logging import subprocess from logging import Handler +logger = logging.getLogger() class NotificationHandler(Handler): """Shows logs as notifications""" def emit(self, record): - subprocess.call(['notify-send', record.levelname, str(record.msg), - '-a', 'Yin & Yang', '-u', 'low', '--icon', 'yin_yang']) + try: + subprocess.call(['notify-send', record.levelname, str(record.msg), + '-a', 'Yin & Yang', '-u', 'low', '--icon', 'yin_yang']) + except FileNotFoundError: + logger.warn('notify-send not found. Notifications will not work!') From 8052b4a0b671f1b1281bb9a378a4f4a32f61defd Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 4 Dec 2023 14:33:08 -0600 Subject: [PATCH 05/29] WIP: Fix systemd units for Flatpak --- sh.oskar.yin-yang.json | 22 ++++++++++++++++++++++ tests/test_daemon_handler.py | 14 +++++++++++--- yin_yang/daemon_handler.py | 9 +++++++++ yin_yang/helpers.py | 2 +- 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index 3c446a3d..1eba1d04 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -31,6 +31,7 @@ "install -D yin_yang/__main__.py /app/__main__.py", "cp -r yin_yang /app/yin_yang", "cp -r resources /app/resources", + "sed -i 's|/ExecStart=/usr/bin/yin-yang --systemd|ExecStart=$HOME/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd|' /app/resources/yin_yang.service", "install -D runner.sh /app/bin/runner.sh", "sed -i 's|/bin/env python3|/app/bin/python3|' /app/__main__.py" ], @@ -40,6 +41,27 @@ "path": "." } ] + }, + { + "name": "yin-yang-metadata", + "buildsystem": "simple", + "build-commands": [ + "install -Dm644 Yin-Yang.desktop /app/share/applications/sh.oskar.yin-yang.desktop", + "sed -i 's|Path=/opt/yin-yang|Path=$HOME/.local/share/flatpak/app/sh.oskar.yin-yang/current/active/files|' /app/share/applications/sh.oskar.yin-yang.desktop", + "sed -i 's|Icon=yin_yang|Icon=sh.oskar.yin-yang|' /app/share/applications/sh.oskar.yin-yang.desktop", + "sed -i 's|Exec=yin-yang|Exec=runner.sh|' /app/share/applications/sh.oskar.yin-yang.desktop", + "install -Dm664 logo.svg /app/share/icons/hicolor/256x256/apps/sh.oskar.yin-yang.svg" + ], + "sources": [ + { + "type": "file", + "path": "./resources/Yin-Yang.desktop" + }, + { + "type": "file", + "path": "./resources/logo.svg" + } + ] } ] } \ No newline at end of file diff --git a/tests/test_daemon_handler.py b/tests/test_daemon_handler.py index 0d845b43..c8a32096 100644 --- a/tests/test_daemon_handler.py +++ b/tests/test_daemon_handler.py @@ -1,11 +1,12 @@ -import pathlib +from pathlib import Path +import re import shutil import subprocess import unittest from datetime import time from os.path import isfile -from yin_yang import daemon_handler +from yin_yang import daemon_handler, helpers from yin_yang.config import config from yin_yang.meta import Modes, ConfigEvent @@ -26,9 +27,16 @@ def tearDown(self) -> None: def setUpClass(cls) -> None: super().setUpClass() if not isfile(daemon_handler.TIMER_PATH): - pathlib.Path(daemon_handler.SYSTEMD_PATH).mkdir(parents=True, exist_ok=True) + Path(daemon_handler.SYSTEMD_PATH).mkdir(parents=True, exist_ok=True) shutil.copyfile('./resources/yin_yang.timer', daemon_handler.TIMER_PATH) shutil.copyfile('./resources/yin_yang.service', daemon_handler.SERVICE_PATH) + # If we're in a flatpak, the service file needs to be updated + if (helpers.is_flatpak()): + with open(daemon_handler.SERVICE_PATH, 'r') as service: + lines = service.readlines() + with open(daemon_handler.SERVICE_PATH, 'w') as service: + for line in lines: + service.write(re.sub('ExecStart=\/usr\/bin\/yin-yang --systemd', 'ExecStart='+str(Path.home())+'\/.local\/share\/flatpak\/exports\/bin\/sh.oskar.yin-yang --systemd', line)) shutil.copyfile(daemon_handler.TIMER_PATH, daemon_handler.TIMER_PATH.with_suffix('.timer_backup')) @classmethod diff --git a/yin_yang/daemon_handler.py b/yin_yang/daemon_handler.py index 7ee39ac2..096b2f8d 100644 --- a/yin_yang/daemon_handler.py +++ b/yin_yang/daemon_handler.py @@ -3,6 +3,7 @@ import subprocess from enum import Enum, auto from pathlib import Path +import re from yin_yang import helpers from .config import ConfigWatcher, config @@ -14,6 +15,7 @@ SERVICE_PATH = SYSTEMD_PATH / 'yin_yang.service' + def create_files(): logger.debug('Creating systemd files') if not SYSTEMD_PATH.is_dir(): @@ -22,6 +24,13 @@ def create_files(): shutil.copy('./resources/yin_yang.timer', TIMER_PATH) if not SERVICE_PATH.is_file(): shutil.copy('./resources/yin_yang.service', SERVICE_PATH) + # TODO: Will this cause an issue switching back from flatpak? + if (helpers.is_flatpak()): + with open(SERVICE_PATH, 'r') as service: + lines = service.readlines() + with open(SERVICE_PATH, 'w') as service: + for line in lines: + service.write(re.sub('ExecStart=\/usr\/bin\/yin-yang --systemd', 'ExecStart='+str(Path.home())+'/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd', line)) def run_command(command, **kwargs): diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 29b83e78..35a3b798 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -4,7 +4,7 @@ """Check output of a command. This is a helper method which will change how we check output depending on if -The application is running in a flatpak or not. +The application is running in a Flatpak or not. """ From c20706651c5ed4a1f05d3d1dc192f03e7eabf9fc Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 18 Dec 2023 17:59:33 -0600 Subject: [PATCH 06/29] Fix installing and running Flatpak --- python3-PySide6-Addons.json | 6 +++--- python3-PySide6-Essentials.json | 8 ++++---- python3-psutil.json | 4 ++-- python3-requests.json | 22 +++++++++++----------- sh.oskar.yin-yang.json | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/python3-PySide6-Addons.json b/python3-PySide6-Addons.json index 3fd9c85a..d1173961 100644 --- a/python3-PySide6-Addons.json +++ b/python3-PySide6-Addons.json @@ -2,7 +2,7 @@ "name": "pyside6-addons", "buildsystem": "simple", "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_addons --no-build-isolation" + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_addons" ], "only-arches": [ "x86_64" @@ -10,8 +10,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/b1/c5/85ddc6e502ab88727ec3316c38f65830f82bfc66175f00349488a6431258/PySide6_Addons-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", - "sha256": "e5bc1fa95351182dc2c003e07320d5509218ccc0840d10197d7d452aa5de5d2e" + "url": "https://files.pythonhosted.org/packages/ec/b8/1f5335580241c3863584173308c842ffc74e05074f3f72b49e5b54ca18e3/PySide6_Addons-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "a0982da4033319667f9df5ed6fa8eff300a88216aec103a1fff6751a172b19a0" } ] } \ No newline at end of file diff --git a/python3-PySide6-Essentials.json b/python3-PySide6-Essentials.json index b5328a66..649e23c1 100644 --- a/python3-PySide6-Essentials.json +++ b/python3-PySide6-Essentials.json @@ -10,8 +10,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/e5/93/98f660dde373e2fba01caea8bbb2c986f94f02e32afab7b577df03ef744f/PySide6_Essentials-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", - "sha256": "45580138be91f5fdcefb4d28dadb56d3640eb658575af97b49057e10c22a024d" + "url": "https://files.pythonhosted.org/packages/56/65/50d0ced768b717f709a5ab224b648eb533a862efd0cde67d19c2727200b0/PySide6_Essentials-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "c7185616083eab6f42eaed598d97d49fac4f60ae2e7415194140d54f58c2b42c" } ], "modules": [ @@ -24,8 +24,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/55/b4/370f7a1dd3c02150b60073f7a46418fa2932f8d3b864bc58883154c6a423/shiboken6-6.5.3-cp37-abi3-manylinux_2_28_x86_64.whl", - "sha256": "4cdda98df511243c40f1dd4d9eac25a7191c2583ac673147ecdae0ffa3b9223f" + "url": "https://files.pythonhosted.org/packages/bb/72/e54f758e49e8da0dcd9490d006c41a814b0e56898ce4ca054d60cdba97bd/shiboken6-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "fb102e4bc210006f0cdd0ce38e1aaaaf792bd871f02a2b3f01d07922c5cf4c59" } ] } diff --git a/python3-psutil.json b/python3-psutil.json index 34836d47..a44ef992 100644 --- a/python3-psutil.json +++ b/python3-psutil.json @@ -7,8 +7,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/3d/7d/d05864a69e452f003c0d77e728e155a89a2a26b09e64860ddd70ad64fb26/psutil-5.9.4.tar.gz", - "sha256": "3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62" + "url": "https://files.pythonhosted.org/packages/d6/0f/96b7309212a926c1448366e9ce69b081ea79d63265bde33f11cc9cfc2c07/psutil-5.9.5.tar.gz", + "sha256": "5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c" } ] } \ No newline at end of file diff --git a/python3-requests.json b/python3-requests.json index c5cfb9d7..1a7a6aef 100644 --- a/python3-requests.json +++ b/python3-requests.json @@ -2,33 +2,33 @@ "name": "python3-requests", "buildsystem": "simple", "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests\" --no-build-isolation" + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests~=2.28.2\"" ], "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/9d/19/59961b522e6757f0c9097e4493fa906031b95b3ebe9360b2c3083561a6b4/certifi-2023.5.7-py3-none-any.whl", - "sha256": "c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716" + "url": "https://files.pythonhosted.org/packages/64/62/428ef076be88fa93716b576e4a01f919d25968913e817077a386fcbe4f42/certifi-2023.11.17-py3-none-any.whl", + "sha256": "e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/ff/d7/8d757f8bd45be079d76309248845a04f09619a7b17d6dfc8c9ff6433cac2/charset-normalizer-3.1.0.tar.gz", - "sha256": "34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5" + "url": "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", + "sha256": "f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5" }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/fc/34/3030de6f1370931b9dbb4dad48f6ab1015ab1d32447850b9fc94e60097be/idna-3.4-py3-none-any.whl", - "sha256": "90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" + "url": "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", + "sha256": "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", - "sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f" + "url": "https://files.pythonhosted.org/packages/d2/f4/274d1dbe96b41cf4e0efb70cbced278ffd61b5c7bb70338b62af94ccb25b/requests-2.28.2-py3-none-any.whl", + "sha256": "64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa" }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/8a/03/ad9306a50d05c166e3456fe810f33cee2b8b2a7a6818ec5d4908c4ec6b36/urllib3-2.0.3-py3-none-any.whl", - "sha256": "48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1" + "url": "https://files.pythonhosted.org/packages/b0/53/aa91e163dcfd1e5b82d8a890ecf13314e3e149c05270cc644581f77f17fd/urllib3-1.26.18-py2.py3-none-any.whl", + "sha256": "34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07" } ] } \ No newline at end of file diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index 1eba1d04..ab899bbd 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -28,12 +28,12 @@ "name": "yin-yang", "buildsystem": "simple", "build-commands": [ - "install -D yin_yang/__main__.py /app/__main__.py", + "python3 -m pip install --no-deps --no-use-pep517 --prefix=/app .", "cp -r yin_yang /app/yin_yang", "cp -r resources /app/resources", "sed -i 's|/ExecStart=/usr/bin/yin-yang --systemd|ExecStart=$HOME/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd|' /app/resources/yin_yang.service", "install -D runner.sh /app/bin/runner.sh", - "sed -i 's|/bin/env python3|/app/bin/python3|' /app/__main__.py" + "sed -i 's|/bin/env python3|/app/bin/python3|' /app/yin_yang/__main__.py" ], "sources": [ { @@ -47,7 +47,7 @@ "buildsystem": "simple", "build-commands": [ "install -Dm644 Yin-Yang.desktop /app/share/applications/sh.oskar.yin-yang.desktop", - "sed -i 's|Path=/opt/yin-yang|Path=$HOME/.local/share/flatpak/app/sh.oskar.yin-yang/current/active/files|' /app/share/applications/sh.oskar.yin-yang.desktop", + "sed -i 's|Path=/opt/yin-yang||' /app/share/applications/sh.oskar.yin-yang.desktop", "sed -i 's|Icon=yin_yang|Icon=sh.oskar.yin-yang|' /app/share/applications/sh.oskar.yin-yang.desktop", "sed -i 's|Exec=yin-yang|Exec=runner.sh|' /app/share/applications/sh.oskar.yin-yang.desktop", "install -Dm664 logo.svg /app/share/icons/hicolor/256x256/apps/sh.oskar.yin-yang.svg" From bfe0467794173eaf15c8ef66a75d7663b22008f5 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Mon, 18 Dec 2023 18:11:28 -0600 Subject: [PATCH 07/29] Tidy up build files --- sh.oskar.yin-yang.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index ab899bbd..294487b6 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -29,11 +29,7 @@ "buildsystem": "simple", "build-commands": [ "python3 -m pip install --no-deps --no-use-pep517 --prefix=/app .", - "cp -r yin_yang /app/yin_yang", - "cp -r resources /app/resources", - "sed -i 's|/ExecStart=/usr/bin/yin-yang --systemd|ExecStart=$HOME/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd|' /app/resources/yin_yang.service", - "install -D runner.sh /app/bin/runner.sh", - "sed -i 's|/bin/env python3|/app/bin/python3|' /app/yin_yang/__main__.py" + "install -D runner.sh /app/bin/runner.sh" ], "sources": [ { From a3d3644af53a9d3b35e5ca7d1195d2f33a0858aa Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 20 Jan 2024 11:49:14 -0600 Subject: [PATCH 08/29] Update check for flatpak environment --- yin_yang/helpers.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 35a3b798..b3c1d6a3 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -1,4 +1,4 @@ -import subprocess +import subprocess, os """Check output of a command. @@ -30,11 +30,7 @@ def check_call(command, stdout=None) -> int: def is_flatpak() -> bool: - try: - subprocess.run('lookandfeeltool') - return False - except FileNotFoundError: - return True + return os.path.isfile('/.flatpak-info') def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProcess[str]: try: From 4e48944f1357afd77e0a44e4ad72b4a6529e5b0d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 20 Jan 2024 11:57:39 -0600 Subject: [PATCH 09/29] Move repeated flatpak args to a global variable. --- yin_yang/helpers.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index b3c1d6a3..7e80dd3b 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -7,6 +7,13 @@ The application is running in a Flatpak or not. """ +"""Base Flatpak Arguments + +These are the base arguments we use to execute commands when running in +a flatpak environment. +""" +base_flatpak_args = ["flatpak-spawn", "--host"] + def check_output(args, universal_newlines=False) -> bytes: try: @@ -15,7 +22,7 @@ def check_output(args, universal_newlines=False) -> bytes: ) return output except FileNotFoundError: - flatpak_args = ["flatpak-spawn", "--host"] + args + flatpak_args = base_flatpak_args + args return subprocess.check_output( args=flatpak_args, universal_newlines=universal_newlines ) @@ -25,7 +32,7 @@ def check_call(command, stdout=None) -> int: try: return subprocess.check_call(command, stdout=stdout) except FileNotFoundError: - flatpak_args = ["flatpak-spawn", "--host"] + command + flatpak_args = base_flatpak_args + command return subprocess.check_call(flatpak_args, stdout=stdout) @@ -39,7 +46,7 @@ def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProce else: return subprocess.run(command, **kwargs) except FileNotFoundError: - flatpak_args = ["flatpak-spawn", "--host"] + command + flatpak_args = base_flatpak_args + command if len(kwargs) == 0: return subprocess.run(flatpak_args) else: From e3fb1febb4e637e1f897ae5cb028f14a6cd4bc8e Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 20 Jan 2024 12:40:14 -0600 Subject: [PATCH 10/29] Update flatpak deps --- python3-psutil.json | 6 +++--- python3-requests.json | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python3-psutil.json b/python3-psutil.json index a44ef992..a0b6c581 100644 --- a/python3-psutil.json +++ b/python3-psutil.json @@ -2,13 +2,13 @@ "name": "python3-psutil", "buildsystem": "simple", "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil\" --no-build-isolation" + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil==5.9.7\" --no-build-isolation" ], "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/d6/0f/96b7309212a926c1448366e9ce69b081ea79d63265bde33f11cc9cfc2c07/psutil-5.9.5.tar.gz", - "sha256": "5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c" + "url": "https://files.pythonhosted.org/packages/a0/d0/c9ae661a302931735237791f04cb7086ac244377f78692ba3b3eae3a9619/psutil-5.9.7.tar.gz", + "sha256": "3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c" } ] } \ No newline at end of file diff --git a/python3-requests.json b/python3-requests.json index 1a7a6aef..3ba0cb22 100644 --- a/python3-requests.json +++ b/python3-requests.json @@ -2,7 +2,7 @@ "name": "python3-requests", "buildsystem": "simple", "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests~=2.28.2\"" + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests~=2.31.0\"" ], "sources": [ { @@ -22,13 +22,13 @@ }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/d2/f4/274d1dbe96b41cf4e0efb70cbced278ffd61b5c7bb70338b62af94ccb25b/requests-2.28.2-py3-none-any.whl", - "sha256": "64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa" + "url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", + "sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f" }, { "type": "file", - "url": "https://files.pythonhosted.org/packages/b0/53/aa91e163dcfd1e5b82d8a890ecf13314e3e149c05270cc644581f77f17fd/urllib3-1.26.18-py2.py3-none-any.whl", - "sha256": "34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07" + "url": "https://files.pythonhosted.org/packages/96/94/c31f58c7a7f470d5665935262ebd7455c7e4c7782eb525658d3dbf4b9403/urllib3-2.1.0-py3-none-any.whl", + "sha256": "55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3" } ] } \ No newline at end of file From 47dd739003bcaa7c95bdd9805b5c7306a7af695a Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 20 Jan 2024 12:49:36 -0600 Subject: [PATCH 11/29] Change a couple of calls to subprocess to use helper class --- yin_yang/plugins/gtk.py | 5 +++-- yin_yang/plugins/konsole.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/yin_yang/plugins/gtk.py b/yin_yang/plugins/gtk.py index 1a5eb206..fe4ca840 100755 --- a/yin_yang/plugins/gtk.py +++ b/yin_yang/plugins/gtk.py @@ -1,10 +1,11 @@ import logging -import subprocess from os import scandir, path from pathlib import Path from PySide6.QtDBus import QDBusMessage +from yin_yang import helpers + from ._plugin import PluginDesktopDependent, PluginCommandline, DBusPlugin from .system import test_gnome_availability from ..meta import Desktop @@ -119,7 +120,7 @@ def set_theme(self, theme: str): f.writelines(lines) # send signal to read new config - subprocess.run(['killall', '-HUP', 'xsettingsd']) + helpers.run(['killall', '-HUP', 'xsettingsd']) class _Xfce(PluginCommandline): diff --git a/yin_yang/plugins/konsole.py b/yin_yang/plugins/konsole.py index 8a9a3a03..4619bf5c 100644 --- a/yin_yang/plugins/konsole.py +++ b/yin_yang/plugins/konsole.py @@ -267,7 +267,7 @@ def set_profile(service: str, profile: str, set_default_profile: bool = False): sessions = helpers.check_output(f'qdbus {service} | grep "{path}"') except subprocess.CalledProcessError: try: - sessions = subprocess.check_output( + sessions = helpers.check_output( f'qdbus org.kde.konsole | grep "{path}"', shell=True ) logger.debug(f"Found org.kde.konsole, use that instead") From 0ec4a0486b659ea3643e1585e31fe6fd6a028afe Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 21 Jan 2024 09:24:17 -0600 Subject: [PATCH 12/29] Add logic for Kvantum themes in flatpak --- yin_yang/plugins/kvantum.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yin_yang/plugins/kvantum.py b/yin_yang/plugins/kvantum.py index f9befeb7..5cd8dae0 100755 --- a/yin_yang/plugins/kvantum.py +++ b/yin_yang/plugins/kvantum.py @@ -1,6 +1,8 @@ from os import walk from pathlib import Path +from yin_yang import helpers + from ._plugin import PluginCommandline @@ -25,6 +27,9 @@ def available_themes(self) -> dict: return {} paths = [Path('/usr/share/Kvantum'), Path.home() / '.config/Kvantum'] + # Flatpak doesn't allow direct access to /usr + if (helpers.is_flatpak()): + paths[0] = Path('/var/run/host/usr/share/Kvantum') themes = list() for path in paths: themes = themes + self.get_kvantum_theme_from_dir(path) From a861944499cc84eadbd5df287556a2cbe28fef5d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 6 Apr 2024 16:53:38 -0500 Subject: [PATCH 13/29] Add helpers for finding /usr and /etc This is needed because these paths are mounted differently while running in a Flatpak environment. --- yin_yang/helpers.py | 27 +++++++++++++++++++++++++-- yin_yang/plugins/gtk.py | 2 +- yin_yang/plugins/konsole.py | 2 +- yin_yang/plugins/kvantum.py | 5 +---- yin_yang/plugins/system.py | 7 ++++--- yin_yang/plugins/vscode.py | 9 +++++---- 6 files changed, 37 insertions(+), 15 deletions(-) diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 7e80dd3b..36046431 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -1,5 +1,5 @@ -import subprocess, os - +import os +import subprocess """Check output of a command. @@ -39,6 +39,29 @@ def check_call(command, stdout=None) -> int: def is_flatpak() -> bool: return os.path.isfile('/.flatpak-info') + +def get_usr() -> str: + """ + Returns the proper path to /usr. + This is need as the path to /usr is different in a flatpak environment. + :return: The path to /usr with a trailing / + """ + if is_flatpak(): + return '/var/run/host/usr/' + return '/usr/' + + +def get_etc() -> str: + """ + Returns the proper path to /etc. + This is need as the path to /etc is different in a flatpak environment. + :return: The path to /etc with a trailing / + """ + if is_flatpak(): + return '/var/run/host/etc/' + return '/etc/' + + def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProcess[str]: try: if len(kwargs) == 0: diff --git a/yin_yang/plugins/gtk.py b/yin_yang/plugins/gtk.py index fe4ca840..7fe13db7 100755 --- a/yin_yang/plugins/gtk.py +++ b/yin_yang/plugins/gtk.py @@ -13,7 +13,7 @@ logger = logging.getLogger(__name__) -theme_directories = ['/usr/share/themes', f'{Path.home()}/.themes'] +theme_directories = [helpers.get_usr() + 'share/themes', f'{Path.home()}/.themes'] class Gtk(PluginDesktopDependent): diff --git a/yin_yang/plugins/konsole.py b/yin_yang/plugins/konsole.py index 4619bf5c..a5954a30 100644 --- a/yin_yang/plugins/konsole.py +++ b/yin_yang/plugins/konsole.py @@ -24,7 +24,7 @@ class Konsole(Plugin): This is necessary to allow live theme changes. """ - global_path = Path("/usr/share/konsole") + global_path = Path(helpers.get_usr() + "share/konsole") config_path = Path.home() / ".config/konsolerc" @property diff --git a/yin_yang/plugins/kvantum.py b/yin_yang/plugins/kvantum.py index 5cd8dae0..4e83292b 100755 --- a/yin_yang/plugins/kvantum.py +++ b/yin_yang/plugins/kvantum.py @@ -26,10 +26,7 @@ def available_themes(self) -> dict: if not self.available: return {} - paths = [Path('/usr/share/Kvantum'), Path.home() / '.config/Kvantum'] - # Flatpak doesn't allow direct access to /usr - if (helpers.is_flatpak()): - paths[0] = Path('/var/run/host/usr/share/Kvantum') + paths = [Path(helpers.get_usr() + 'share/Kvantum'), Path.home() / '.config/Kvantum'] themes = list() for path in paths: themes = themes + self.get_kvantum_theme_from_dir(path) diff --git a/yin_yang/plugins/system.py b/yin_yang/plugins/system.py index b5ba0381..85f2f680 100644 --- a/yin_yang/plugins/system.py +++ b/yin_yang/plugins/system.py @@ -141,14 +141,15 @@ def available_themes(self) -> dict: # trying to get the Desktop file try: # json in newer versions - with open(f'/usr/share/plasma/look-and-feel/{long_name}/metadata.json', 'r') as file: + with open(f'{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.json', 'r') as file: meta = json.load(file) key = get_name_key(meta) self.translations[long_name] = meta['KPlugin'][key] except OSError: try: # load the name from the metadata.desktop file - with open(f'/usr/share/plasma/look-and-feel/{long_name}/metadata.desktop', 'r') as file: + with open(f'{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.desktop', + 'r') as file: self.translations[long_name] = get_readable_kde_theme_name(file) except OSError: # check the next path if the themes exist there @@ -165,7 +166,7 @@ def available_themes(self) -> dict: class _Mate(PluginCommandline): - theme_directories = [Path('/usr/share/themes'), Path.home() / '.themes'] + theme_directories = [Path(helpers.get_usr() + 'share/themes'), Path.home() / '.themes'] def __init__(self): super().__init__(['dconf', 'write', '/org/mate/marco/general/theme', '\'{theme}\'']) diff --git a/yin_yang/plugins/vscode.py b/yin_yang/plugins/vscode.py index a0c65498..58230a7b 100755 --- a/yin_yang/plugins/vscode.py +++ b/yin_yang/plugins/vscode.py @@ -4,6 +4,7 @@ from os.path import isdir, isfile from pathlib import Path +from .. import helpers from ..meta import FileFormat from ._plugin import flatpak_system, flatpak_user, snap_path, ConfigFilePlugin @@ -13,10 +14,10 @@ str(Path.home() / '.vscode/extensions'), str(Path.home() / '.vscode-insiders/extensions'), str(Path.home() / '.vscode-oss/extensions'), - '/usr/lib/code/extensions', - '/usr/lib/code-insiders/extensions', - '/usr/share/code/resources/app/extensions', - '/usr/share/code-insiders/resources/app/extensions', + helpers.get_usr() + 'lib/code/extensions', + helpers.get_usr() + 'lib/code-insiders/extensions', + helpers.get_usr() + 'share/code/resources/app/extensions', + helpers.get_usr() + 'share/code-insiders/resources/app/extensions', '/usr/share/vscodium/resources/app/extensions', '/usr/share/vscodium-git/resources/app/extensions', '/usr/share/vscodium-insiders/resources/app/extensions', From 87072cbdbc58753fc13e9ae7b0e95ddcc2864e3b Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sat, 6 Apr 2024 19:13:13 -0500 Subject: [PATCH 14/29] Update deps and fix flatpak building with poetry Updates KDE frameworks to 5.15-23.08 LTS, which includes Python 3.11. --- pyproject.toml | 11 ++++++++--- python3-PySide6-Addons.json | 4 ++-- python3-PySide6-Essentials.json | 8 ++++---- python3-psutil.json | 6 +++--- sh.oskar.yin-yang.json | 4 ++-- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6f06aacb..5cd08135 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,12 @@ repository = "https://github.com/oskarsh/Yin-Yang" license = "MIT" readme = "README.md" -packages = [{include = "yin_yang"}] +packages = [ + { include = "yin_yang" } +] [tool.poetry.dependencies] -python = "^3.12,<3.13" +python = "^3.11,<3.13" psutil = "5.9.8" PySide6-Essentials = "6.6.3.1" shiboken6 = "6.6.3.1" @@ -26,4 +28,7 @@ pytest = "^8.1.1" [build-system] requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" \ No newline at end of file +build-backend = "poetry.core.masonry.api" + +[tool.poetry.scripts] +yin-yang = "yin_yang:__main__" \ No newline at end of file diff --git a/python3-PySide6-Addons.json b/python3-PySide6-Addons.json index d1173961..d02ff776 100644 --- a/python3-PySide6-Addons.json +++ b/python3-PySide6-Addons.json @@ -10,8 +10,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/ec/b8/1f5335580241c3863584173308c842ffc74e05074f3f72b49e5b54ca18e3/PySide6_Addons-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "a0982da4033319667f9df5ed6fa8eff300a88216aec103a1fff6751a172b19a0" + "url": "https://files.pythonhosted.org/packages/02/fc/e265aa0c338ddd8a4f2c3526aadc58f60980508ac56999ba79cf2ce744a7/PySide6_Addons-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "7373479565e5bd963b9662857c40c20768bc0b5853334e2076a62cb039e91f74" } ] } \ No newline at end of file diff --git a/python3-PySide6-Essentials.json b/python3-PySide6-Essentials.json index 649e23c1..c0db92e4 100644 --- a/python3-PySide6-Essentials.json +++ b/python3-PySide6-Essentials.json @@ -10,8 +10,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/56/65/50d0ced768b717f709a5ab224b648eb533a862efd0cde67d19c2727200b0/PySide6_Essentials-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "c7185616083eab6f42eaed598d97d49fac4f60ae2e7415194140d54f58c2b42c" + "url": "https://files.pythonhosted.org/packages/4a/29/2375cccf188862c3297f40cb06832cd48fd98fd5da73b0b296a59f54c9f4/PySide6_Essentials-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "1f41f357ce2384576581e76c9c3df1c4fa5b38e347f0bcd0cae7c5bce42a917c" } ], "modules": [ @@ -24,8 +24,8 @@ "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/bb/72/e54f758e49e8da0dcd9490d006c41a814b0e56898ce4ca054d60cdba97bd/shiboken6-6.6.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "fb102e4bc210006f0cdd0ce38e1aaaaf792bd871f02a2b3f01d07922c5cf4c59" + "url": "https://files.pythonhosted.org/packages/77/f1/feb2a8be699f91fb27fbe8758b405fb38a22e3ae5bd5e05258dbef18d462/shiboken6-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "b1aeff0d79d84ddbdc9970144c1bbc3a52fcb45618d1b33d17d57f99f1246d45" } ] } diff --git a/python3-psutil.json b/python3-psutil.json index a0b6c581..b9c1ef37 100644 --- a/python3-psutil.json +++ b/python3-psutil.json @@ -2,13 +2,13 @@ "name": "python3-psutil", "buildsystem": "simple", "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil==5.9.7\" --no-build-isolation" + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil==5.9.8\" --no-build-isolation" ], "sources": [ { "type": "file", - "url": "https://files.pythonhosted.org/packages/a0/d0/c9ae661a302931735237791f04cb7086ac244377f78692ba3b3eae3a9619/psutil-5.9.7.tar.gz", - "sha256": "3f02134e82cfb5d089fddf20bb2e03fd5cd52395321d1c8458a9e58500ff417c" + "url": "https://files.pythonhosted.org/packages/c5/4f/0e22aaa246f96d6ac87fe5ebb9c5a693fbe8877f537a1022527c47ca43c5/psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "sha256": "d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4" } ] } \ No newline at end of file diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index 294487b6..bf990029 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -1,7 +1,7 @@ { "id": "sh.oskar.yin-yang", "runtime": "org.kde.Platform", - "runtime-version": "5.15-22.08", + "runtime-version": "5.15-23.08", "sdk": "org.kde.Sdk", "command": "runner.sh", "finish-args": [ @@ -28,7 +28,7 @@ "name": "yin-yang", "buildsystem": "simple", "build-commands": [ - "python3 -m pip install --no-deps --no-use-pep517 --prefix=/app .", + "python3 -m pip install --no-deps --no-use-pep517 --prefix=/app dist/yin_yang-*-py3-none-any.whl", "install -D runner.sh /app/bin/runner.sh" ], "sources": [ From 0b46f084d90490d8ae70e080c4569bb4916709db Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 14 Apr 2024 09:11:53 -0500 Subject: [PATCH 15/29] Update flatpak to build Poetry deps --- .vscode/launch.json | 13 ++- flatpak-poetry-generator.py | 199 ++++++++++++++++++++++++++++++++ generated-poetry-sources.json | 144 +++++++++++++++++++++++ poetry.lock | 162 +++++++++++++++++++++++++- pyproject.toml | 5 + python3-PySide6-Addons.json | 17 --- python3-PySide6-Essentials.json | 33 ------ python3-numpy.json | 14 --- python3-psutil.json | 14 --- python3-python-dateutil.json | 14 --- python3-requests.json | 34 ------ python3-shiboken6.json | 14 --- python3-suntime.json | 19 --- python3-systemd-python.json | 14 --- sh.oskar.yin-yang.json | 11 +- 15 files changed, 518 insertions(+), 189 deletions(-) create mode 100644 flatpak-poetry-generator.py create mode 100644 generated-poetry-sources.json delete mode 100644 python3-PySide6-Addons.json delete mode 100644 python3-PySide6-Essentials.json delete mode 100644 python3-numpy.json delete mode 100644 python3-psutil.json delete mode 100644 python3-python-dateutil.json delete mode 100644 python3-requests.json delete mode 100644 python3-shiboken6.json delete mode 100644 python3-suntime.json delete mode 100644 python3-systemd-python.json diff --git a/.vscode/launch.json b/.vscode/launch.json index ae58ed4d..37bc9fce 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,11 +6,20 @@ "configurations": [ { "name": "Python: Main", - "type": "python", + "type": "debugpy", "request": "launch", "console": "integratedTerminal", "module": "yin_yang", "justMyCode": true + }, + { + "name": "Debug Poetry Generator", + "type": "debugpy", + "request": "launch", + "console": "integratedTerminal", + "program": "flatpak-poetry-generator.py", + "justMyCode": true, + "args": ["poetry.lock"] } ] -} \ No newline at end of file +} diff --git a/flatpak-poetry-generator.py b/flatpak-poetry-generator.py new file mode 100644 index 00000000..59956fc4 --- /dev/null +++ b/flatpak-poetry-generator.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 + +""" +This file is a modified version of the file available here: +https://github.com/flatpak/flatpak-builder-tools/blob/master/poetry/flatpak-poetry-generator.py + +The file above has a long-standing issue pulling dependencies for Pyside6. This modified version +is hard-coded to work with Pyside6. Hopefully there is a better long-term fix in the future. + +Chase Christiansen, 04/13/2024 +""" +__license__ = "MIT" + +import argparse +import json +import re +import sys +import urllib.parse +import urllib.request +from collections import OrderedDict + +import toml + + +def get_pypi_source(name: str, version: str, hashes: list) -> tuple: + """Get the source information for a dependency. + + Args: + name (str): The package name. + version (str): The package version. + hashes (list): The list of hashes for the package version. + + Returns (tuple): The url and sha256 hash. + + """ + url = "https://pypi.org/pypi/{}/json".format(name) + print("Extracting download url and hash for {}, version {}".format(name, version)) + with urllib.request.urlopen(url) as response: + body = json.loads(response.read().decode("utf-8")) + for release, source_list in body["releases"].items(): + if release == version: + for source in source_list: + if ( + name == "pyside6-addons" + or name == "pyside6-essentials" + or name == "shiboken6" + ): + if ( + source["filename"].endswith("x86_64.whl") + and "manylinux" in source["filename"] + ): + return source["url"], source["digests"]["sha256"] + if ( + source["packagetype"] == "bdist_wheel" + and "py3" in source["python_version"] + and source["digests"]["sha256"] in hashes + ): + return source["url"], source["digests"]["sha256"] + for source in source_list: + if ( + source["packagetype"] == "sdist" + and "source" in source["python_version"] + and source["digests"]["sha256"] in hashes + ): + return source["url"], source["digests"]["sha256"] + else: + raise Exception("Failed to extract url and hash from {}".format(url)) + + +def get_module_sources(parsed_lockfile: dict, include_devel: bool = True) -> list: + """Gets the list of sources from a toml parsed lockfile. + + Args: + parsed_lockfile (dict): The dictionary of the parsed lockfile. + include_devel (bool): Include dev dependencies, defaults to True. + + Returns (list): The sources. + + """ + sources = [] + hash_re = re.compile(r"(sha1|sha224|sha384|sha256|sha512|md5):([a-f0-9]+)") + for section, packages in parsed_lockfile.items(): + if section == "package": + for package in packages: + if "category" not in package or ( + ( + package.get("category") == "dev" + and include_devel + and not package.get("optional") + ) + or ( + package.get("category") == "main" + and not package.get("optional") + ) + ): + hashes = [] + # Check for old metadata format (poetry version < 1.0.0b2) + if "hashes" in parsed_lockfile["metadata"]: + hashes = parsed_lockfile["metadata"]["hashes"][package["name"]] + # metadata format 1.1 + elif "files" in parsed_lockfile["metadata"]: + for package_name in parsed_lockfile["metadata"]["files"]: + if package_name == package["name"]: + package_files = parsed_lockfile["metadata"]["files"][ + package["name"] + ] + num_files = len(package_files) + for num in range(num_files): + match = hash_re.search(package_files[num]["hash"]) + if match: + hashes.append(match.group(2)) + # metadata format 2.0 + else: + for file in package["files"]: + match = hash_re.search(file["hash"]) + if match: + hashes.append(match.group(2)) + url, hash = get_pypi_source( + package["name"], package["version"], hashes + ) + source = {"type": "file", "url": url, "sha256": hash} + sources.append(source) + return sources + + +def get_dep_names(parsed_lockfile: dict, include_devel: bool = True) -> list: + """Gets the list of dependency names. + + Args: + parsed_lockfile (dict): The dictionary of the parsed lockfile. + include_devel (bool): Include dev dependencies, defaults to True. + + Returns (list): The dependency names. + + """ + dep_names = [] + for section, packages in parsed_lockfile.items(): + if section == "package": + for package in packages: + if "category" not in package or ( + ( + package.get("category") == "dev" + and include_devel + and not package.get("optional") + ) + or ( + package.get("category") == "main" + and not package.get("optional") + ) + ): + dep_names.append(package["name"]) + return dep_names + + +def main(): + parser = argparse.ArgumentParser(description="Flatpak Poetry generator") + parser.add_argument("lockfile", type=str) + parser.add_argument( + "-o", type=str, dest="outfile", default="generated-poetry-sources.json" + ) + parser.add_argument("--production", action="store_true", default=False) + args = parser.parse_args() + + include_devel = not args.production + outfile = args.outfile + lockfile = args.lockfile + + print('Scanning "%s" ' % lockfile, file=sys.stderr) + + with open(lockfile, "r") as f: + parsed_lockfile = toml.load(f) + dep_names = get_dep_names(parsed_lockfile, include_devel=include_devel) + pip_command = [ + "pip3", + "install", + "--no-index", + '--find-links="file://${PWD}"', + "--prefix=${FLATPAK_DEST}", + " ".join(dep_names), + ] + main_module = OrderedDict( + [ + ("name", "poetry-deps"), + ("buildsystem", "simple"), + ("build-commands", [" ".join(pip_command)]), + ] + ) + sources = get_module_sources(parsed_lockfile, include_devel=include_devel) + main_module["sources"] = sources + + print(" ... %d new entries" % len(sources), file=sys.stderr) + + print('Writing to "%s"' % outfile) + with open(outfile, "w") as f: + f.write(json.dumps(main_module, indent=4)) + + +if __name__ == "__main__": + main() diff --git a/generated-poetry-sources.json b/generated-poetry-sources.json new file mode 100644 index 00000000..57a8dd3f --- /dev/null +++ b/generated-poetry-sources.json @@ -0,0 +1,144 @@ +{ + "name": "poetry-deps", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} certifi charset-normalizer colorama cython flake8 idna iniconfig mccabe packaging pluggy psutil pycodestyle pyflakes pyside6-addons pyside6-essentials pytest python-dateutil pyyaml requests setuptools shiboken6 six suntime systemd-python toml urllib3 wheel" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/ba/06/a07f096c664aeb9f01624f858c3add0a4e913d6c96257acb4fce61e7de14/certifi-2024.2.2-py3-none-any.whl", + "sha256": "dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", + "sha256": "3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/7e/26/9d8de10005fedb1eceabe713348d43bae1dbab1786042ca0751a2e2b0f8c/Cython-0.29.37-py2.py3-none-any.whl", + "sha256": "95f1d6a83ef2729e67b3fa7318c829ce5b07ac64c084cd6af11c228e0364662c" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/e3/01/cc8cdec7b61db0315c2ab62d80677a138ef06832ec17f04d87e6ef858f7f/flake8-7.0.0-py2.py3-none-any.whl", + "sha256": "a6dfbb75e03252917f2473ea9653f7cd799c3064e54d4c8140044c5c065f53c3" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/e5/3e/741d8c82801c347547f8a2a06aa57dbb1992be9e948df2ea0eda2c8b79e8/idna-3.7-py3-none-any.whl", + "sha256": "82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", + "sha256": "b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", + "sha256": "6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl", + "sha256": "2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/a5/5b/0cc789b59e8cc1bf288b38111d002d8c5917123194d45b29dcdac64723cc/pluggy-1.4.0-py3-none-any.whl", + "sha256": "7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/90/c7/6dc0a455d111f68ee43f27793971cf03fe29b6ef972042549db29eec39a2/psutil-5.9.8.tar.gz", + "sha256": "6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/b1/90/a998c550d0ddd07e38605bb5c455d00fcc177a800ff9cc3dafdcb3dd7b56/pycodestyle-2.11.1-py2.py3-none-any.whl", + "sha256": "44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", + "sha256": "84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/02/fc/e265aa0c338ddd8a4f2c3526aadc58f60980508ac56999ba79cf2ce744a7/PySide6_Addons-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "7373479565e5bd963b9662857c40c20768bc0b5853334e2076a62cb039e91f74" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/4a/29/2375cccf188862c3297f40cb06832cd48fd98fd5da73b0b296a59f54c9f4/PySide6_Essentials-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "1f41f357ce2384576581e76c9c3df1c4fa5b38e347f0bcd0cae7c5bce42a917c" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/4d/7e/c79cecfdb6aa85c6c2e3cf63afc56d0f165f24f5c66c03c695c4d9b84756/pytest-8.1.1-py3-none-any.whl", + "sha256": "2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", + "sha256": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/cd/e5/af35f7ea75cf72f2cd079c95ee16797de7cd71f29ea7c68ae5ce7be1eda0/PyYAML-6.0.1.tar.gz", + "sha256": "bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", + "sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/f7/29/13965af254e3373bceae8fb9a0e6ea0d0e571171b80d6646932131d6439b/setuptools-69.5.1-py3-none-any.whl", + "sha256": "c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/77/f1/feb2a8be699f91fb27fbe8758b405fb38a22e3ae5bd5e05258dbef18d462/shiboken6-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", + "sha256": "b1aeff0d79d84ddbdc9970144c1bbc3a52fcb45618d1b33d17d57f99f1246d45" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", + "sha256": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/d1/d5/bb9997169b8b64d48f9a807fb2ec2413ff5e75c4b77612e75dd0aac8369c/suntime-1.3.2-py3-none-any.whl", + "sha256": "33ac6ec2a3e14758cc690f7573f689d19c3131a6c9753f1bb54460bd70372ca4" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", + "sha256": "4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", + "sha256": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", + "sha256": "450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d" + }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/7d/cd/d7460c9a869b16c3dd4e1e403cce337df165368c71d6af229a74699622ce/wheel-0.43.0-py3-none-any.whl", + "sha256": "55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81" + } + ] +} \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 66c01eab..16c467a9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -121,6 +121,57 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "cython" +version = "0.29.37" +description = "The Cython compiler for writing C extensions for the Python language." +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "Cython-0.29.37-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2d621fe4cb50007446742134a890500b34e3f50abaf7993baaca02634af7e15"}, + {file = "Cython-0.29.37-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d94caf90ae9cb56116ca6d54cdcbccd3c4df6b0cb7233922b2233ee7fe81d05b"}, + {file = "Cython-0.29.37-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:852cd4378cbc9ade02f53709107ff9fdad55019a3a636e8a27663ba6cfce10b6"}, + {file = "Cython-0.29.37-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bbce388431a2608a81c8ab13cb14c50611473843ca766031b8b24bb1723faf79"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4658499a41255431f6bbdca7e634e9c8d3a4c190bf24b4aa1646dac751d3da4d"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:12192ab269e7185720f2d2f8894587bf1da4276db1b9b869e4622a093f18cae6"}, + {file = "Cython-0.29.37-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:9450e0766ab65947f8a2a36f9e59079fc879c3807ec936c61725a48c97741a52"}, + {file = "Cython-0.29.37-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:177481b0a7e003e5c49e2bf0dda1d6fe610c239f17642a5da9f18c2ad0c5f6b6"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:b048354fd380278f2fa096e7526973beb6e0491a9d44d7e4e29df52612d25776"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ea6d208be1906c5df25b674777d5905c6d8e9ef0b201b830849e0729ba08caba"}, + {file = "Cython-0.29.37-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:af03854571738307a5f30cc6b724081d72db12f907699e7fdfc04c12c839158e"}, + {file = "Cython-0.29.37-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c33508ede9172a6f6f99d5a6dadc7fee23c840423b411ef8b5a403c04e530297"}, + {file = "Cython-0.29.37-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8af5975ecfae254d8c0051204fca995dda8f93cf9f0bbf7571e3cda2b0cef4d"}, + {file = "Cython-0.29.37-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29415d8eb2fdc1ea518ca4810c50a2d062b387d4c9fbcfb3352346e93db22c6d"}, + {file = "Cython-0.29.37-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe0eaf6b1e9ee97c5ee7bfc943f00e36cf59d929db16886cb018352bff8208da"}, + {file = "Cython-0.29.37-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cc1b9ce2b73b9ee8c305e06173b35c7c202d4b82d084a0cd73dcedfd6d310aec"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2618af0b8df26d32ee4e8858d4ad8167546596762620aeade84954ae37194a0e"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac910a28a2fd3d280faf3077b6fe63b97a4b93994ff05647581846f0e4b2f8d1"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:8bf38373773f967cfd793997a6fb96cf972d41a9fce987ace5767349d6f15572"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6cddb567dadb3aa3e280a8a35e5126030915ea744c2812206e9c194b8881475d"}, + {file = "Cython-0.29.37-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:79ecfc48694e156402c05561e0adb0e25a6e9d35ac0b41693733a08219d38c58"}, + {file = "Cython-0.29.37-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9a455347e20ddfad0c5dfee32a3e855ee96811269e5fd86be622ddc4cb326404"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:fa5b6a0f69bf1823c9fd038fa77a2568b78fda2de045a95b48a71dee4d0d578f"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a6164a05440dcd9daa760c6488bc91bdac1380c7b4b3aca38cf307ba66042d54"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:562f8f911dbd6f1a1b9be8f6cba097125700355688f613994ccd4406f220557a"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8c39c2f5a0fe29bb01de9b1fb449bf65bed6f192317c677f181732791c63fe28"}, + {file = "Cython-0.29.37-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0a0a6d5972bb3b8c7363cf19a42a988bb0c0bb5ebd9c736c84eca85113ccfdbe"}, + {file = "Cython-0.29.37-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b82584836e9e7c0d6effee976595e5cd7fa88dbef3e96e900187983c1d4637d1"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:b6c48f1032b379135a5b4a31976d6c468e02490688acf9254c6c8ed27bd4cbd4"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:3f87bef1808d255cf13be378c7ad27ae7c6db6df7732217d32428d1daf4109be"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:9e68bafeeb97d5a403fb1f7700bd4a55a1f8989824c323ae02ae8a4fcd88f6a1"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e14cd44c830e53cf9d7269c87a6bcc638bb065ec07e24990e338162c7001d3c3"}, + {file = "Cython-0.29.37-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0544f7a3e4437b89b356baa15387494c18214e03f2ffaddada5a2c71c3dfd24b"}, + {file = "Cython-0.29.37-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2de3e729d25f041036e81e2f15683dd129f977dfb5b06267e30e8d7acec43225"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2ad634dc77a6a74022881826099eccac19c9b79153942cc82e754ffac2bec116"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e841a8b4f9ceefb2916e32dac4f28a895cd519e8ece71505144da1ee355c548a"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_24_i686.whl", hash = "sha256:6c672089fba6a8f6690b8d7924a58c04477771401ad101d53171a13405ee12cb"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0301d4739c6894e012f1d410052082fdda9e63888c815d9e23e0f7f82fff7d79"}, + {file = "Cython-0.29.37-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:af8e7b4397620e2d18259a11f3bfa026eff9846657e397d02616962dd5dd035a"}, + {file = "Cython-0.29.37-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b225d5e2091c224d4ab328165fef224ba3919b3ed44bd9b3241416f523b4d51a"}, + {file = "Cython-0.29.37-py2.py3-none-any.whl", hash = "sha256:95f1d6a83ef2729e67b3fa7318c829ce5b07ac64c084cd6af11c228e0364662c"}, + {file = "Cython-0.29.37.tar.gz", hash = "sha256:f813d4a6dd94adee5d4ff266191d1d95bf6d4164a4facc535422c021b2504cfb"}, +] + [[package]] name = "flake8" version = "7.0.0" @@ -139,13 +190,13 @@ pyflakes = ">=3.2.0,<3.3.0" [[package]] name = "idna" -version = "3.6" +version = "3.7" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, - {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, ] [[package]] @@ -313,6 +364,66 @@ files = [ [package.dependencies] six = ">=1.5" +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + [[package]] name = "requests" version = "2.31.0" @@ -334,6 +445,22 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "setuptools" +version = "69.5.1" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"}, + {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + [[package]] name = "shiboken6" version = "6.6.3.1" @@ -382,6 +509,17 @@ files = [ {file = "systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a"}, ] +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "urllib3" version = "2.2.1" @@ -399,7 +537,21 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] +[[package]] +name = "wheel" +version = "0.43.0" +description = "A built-package format for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "wheel-0.43.0-py3-none-any.whl", hash = "sha256:55c570405f142630c6b9f72fe09d9b67cf1477fcf543ae5b8dcb1f5b7377da81"}, + {file = "wheel-0.43.0.tar.gz", hash = "sha256:465ef92c69fa5c5da2d1cf8ac40559a8c940886afcef87dcf14b9470862f1d85"}, +] + +[package.extras] +test = ["pytest (>=6.0.0)", "setuptools (>=65)"] + [metadata] lock-version = "2.0" -python-versions = "^3.12,<3.13" -content-hash = "7c829265c2664d213ae8a819c41dad8b5194c945435f6af16db87ef36b995131" +python-versions = "^3.11,<3.13" +content-hash = "80cb53843cb453c3213b1e16e0be79bcd3116bf0084f75e2167ae6498c86a538" diff --git a/pyproject.toml b/pyproject.toml index 5cd08135..d00310af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,6 +25,11 @@ requests = "2.31.0" [tool.poetry.group.DEV.dependencies] flake8 = "^7.0.0" pytest = "^8.1.1" +pyyaml = "^6.0.1" +toml = "^0.10.2" +setuptools = "^69.5.1" +wheel = "^0.43.0" +cython = "<3.0" [build-system] requires = ["poetry-core"] diff --git a/python3-PySide6-Addons.json b/python3-PySide6-Addons.json deleted file mode 100644 index d02ff776..00000000 --- a/python3-PySide6-Addons.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "pyside6-addons", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_addons" - ], - "only-arches": [ - "x86_64" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/02/fc/e265aa0c338ddd8a4f2c3526aadc58f60980508ac56999ba79cf2ce744a7/PySide6_Addons-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "7373479565e5bd963b9662857c40c20768bc0b5853334e2076a62cb039e91f74" - } - ] -} \ No newline at end of file diff --git a/python3-PySide6-Essentials.json b/python3-PySide6-Essentials.json deleted file mode 100644 index c0db92e4..00000000 --- a/python3-PySide6-Essentials.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "pyside6-essentials", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} pyside6_essentials --no-build-isolation" - ], - "only-arches": [ - "x86_64" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/4a/29/2375cccf188862c3297f40cb06832cd48fd98fd5da73b0b296a59f54c9f4/PySide6_Essentials-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "1f41f357ce2384576581e76c9c3df1c4fa5b38e347f0bcd0cae7c5bce42a917c" - } - ], - "modules": [ - { - "name": "shiboken6", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} shiboken6 --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/77/f1/feb2a8be699f91fb27fbe8758b405fb38a22e3ae5bd5e05258dbef18d462/shiboken6-6.6.3.1-cp38-abi3-manylinux_2_28_x86_64.whl", - "sha256": "b1aeff0d79d84ddbdc9970144c1bbc3a52fcb45618d1b33d17d57f99f1246d45" - } - ] - } - ] -} \ No newline at end of file diff --git a/python3-numpy.json b/python3-numpy.json deleted file mode 100644 index a8e3490c..00000000 --- a/python3-numpy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "python3-numpy", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"numpy\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/e4/a9/6704bb5e1d1d778d3a6ee1278a8d8134f0db160e09d52863a24edb58eab5/numpy-1.24.2.tar.gz", - "sha256": "003a9f530e880cb2cd177cba1af7220b9aa42def9c4afc2a2fc3ee6be7eb2b22" - } - ] -} \ No newline at end of file diff --git a/python3-psutil.json b/python3-psutil.json deleted file mode 100644 index b9c1ef37..00000000 --- a/python3-psutil.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "python3-psutil", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"psutil==5.9.8\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/c5/4f/0e22aaa246f96d6ac87fe5ebb9c5a693fbe8877f537a1022527c47ca43c5/psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", - "sha256": "d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4" - } - ] -} \ No newline at end of file diff --git a/python3-python-dateutil.json b/python3-python-dateutil.json deleted file mode 100644 index befceb70..00000000 --- a/python3-python-dateutil.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "python3-python-dateutil", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"python-dateutil\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", - "sha256": "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - } - ] -} \ No newline at end of file diff --git a/python3-requests.json b/python3-requests.json deleted file mode 100644 index 3ba0cb22..00000000 --- a/python3-requests.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "python3-requests", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"requests~=2.31.0\"" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/64/62/428ef076be88fa93716b576e4a01f919d25968913e817077a386fcbe4f42/certifi-2023.11.17-py3-none-any.whl", - "sha256": "e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474" - }, - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", - "sha256": "f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5" - }, - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/c2/e7/a82b05cf63a603df6e68d59ae6a68bf5064484a0718ea5033660af4b54a9/idna-3.6-py3-none-any.whl", - "sha256": "c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" - }, - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/70/8e/0e2d847013cb52cd35b38c009bb167a1a26b2ce6cd6965bf26b47bc0bf44/requests-2.31.0-py3-none-any.whl", - "sha256": "58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f" - }, - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/96/94/c31f58c7a7f470d5665935262ebd7455c7e4c7782eb525658d3dbf4b9403/urllib3-2.1.0-py3-none-any.whl", - "sha256": "55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3" - } - ] -} \ No newline at end of file diff --git a/python3-shiboken6.json b/python3-shiboken6.json deleted file mode 100644 index 7488be78..00000000 --- a/python3-shiboken6.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "python3-shiboken6", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"shiboken6==6.4.1\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/72/ec/6bef61f5b07be13fd8255fdc5c66d8a097581cc58163457cc219ea3afe7b/shiboken6-6.4.1-cp37-abi3-manylinux_2_28_x86_64.whl", - "sha256": "41e67b67f65626bdd909f9c5fd5f80231ee6ae43418b331590ba225b3cfabd5b" - } - ] -} \ No newline at end of file diff --git a/python3-suntime.json b/python3-suntime.json deleted file mode 100644 index f14f0ba0..00000000 --- a/python3-suntime.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "python3-suntime", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"suntime\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/36/7a/87837f39d0296e723bb9b62bbb257d0355c7f6128853c78955f57342a56d/python_dateutil-2.8.2-py2.py3-none-any.whl", - "sha256": "961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - }, - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/93/95/a4eec0b36daeda6fa84b804da308211141d4a6ada13da228ecdf49600434/suntime-1.2.5-py3-none-any.whl", - "sha256": "d957e9ca786ab3cd80bf624b007fed7d07f07c6fa33f3ccc5ec34c9bb0c380c6" - } - ] -} \ No newline at end of file diff --git a/python3-systemd-python.json b/python3-systemd-python.json deleted file mode 100644 index 08b99dac..00000000 --- a/python3-systemd-python.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "python3-systemd-python", - "buildsystem": "simple", - "build-commands": [ - "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"systemd-python\" --no-build-isolation" - ], - "sources": [ - { - "type": "file", - "url": "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", - "sha256": "4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a" - } - ] -} \ No newline at end of file diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index bf990029..b5f3cea1 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -16,19 +16,12 @@ "--filesystem=~/.mozilla:rw" ], "modules": [ - "python3-numpy.json", - "python3-psutil.json", - "python3-python-dateutil.json", - "python3-suntime.json", - "python3-PySide6-Essentials.json", - "python3-PySide6-Addons.json", - "python3-systemd-python.json", - "python3-requests.json", + "generated-poetry-sources.json", { "name": "yin-yang", "buildsystem": "simple", "build-commands": [ - "python3 -m pip install --no-deps --no-use-pep517 --prefix=/app dist/yin_yang-*-py3-none-any.whl", + "pip install --no-deps --no-build-isolation --prefix=/app dist/yin_yang-*-py3-none-any.whl", "install -D runner.sh /app/bin/runner.sh" ], "sources": [ From cd60abb47d03c848a1a13009031f7b04760b79cb Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 14 Apr 2024 09:17:39 -0500 Subject: [PATCH 16/29] Add Github action for building Flatpak --- .github/workflows/flatpak-ci.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .github/workflows/flatpak-ci.yml diff --git a/.github/workflows/flatpak-ci.yml b/.github/workflows/flatpak-ci.yml new file mode 100644 index 00000000..8dd9d16b --- /dev/null +++ b/.github/workflows/flatpak-ci.yml @@ -0,0 +1,21 @@ +name: Flatpak CI Tests + +on: + push: + branches: [main] + pull_request: + +jobs: + flatpak: + name: "Flatpak" + runs-on: ubuntu-latest + container: + image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08 + options: --privileged + steps: + - uses: actions/checkout@v4 + - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 + with: + bundle: yin-yang.flatpak + manifest-path: sh.oskar.yin-yang.json + cache-key: flatpak-builder-${{ github.sha }} \ No newline at end of file From c50552ffcefad9e431fa560f003e78a02faddf52 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 14 Apr 2024 10:27:10 -0500 Subject: [PATCH 17/29] Setup pyright for VSCode usage Not excluding build dirs was causing VSCode's Intellisense completions to time out on my machine. I also set max line length to 90 chars since it's not 2001 anymore! --- .flake8 | 8 +++++++- pyproject.toml | 11 ++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/.flake8 b/.flake8 index af9bc26b..713d0e3d 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,8 @@ [flake8] -exclude = resources_rc.py,.venv,main_window.py +exclude = + resources_rc.py, + .venv, + main_window.py + build, + dist +max-line-length = 90 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index d00310af..311e6e7f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,4 +36,13 @@ requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] -yin-yang = "yin_yang:__main__" \ No newline at end of file +yin-yang = "yin_yang:__main__" + +[tool.pyright] +include = ["yin_yang"] +exclude = ["**/node_modules", + "**/__pycache__", + "build", + "pytest_cache", + ".flatpak-builder" +] \ No newline at end of file From 88fb7bc8c82a1f0c22be3b1c263ca0fd4b0be402 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 14 Apr 2024 10:32:00 -0500 Subject: [PATCH 18/29] Fix pip install path for ci environment --- sh.oskar.yin-yang.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index b5f3cea1..1c565d93 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -21,7 +21,7 @@ "name": "yin-yang", "buildsystem": "simple", "build-commands": [ - "pip install --no-deps --no-build-isolation --prefix=/app dist/yin_yang-*-py3-none-any.whl", + "find dist -name 'yin_yang-*-py3-none-any.whl' -exec pip install --no-deps --no-build-isolation --prefix=/app {} \\;", "install -D runner.sh /app/bin/runner.sh" ], "sources": [ From 2a41bb9603ea7921782223d1b2e8660abd589b4a Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Sun, 14 Apr 2024 20:36:47 -0500 Subject: [PATCH 19/29] Add VSCode test configs and fix pytest errors --- .vscode/launch.json | 2 +- .vscode/settings.json | 8 +++++++- pyproject.toml | 5 ++++- yin_yang/helpers.py | 22 ++++++++++++---------- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 37bc9fce..18c078ae 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Python: Main", + "name": "Debug Yin-Yang", "type": "debugpy", "request": "launch", "console": "integratedTerminal", diff --git a/.vscode/settings.json b/.vscode/settings.json index 0967ef42..4911468b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1 +1,7 @@ -{} +{ + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true +} diff --git a/pyproject.toml b/pyproject.toml index 311e6e7f..ed76a458 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,4 +45,7 @@ exclude = ["**/node_modules", "build", "pytest_cache", ".flatpak-builder" -] \ No newline at end of file +] + +[tool.pytest.ini_options] +addopts = "--import-mode=importlib" \ No newline at end of file diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 36046431..64afafaf 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -37,7 +37,7 @@ def check_call(command, stdout=None) -> int: def is_flatpak() -> bool: - return os.path.isfile('/.flatpak-info') + return os.path.isfile("/.flatpak-info") def get_usr() -> str: @@ -47,8 +47,8 @@ def get_usr() -> str: :return: The path to /usr with a trailing / """ if is_flatpak(): - return '/var/run/host/usr/' - return '/usr/' + return "/var/run/host/usr/" + return "/usr/" def get_etc() -> str: @@ -58,19 +58,21 @@ def get_etc() -> str: :return: The path to /etc with a trailing / """ if is_flatpak(): - return '/var/run/host/etc/' - return '/etc/' + return "/var/run/host/etc/" + return "/etc/" -def run(command: list[str], kwargs: list[str] = []) -> subprocess.CompletedProcess[str]: +def run( + command: list[str], kwargs: list[str] = [], stdout=None +) -> subprocess.CompletedProcess[str]: try: if len(kwargs) == 0: - return subprocess.run(command) + return subprocess.run(command, stdout=stdout) else: - return subprocess.run(command, **kwargs) + return subprocess.run(command, **kwargs, stdout=stdout) except FileNotFoundError: flatpak_args = base_flatpak_args + command if len(kwargs) == 0: - return subprocess.run(flatpak_args) + return subprocess.run(flatpak_args, stdout=stdout) else: - return subprocess.run(flatpak_args, **kwargs) + return subprocess.run(flatpak_args, **kwargs, stdout=stdout) From 1177eb0fd9602f7958fe3c687e97cf6b168e38d1 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Tue, 16 Apr 2024 19:19:23 -0500 Subject: [PATCH 20/29] Update workflow to separate building from CI --- .github/workflows/build-and-release.yml | 80 +++++++++++++++++++ .github/workflows/flatpak-ci.yml | 28 ------- .../{python-app.yml => python-ci.yml} | 0 3 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 .github/workflows/build-and-release.yml delete mode 100644 .github/workflows/flatpak-ci.yml rename .github/workflows/{python-app.yml => python-ci.yml} (100%) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml new file mode 100644 index 00000000..34657c78 --- /dev/null +++ b/.github/workflows/build-and-release.yml @@ -0,0 +1,80 @@ +name: Build and Release App + +on: + push: + branches: [master, beta] + # workflow_dispatch: + # release: + # types: [published] + +jobs: + build: + name: "Build application as Whl" + strategy: + fail-fast: false + matrix: + python-version: ["3.12"] + os: [ubuntu-22.04] + runs-on: ${{matrix.os}} + steps: + # Checkout repo and set up python + - uses: actions/checkout@v4 + - name: Install Python + uses: actions/setup-python@v5 + with: + python-version: ${{matrix.python-version}} + # Install and configure poetry + - name: Install Poetry + uses: abatilo/actions-poetry@v2 + - name: Set up local virtual environment + run: | + poetry config virtualenvs.create true --local + poetry config virtualenvs.in-project true --local + # Load cached venv if it exists + - name: Cache packages + id: cached-poetry-dependencies + uses: actions/cache@v4 + with: + # This path is specific to ubuntu + path: ./.venv + key: venv-${{ hashFiles('poetry.lock') }} + # Install dependencies of cache does not exist + - name: Install dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: | + sudo apt install qt6-base-dev libsystemd-dev gcc + poetry install --no-interaction + # Compile and build Yin-Yang + - name: Compile ui, translations and resources + run: poetry run ./scripts/build_ui.sh + - name: Build Whl for release + run: poetry build -f=wheel -n + # Upload build artifacts for later use + - name: Upload yin-yang whl for flatpak build + uses: actions/upload-artifact@v4 + with: + name: yin-yang-{{GITHUB_REF}}-py3-none-any.whl + path: dist/$(ls dist) + + flatpak: + name: "Build flatpak file" + runs-on: ubuntu-22.04 + container: + image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08 + options: --privileged + strategy: + matrix: + arch: [x86_64] + steps: + - uses: actions/checkout@v4 + - name: Download build from last step + uses: actions/download-artifact@v4 + with: + path: dist/ + name: yin-yang-{{GITHUB_REF}}-py3-none-any.whl + - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 + with: + bundle: yin-yang.flatpak + manifest-path: sh.oskar.yin-yang.json + cache-key: flatpak-builder-${{ github.sha }} + arch: ubuntu-22.04 \ No newline at end of file diff --git a/.github/workflows/flatpak-ci.yml b/.github/workflows/flatpak-ci.yml deleted file mode 100644 index 510b91f3..00000000 --- a/.github/workflows/flatpak-ci.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Flatpak CI Tests - -on: - push: - branches: [main] - pull_request: - -jobs: - flatpak: - name: "Flatpak" - runs-on: ubuntu-latest - container: - image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08 - options: --privileged - strategy: - matrix: - arch: [x86_64] - steps: - - uses: actions/checkout@v4 - - name: Install packaging deps - run: | - dnf -y install gcc systemd-devel python3-devel libnotify poetry - - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 - with: - bundle: yin-yang.flatpak - manifest-path: sh.oskar.yin-yang.json - cache-key: flatpak-builder-${{ github.sha }} - arch: ${{ matrix.arch }} \ No newline at end of file diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-ci.yml similarity index 100% rename from .github/workflows/python-app.yml rename to .github/workflows/python-ci.yml From df0f785a7be16fe5bea1feed24b126b97579ca7d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Tue, 16 Apr 2024 19:25:32 -0500 Subject: [PATCH 21/29] New commit to get workflow to run --- .github/workflows/build-and-release.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 34657c78..cc0a46af 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -2,10 +2,7 @@ name: Build and Release App on: push: - branches: [master, beta] - # workflow_dispatch: - # release: - # types: [published] + pull_request: jobs: build: @@ -48,17 +45,18 @@ jobs: - name: Compile ui, translations and resources run: poetry run ./scripts/build_ui.sh - name: Build Whl for release - run: poetry build -f=wheel -n + run: poetry build -f wheel -n -o . # Upload build artifacts for later use - name: Upload yin-yang whl for flatpak build uses: actions/upload-artifact@v4 with: - name: yin-yang-{{GITHUB_REF}}-py3-none-any.whl - path: dist/$(ls dist) + name: yin-yang-${{ github.sha }}-py3-none-any.whl + path: '*.whl' flatpak: name: "Build flatpak file" runs-on: ubuntu-22.04 + needs: build container: image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08 options: --privileged @@ -71,7 +69,7 @@ jobs: uses: actions/download-artifact@v4 with: path: dist/ - name: yin-yang-{{GITHUB_REF}}-py3-none-any.whl + name: yin-yang-${{ github.sha }}-py3-none-any.whl - uses: flatpak/flatpak-github-actions/flatpak-builder@v6 with: bundle: yin-yang.flatpak From 9209b0c682277efb0984d061c8985dc442146b1d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Tue, 16 Apr 2024 19:52:15 -0500 Subject: [PATCH 22/29] Add cache to base CI workflow --- .github/workflows/build-and-release.yml | 8 +++++--- .github/workflows/python-ci.yml | 10 ++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index cc0a46af..ff526d05 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -1,4 +1,4 @@ -name: Build and Release App +name: Build and Release Yin-Yang on: push: @@ -36,10 +36,12 @@ jobs: path: ./.venv key: venv-${{ hashFiles('poetry.lock') }} # Install dependencies of cache does not exist - - name: Install dependencies - if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + - name: Install system dependencies run: | sudo apt install qt6-base-dev libsystemd-dev gcc + - name: Install Poetry dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: | poetry install --no-interaction # Compile and build Yin-Yang - name: Compile ui, translations and resources diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 6c615b52..aed09b2a 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -29,15 +29,21 @@ jobs: poetry config virtualenvs.create true --local poetry config virtualenvs.in-project true --local - name: Cache packages + id: cached-poetry-dependencies uses: actions/cache@v4 with: # This path is specific to ubuntu path: ./.venv key: venv-${{ hashFiles('poetry.lock') }} - - name: Install dependencies + # Install dependencies + - name: Install system dependencies run: | sudo apt install qt6-base-dev libsystemd-dev gcc - poetry install + - name: Install Poetry dependencies + if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true' + run: | + poetry install --no-interaction + # Build and test Yin-Yang - name: Compile ui, translations and resources run: poetry run ./scripts/build_ui.sh - name: Lint with flake8 From 0736169e876c06b8793b95571962fa068e3535e1 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 15:22:37 -0500 Subject: [PATCH 23/29] Fix bad import on gtk.py --- yin_yang/plugins/gtk.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/yin_yang/plugins/gtk.py b/yin_yang/plugins/gtk.py index b30b84de..e5a95107 100755 --- a/yin_yang/plugins/gtk.py +++ b/yin_yang/plugins/gtk.py @@ -7,7 +7,12 @@ from yin_yang import helpers from ..meta import Desktop -from ._plugin import DBusPlugin, PluginCommandline, PluginDesktopDependent +from ._plugin import ( + DBusPlugin, + PluginCommandline, + PluginDesktopDependent, + themes_from_theme_directories, +) from .system import test_gnome_availability logger = logging.getLogger(__name__) From 38baf40a9065e9d945899775b44d84840c043bae Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:16:59 -0500 Subject: [PATCH 24/29] Standardize on single quotes --- .vscode/settings.json | 5 +- yin_yang/NotificationHandler.py | 18 ++--- yin_yang/helpers.py | 12 +-- yin_yang/plugins/custom.py | 5 +- yin_yang/plugins/gtk.py | 72 ++++++++--------- yin_yang/plugins/icons.py | 42 +++++++--- yin_yang/plugins/konsole.py | 134 ++++++++++++++++---------------- yin_yang/plugins/system.py | 106 ++++++++++++------------- 8 files changed, 211 insertions(+), 183 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4911468b..be93e3d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,8 @@ "tests" ], "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true + "python.testing.pytestEnabled": true, + "black-formatter.args": [ + "--skip-string-normalization" + ] } diff --git a/yin_yang/NotificationHandler.py b/yin_yang/NotificationHandler.py index 4ce908ed..cbd828e8 100644 --- a/yin_yang/NotificationHandler.py +++ b/yin_yang/NotificationHandler.py @@ -5,20 +5,20 @@ def create_dbus_message(title: str, body: str): message = QDBusMessage.createMethodCall( - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.Notification", - "AddNotification", + 'org.freedesktop.portal.Desktop', + '/org/freedesktop/portal/desktop', + 'org.freedesktop.portal.Notification', + 'AddNotification', ) notification = { - "title": title, - "body": body, - "icon": "yin_yang", - "priority": "low", + 'title': title, + 'body': body, + 'icon': 'yin_yang', + 'priority': 'low', } - message.setArguments(["YingYang.ThemeChanged", notification]) + message.setArguments(['YingYang.ThemeChanged', notification]) return message diff --git a/yin_yang/helpers.py b/yin_yang/helpers.py index 64afafaf..79d8c3d6 100644 --- a/yin_yang/helpers.py +++ b/yin_yang/helpers.py @@ -12,7 +12,7 @@ These are the base arguments we use to execute commands when running in a flatpak environment. """ -base_flatpak_args = ["flatpak-spawn", "--host"] +base_flatpak_args = ['flatpak-spawn', '--host'] def check_output(args, universal_newlines=False) -> bytes: @@ -37,7 +37,7 @@ def check_call(command, stdout=None) -> int: def is_flatpak() -> bool: - return os.path.isfile("/.flatpak-info") + return os.path.isfile('/.flatpak-info') def get_usr() -> str: @@ -47,8 +47,8 @@ def get_usr() -> str: :return: The path to /usr with a trailing / """ if is_flatpak(): - return "/var/run/host/usr/" - return "/usr/" + return '/var/run/host/usr/' + return '/usr/' def get_etc() -> str: @@ -58,8 +58,8 @@ def get_etc() -> str: :return: The path to /etc with a trailing / """ if is_flatpak(): - return "/var/run/host/etc/" - return "/etc/" + return '/var/run/host/etc/' + return '/etc/' def run( diff --git a/yin_yang/plugins/custom.py b/yin_yang/plugins/custom.py index 7e1e87f7..14a0a314 100644 --- a/yin_yang/plugins/custom.py +++ b/yin_yang/plugins/custom.py @@ -1,6 +1,7 @@ from PySide6.QtWidgets import QLineEdit from yin_yang import helpers + from ._plugin import PluginCommandline @@ -17,8 +18,8 @@ def available(self) -> bool: def get_input(self, widget): inputs: list[QLineEdit | QLineEdit] = super().get_input(widget) - inputs[0].setPlaceholderText("Light script") - inputs[1].setPlaceholderText("Dark script") + inputs[0].setPlaceholderText('Light script') + inputs[1].setPlaceholderText('Dark script') return inputs def set_theme(self, theme: str): diff --git a/yin_yang/plugins/gtk.py b/yin_yang/plugins/gtk.py index e5a95107..6a08cd71 100755 --- a/yin_yang/plugins/gtk.py +++ b/yin_yang/plugins/gtk.py @@ -19,7 +19,7 @@ class Gtk(PluginDesktopDependent): - name = "GTK" + name = 'GTK' def __init__(self, desktop: Desktop): match desktop: @@ -29,8 +29,8 @@ def __init__(self, desktop: Desktop): super().__init__(_Gnome()) if not self.strategy.available: print( - "You need to install an extension for gnome to use it. \n" - "You can get it from here: https://extensions.gnome.org/extension/19/user-themes/" + 'You need to install an extension for gnome to use it. \n' + 'You can get it from here: https://extensions.gnome.org/extension/19/user-themes/' ) case Desktop.MATE: super().__init__(_Mate()) @@ -45,19 +45,19 @@ def __init__(self, desktop: Desktop): @property def available_themes(self) -> dict: - themes = themes_from_theme_directories("gtk-3.0") + themes = themes_from_theme_directories('gtk-3.0') return {t: t for t in themes} class _Gnome(PluginCommandline): - name = "GTK" + name = 'GTK' def __init__(self): super().__init__( - ["gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "{theme}"] + ['gsettings', 'set', 'org.gnome.desktop.interface', 'gtk-theme', '{theme}'] ) - self.theme_light = "Default" - self.theme_dark = "Default" + self.theme_light = 'Default' + self.theme_dark = 'Default' @property def available(self) -> bool: @@ -65,14 +65,14 @@ def available(self) -> bool: class _Budgie(PluginCommandline): - name = "GTK" + name = 'GTK' def __init__(self): super().__init__( - ["gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", "{theme}"] + ['gsettings', 'set', 'org.gnome.desktop.interface', 'gtk-theme', '{theme}'] ) - self.theme_light = "Default" - self.theme_dark = "Default" + self.theme_light = 'Default' + self.theme_dark = 'Default' @property def available(self) -> bool: @@ -80,16 +80,16 @@ def available(self) -> bool: class _Kde(DBusPlugin): - name = "GTK" + name = 'GTK' def __init__(self): super().__init__() - self.theme_light = "Breeze" - self.theme_dark = "Breeze" + self.theme_light = 'Breeze' + self.theme_dark = 'Breeze' def create_message(self, theme: str) -> QDBusMessage: message = QDBusMessage.createMethodCall( - "org.kde.GtkConfig", "/GtkConfig", "org.kde.GtkConfig", "setGtkTheme" + 'org.kde.GtkConfig', '/GtkConfig', 'org.kde.GtkConfig', 'setGtkTheme' ) message.setArguments([theme]) return message @@ -100,61 +100,61 @@ def set_theme(self, theme: str): if response.type() != QDBusMessage.MessageType.ErrorMessage: return - logger.warning("kde-gtk-config not available, trying xsettingsd") - xsettingsd_conf_path = Path.home() / ".config/xsettingsd/xsettingsd.conf" + logger.warning('kde-gtk-config not available, trying xsettingsd') + xsettingsd_conf_path = Path.home() / '.config/xsettingsd/xsettingsd.conf' if not xsettingsd_conf_path.exists(): - logger.warning("xsettingsd not available") + logger.warning('xsettingsd not available') return - with open(xsettingsd_conf_path, "r") as f: + with open(xsettingsd_conf_path, 'r') as f: lines = f.readlines() for i, line in enumerate(lines): - if line.startswith("Net/ThemeName"): + if line.startswith('Net/ThemeName'): lines[i] = f'Net/ThemeName "{theme}"\n' break - with open(xsettingsd_conf_path, "w") as f: + with open(xsettingsd_conf_path, 'w') as f: f.writelines(lines) # send signal to read new config - helpers.run(["killall", "-HUP", "xsettingsd"]) + helpers.run(['killall', '-HUP', 'xsettingsd']) class _Xfce(PluginCommandline): def __init__(self): super(_Xfce, self).__init__( - ["xfconf-query", "-c", "xsettings", "-p", "/Net/ThemeName", "-s", "{theme}"] + ['xfconf-query', '-c', 'xsettings', '-p', '/Net/ThemeName', '-s', '{theme}'] ) - self.theme_light = "Adwaita" - self.theme_dark = "Adwaita-dark" + self.theme_light = 'Adwaita' + self.theme_dark = 'Adwaita-dark' class _Mate(PluginCommandline): def __init__(self): super().__init__( - ["dconf", "write", "/org/mate/desktop/interface/gtk-theme", "'{theme}'"] + ['dconf', 'write', '/org/mate/desktop/interface/gtk-theme', '"{theme}"'] ) - self.theme_light = "Yaru" - self.theme_dark = "Yaru-dark" + self.theme_light = 'Yaru' + self.theme_dark = 'Yaru-dark' @property def available(self) -> bool: - return self.check_command(["dconf", "help"]) + return self.check_command(['dconf', 'help']) class _Cinnamon(PluginCommandline): def __init__(self): super().__init__( [ - "gsettings", - "set", - "org.cinnamon.desktop.interface", - "gtk-theme", + 'gsettings', + 'set', + 'org.cinnamon.desktop.interface', + 'gtk-theme', '"{theme}"', ] ) - self.theme_light = "Adwaita" - self.theme_dark = "Adwaita-dark" + self.theme_light = 'Adwaita' + self.theme_dark = 'Adwaita-dark' @property def available(self) -> bool: diff --git a/yin_yang/plugins/icons.py b/yin_yang/plugins/icons.py index c175ed15..e50c8a9d 100644 --- a/yin_yang/plugins/icons.py +++ b/yin_yang/plugins/icons.py @@ -1,9 +1,10 @@ -from .system import test_gnome_availability -from ..meta import Desktop -from ._plugin import PluginDesktopDependent, PluginCommandline import configparser +from os import path, scandir from pathlib import Path -from os import scandir, path + +from ..meta import Desktop +from ._plugin import PluginCommandline, PluginDesktopDependent +from .system import test_gnome_availability theme_directories = ['/usr/share/icons', f'{Path.home()}/.icons'] @@ -25,7 +26,9 @@ def __init__(self, desktop: Desktop): class _Mate(PluginCommandline): def __init__(self): - super().__init__(['dconf', 'write', '/org/mate/desktop/interface/icon-theme', '\'{theme}\'']) + super().__init__( + ['dconf', 'write', '/org/mate/desktop/interface/icon-theme', '\"{theme}\"'] + ) self.theme_light = 'Yaru' self.theme_dark = 'Yaru-dark' @@ -36,18 +39,34 @@ def available(self): class _Cinnamon(PluginCommandline): def __init__(self): - super().__init__(['gsettings', 'set', 'org.cinnamon.desktop.interface', 'icon-theme', '\"{theme}\"']) + super().__init__( + [ + 'gsettings', + 'set', + 'org.cinnamon.desktop.interface', + 'icon-theme', + '\"{theme}\"', + ] + ) self.theme_light = 'Mint-X' self.theme_dark = 'gnome' @property def available(self) -> bool: return test_gnome_availability(self.command) - + class _Budgie(PluginCommandline): def __init__(self): - super().__init__(['gsettings', 'set', 'org.gnome.desktop.interface', 'icon-theme', '\"{theme}\"']) + super().__init__( + [ + 'gsettings', + 'set', + 'org.gnome.desktop.interface', + 'icon-theme', + '\"{theme}\"', + ] + ) self.theme_light = 'Default' self.theme_dark = 'Default' @@ -64,10 +83,15 @@ def available_themes(self) -> dict: continue with scandir(directory) as entries: - themes.extend(d.name for d in entries if d.is_dir() and path.isfile(d.path + '/index.theme')) + themes.extend( + d.name + for d in entries + if d.is_dir() and path.isfile(d.path + '/index.theme') + ) return {t: t for t in themes} + class _Kde(PluginCommandline): def __init__(self): super().__init__(["/usr/lib/plasma-changeicons", r"{theme}"]) diff --git a/yin_yang/plugins/konsole.py b/yin_yang/plugins/konsole.py index a5954a30..cf304e08 100644 --- a/yin_yang/plugins/konsole.py +++ b/yin_yang/plugins/konsole.py @@ -18,23 +18,23 @@ class Konsole(Plugin): - """ + ''' Themes are profiles. To use a color scheme, create a new profile or edit one to use the desired color scheme. This is necessary to allow live theme changes. - """ + ''' - global_path = Path(helpers.get_usr() + "share/konsole") - config_path = Path.home() / ".config/konsolerc" + global_path = Path(helpers.get_usr() + 'share/konsole') + config_path = Path.home() / '.config/konsolerc' @property def user_path(self) -> Path: - return Path.home() / ".local/share/konsole" + return Path.home() / '.local/share/konsole' def __init__(self): super().__init__() - self._theme_light = "BlackOnWhite" - self._theme_dark = "Breeze" + self._theme_light = 'BlackOnWhite' + self._theme_dark = 'Breeze' @property def theme_light(self): @@ -59,10 +59,10 @@ def set_mode(self, dark: bool) -> bool: if not super().set_mode(dark): return False - profile = "Dark" if dark else "Light" + profile = 'Dark' if dark else 'Light' # update default profile, if application is started afterward - self.default_profile = profile + ".profile" + self.default_profile = profile + '.profile' # Set Konsole profile for all sessions @@ -70,32 +70,32 @@ def set_mode(self, dark: bool) -> bool: process_ids = [ proc.pid for proc in psutil.process_iter() - if proc.name() == "konsole" and proc.username() == os.getlogin() + if proc.name() == 'konsole' and proc.username() == os.getlogin() ] # loop: console processes for proc_id in process_ids: - logger.debug(f"Changing profile in konsole session {proc_id}") - set_profile(f"org.kde.konsole-{proc_id}", profile) - set_profile(f"org.kde.konsole-{proc_id}", profile, set_default_profile=True) + logger.debug(f'Changing profile in konsole session {proc_id}') + set_profile(f'org.kde.konsole-{proc_id}', profile) + set_profile(f'org.kde.konsole-{proc_id}', profile, set_default_profile=True) # konsole may don't have session dbus like above - set_profile("org.kde.konsole", profile) - set_profile("org.kde.yakuake", profile) - set_profile("org.kde.konsole", profile, set_default_profile=True) - set_profile("org.kde.yakuake", profile, set_default_profile=True) + set_profile('org.kde.konsole', profile) + set_profile('org.kde.yakuake', profile) + set_profile('org.kde.konsole', profile, set_default_profile=True) + set_profile('org.kde.yakuake', profile, set_default_profile=True) process_ids = [ proc.pid for proc in psutil.process_iter() - if proc.name() == "dolphin" and proc.username() == os.getlogin() + if proc.name() == 'dolphin' and proc.username() == os.getlogin() ] # loop: dolphin processes for proc_id in process_ids: - logger.debug(f"Changing profile in dolphin session {proc_id}") - set_profile(f"org.kde.dolphin-{proc_id}", profile) - set_profile(f"org.kde.dolphin-{proc_id}", profile, set_default_profile=True) + logger.debug(f'Changing profile in dolphin session {proc_id}') + set_profile(f'org.kde.dolphin-{proc_id}', profile) + set_profile(f'org.kde.dolphin-{proc_id}', profile, set_default_profile=True) return True @@ -111,9 +111,9 @@ def available_themes(self) -> dict: themes = dict( sorted( [ - (p.with_suffix("").name, p) + (p.with_suffix('').name, p) for p in chain(self.global_path.iterdir(), self.user_path.iterdir()) - if p.is_file() and p.suffix == ".colorscheme" + if p.is_file() and p.suffix == '.colorscheme' ] ) ) @@ -123,10 +123,10 @@ def available_themes(self) -> dict: for theme, theme_path in themes.items(): config_parser.read(theme_path) - theme_name = config_parser["General"]["Description"] + theme_name = config_parser['General']['Description'] themes_dict[theme] = theme_name - assert themes_dict != {}, "No themes found!" + assert themes_dict != {}, 'No themes found!' return themes_dict @property @@ -137,10 +137,10 @@ def available(self) -> bool: def default_profile(self): value = None # cant use config parser because of weird file structure - with self.config_path.open("r") as file: + with self.config_path.open('r') as file: for line in file: - # Search for the pattern "DefaultProfile=*" - match = re.search(r"DefaultProfile=(.*)", line) + # Search for the pattern 'DefaultProfile=*' + match = re.search(r'DefaultProfile=(.*)', line) # If a match is found, return the content of the wildcard '*' if match: @@ -151,61 +151,61 @@ def default_profile(self): if value is None: # use the first found profile for file in self.user_path.iterdir(): - if file.suffix == ".profile": + if file.suffix == '.profile': value = file.name break if value is not None: - logger.warning(f"No default profile found, using {value} instead.") + logger.warning(f'No default profile found, using {value} instead.') if value is None: # create a custom profile manually - file_content = """[Appearance] + file_content = '''[Appearance] ColorScheme=Breeze [General] Command=/bin/bash Name=Fish Parent=FALLBACK/ -""" +''' - with (self.user_path / "Default.profile").open("w") as file: + with (self.user_path / 'Default.profile').open('w') as file: file.writelines(file_content) - self.default_profile = "Default.profile" + self.default_profile = 'Default.profile' - return "Default.profile" + return 'Default.profile' return value @default_profile.setter def default_profile(self, value: str): - assert value.endswith(".profile") + assert value.endswith('.profile') - with self.config_path.open("r") as file: + with self.config_path.open('r') as file: lines = file.readlines() for i, line in enumerate(lines): - # Search for the pattern "DefaultProfile=*" - match = re.search(r"DefaultProfile=(.*)", line) + # Search for the pattern 'DefaultProfile=*' + match = re.search(r'DefaultProfile=(.*)', line) # If a match is found, return the content of the wildcard '*' if match: - logger.debug(f"Changing default profile to {value}") - lines[i] = f"DefaultProfile={value}\n" + logger.debug(f'Changing default profile to {value}') + lines[i] = f'DefaultProfile={value}\n' break else: - logger.debug("No default profile found") - with self.config_path.open("w") as file: + logger.debug('No default profile found') + with self.config_path.open('w') as file: file.writelines(lines) def update_profile(self, dark: bool, theme: str): - if not self.available or theme == "": + if not self.available or theme == '': # theme is empty string on super init return # update the color scheme setting in either dark or light profile - logger.debug("Updating konsole profile") + logger.debug('Updating konsole profile') - file_path = self.user_path / ("Dark.profile" if dark else "Light.profile") + file_path = self.user_path / ('Dark.profile' if dark else 'Light.profile') if not file_path.exists(): self.create_profiles() @@ -214,21 +214,21 @@ def update_profile(self, dark: bool, theme: str): profile_config.read(file_path) try: - profile_config["Appearance"]["ColorScheme"] = theme + profile_config['Appearance']['ColorScheme'] = theme except KeyError: - profile_config.add_section("Appearance") - profile_config["Appearance"]["ColorScheme"] = theme + profile_config.add_section('Appearance') + profile_config['Appearance']['ColorScheme'] = theme - with open(file_path, "w") as file: + with open(file_path, 'w') as file: profile_config.write(file) def create_profiles(self): logger.debug( - "Creating new profiles for live-switching between light and dark themes." + 'Creating new profiles for live-switching between light and dark themes.' ) # copy default profile to create theme profiles - light_profile = self.user_path / "Light.profile" - dark_profile = self.user_path / "Dark.profile" + light_profile = self.user_path / 'Light.profile' + dark_profile = self.user_path / 'Dark.profile' # TODO there is a parent profile section in the profile file, maybe we can use that (in a later version)? copyfile(self.user_path / self.default_profile, light_profile) copyfile(self.user_path / self.default_profile, dark_profile) @@ -238,15 +238,15 @@ def create_profiles(self): profile_config.optionxform = str profile_config.read(light_profile) - profile_config["General"]["Name"] = light_profile.stem + profile_config['General']['Name'] = light_profile.stem - with open(light_profile, "w") as file: + with open(light_profile, 'w') as file: profile_config.write(file) profile_config.read(dark_profile) - profile_config["General"]["Name"] = dark_profile.stem + profile_config['General']['Name'] = dark_profile.stem - with open(dark_profile, "w") as file: + with open(dark_profile, 'w') as file: profile_config.write(file) @@ -254,13 +254,13 @@ def set_profile(service: str, profile: str, set_default_profile: bool = False): # connect to the session bus connection = QDBusConnection.sessionBus() if set_default_profile: - path = "Sessions/" - interface = "org.kde.konsole.Session" - method = "setProfile" + path = 'Sessions/' + interface = 'org.kde.konsole.Session' + method = 'setProfile' else: - path = "Windows/" - interface = "org.kde.konsole.Window" - method = "setDefaultProfile" + path = 'Windows/' + interface = 'org.kde.konsole.Window' + method = 'setDefaultProfile' # maybe it's possible with pyside6 dbus packages, but this was simpler and worked try: @@ -270,15 +270,15 @@ def set_profile(service: str, profile: str, set_default_profile: bool = False): sessions = helpers.check_output( f'qdbus org.kde.konsole | grep "{path}"', shell=True ) - logger.debug(f"Found org.kde.konsole, use that instead") - service = "org.kde.konsole" + logger.debug(f'Found org.kde.konsole, use that instead') + service = 'org.kde.konsole' except subprocess.CalledProcessError: # happens when dolphins konsole is not opened logger.debug( - f"No Konsole sessions available in service {service}, skipping" + f'No Konsole sessions available in service {service}, skipping' ) return - sessions = sessions.decode("utf-8").removesuffix("\n").split("\n") + sessions = sessions.decode('utf-8').removesuffix('\n').split('\n') # loop: process sessions for session in sessions: diff --git a/yin_yang/plugins/system.py b/yin_yang/plugins/system.py index 8e05ec24..fb94da1a 100644 --- a/yin_yang/plugins/system.py +++ b/yin_yang/plugins/system.py @@ -22,7 +22,7 @@ def test_gnome_availability(command) -> bool: - return PluginCommandline.check_command([command[0], "get", command[2], command[3]]) + return PluginCommandline.check_command([command[0], 'get', command[2], command[3]]) class System(PluginDesktopDependent): @@ -45,18 +45,18 @@ def __init__(self, desktop: Desktop): class _Gnome(PluginCommandline): - name = "System" + name = 'System' # TODO allow using the default themes, not only user themes def __init__(self): super().__init__( [ - "gsettings", - "set", - "org.gnome.shell.extensions.user-theme", - "name", - "{theme}", + 'gsettings', + 'set', + 'org.gnome.shell.extensions.user-theme', + 'name', + '{theme}', ] ) @@ -66,20 +66,20 @@ def available(self) -> bool: class _Budgie(PluginCommandline): - name = "System" + name = 'System' def __init__(self): super().__init__( [ - "gsettings", - "set", - "com.solus-project.budgie-panel", - "dark-theme", - "{theme}", + 'gsettings', + 'set', + 'com.solus-project.budgie-panel', + 'dark-theme', + '{theme}', ] ) - self.theme_light = "light" - self.theme_dark = "dark" + self.theme_light = 'light' + self.theme_dark = 'dark' @property def available(self) -> bool: @@ -89,10 +89,10 @@ def available(self) -> bool: def insert_theme(self, theme: str) -> list: command = self.command.copy() match theme.lower(): - case "dark": - theme_bool = "true" - case "light": - theme_bool = "false" + case 'dark': + theme_bool = 'true' + case 'light': + theme_bool = 'false' case _: raise NotImplementedError @@ -103,44 +103,44 @@ def insert_theme(self, theme: str) -> list: @property def available_themes(self) -> dict: - themes: dict[str, str] = {"dark": "Dark", "light": "Light"} + themes: dict[str, str] = {'dark': 'Dark', 'light': 'Light'} return themes def get_readable_kde_theme_name(file) -> str: - """Searches for the long_name in the file and maps it to the found short name""" + '''Searches for the long_name in the file and maps it to the found short name''' for line in file: - if "Name=" in line: - name: str = "" + if 'Name=' in line: + name: str = '' write: bool = False for letter in line: - if letter == "\n": + if letter == '\n': write = False if write: name += letter - if letter == "=": + if letter == '=': write = True return name def get_name_key(meta): locale = filter( - lambda name: name in meta["KPlugin"], - [f"Name[{QLocale().name()}]", f"Name[{QLocale().language()}]", "Name"], + lambda name: name in meta['KPlugin'], + [f'Name[{QLocale().name()}]', f'Name[{QLocale().language()}]', 'Name'], ) return next(locale) class _Kde(PluginCommandline): - name = "System" + name = 'System' translations = {} def __init__(self): - super().__init__(["lookandfeeltool", "-a", "{theme}"]) - self.theme_light = "org.kde.breeze.desktop" - self.theme_dark = "org.kde.breezedark.desktop" + super().__init__(['lookandfeeltool', '-a', '{theme}']) + self.theme_light = 'org.kde.breeze.desktop' + self.theme_dark = 'org.kde.breezedark.desktop' @property def available_themes(self) -> dict: @@ -149,12 +149,12 @@ def available_themes(self) -> dict: # aliases for path to use later on user = pwd.getpwuid(os.getuid())[0] - path = "/home/" + user + "/.local/share/plasma/look-and-feel/" + path = '/home/' + user + '/.local/share/plasma/look-and-feel/' # asks the system what themes are available # noinspection SpellCheckingInspection long_names = helpers.check_output( - ["lookandfeeltool", "-l"], universal_newlines=True + ['lookandfeeltool', '-l'], universal_newlines=True ) long_names = long_names.splitlines() long_names.sort() @@ -165,25 +165,25 @@ def available_themes(self) -> dict: try: # json in newer versions with open( - f"{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.json", - "r", + f'{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.json', + 'r', ) as file: meta = json.load(file) key = get_name_key(meta) - self.translations[long_name] = meta["KPlugin"][key] + self.translations[long_name] = meta['KPlugin'][key] except OSError: try: # load the name from the metadata.desktop file with open( - f"{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.desktop", - "r", + f'{helpers.get_usr()}share/plasma/look-and-feel/{long_name}/metadata.desktop', + 'r', ) as file: self.translations[long_name] = get_readable_kde_theme_name(file) except OSError: # check the next path if the themes exist there try: # load the name from the metadata.desktop file - with open(f"{path}{long_name}/metadata.desktop", "r") as file: + with open(f'{path}{long_name}/metadata.desktop', 'r') as file: # search for the name self.translations[long_name] = get_readable_kde_theme_name( file @@ -197,16 +197,16 @@ def available_themes(self) -> dict: class _Mate(PluginCommandline): theme_directories = [ - Path(helpers.get_usr() + "share/themes"), - Path.home() / ".themes", + Path(helpers.get_usr() + 'share/themes'), + Path.home() / '.themes', ] def __init__(self): super().__init__( - ["dconf", "write", "/org/mate/marco/general/theme", "'{theme}'"] + ['dconf', 'write', '/org/mate/marco/general/theme', '"{theme}"'] ) - self.theme_light = "Yaru" - self.theme_dark = "Yaru-dark" + self.theme_light = 'Yaru' + self.theme_dark = 'Yaru-dark' @property def available_themes(self) -> dict: @@ -217,14 +217,14 @@ def available_themes(self) -> dict: continue for d in directory.iterdir(): - index = d / "index.theme" + index = d / 'index.theme' if not index.is_file(): continue config = ConfigParser() config.read(index) try: - theme = config["X-GNOME-Metatheme"]["MetacityTheme"] + theme = config['X-GNOME-Metatheme']['MetacityTheme'] themes.append(theme) except KeyError: continue @@ -233,16 +233,16 @@ def available_themes(self) -> dict: @property def available(self): - return self.check_command(["dconf", "help"]) + return self.check_command(['dconf', 'help']) class _Cinnamon(PluginCommandline): def __init__(self): super().__init__( - ["gsettings", "set", "org.cinnamon.theme", "name", '"{theme}"'] + ['gsettings', 'set', 'org.cinnamon.theme', 'name', '"{theme}"'] ) - self.theme_light = "Mint-X-Teal" - self.theme_dark = "Mint-Y-Dark-Brown" + self.theme_light = 'Mint-X-Teal' + self.theme_dark = 'Mint-Y-Dark-Brown' @property def available(self) -> bool: @@ -252,14 +252,14 @@ def available(self) -> bool: class _Xfce(DBusPlugin): def create_message(self, theme: str) -> QDBusMessage: message = QDBusMessage.createMethodCall( - "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "SetProperty" + 'org.xfce.Xfconf', '/org/xfce/Xfconf', 'org.xfce.Xfconf', 'SetProperty' ) theme_variant = QDBusVariant() theme_variant.setVariant(theme) - message.setArguments(["xfwm4", "/general/theme", theme_variant]) + message.setArguments(['xfwm4', '/general/theme', theme_variant]) return message @property def available_themes(self) -> dict: - themes = themes_from_theme_directories("xfwm4") + themes = themes_from_theme_directories('xfwm4') return {t: t for t in themes} From 0550cf0d5fe81cbece88d32b7a28c8350f36fa8d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:17:30 -0500 Subject: [PATCH 25/29] Add back in assertion to firefox.py --- yin_yang/plugins/firefox.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yin_yang/plugins/firefox.py b/yin_yang/plugins/firefox.py index 2cd47769..a95d347b 100755 --- a/yin_yang/plugins/firefox.py +++ b/yin_yang/plugins/firefox.py @@ -1,6 +1,6 @@ import json -from configparser import ConfigParser import logging +from configparser import ConfigParser from os.path import isdir from pathlib import Path @@ -48,7 +48,7 @@ def available_themes(self) -> dict: logger.warning(f'Firefox profile has no extensions installed: {path}') continue - # assert themes != {}, 'No themes found!' + assert themes != {}, 'No themes found!' return themes @property From dbae8f2f7ee22edf40c3e6adf8004e79f653557d Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:18:39 -0500 Subject: [PATCH 26/29] Remove print statement from colors.py --- yin_yang/plugins/colors.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/yin_yang/plugins/colors.py b/yin_yang/plugins/colors.py index c2f818ad..15e7febc 100644 --- a/yin_yang/plugins/colors.py +++ b/yin_yang/plugins/colors.py @@ -1,8 +1,9 @@ import re + from yin_yang import helpers from ..meta import Desktop -from ._plugin import Plugin, PluginDesktopDependent, PluginCommandline +from ._plugin import Plugin, PluginCommandline, PluginDesktopDependent class Colors(PluginDesktopDependent): @@ -18,7 +19,7 @@ def strategy(self) -> Plugin: class _KDEColors(PluginCommandline): - name = "Colors" + name = 'Colors' translations = {} def __init__(self): @@ -30,9 +31,12 @@ def available_themes(self) -> dict: if self.translations: return self.translations - colors = str(helpers.check_output(['plasma-apply-colorscheme', '--list-schemes'], - universal_newlines=True)) - print(colors) + colors = str( + helpers.check_output( + ['plasma-apply-colorscheme', '--list-schemes'], universal_newlines=True + ) + ) + colors = colors.splitlines() del colors[0] From 4757a612f02ece433e4163851c8719c151a1b21f Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:20:48 -0500 Subject: [PATCH 27/29] Remove unnesseccary TODO and refactor daemon_handler.py --- yin_yang/daemon_handler.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/yin_yang/daemon_handler.py b/yin_yang/daemon_handler.py index 096b2f8d..1342720d 100644 --- a/yin_yang/daemon_handler.py +++ b/yin_yang/daemon_handler.py @@ -1,11 +1,11 @@ import logging +import re import shutil -import subprocess from enum import Enum, auto from pathlib import Path -import re from yin_yang import helpers + from .config import ConfigWatcher, config from .meta import ConfigEvent, Modes @@ -15,7 +15,6 @@ SERVICE_PATH = SYSTEMD_PATH / 'yin_yang.service' - def create_files(): logger.debug('Creating systemd files') if not SYSTEMD_PATH.is_dir(): @@ -24,13 +23,20 @@ def create_files(): shutil.copy('./resources/yin_yang.timer', TIMER_PATH) if not SERVICE_PATH.is_file(): shutil.copy('./resources/yin_yang.service', SERVICE_PATH) - # TODO: Will this cause an issue switching back from flatpak? - if (helpers.is_flatpak()): + if helpers.is_flatpak(): with open(SERVICE_PATH, 'r') as service: lines = service.readlines() with open(SERVICE_PATH, 'w') as service: for line in lines: - service.write(re.sub('ExecStart=\/usr\/bin\/yin-yang --systemd', 'ExecStart='+str(Path.home())+'/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd', line)) + service.write( + re.sub( + 'ExecStart=\/usr\/bin\/yin-yang --systemd', + 'ExecStart=' + + str(Path.home()) + + '/.local/share/flatpak/exports/bin/sh.oskar.yin-yang --systemd', + line, + ) + ) def run_command(command, **kwargs): @@ -70,7 +76,9 @@ class _UpdateTimerStatus(Enum): STOP = auto() def __init__(self): - self._next_timer_update: SaveWatcher._UpdateTimerStatus = SaveWatcher._UpdateTimerStatus.NO_UPDATE + self._next_timer_update: SaveWatcher._UpdateTimerStatus = ( + SaveWatcher._UpdateTimerStatus.NO_UPDATE + ) def _set_needed_updates(self, change_values): assert change_values['old_value'] != change_values['new_value'], 'No change!' @@ -83,7 +91,9 @@ def _set_needed_updates(self, change_values): elif change_values['new_value'] == Modes.MANUAL.value: self._next_timer_update = SaveWatcher._UpdateTimerStatus.STOP else: - self._next_timer_update = SaveWatcher._UpdateTimerStatus.UPDATE_TIMES + self._next_timer_update = ( + SaveWatcher._UpdateTimerStatus.UPDATE_TIMES + ) case 'times' | 'coordinates' | 'boot_offset': self._next_timer_update = SaveWatcher._UpdateTimerStatus.UPDATE_TIMES @@ -91,7 +101,10 @@ def _update_timer(self): match self._next_timer_update: case SaveWatcher._UpdateTimerStatus.STOP: run_command('stop') - case SaveWatcher._UpdateTimerStatus.UPDATE_TIMES | SaveWatcher._UpdateTimerStatus.START: + case ( + SaveWatcher._UpdateTimerStatus.UPDATE_TIMES + | SaveWatcher._UpdateTimerStatus.START + ): update_times() self._next_timer_update = SaveWatcher._UpdateTimerStatus.NO_UPDATE From 5111101f836dc7e6a5bc84cbb55943eeb3133c67 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:45:55 -0500 Subject: [PATCH 28/29] Downgrade required python version to 3.10 --- generated-poetry-sources.json | 12 +++++++++++- poetry.lock | 31 +++++++++++++++++++++++++++++-- pyproject.toml | 2 +- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/generated-poetry-sources.json b/generated-poetry-sources.json index 57a8dd3f..f15b254e 100644 --- a/generated-poetry-sources.json +++ b/generated-poetry-sources.json @@ -2,7 +2,7 @@ "name": "poetry-deps", "buildsystem": "simple", "build-commands": [ - "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} certifi charset-normalizer colorama cython flake8 idna iniconfig mccabe packaging pluggy psutil pycodestyle pyflakes pyside6-addons pyside6-essentials pytest python-dateutil pyyaml requests setuptools shiboken6 six suntime systemd-python toml urllib3 wheel" + "pip3 install --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} certifi charset-normalizer colorama cython exceptiongroup flake8 idna iniconfig mccabe packaging pluggy psutil pycodestyle pyflakes pyside6-addons pyside6-essentials pytest python-dateutil pyyaml requests setuptools shiboken6 six suntime systemd-python toml tomli urllib3 wheel" ], "sources": [ { @@ -25,6 +25,11 @@ "url": "https://files.pythonhosted.org/packages/7e/26/9d8de10005fedb1eceabe713348d43bae1dbab1786042ca0751a2e2b0f8c/Cython-0.29.37-py2.py3-none-any.whl", "sha256": "95f1d6a83ef2729e67b3fa7318c829ce5b07ac64c084cd6af11c228e0364662c" }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/01/90/79fe92dd413a9cab314ef5c591b5aa9b9ba787ae4cadab75055b0ae00b33/exceptiongroup-1.2.1-py3-none-any.whl", + "sha256": "5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad" + }, { "type": "file", "url": "https://files.pythonhosted.org/packages/e3/01/cc8cdec7b61db0315c2ab62d80677a138ef06832ec17f04d87e6ef858f7f/flake8-7.0.0-py2.py3-none-any.whl", @@ -130,6 +135,11 @@ "url": "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", "sha256": "806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" }, + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc" + }, { "type": "file", "url": "https://files.pythonhosted.org/packages/a2/73/a68704750a7679d0b6d3ad7aa8d4da8e14e151ae82e6fee774e6e0d05ec8/urllib3-2.2.1-py3-none-any.whl", diff --git a/poetry.lock b/poetry.lock index 16c467a9..f8331fc0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -172,6 +172,20 @@ files = [ {file = "Cython-0.29.37.tar.gz", hash = "sha256:f813d4a6dd94adee5d4ff266191d1d95bf6d4164a4facc535422c021b2504cfb"}, ] +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, + {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "flake8" version = "7.0.0" @@ -343,9 +357,11 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" pluggy = ">=1.4,<2.0" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] @@ -520,6 +536,17 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + [[package]] name = "urllib3" version = "2.2.1" @@ -553,5 +580,5 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [metadata] lock-version = "2.0" -python-versions = "^3.11,<3.13" -content-hash = "80cb53843cb453c3213b1e16e0be79bcd3116bf0084f75e2167ae6498c86a538" +python-versions = "^3.10,<3.13" +content-hash = "0fafd0ba61f1f9f40d4cf556a63e2ed5e073dc6c36a7bc56183be2d7bcd56725" diff --git a/pyproject.toml b/pyproject.toml index ed76a458..27241891 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ packages = [ ] [tool.poetry.dependencies] -python = "^3.11,<3.13" +python = "^3.10,<3.13" psutil = "5.9.8" PySide6-Essentials = "6.6.3.1" shiboken6 = "6.6.3.1" From 1820b6a5dd635b380e18e970076a5793c323f5c1 Mon Sep 17 00:00:00 2001 From: Chase Lau Date: Fri, 19 Apr 2024 18:49:46 -0500 Subject: [PATCH 29/29] Move runner.sh to scripts folder --- runner.sh => scripts/runner.sh | 0 sh.oskar.yin-yang.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename runner.sh => scripts/runner.sh (100%) diff --git a/runner.sh b/scripts/runner.sh similarity index 100% rename from runner.sh rename to scripts/runner.sh diff --git a/sh.oskar.yin-yang.json b/sh.oskar.yin-yang.json index 1c565d93..1bf0de24 100644 --- a/sh.oskar.yin-yang.json +++ b/sh.oskar.yin-yang.json @@ -22,7 +22,7 @@ "buildsystem": "simple", "build-commands": [ "find dist -name 'yin_yang-*-py3-none-any.whl' -exec pip install --no-deps --no-build-isolation --prefix=/app {} \\;", - "install -D runner.sh /app/bin/runner.sh" + "install -D scripts/runner.sh /app/bin/runner.sh" ], "sources": [ {