From e2c3be25a2205b43ed4f63c2c75c84d2b85331b3 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 1 Jun 2025 18:12:20 +0800 Subject: [PATCH] feat: add `black` formatter --- pyproject.toml | 16 ++++++++-- src/syncplay_boot/boot.py | 56 +++++++++++++++++++++++---------- tests/test_convert.py | 30 ++++++++++-------- uv.lock | 65 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 32 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 521f6f5..fab2efb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ dependencies = [ [dependency-groups] dev = [ + "black>=25.1.0", "pyright>=1.1.400", "pytest>=8.3.5", "ruff>=0.11.10", @@ -28,19 +29,28 @@ dev = [ ] [tool.uv.sources] -syncplay = { path = "./src/syncplay/" } +syncplay = { path = "src/syncplay" } [tool.ruff] line-length = 120 target-version = "py312" lint.select = ["E", "F", "B", "N", "W"] -lint.ignore = ["E701"] +exclude = ["src/syncplay"] + +[tool.black] +line-length = 120 +target-version = ["py312"] +skip-string-normalization = true +include = "(src/syncplay_boot|tests)" [tool.pyright] pythonVersion = "3.12" typeCheckingMode = "basic" pythonPlatform = "All" -include = ["src"] +include = [ + "src/syncplay_boot", + "tests", +] [tool.hatch.version] path = "src/syncplay/syncplay/__init__.py" diff --git a/src/syncplay_boot/boot.py b/src/syncplay_boot/boot.py index de8e380..718104f 100644 --- a/src/syncplay_boot/boot.py +++ b/src/syncplay_boot/boot.py @@ -101,13 +101,17 @@ CFG_OPTS: dict[str, tuple[type, bool]] = {} # for loading configure file def debug_msg(prefix: str, message: Any) -> None: - """ Output debug message. """ + """ + Output debug message. + """ if os.environ.get('DEBUG', '').upper() in ['ON', 'TRUE']: print(f'\033[33m{prefix}\033[0m -> \033[90m{message}\033[0m', file=sys.stderr) def init_opts() -> None: - """ Build syncplay formatting options. """ + """ + Build syncplay formatting options. + """ for name, field in SyncplayOptions.__annotations__.items(): field_t, is_list = field.__args__[0], False if type(field_t) is GenericAlias: @@ -131,7 +135,9 @@ def init_opts() -> None: def load_from_env() -> SyncplayOptions: - """ Load syncplay options from environment variables. """ + """ + Load syncplay options from environment variables. + """ options: SyncplayOptions = {} for name, field_t in ENV_OPTS.items(): if name.upper() in os.environ: @@ -148,21 +154,30 @@ def load_from_env() -> SyncplayOptions: def load_from_args() -> SyncplayOptions: - """ Load syncplay options from command line arguments. """ + """ + Load syncplay options from command line arguments. + """ def __version_msg() -> str: python_ver = f'{platform.python_implementation()} {platform.python_version()}' - return (f'{parser.description} v{syncplay.version} ' - f'({syncplay.milestone} {syncplay.release_number}) ' - f'[{python_ver} {platform.machine()}]') + return ( + f'{parser.description} v{syncplay.version} ' + f'({syncplay.milestone} {syncplay.release_number}) ' + f'[{python_ver} {platform.machine()}]' + ) def __build_args(opt: str) -> list[str]: match opt := opt.replace('_', '-'): - case 'config': return ['-c', f'--{opt}'] - case 'port': return ['-p', f'--{opt}'] - case 'motd': return ['-m', f'--{opt}'] - case 'password': return ['-k', f'--{opt}'] - case _: return [f'--{opt}'] + case 'config': + return ['-c', f'--{opt}'] + case 'port': + return ['-p', f'--{opt}'] + case 'motd': + return ['-m', f'--{opt}'] + case 'password': + return ['-k', f'--{opt}'] + case _: + return [f'--{opt}'] parser = argparse.ArgumentParser(description='Syncplay Docker Bootstrap') parser.add_argument('-v', '--version', action='version', version=__version_msg()) @@ -181,7 +196,9 @@ def load_from_args() -> SyncplayOptions: def load_from_config(path: str) -> SyncplayOptions: - """ Load syncplay options from configure file. """ + """ + Load syncplay options from configure file. + """ def __load_file() -> dict[str, Any]: if not os.path.exists(path): @@ -211,7 +228,9 @@ def load_from_config(path: str) -> SyncplayOptions: def load_opts() -> SyncplayOptions: - """ Combine syncplay options from multiple source. """ + """ + Combine syncplay options from multiple source. + """ env_opts = load_from_env() cli_opts = load_from_args() cfg_opts = load_from_config((env_opts | cli_opts).get('config', 'config.yml')) @@ -229,10 +248,14 @@ def load_opts() -> SyncplayOptions: def sp_convert(opts: SyncplayOptions) -> list[str]: - """ Construct the startup arguments for syncplay server. """ + """ + Construct the startup arguments for syncplay server. + """ def __temp_file(file: str, content: str) -> str: - """ Create and save content to temporary files. """ + """ + Create and save content to temporary files. + """ file = os.path.join(temp_dir, file) with open(file, 'w', encoding='utf-8') as fp: fp.write(content) @@ -288,6 +311,7 @@ def bootstrap(opts: SyncplayOptions | None = None) -> None: debug_msg('Syncplay startup arguments', sys.argv) from syncplay import ep_server + sys.exit(ep_server.main()) diff --git a/tests/test_convert.py b/tests/test_convert.py index fcd422f..81033aa 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -35,12 +35,12 @@ def convert_builder(keep_port: bool = False, keep_salt: bool = False) -> Callabl if not keep_port: if '--port' in output and '8999' in output: if (index := output.index('--port')) + 1 == output.index('8999'): - output = output[:index] + output[index + 2:] + output = output[:index] + output[index + 2 :] if not keep_salt: if '--salt' in output and '' in output: if (index := output.index('--salt')) + 1 == output.index(''): - output = output[:index] + output[index + 2:] + output = output[:index] + output[index + 2 :] return output @@ -96,9 +96,9 @@ def test_boolean_flags() -> None: Test boolean flags handling of options conversion. """ convert = convert_builder() - assert convert({'isolate_rooms': True}) == [f'--isolate-rooms'] - assert convert({'disable_chat': True}) == [f'--disable-chat'] - assert convert({'disable_ready': True}) == [f'--disable-ready'] + assert convert({'isolate_rooms': True}) == ['--isolate-rooms'] + assert convert({'disable_chat': True}) == ['--disable-chat'] + assert convert({'disable_ready': True}) == ['--disable-ready'] assert convert({'enable_stats': True}) == ['--stats-db-file', '/data/stats.db'] assert convert({'enable_tls': True}) == ['--tls', '/certs/'] @@ -132,8 +132,12 @@ def test_ip_configure() -> None: convert = convert_builder() assert convert({}) == [] assert convert({'listen_ipv4': '0.0.0.0'}) == ['--ipv4-only', '--interface-ipv4', '0.0.0.0'] - assert convert({'listen_ipv6': '::'}) == ['--ipv6-only', '--interface-ipv6', '::'] - assert convert({'listen_ipv4': '0.0.0.0', 'listen_ipv6': '::'}) == ['--interface-ipv4', '0.0.0.0', '--interface-ipv6', '::'] + assert convert({'listen_ipv6': 'fc00::1'}) == ['--ipv6-only', '--interface-ipv6', 'fc00::1'] + # fmt: off + assert convert({'listen_ipv4': '0.0.0.0', 'listen_ipv6': 'fc00::1'}) == [ + '--interface-ipv4', '0.0.0.0', + '--interface-ipv6', 'fc00::1', + ] # fmt: on def test_path_env(temp_dir_setup) -> None: @@ -157,7 +161,7 @@ def test_full_options() -> None: Test full options conversion. """ convert = convert_builder(keep_port=True, keep_salt=True) - options = convert({ + opts: boot.SyncplayOptions = { 'port': 12345, 'password': 'secret', 'motd': 'Welcome to Syncplay', @@ -173,9 +177,9 @@ def test_full_options() -> None: 'max_chat_message': 500, 'permanent_rooms': ['room1', 'room2', 'room3'], 'listen_ipv4': '0.0.0.0', - 'listen_ipv6': '::' - }) - + 'listen_ipv6': '::', + } + # fmt: off expected = [ '--port', '12345', '--password', 'secret', @@ -192,6 +196,6 @@ def test_full_options() -> None: '--permanent-rooms-file', '/tmp/rooms.list', '--interface-ipv4', '0.0.0.0', '--interface-ipv6', '::' - ] + ] # fmt: on - assert options == expected + assert convert(opts) == expected diff --git a/uv.lock b/uv.lock index 34f39b5..d017e1f 100644 --- a/uv.lock +++ b/uv.lock @@ -29,6 +29,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/02/ff/1175b0b7371e46244032d43a56862d0af455823b5280a50c63d99cc50f18/automat-25.4.16-py3-none-any.whl", hash = "sha256:04e9bce696a8d5671ee698005af6e5a9fa15354140a87f4870744604dcdd3ba1", size = 42842, upload-time = "2025-04-16T20:12:14.447Z" }, ] +[[package]] +name = "black" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, + { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, + { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, + { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, + { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673, upload-time = "2025-01-29T05:37:20.574Z" }, + { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190, upload-time = "2025-01-29T05:37:22.106Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926, upload-time = "2025-01-29T04:18:58.564Z" }, + { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613, upload-time = "2025-01-29T04:19:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, +] + [[package]] name = "certifi" version = "2025.4.26" @@ -71,6 +95,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, ] +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -166,6 +202,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, ] +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -184,6 +229,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + [[package]] name = "pem" version = "23.1.0" @@ -193,6 +247,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/97/8299a481ae6c08494b5d53511e6a4746775d8a354c685c69d8796b2ed482/pem-23.1.0-py3-none-any.whl", hash = "sha256:78bbb1e75b737891350cb9499cbba31da5d59545f360f44163c0bc751cad55d3", size = 9195, upload-time = "2023-06-21T10:24:39.164Z" }, ] +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + [[package]] name = "pluggy" version = "1.6.0" @@ -406,6 +469,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "black" }, { name = "pyright" }, { name = "pytest" }, { name = "ruff" }, @@ -420,6 +484,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "black", specifier = ">=25.1.0" }, { name = "pyright", specifier = ">=1.1.400" }, { name = "pytest", specifier = ">=8.3.5" }, { name = "ruff", specifier = ">=0.11.10" },