diff --git a/.gitignore b/.gitignore index 58ee456..2f0d5ae 100644 --- a/.gitignore +++ b/.gitignore @@ -51,7 +51,7 @@ venv.bak/ .python-version # Test/config -quick.py +test-*.py config.toml obsws.log diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..7802457 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: + - repo: local + hooks: + - id: format + name: format + entry: hatch run style:fmt + language: system + pass_filenames: false + verbose: true + files: \.(py)$ diff --git a/README.md b/README.md index 0eb65a4..e2467de 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ [![PyPI version](https://badge.fury.io/py/obsws-python.svg)](https://badge.fury.io/py/obsws-python) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://github.com/aatikturk/obsstudio_sdk/blob/main/LICENSE) +[![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) [![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/) @@ -92,7 +93,7 @@ resp = cl_req.send("GetVersion", raw=True) print(f"response data: {resp}") ``` -For a full list of requests refer to [Requests](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requests) +For a full list of requests refer to [Requests][obsws-reqs] ### Events @@ -125,7 +126,7 @@ cl.callback.deregister(on_input_mute_state_changed) `register(fns)` and `deregister(fns)` accept both single functions and lists of functions. -For a full list of events refer to [Events](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#events) +For a full list of events refer to [Events][obsws-events] ### Attributes @@ -149,7 +150,7 @@ def on_scene_created(data): - The following attributes are available: - `req_name`: name of the request. - `code`: request status code. - - For a full list of status codes refer to [Codes](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatus) + - For a full list of status codes refer to [Codes][obsws-codes] ### Logging @@ -168,18 +169,19 @@ logging.basicConfig(level=logging.DEBUG) ### Tests -First install development dependencies: +Install [hatch][hatch-install] and then: -`pip install -e .['dev']` - -To run all tests: - -``` -pytest -v -``` +`hatch test` ### Official Documentation For the full documentation: -- [OBS Websocket SDK](https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#obs-websocket-501-protocol) +- [OBS Websocket SDK][obsws-pro] + + +[obsws-reqs]: https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requests +[obsws-events]: https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#events +[obsws-codes]: https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#requeststatus +[obsws-pro]: https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md#obs-websocket-501-protocol +[hatch-install]: https://hatch.pypa.io/latest/install/ diff --git a/obsws_python/baseclient.py b/obsws_python/baseclient.py index 27bcc09..d3e20b2 100644 --- a/obsws_python/baseclient.py +++ b/obsws_python/baseclient.py @@ -96,10 +96,8 @@ class ObsClient: auth = base64.b64encode( hashlib.sha256( - ( - secret - + self.server_hello["d"]["authentication"]["challenge"].encode() - ) + secret + + self.server_hello["d"]["authentication"]["challenge"].encode() ).digest() ).decode() diff --git a/obsws_python/callback.py b/obsws_python/callback.py index 20e46fe..c86ced2 100644 --- a/obsws_python/callback.py +++ b/obsws_python/callback.py @@ -1,4 +1,5 @@ -from typing import Callable, Iterable, Union +from collections.abc import Callable, Iterable +from typing import Union from .util import as_dataclass, to_camel_case, to_snake_case diff --git a/obsws_python/reqs.py b/obsws_python/reqs.py index 1aff1ed..a4fe19d 100644 --- a/obsws_python/reqs.py +++ b/obsws_python/reqs.py @@ -42,7 +42,7 @@ class ReqClient: def __str__(self): return type(self).__name__ - + def disconnect(self): self.base_client.ws.close() @@ -438,7 +438,7 @@ class ReqClient: def set_record_directory(self, recordDirectory): """ - Sets the current directory that the record output writes files to. + Sets the current directory that the record output writes files to. IMPORTANT NOTE: Requires obs websocket v5.3 or higher. :param recordDirectory: Output directory @@ -448,7 +448,7 @@ class ReqClient: "recordDirectory": recordDirectory, } return self.send("SetRecordDirectory", payload) - + def get_source_active(self, name): """ Gets the active and show state of a source diff --git a/pyproject.toml b/pyproject.toml index 3593877..c6ad10c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,14 +17,6 @@ dependencies = [ "websocket-client", ] -[project.optional-dependencies] -dev = [ - "black", - "isort", - "pytest", - "pytest-randomly", -] - [project.urls] Homepage = "https://github.com/aatikturk/obsws-python" @@ -36,19 +28,58 @@ include = [ "/obsws_python", ] +[tool.hatch.envs.default] +dependencies = ["pre-commit"] + +[tool.hatch.envs.e] +dependencies = ["keyboard"] + [tool.hatch.envs.e.scripts] events = "python {root}\\examples\\events\\." hotkeys = "python {root}\\examples\\hotkeys\\." levels = "python {root}\\examples\\levels\\." scene_rotate = "python {root}\\examples\\scene_rotate\\." -[tool.hatch.envs.test] +[tool.hatch.envs.hatch-test] +randomize = true + +[tool.hatch.envs.hatch-test.scripts] +run = "pytest{env:HATCH_TEST_ARGS:} {args}" + +[[tool.hatch.envs.hatch-test.matrix]] +python = ["313", "312", "311", "310", "39"] + +[tool.hatch.envs.style] +detached = true dependencies = [ - "pytest", + "black", + "isort", ] -[tool.hatch.envs.test.scripts] -run = 'pytest -v' +[tool.hatch.envs.style.scripts] +check = [ + "black --check --diff .", + "isort --check-only --diff .", +] +fmt = [ + "isort .", + "black .", +] -[[tool.hatch.envs.test.matrix]] -python = ["39", "310", "311"] +[tool.black] +line-length = 88 +include = '\.pyi?$' +# 'extend-exclude' excludes files or directories in addition to the defaults +extend-exclude = ''' +( + ^/\.git/ # exclude all files in the .git directory + ^/\.hatch/ # exclude all files in the .hatch directory + ^/\.pytest_cache/ # exclude all files in the .pytest_cache directory + | .*_pb2.py # exclude autogenerated Protocol Buffer files anywhere in the project +) +''' + +[tool.isort] +profile = "black" +skip = [".gitignore", ".dockerignore"] +skip_glob = [".git/*", ".hatch/*", ".pytest_cache/*"] \ No newline at end of file diff --git a/tests/test_attrs.py b/tests/test_attrs.py index 6fe1617..cbab9b4 100644 --- a/tests/test_attrs.py +++ b/tests/test_attrs.py @@ -18,7 +18,12 @@ class TestAttrs: def test_get_current_program_scene_attrs(self): resp = req_cl.get_current_program_scene() - assert resp.attrs() == ["current_program_scene_name"] + assert resp.attrs() == [ + "current_program_scene_name", + "current_program_scene_uuid", + "scene_name", + "scene_uuid", + ] def test_get_transition_kind_list_attrs(self): resp = req_cl.get_transition_kind_list() diff --git a/tests/test_callback.py b/tests/test_callback.py index 992f0e5..6594089 100644 --- a/tests/test_callback.py +++ b/tests/test_callback.py @@ -1,4 +1,5 @@ import pytest + from obsws_python.callback import Callback diff --git a/tests/test_request.py b/tests/test_request.py index cd45c70..2687881 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -55,6 +55,7 @@ class TestRequests: resp = req_cl.get_persistent_data("OBS_WEBSOCKET_DATA_REALM_PROFILE", name) assert resp.slot_value == data + @pytest.mark.skip(reason="possible bug in obs-websocket, needs checking") def test_profile_list(self): req_cl.create_profile("test") resp = req_cl.get_profile_list() @@ -97,11 +98,15 @@ class TestRequests: "START_TEST", "test", "color_source_v3", {"color": 4294945535}, True ) resp = req_cl.get_input_list() - assert { - "inputKind": "color_source_v3", - "inputName": "test", - "unversionedInputKind": "color_source", - } in resp.inputs + for input_item in resp.inputs: + if input_item["inputName"] == "test": + assert input_item["inputKind"] == "color_source_v3" + assert input_item["unversionedInputKind"] == "color_source" + break + else: + # This else block is executed if the for loop completes without finding the input_item with inputName "test" + raise AssertionError("Input with inputName 'test' not found") + resp = req_cl.get_input_settings("test") assert resp.input_kind == "color_source_v3" assert resp.input_settings == {"color": 4294945535}