From aebd41976c28f8d5d589b45ae48d2462eac23b44 Mon Sep 17 00:00:00 2001 From: Rudoruka Date: Wed, 8 Oct 2025 11:07:21 +0300 Subject: [PATCH 1/4] add src/masks.py --- poetry.lock | 301 ++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 4 +- src/masks.py | 10 -- src/processing.py | 34 ++++++ src/widget.py | 61 ++++++---- 5 files changed, 373 insertions(+), 37 deletions(-) create mode 100644 poetry.lock create mode 100644 src/processing.py diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..3dec275 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,301 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "black" +version = "25.9.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "black-25.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ce41ed2614b706fd55fd0b4a6909d06b5bab344ffbfadc6ef34ae50adba3d4f7"}, + {file = "black-25.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ab0ce111ef026790e9b13bd216fa7bc48edd934ffc4cbf78808b235793cbc92"}, + {file = "black-25.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f96b6726d690c96c60ba682955199f8c39abc1ae0c3a494a9c62c0184049a713"}, + {file = "black-25.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:d119957b37cc641596063cd7db2656c5be3752ac17877017b2ffcdb9dfc4d2b1"}, + {file = "black-25.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:456386fe87bad41b806d53c062e2974615825c7a52159cde7ccaeb0695fa28fa"}, + {file = "black-25.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a16b14a44c1af60a210d8da28e108e13e75a284bf21a9afa6b4571f96ab8bb9d"}, + {file = "black-25.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaf319612536d502fdd0e88ce52d8f1352b2c0a955cc2798f79eeca9d3af0608"}, + {file = "black-25.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:c0372a93e16b3954208417bfe448e09b0de5cc721d521866cd9e0acac3c04a1f"}, + {file = "black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0"}, + {file = "black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4"}, + {file = "black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e"}, + {file = "black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a"}, + {file = "black-25.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0172a012f725b792c358d57fe7b6b6e8e67375dd157f64fa7a3097b3ed3e2175"}, + {file = "black-25.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3bec74ee60f8dfef564b573a96b8930f7b6a538e846123d5ad77ba14a8d7a64f"}, + {file = "black-25.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b756fc75871cb1bcac5499552d771822fd9db5a2bb8db2a7247936ca48f39831"}, + {file = "black-25.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:846d58e3ce7879ec1ffe816bb9df6d006cd9590515ed5d17db14e17666b2b357"}, + {file = "black-25.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ef69351df3c84485a8beb6f7b8f9721e2009e20ef80a8d619e2d1788b7816d47"}, + {file = "black-25.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e3c1f4cd5e93842774d9ee4ef6cd8d17790e65f44f7cdbaab5f2cf8ccf22a823"}, + {file = "black-25.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:154b06d618233fe468236ba1f0e40823d4eb08b26f5e9261526fde34916b9140"}, + {file = "black-25.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:e593466de7b998374ea2585a471ba90553283fb9beefcfa430d84a2651ed5933"}, + {file = "black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae"}, + {file = "black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +pytokens = ">=0.1.10" + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.10)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.3.0" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["lint"] +files = [ + {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, + {file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["lint"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "flake8" +version = "7.3.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e"}, + {file = "flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.14.0,<2.15.0" +pyflakes = ">=3.4.0,<3.5.0" + +[[package]] +name = "isort" +version = "6.0.1" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.9.0" +groups = ["lint"] +files = [ + {file = "isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615"}, + {file = "isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450"}, +] + +[package.extras] +colors = ["colorama"] +plugins = ["setuptools"] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +groups = ["lint"] +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy" +version = "1.18.2" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "mypy-1.18.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c1eab0cf6294dafe397c261a75f96dc2c31bffe3b944faa24db5def4e2b0f77c"}, + {file = "mypy-1.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7a780ca61fc239e4865968ebc5240bb3bf610ef59ac398de9a7421b54e4a207e"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:448acd386266989ef11662ce3c8011fd2a7b632e0ec7d61a98edd8e27472225b"}, + {file = "mypy-1.18.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f9e171c465ad3901dc652643ee4bffa8e9fef4d7d0eece23b428908c77a76a66"}, + {file = "mypy-1.18.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:592ec214750bc00741af1f80cbf96b5013d81486b7bb24cb052382c19e40b428"}, + {file = "mypy-1.18.2-cp310-cp310-win_amd64.whl", hash = "sha256:7fb95f97199ea11769ebe3638c29b550b5221e997c63b14ef93d2e971606ebed"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:807d9315ab9d464125aa9fcf6d84fde6e1dc67da0b6f80e7405506b8ac72bc7f"}, + {file = "mypy-1.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:776bb00de1778caf4db739c6e83919c1d85a448f71979b6a0edd774ea8399341"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1379451880512ffce14505493bd9fe469e0697543717298242574882cf8cdb8d"}, + {file = "mypy-1.18.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1331eb7fd110d60c24999893320967594ff84c38ac6d19e0a76c5fd809a84c86"}, + {file = "mypy-1.18.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ca30b50a51e7ba93b00422e486cbb124f1c56a535e20eff7b2d6ab72b3b2e37"}, + {file = "mypy-1.18.2-cp311-cp311-win_amd64.whl", hash = "sha256:664dc726e67fa54e14536f6e1224bcfce1d9e5ac02426d2326e2bb4e081d1ce8"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:33eca32dd124b29400c31d7cf784e795b050ace0e1f91b8dc035672725617e34"}, + {file = "mypy-1.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a3c47adf30d65e89b2dcd2fa32f3aeb5e94ca970d2c15fcb25e297871c8e4764"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d6c838e831a062f5f29d11c9057c6009f60cb294fea33a98422688181fe2893"}, + {file = "mypy-1.18.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01199871b6110a2ce984bde85acd481232d17413868c9807e95c1b0739a58914"}, + {file = "mypy-1.18.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a2afc0fa0b0e91b4599ddfe0f91e2c26c2b5a5ab263737e998d6817874c5f7c8"}, + {file = "mypy-1.18.2-cp312-cp312-win_amd64.whl", hash = "sha256:d8068d0afe682c7c4897c0f7ce84ea77f6de953262b12d07038f4d296d547074"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:07b8b0f580ca6d289e69209ec9d3911b4a26e5abfde32228a288eb79df129fcc"}, + {file = "mypy-1.18.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ed4482847168439651d3feee5833ccedbf6657e964572706a2adb1f7fa4dfe2e"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c3ad2afadd1e9fea5cf99a45a822346971ede8685cc581ed9cd4d42eaf940986"}, + {file = "mypy-1.18.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a431a6f1ef14cf8c144c6b14793a23ec4eae3db28277c358136e79d7d062f62d"}, + {file = "mypy-1.18.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7ab28cc197f1dd77a67e1c6f35cd1f8e8b73ed2217e4fc005f9e6a504e46e7ba"}, + {file = "mypy-1.18.2-cp313-cp313-win_amd64.whl", hash = "sha256:0e2785a84b34a72ba55fb5daf079a1003a34c05b22238da94fcae2bbe46f3544"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:62f0e1e988ad41c2a110edde6c398383a889d95b36b3e60bcf155f5164c4fdce"}, + {file = "mypy-1.18.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8795a039bab805ff0c1dfdb8cd3344642c2b99b8e439d057aba30850b8d3423d"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ca1e64b24a700ab5ce10133f7ccd956a04715463d30498e64ea8715236f9c9c"}, + {file = "mypy-1.18.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d924eef3795cc89fecf6bedc6ed32b33ac13e8321344f6ddbf8ee89f706c05cb"}, + {file = "mypy-1.18.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:20c02215a080e3a2be3aa50506c67242df1c151eaba0dcbc1e4e557922a26075"}, + {file = "mypy-1.18.2-cp314-cp314-win_amd64.whl", hash = "sha256:749b5f83198f1ca64345603118a6f01a4e99ad4bf9d103ddc5a3200cc4614adf"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25a9c8fb67b00599f839cf472713f54249a62efd53a54b565eb61956a7e3296b"}, + {file = "mypy-1.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2b9c7e284ee20e7598d6f42e13ca40b4928e6957ed6813d1ab6348aa3f47133"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6985ed057513e344e43a26cc1cd815c7a94602fb6a3130a34798625bc2f07b6"}, + {file = "mypy-1.18.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:22f27105f1525ec024b5c630c0b9f36d5c1cc4d447d61fe51ff4bd60633f47ac"}, + {file = "mypy-1.18.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:030c52d0ea8144e721e49b1f68391e39553d7451f0c3f8a7565b59e19fcb608b"}, + {file = "mypy-1.18.2-cp39-cp39-win_amd64.whl", hash = "sha256:aa5e07ac1a60a253445797e42b8b2963c9675563a94f11291ab40718b016a7a0"}, + {file = "mypy-1.18.2-py3-none-any.whl", hash = "sha256:22a1748707dd62b58d2ae53562ffc4d7f8bcc727e8ac7cbc69c053ddc874d47e"}, + {file = "mypy-1.18.2.tar.gz", hash = "sha256:06a398102a5f203d7477b2923dda3634c36727fa5c237d8f859ef90c42a9924b"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["lint"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["lint"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["lint"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "platformdirs" +version = "4.4.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "poetry-core" +version = "2.2.1" +description = "Poetry PEP 517 Build Backend" +optional = false +python-versions = "<4.0,>=3.9" +groups = ["main"] +files = [ + {file = "poetry_core-2.2.1-py3-none-any.whl", hash = "sha256:bdfce710edc10bfcf9ab35041605c480829be4ab23f5bc01202cfe5db8f125ab"}, + {file = "poetry_core-2.2.1.tar.gz", hash = "sha256:97e50d8593c8729d3f49364b428583e044087ee3def1e010c6496db76bd65ac5"}, +] + +[[package]] +name = "pycodestyle" +version = "2.14.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d"}, + {file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"}, +] + +[[package]] +name = "pyflakes" +version = "3.4.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f"}, + {file = "pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58"}, +] + +[[package]] +name = "pytokens" +version = "0.1.10" +description = "A Fast, spec compliant Python 3.12+ tokenizer that runs on older Pythons." +optional = false +python-versions = ">=3.8" +groups = ["lint"] +files = [ + {file = "pytokens-0.1.10-py3-none-any.whl", hash = "sha256:db7b72284e480e69fb085d9f251f66b3d2df8b7166059261258ff35f50fb711b"}, + {file = "pytokens-0.1.10.tar.gz", hash = "sha256:c9a4bfa0be1d26aebce03e6884ba454e842f186a59ea43a6d3b25af58223c044"}, +] + +[package.extras] +dev = ["black", "build", "mypy", "pytest", "pytest-cov", "setuptools", "tox", "twine", "wheel"] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["lint"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[metadata] +lock-version = "2.1" +python-versions = "^3.13" +content-hash = "7677a0b78312c14d8e96ae6ca24cacf034a6fc428c1129c52ea2967b710ad6b4" diff --git a/pyproject.toml b/pyproject.toml index 142e148..27bbc4d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,12 +31,12 @@ exclude = "venv" [tool.flake8] max-line-length = 119 -exclude = .git, __pycache__ +exclude = ["__pycache__", ".git"] [tool.black] max-line-length = 119 -exclude = .git +exclude = [".git"] [tool.isort] diff --git a/src/masks.py b/src/masks.py index e197218..7c56008 100644 --- a/src/masks.py +++ b/src/masks.py @@ -1,5 +1,3 @@ - - """принимает на вход номер карты в виде числа и возвращает маску""" @@ -7,11 +5,9 @@ def get_mask_card_number(card_number: str) -> str: """Функция входа номер карты в виде числа и возврата в виде маски """ # Убираем все пробелы из переданной строки card_number = card_number.replace(" ", "") - # Проверяем, что длина карты 16 символов и все символы цифры if len(card_number) != 16 or not card_number.isdigit(): return "Неверный номер карты" - # Формируем формат XXXX XX** **** XXXX # Первые 4 цифры остаются part1 = card_number[:4] @@ -27,9 +23,6 @@ def get_mask_card_number(card_number: str) -> str: return f"{part1} {part2}{part2_mask} {part3_mask} {part4}" - - - """Принимает на вход номер счета в виде числа и возвращает маску номера""" @@ -45,6 +38,3 @@ def get_mask_account(mask_account: str) -> str: # начиная с 2х ** part_1_mask = "**" return f"{part_1_mask}{part_1}" - - - diff --git a/src/processing.py b/src/processing.py new file mode 100644 index 0000000..62ac870 --- /dev/null +++ b/src/processing.py @@ -0,0 +1,34 @@ +from datetime import datetime + +def filter_by_state(dictionary_1, state_value): + """Фильтрация списка словарей по ключу 'state' и значению state_value""" + return [d for d in dictionary_1 if d.get('state') == state_value] + +def sort_by_date(dictionary_2, date_key="date", date_format="%Y-%m-%dT%H:%M:%S.%f", reverse=False): + """Сортирует список словарей по дате, учитывая формат даты с временем и миллисекундами""" + return sorted( + dictionary_2, + key=lambda d: datetime.strptime(d[date_key], date_format), + reverse=reverse + ) + +# Исходный список словарей +dictionary = [ + {'id': 41428829, 'state': 'EXECUTED', 'date': '2019-07-03T18:35:29.512364'}, + {'id': 939719570, 'state': 'EXECUTED', 'date': '2018-06-30T02:08:58.425572'}, + {'id': 594226727, 'state': 'CANCELED', 'date': '2018-09-12T21:27:25.241689'}, + {'id': 615064591, 'state': 'CANCELED', 'date': '2018-10-14T08:21:33.419441'} +] + +# Использование функции фильтрации +filtered = filter_by_state(dictionary, 'EXECUTED') +print(filtered) +print() + +filtered_1 = filter_by_state(dictionary, 'CANCELED') +print(filtered_1) +print() + +# Использование функции сортировки +sorted_events = sort_by_date(dictionary, 'date') +print(sorted_events) \ No newline at end of file diff --git a/src/widget.py b/src/widget.py index b2cff6c..a2bb78d 100644 --- a/src/widget.py +++ b/src/widget.py @@ -1,39 +1,48 @@ - - """Обрабатывает информацию как о картах, так и о счетах.""" +from src.masks import get_mask_account, get_mask_card_number +from datetime import datetime -from src.masks import get_mask_account, get_mask_card_number +def mask_account_card(input_str: str) -> str: + """ Принимает строку формата: + - "Visa Platinum 7000792289606361" + - "Maestro 7000792289606361" + - "Счет 73654108430135874305" + Возвращает строку с замаскированным номером. """ -#Функция -def mask_account_card(): - """Обрабатывает информацию как о картах, так и о счетах.""" - card_types = ['Maestro', 'MasterCard', 'Visa Classic', 'Visa Platinum', 'Visa Gold'] # Список карт - account_types = ['Счет'] # Список счет - - account_card = input("Введите название карты или счета: ").strip() # - Убирает лишние пробелы вокруг текста. - # Помогает избежать ошибок при вводе данных, если пользователь случайно добавил пробелы. - if account_card in card_types: # Проверяем есть-ли в списке вводамая карта. - number = input("Введите номер карты (16 цифр): ").strip() # Ввод номера карты - return f"{account_card} {get_mask_card_number(number)}" # Нашу функцию ставим 1 затем функц маски. При вызове. - elif account_card in account_types: # Проверяем список если указали Счет. - number = input("Введите номер счёта (20 цифр): ").strip() # Тоже что и скартой только 20 цифр. - return f"{account_card} {get_mask_account(number)}" # Все тоже что и выше - else: - return "Неизвестный тип карты или счёта" # Если указаны не верные имена Карт и Счет. -# Пример вызова -print(mask_account_card()) # Вызов функции. + card_types = ['Maestro', 'MasterCard', + 'Visa Classic', 'Visa Platinum', + 'Visa Gold' + ] + account_types = ['Счет'] + + input_str = input_str.strip() + parts = input_str.split() + # Определяем тип карты/счёта и номер (номер - всегда последний элемент) + name = " ".join(parts[:-1]) + number = parts[-1] + if name in card_types: + masked_number = get_mask_card_number(number) + return f"{name} {masked_number}" + elif name in account_types: + masked_number = get_mask_account(number) + return f"{name} {masked_number}" + else: + return "Неизвестный тип карты или счёта" -""" Принимает строку с датой в формате "2024-03-11T02:26:18.671407" - и возвращает строку с датой в формате "ДД.ММ.ГГГГ" """ +# Пример вызова +print(mask_account_card("Visa Platinum 7000792289606361")) +print(mask_account_card("Maestro 7000792289606361")) +print(mask_account_card("Счет 73654108430135874305")) -from datetime import datetime +""" Принимает строку с датой в формате "2024-03-11T02:26:18.671407" +и возвращает строку с датой в формате "ДД.ММ.ГГГГ" """ def get_date(date_str: str) -> str: @@ -43,5 +52,7 @@ def get_date(date_str: str) -> str: # Форматируем дату в нужный формат: День.Месяц.Год return dt.strftime("%d.%m.%Y") + # Пример использования: -print(get_date("2024-03-11T02:26:18.671407")) # Выведет: 11.03.2024 +# Выведет: 11.03.2024 +print(get_date("2024-03-11T02:26:18.671407")) From 88cfbffcff990cfd254fd99e490b6b542b5d3345 Mon Sep 17 00:00:00 2001 From: Rudoruka Date: Sun, 19 Oct 2025 15:04:30 +0300 Subject: [PATCH 2/4] add src/masks.py --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..b1dd609 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Учебный проект. +## Это проект исключительно создан для сдачи домашнего задания, по учебе. + + +## Установка +### 1. Скачайте архвив с [GitHub](https://github.com/Vladimir9645/PythonProject1) +### 2. Зарегеструйте аккаунт в [GitHub](github.com) +### 3. скачаный архив запустите в Pycharm + + +## Описание +### В моем проэете на данный момент находиться 2 домашние работы. +### 1. masks.py и widget.py где реализованы функции маски банковской карты +### 2. processing.py фильтрация списков From 1bf220473ddb6d8c7faf572f6c725a20b9a05624 Mon Sep 17 00:00:00 2001 From: Rudoruka Date: Sun, 19 Oct 2025 18:01:51 +0300 Subject: [PATCH 3/4] add src/masks.py --- README.md | 8 +++++--- src/masks.py | 8 +------- src/processing.py | 21 ++++++++++++++++----- src/widget.py | 22 +++++++--------------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index b1dd609..ef6795d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # Учебный проект. -## Это проект исключительно создан для сдачи домашнего задания, по учебе. +## Это проект исключительно создан для сдачи домашнего задания. ## Установка ### 1. Скачайте архвив с [GitHub](https://github.com/Vladimir9645/PythonProject1) +#### 1.1 скопируйте SSH ключ +#### 1.2 перейдите в Pycharm найдите Clone repository и туда вставьте ссылку ### 2. Зарегеструйте аккаунт в [GitHub](github.com) -### 3. скачаный архив запустите в Pycharm + ## Описание -### В моем проэете на данный момент находиться 2 домашние работы. +### В моем проекте на данный моменте находиться 2 домашние работы. ### 1. masks.py и widget.py где реализованы функции маски банковской карты ### 2. processing.py фильтрация списков diff --git a/src/masks.py b/src/masks.py index 7c56008..301ed17 100644 --- a/src/masks.py +++ b/src/masks.py @@ -1,8 +1,5 @@ -"""принимает на вход номер карты в виде числа и возвращает маску""" - - def get_mask_card_number(card_number: str) -> str: - """Функция входа номер карты в виде числа и возврата в виде маски """ + """Функция входа номер карты в виде числа и возврата в виде маски""" # Убираем все пробелы из переданной строки card_number = card_number.replace(" ", "") # Проверяем, что длина карты 16 символов и все символы цифры @@ -23,9 +20,6 @@ def get_mask_card_number(card_number: str) -> str: return f"{part1} {part2}{part2_mask} {part3_mask} {part4}" -"""Принимает на вход номер счета в виде числа и возвращает маску номера""" - - def get_mask_account(mask_account: str) -> str: """функция ввода номера счета и вывода с маской""" diff --git a/src/processing.py b/src/processing.py index 62ac870..08f2da6 100644 --- a/src/processing.py +++ b/src/processing.py @@ -1,16 +1,27 @@ from datetime import datetime +from typing import List, Dict, Any -def filter_by_state(dictionary_1, state_value): - """Фильтрация списка словарей по ключу 'state' и значению state_value""" - return [d for d in dictionary_1 if d.get('state') == state_value] -def sort_by_date(dictionary_2, date_key="date", date_format="%Y-%m-%dT%H:%M:%S.%f", reverse=False): +def filter_by_state(dictionary_1: List[Dict[str, Any]], + state: str) -> List[Dict[str, Any]]: + """Фильтрация списка словарей по ключу 'state'""" + return [d for d in dictionary_1 if d.get('state') == state] + + +def sort_by_date(dictionary_2: List[Dict[str, Any]], + date_key: str = "date", + date_format: str = "%Y-%m-%dT%H:%M:%S.%f", + reverse: bool = True) -> List[Dict[str, Any]]: """Сортирует список словарей по дате, учитывая формат даты с временем и миллисекундами""" return sorted( dictionary_2, key=lambda d: datetime.strptime(d[date_key], date_format), reverse=reverse ) +# код сортирует список словарей по дате, +# указанной в каждом словаре, +# в том порядке, который задаётся переменной reverse + # Исходный список словарей dictionary = [ @@ -31,4 +42,4 @@ def sort_by_date(dictionary_2, date_key="date", date_format="%Y-%m-%dT%H:%M:%S.% # Использование функции сортировки sorted_events = sort_by_date(dictionary, 'date') -print(sorted_events) \ No newline at end of file +print(sorted_events) diff --git a/src/widget.py b/src/widget.py index a2bb78d..f6c0be3 100644 --- a/src/widget.py +++ b/src/widget.py @@ -1,22 +1,17 @@ -"""Обрабатывает информацию как о картах, так и о счетах.""" +from datetime import datetime from src.masks import get_mask_account, get_mask_card_number -from datetime import datetime def mask_account_card(input_str: str) -> str: - - """ Принимает строку формата: + """Принимает строку формата: - "Visa Platinum 7000792289606361" - "Maestro 7000792289606361" - "Счет 73654108430135874305" - Возвращает строку с замаскированным номером. """ + Возвращает строку с замаскированным номером.""" - card_types = ['Maestro', 'MasterCard', - 'Visa Classic', 'Visa Platinum', - 'Visa Gold' - ] - account_types = ['Счет'] + card_types = ["Maestro", "MasterCard", "Visa Classic", "Visa Platinum", "Visa Gold"] + account_types = ["Счет"] input_str = input_str.strip() parts = input_str.split() @@ -41,12 +36,9 @@ def mask_account_card(input_str: str) -> str: print(mask_account_card("Счет 73654108430135874305")) -""" Принимает строку с датой в формате "2024-03-11T02:26:18.671407" -и возвращает строку с датой в формате "ДД.ММ.ГГГГ" """ - - def get_date(date_str: str) -> str: - """Принимает строку с датой в формает и возвращает строку с датой.""" + """ Принимает строку с датой в формате "2024-03-11T02:26:18.671407" +и возвращает строку с датой в формате "ДД.ММ.ГГГГ" """ # Переносим входную строку в объект datetime dt = datetime.fromisoformat(date_str) # Форматируем дату в нужный формат: День.Месяц.Год From f055a3eadbbf8bd1e9b01ea6c2cf9da73b885ab2 Mon Sep 17 00:00:00 2001 From: Rudoruka Date: Thu, 23 Oct 2025 14:31:58 +0300 Subject: [PATCH 4/4] add src/masks.py --- main.py | 16 ------------- src/processing.py | 59 ++++++++++++++++++++++++++--------------------- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/main.py b/main.py index 5596b44..e69de29 100644 --- a/main.py +++ b/main.py @@ -1,16 +0,0 @@ -# This is a sample Python script. - -# Press Shift+F10 to execute it or replace it with your code. -# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings. - - -def print_hi(name): - # Use a breakpoint in the code line below to debug your script. - print(f'Hi, {name}') # Press Ctrl+F8 to toggle the breakpoint. - - -# Press the green button in the gutter to run the script. -if __name__ == '__main__': - print_hi('PyCharm') - -# See PyCharm help at https://www.jetbrains.com/help/pycharm/ diff --git a/src/processing.py b/src/processing.py index 08f2da6..6d828bf 100644 --- a/src/processing.py +++ b/src/processing.py @@ -1,23 +1,22 @@ from datetime import datetime -from typing import List, Dict, Any +from typing import Any, Dict, List -def filter_by_state(dictionary_1: List[Dict[str, Any]], - state: str) -> List[Dict[str, Any]]: - """Фильтрация списка словарей по ключу 'state'""" - return [d for d in dictionary_1 if d.get('state') == state] +def filter_by_state(dictionary_1: List[Dict[str, Any]], state: str = "EXECUTED") -> List[Dict[str, Any]]: + """Фильтрует список словарей по значению ключа 'state'""" + return [item for item in dictionary_1 if item.get("state") == state] -def sort_by_date(dictionary_2: List[Dict[str, Any]], - date_key: str = "date", - date_format: str = "%Y-%m-%dT%H:%M:%S.%f", - reverse: bool = True) -> List[Dict[str, Any]]: +def sort_by_date( + dictionary_2: List[Dict[str, Any]], + date_key: str = "date", + date_format: str = "%Y-%m-%dT%H:%M:%S.%f", + reverse: bool = True, +) -> List[Dict[str, Any]]: """Сортирует список словарей по дате, учитывая формат даты с временем и миллисекундами""" - return sorted( - dictionary_2, - key=lambda d: datetime.strptime(d[date_key], date_format), - reverse=reverse - ) + return sorted(dictionary_2, key=lambda d: datetime.strptime(d[date_key], date_format), reverse=reverse) + + # код сортирует список словарей по дате, # указанной в каждом словаре, # в том порядке, который задаётся переменной reverse @@ -25,21 +24,29 @@ def sort_by_date(dictionary_2: List[Dict[str, Any]], # Исходный список словарей dictionary = [ - {'id': 41428829, 'state': 'EXECUTED', 'date': '2019-07-03T18:35:29.512364'}, - {'id': 939719570, 'state': 'EXECUTED', 'date': '2018-06-30T02:08:58.425572'}, - {'id': 594226727, 'state': 'CANCELED', 'date': '2018-09-12T21:27:25.241689'}, - {'id': 615064591, 'state': 'CANCELED', 'date': '2018-10-14T08:21:33.419441'} + {"id": 41428829, "state": "EXECUTED", "date": "2019-07-03T18:35:29.512364"}, + {"id": 939719570, "state": "EXECUTED", "date": "2018-06-30T02:08:58.425572"}, + {"id": 594226727, "state": "CANCELED", "date": "2018-09-12T21:27:25.241689"}, + {"id": 615064591, "state": "CANCELED", "date": "2018-10-14T08:21:33.419441"}, ] -# Использование функции фильтрации -filtered = filter_by_state(dictionary, 'EXECUTED') -print(filtered) -print() - -filtered_1 = filter_by_state(dictionary, 'CANCELED') -print(filtered_1) +# Фильтруем словарь по состоянию 'EXECUTED' +filtered = filter_by_state(dictionary, "EXECUTED") +# Сортируем отфильтрованные данные по дате +sorted_filtered = sort_by_date(filtered) +# Выводим отсортированные данные для состояния 'EXECUTED' +print(sorted_filtered) + + +# Фильтруем словарь по состоянию 'CANCELED' +filtered = filter_by_state(dictionary, "CANCELED") +# Сортируем отфильтрованные данные по дате +sorted_filtered = sort_by_date(filtered) +# Выводим отсортированные данные для состояния 'CANCELED' +print(sorted_filtered) +# пустая строка print() # Использование функции сортировки -sorted_events = sort_by_date(dictionary, 'date') +sorted_events = sort_by_date(dictionary, "date") print(sorted_events)