diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f19dd7d..555bc22 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,6 +16,11 @@ jobs: - "3.7" - "3.8" - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" steps: - name: Set up Python ${{ matrix.python-version }} diff --git a/README.md b/README.md index 639f4ea..e039148 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,17 @@ pip install winregistry ## Usage ```py -from winregistry import WinRegistry +from _winregistry import WinRegistry TEST_REG_PATH = r"HKLM\SOFTWARE\_REMOVE_ME_" - if __name__ == "__main__": - with WinRegistry() as client: - client.create_key(TEST_REG_PATH) - client.write_entry(TEST_REG_PATH, "remove_me", "test") - test_entry = client.read_entry(TEST_REG_PATH, "remove_me") - assert test_entry.value == "test" - client.delete_entry(TEST_REG_PATH, "remove_me") + with WinRegistry() as client: + client.create_key(TEST_REG_PATH) + client.write_entry(TEST_REG_PATH, "remove_me", "test") + test_entry = client.read_entry(TEST_REG_PATH, "remove_me") + assert test_entry.value == "test" + client.delete_entry(TEST_REG_PATH, "remove_me") ``` Usage with ``Robot Testing Framework`` Library diff --git a/poetry.lock b/poetry.lock index bdfc58f..60356f2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,17 +46,6 @@ d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "cfgv" -version = "3.4.0" -description = "Validate configuration and produce human readable error messages." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, - {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, -] - [[package]] name = "click" version = "8.1.7" @@ -82,17 +71,6 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -[[package]] -name = "distlib" -version = "0.3.9" -description = "Distribution utilities" -optional = false -python-versions = "*" -files = [ - {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, - {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, -] - [[package]] name = "exceptiongroup" version = "1.2.2" @@ -107,36 +85,6 @@ files = [ [package.extras] test = ["pytest (>=6)"] -[[package]] -name = "filelock" -version = "3.16.1" -description = "A platform independent file lock." -optional = false -python-versions = ">=3.8" -files = [ - {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, - {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, -] - -[package.extras] -docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] -typing = ["typing-extensions (>=4.12.2)"] - -[[package]] -name = "identify" -version = "2.6.1" -description = "File identification library for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, - {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, -] - -[package.extras] -license = ["ukkonen"] - [[package]] name = "iniconfig" version = "2.0.0" @@ -226,17 +174,6 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "nodeenv" -version = "1.9.1" -description = "Node.js virtual environment builder" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, - {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, -] - [[package]] name = "packaging" version = "24.2" @@ -290,24 +227,6 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] -[[package]] -name = "pre-commit" -version = "4.0.1" -description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false -python-versions = ">=3.9" -files = [ - {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, - {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, -] - -[package.dependencies] -cfgv = ">=2.0.0" -identify = ">=1.0.0" -nodeenv = ">=0.11.1" -pyyaml = ">=5.1" -virtualenv = ">=20.10.0" - [[package]] name = "pytest" version = "8.3.3" @@ -330,68 +249,6 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] -[[package]] -name = "pyyaml" -version = "6.0.2" -description = "YAML parser and emitter for Python" -optional = false -python-versions = ">=3.8" -files = [ - {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, - {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, - {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, - {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, - {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, - {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, - {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, - {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, - {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, - {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, - {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, - {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, - {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, - {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, - {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, - {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, - {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, - {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, - {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, - {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, - {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, - {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, - {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, - {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, - {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, - {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, - {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, - {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, - {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, - {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, - {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, - {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, -] - [[package]] name = "robotframework" version = "7.1.1" @@ -432,13 +289,13 @@ files = [ [[package]] name = "tomli" -version = "2.0.2" +version = "2.1.0" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -452,27 +309,7 @@ files = [ {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] -[[package]] -name = "virtualenv" -version = "20.27.1" -description = "Virtual Python Environment builder" -optional = false -python-versions = ">=3.8" -files = [ - {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, - {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, -] - -[package.dependencies] -distlib = ">=0.3.7,<1" -filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<5" - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] - [metadata] lock-version = "2.0" python-versions = ">=3.9" -content-hash = "9df1ee34cc8e8d8d768dad97f5ba88b8d85ca7d9a217f6f1116b38dcdbe101b8" +content-hash = "ff976ea2fe0527b99da3330da1712154f28a6f17141c00b66cade91183787cee" diff --git a/pyproject.toml b/pyproject.toml index e55bad6..5c15747 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ python = ">=3.9" mypy = "^1.13" pytest = "^8.3" black = "^24.10" -robotframework = "^7.1" +robotframework = ">=7.1" isort = "^5.13" ruff = "^0.7.3" diff --git a/tests/test_utils.py b/tests/test_utils.py index 8ce1e25..54ff8a3 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,7 @@ from winreg import HKEY_CURRENT_USER, KEY_READ -from winregistry import WinRegistry -from winregistry._utils import get_access_key, parse_key_name +from _winregistry import WinRegistry +from _winregistry._utils import get_access_key, parse_key_name TEST_REG_PATH = r"HKCU\SOFTWARE\_REMOVE_ME_" diff --git a/winregistry.py b/winregistry.py new file mode 100644 index 0000000..7d8edbe --- /dev/null +++ b/winregistry.py @@ -0,0 +1,254 @@ +import typing as tp +import winreg + +from abc import ABC, abstractmethod +from contextlib import contextmanager +from datetime import datetime, timedelta + +from _winregistry._utils import str_to_winreg + + +class _RegEntity(ABC): + _winreg_pkg = winreg + + def __init__(self, reg_key, wow64_32=False): + self._reg_key = reg_key + self._wow = self._winreg_pkg.wow64_32 if wow64_32 else self._winreg_pkg.KEY_WOW64_64KEY + self._raw = self._get_reg_raw_data() + + @abstractmethod + def _get_reg_raw_data(self): ... + + def _get_access_key(self, winreg_access_mode) -> int: + return winreg_access_mode | self._wow + + +class RegValue(_RegEntity): + def __init__(self, reg_key, name, wow64_32=False): + super().__init__(reg_key, wow64_32) + self._name = name + + def _get_reg_raw_data(self): + return self._winreg_pkg.QueryValueEx(self._reg_key, self._name) + + @property + def value(self): + return self._raw[0] + + @value.setter + def value(self, value): ... + + @property + def type(self): + return self._raw[1] + + @type.setter + def type(self, value): ... + + def delete(self): ... + + +class RegKey(_RegEntity): + + def _get_reg_raw_data(self): + return self._winreg_pkg.QueryInfoKey(self._reg_key) + + def close(self): + self._reg_key.Close() + + @property + def child_keys_count(self): + return self._raw[0] + + @property + def modified_at(self): + return datetime(1601, 1, 1) + timedelta(microseconds=self._raw[2] / 10) + + @property + def child_keys_names(self) -> tp.Generator[str, None]: + for name in range(self.child_keys_count()): + yield self._winreg_pkg.EnumKey(self._reg_key, name) + + @property + def child_keys(self) -> tp.Generator[None, str]: + for name in self.child_keys_names: + yield self.open_key(name) + + # @property + # def get_values(self) -> tp.Generator[str, None]: + # for name in range(0, self._key_info[0]): + # yield self._winreg.EnumKey(self._winreg_key, name) + + @contextmanager + def open_key(self, name: str): + key = RegKey( + self._winreg_pkg.OpenKey( + key=self._reg_key, + sub_key=name, + reserved=0, + access=self._get_access_key(self._winreg_pkg.KEY_READ), + ) + ) + yield key + key.close() + + def create_key(self, name): + self._winreg_pkg.CreateKeyEx( + key=self._reg_key, # type: ignore + sub_key=name, + reserved=0, + access=self._get_access_key(self._winreg_pkg.KEY_WRITE), + ) + + def delete_key(self, name, recursive=False): + if not recursive: + self._winreg_pkg.DeleteKey(self._reg_key, name) + + def read_value(self, name): + return RegValue(self._reg_key, name, self._wow) + + def set_value(self, name, value): ... + + def delete_value(self, name): ... + + def __enter__(self) -> tp.Self: + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + + +class WinRegistry(RegKey): + @classmethod + def connect(cls, root, host=None, wow64_32=False) -> tp.Self: + return cls( + cls._winreg_pkg.ConnectRegistry(host, str_to_winreg(root.upper())), + wow64_32, + ) + + +def read_registry_key( + key: str, + wow64_32: bool = False, +) -> RegKey: + """Reading registry key""" + with WinRegistry() as client: + return client.read_key(key, wow64_32) + + +def create_registry_key( + key: str, + wow64_32: bool = False, +) -> None: + """Creating registry key""" + with WinRegistry() as client: + client.create_key(key, wow64_32) + + +def delete_registry_key( + key: str, + wow64_32: bool = False, +) -> None: + """Deleting registry key""" + with WinRegistry() as client: + client.delete_key(key, wow64_32) + + +def read_registry_value( + key: str, + value: tp.Any, + wow64_32: bool = False, +) -> RegEntry: + """Reading value from registry""" + with WinRegistry() as client: + return client.read_entry(key, value, wow64_32) + + +def set_registry_value( + key: str, + value: str, + data: Any = None, + reg_type: str = "REG_SZ", + wow64_32: bool = False, +) -> None: + """Writing (or creating) data in value""" + with WinRegistry() as client: + client.write_entry(key, value, data, 'WinregType'[reg_type], wow64_32) + + +def delete_registry_value( + key: str, + value: str, + wow64_32: bool = False, +) -> None: + """Deleting value from registry""" + with WinRegistry() as client: + client.delete_entry(key, value, wow64_32) + + +class robot: + def read_registry_key( + key: str, + wow64_32: bool = False, + ) -> RegKey: + """Reading registry key""" + with WinRegistry() as client: + return client.read_key(key, wow64_32) + + def create_registry_key( + self, + key: str, + wow64_32: bool = False, + ) -> None: + """Creating registry key""" + with WinRegistry() as client: + client.create_key(key, wow64_32) + + def delete_registry_key( + self, + key: str, + wow64_32: bool = False, + ) -> None: + """Deleting registry key""" + with WinRegistry() as client: + client.delete_key(key, wow64_32) + + def read_registry_value( + self, + key: str, + value: tp.Any, + wow64_32: bool = False, + ) -> RegEntry: + """Reading value from registry""" + with WinRegistry() as client: + return client.read_entry(key, value, wow64_32) + + def set_registry_value( + self, + key: str, + value: str, + data: Any = None, + reg_type: str = "REG_SZ", + wow64_32: bool = False, + ) -> None: + """Writing (or creating) data in value""" + with WinRegistry() as client: + client.write_entry(key, value, data, 'WinregType'[reg_type], wow64_32) + + def delete_registry_value( + self, + key: str, + value: str, + wow64_32: bool = False, + ) -> None: + """Deleting value from registry""" + with WinRegistry() as client: + client.delete_entry(key, value, wow64_32) + + +__all__ = [ + 'WinRegistry', + 'RegKey', + 'RegValue', +] +__version__ = '0.0.0' diff --git a/winregistry/__init__.py b/winregistry/__init__.py deleted file mode 100644 index 7f1a9ac..0000000 --- a/winregistry/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -from winregistry._types import RegEntry, RegKey, WinregType -from winregistry._winregistry import WinRegistry - -__all__ = ( - "WinRegistry", - "RegEntry", - "RegKey", -) diff --git a/winregistry/_types.py b/winregistry/_types.py deleted file mode 100644 index 003e8fd..0000000 --- a/winregistry/_types.py +++ /dev/null @@ -1,50 +0,0 @@ -import typing as tp -import winreg - -from dataclasses import dataclass -from datetime import datetime -from enum import IntEnum - -ROOT_ALIASES = tp.Literal['HKCR', 'HKCU', 'HKLM', 'HKU', 'HKCC'] - - -@dataclass(frozen=True) -class RegEntry: - name: str - reg_key: str - value: tp.Any - type: winreg.WinregType - host: str | None = None - - -@dataclass(frozen=True) -class RegKey: - name: str - reg_keys: list[str] - entries: list[RegEntry] - modify_at: datetime - - -class Value(tp.Protocol): - def read(self): ... - - def write(self): ... - - def delete(self): ... - - -class RegType(IntEnum): - REG_NONE = winreg.REG_NONE - REG_SZ = winreg.REG_SZ - REG_EXPAND_SZ = winreg.REG_EXPAND_SZ - REG_BINARY = winreg.REG_BINARY - REG_DWORD = winreg.REG_DWORD - REG_DWORD_LITTLE_ENDIAN = winreg.REG_DWORD_LITTLE_ENDIAN - REG_DWORD_BIG_ENDIAN = winreg.REG_DWORD_BIG_ENDIAN - REG_LINK = winreg.REG_LINK - REG_MULTI_SZ = winreg.REG_MULTI_SZ - REG_RESOURCE_LIST = winreg.REG_RESOURCE_LIST - REG_FULL_RESOURCE_DESCRIPTOR = winreg.REG_FULL_RESOURCE_DESCRIPTOR - REG_RESOURCE_REQUIREMENTS_LIST = winreg.REG_RESOURCE_REQUIREMENTS_LIST - REG_QWORD = winreg.REG_QWORD - REG_QWORD_LITTLE_ENDIAN = winreg.REG_QWORD_LITTLE_ENDIAN diff --git a/winregistry/_utils.py b/winregistry/_utils.py deleted file mode 100644 index d32fef2..0000000 --- a/winregistry/_utils.py +++ /dev/null @@ -1,40 +0,0 @@ -import typing as tp -import winreg - -from typing_extensions import Unpack - -HIVE_ALIASES_MAPPING: dict[str, str] = { - 'HKCR': "HKEY_CLASSES_ROOT", - 'HKCU': "HKEY_CURRENT_USER", - 'HKLM': "HKEY_LOCAL_MACHINE", - 'HKU': "HKEY_USERS", - 'HKPD': 'HKEY_PERFORMANCE_DATA', - 'HKCC': "HKEY_CURRENT_CONFIG", - 'HKDD': 'HKEY_DYN_DATA', -} - -ROOT_NAMES = tp.Literal[tp.Literal[Unpack[(list(HIVE_ALIASES_MAPPING.keys()) + list(HIVE_ALIASES_MAPPING.values()))]]] - - -def get_access_key( - access: int, - key_wow64_32key: bool = False, -) -> int: - x64_key = winreg.KEY_WOW64_32KEY if key_wow64_32key else winreg.KEY_WOW64_64KEY - return access | x64_key - - -def parse_key_name( - name: str, -) -> tuple[winreg.HKEYType | None, str]: - root, path = name.split("\\", maxsplit=1) - root = HIVE_ALIASES_MAPPING.get(root.upper()) - return root, path if root else name - - -def str_to_winreg( - value: str, -) -> tp.Any: - if not (obj := getattr(winreg, value)): - raise ValueError(f'unknown value {value}') - return obj diff --git a/winregistry/_winregistry.py b/winregistry/_winregistry.py deleted file mode 100644 index 6ce21a3..0000000 --- a/winregistry/_winregistry.py +++ /dev/null @@ -1,127 +0,0 @@ -import typing as tp -import winreg - -from abc import ABC, abstractmethod -from contextlib import contextmanager -from datetime import datetime, timedelta - -from winregistry._utils import str_to_winreg - - -class RegEntity(ABC): - _winreg_pkg = winreg - - def __init__(self, reg_key, wow64_32=False): - self._reg_key = reg_key - self._wow = self._winreg_pkg.KEY_WOW64_32KEY if wow64_32 else self._winreg_pkg.KEY_WOW64_64KEY - self._raw = self._get_reg_raw_data() - - @abstractmethod - def _get_reg_raw_data(self): ... - - def _get_access_key(self, winreg_access_mode) -> int: - return winreg_access_mode | self._wow - - -class RegValue(RegEntity): - def __init__(self, reg_key, name, wow64_32=False): - super().__init__(reg_key, wow64_32) - self._name = name - - def _get_reg_raw_data(self): - return self._winreg_pkg.QueryValueEx(self._reg_key, self._name) - - @property - def value(self): - return self._raw[0] - - @value.setter - def value(self, value): ... - - @property - def type(self): - return self._raw[1] - - @type.setter - def type(self, value): ... - - def delete(self): ... - - -class RegKey(RegEntity): - - def _get_reg_raw_data(self): - return self._winreg_pkg.QueryInfoKey(self._reg_key) - - def close(self): - self._reg_key.Close() - - @property - def child_keys_count(self): - return self._raw[0] - - @property - def modified_at(self): - return datetime(1601, 1, 1) + timedelta(microseconds=self._raw[2] / 10) - - @property - def child_keys_names(self) -> tp.Generator[str, None]: - for name in range(self.child_keys_count()): - yield self._winreg_pkg.EnumKey(self._reg_key, name) - - @property - def child_keys(self) -> tp.Generator[None, str]: - for name in self.child_keys_names: - yield self.open_key(name) - - # @property - # def get_values(self) -> tp.Generator[str, None]: - # for name in range(0, self._key_info[0]): - # yield self._winreg.EnumKey(self._winreg_key, name) - - @contextmanager - def open_key(self, name: str): - key = RegKey( - self._winreg_pkg.OpenKey( - key=self._reg_key, - sub_key=name, - reserved=0, - access=self._get_access_key(self._winreg_pkg.KEY_READ), - ) - ) - yield key - key.close() - - def create_key(self, name): - self._winreg_pkg.CreateKeyEx( - key=self._reg_key, # type: ignore - sub_key=name, - reserved=0, - access=self._get_access_key(self._winreg_pkg.KEY_WRITE), - ) - - def delete_key(self, name, recursive=False): - if not recursive: - self._winreg_pkg.DeleteKey(self._reg_key, name) - - def read_value(self, name): - return RegValue(self._reg_key, name, self._wow) - - def set_value(self, name, value): ... - - def delete_value(self, name): ... - - def __enter__(self) -> tp.Self: - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - - -class WinRegistry(RegKey): - @classmethod - def connect(cls, root, host=None, key_wow64_32key=False) -> tp.Self: - return cls( - cls._winreg_pkg.ConnectRegistry(host, str_to_winreg(root.upper())), - key_wow64_32key, - ) diff --git a/winregistry/robot/__init__.py b/winregistry/robot/__init__.py deleted file mode 100644 index 4fa4f7d..0000000 --- a/winregistry/robot/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -from winregistry.robot.keywords import Keywords - -ROBOT_LIBRARY_SCOPE = "GLOBAL" - - -class robot(Keywords): # pylint: disable=invalid-name - """ - Minimalist Python library aimed at working with Windows Registry. - https://github.com/shpaker/winregistry - Examples: - | ${path} | HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run | - | Write Registry Entry | ${path} | Notepad | notepad.exe | - | ${autorun} = | Read Registry Key | ${path} | | - | Log | ${autorun} | | | - | Delete Registry Entry | ${path} | Notepad | | - """ - - -__all__ = [ - 'robot', -] diff --git a/winregistry/robot/keywords.py b/winregistry/robot/keywords.py deleted file mode 100644 index 6bf9a09..0000000 --- a/winregistry/robot/keywords.py +++ /dev/null @@ -1,64 +0,0 @@ -from typing import Any - -from winregistry import RegEntry, RegKey, WinRegistry, WinregType - - -class Keywords: - def read_registry_key( - self, - key: str, - key_wow64_32key: bool = False, - ) -> RegKey: - """Reading registry key""" - with WinRegistry() as client: - return client.read_key(key, key_wow64_32key) - - def create_registry_key( - self, - key: str, - key_wow64_32key: bool = False, - ) -> None: - """Creating registry key""" - with WinRegistry() as client: - client.create_key(key, key_wow64_32key) - - def delete_registry_key( - self, - key: str, - key_wow64_32key: bool = False, - ) -> None: - """Deleting registry key""" - with WinRegistry() as client: - client.delete_key(key, key_wow64_32key) - - def read_registry_entry( - self, - key: str, - value: Any, - key_wow64_32key: bool = False, - ) -> RegEntry: - """Reading value from registry""" - with WinRegistry() as client: - return client.read_entry(key, value, key_wow64_32key) - - def write_registry_entry( - self, - key: str, - value: str, - data: Any = None, - reg_type: str = "REG_SZ", - key_wow64_32key: bool = False, - ) -> None: - """Writing (or creating) data in value""" - with WinRegistry() as client: - client.write_entry(key, value, data, WinregType[reg_type], key_wow64_32key) - - def delete_registry_entry( - self, - key: str, - value: str, - key_wow64_32key: bool = False, - ) -> None: - """Deleting value from registry""" - with WinRegistry() as client: - client.delete_entry(key, value, key_wow64_32key)