diff --git a/.gitignore b/.gitignore index 6a8ae99..f9db17e 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ pyproject.toml requirements.txt requirement/ignore_requirements.txt screenshots +screencasts script/todo/todo_override.json diff --git a/Makefile b/Makefile index a498c59..bb7e9f4 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,8 @@ else endif endif +# Can integrate dedicated makefile of custom project +-include Common.Makefile # Example for update .PHONY: custom_run_example diff --git a/docker-compose.yml b/docker-compose.yml index 7f09eff..adf1c55 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: "3.3" services: ERPLibre: - image: technolibre/erplibre:1.6.0 + image: technolibre/erplibre:1.5.0_odoo_16.0_91a7d1b ports: - 8069:8069 - 8071:8071 diff --git a/requirement/poetry.odoo14.0_python3.8.20.lock b/requirement/poetry.odoo14.0_python3.8.20.lock index a790337..06fa039 100644 --- a/requirement/poetry.odoo14.0_python3.8.20.lock +++ b/requirement/poetry.odoo14.0_python3.8.20.lock @@ -255,6 +255,63 @@ files = [ [package.extras] test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + [[package]] name = "asn1crypto" version = "1.5.1" @@ -850,6 +907,20 @@ files = [ {file = "compressed_rtf-1.0.6.tar.gz", hash = "sha256:c1c827f1d124d24608981a56e8b8691eb1f2a69a78ccad6440e7d92fde1781dd"}, ] +[[package]] +name = "construct" +version = "2.10.70" +description = "A powerful declarative symmetric parser/builder for binary data" +optional = false +python-versions = ">=3.6" +files = [ + {file = "construct-2.10.70-py3-none-any.whl", hash = "sha256:c80be81ef595a1a821ec69dc16099550ed22197615f4320b57cc9ce2a672cb30"}, + {file = "construct-2.10.70.tar.gz", hash = "sha256:4d2472f9684731e58cc9c56c463be63baa1447d674e0d66aeb5627b22f512c29"}, +] + +[package.extras] +extras = ["arrow", "cloudpickle", "cryptography", "lz4", "numpy", "ruamel.yaml"] + [[package]] name = "contextvars" version = "2.4" @@ -1342,20 +1413,6 @@ wrapt = ">=1.10,<2" [package.extras] dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] -[[package]] -name = "deprecation" -version = "2.1.0" -description = "A library to handle automated deprecations" -optional = false -python-versions = "*" -files = [ - {file = "deprecation-2.1.0-py2.py3-none-any.whl", hash = "sha256:a10811591210e1fb0e768a8c25517cabeabcba6f0bf96564f8ff45189f90b14a"}, - {file = "deprecation-2.1.0.tar.gz", hash = "sha256:72b3bde64e5d778694b0cf68178aed03d15e15477116add3fb773e581f9518ff"}, -] - -[package.dependencies] -packaging = "*" - [[package]] name = "dicttoxml" version = "1.7.16" @@ -3813,62 +3870,6 @@ files = [ {file = "phonenumbers-9.0.4.tar.gz", hash = "sha256:b1530fc2a7b67e4c37c63e8e736c7e6efe2fed283c1bbb5c08c4511ec0c160ed"}, ] -[[package]] -name = "pikepdf" -version = "8.4.1" -description = "Read and write PDFs with Python, powered by qpdf" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pikepdf-8.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:35d306fc41adb50e556fe4050645cde37a3dd407526422e44728823045710ebd"}, - {file = "pikepdf-8.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:183cf6e9b1b910257e821079c13b7560f5f39f36dc79b5389cd3cb17fb674814"}, - {file = "pikepdf-8.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b07aa656bb488495ac995dae6cbb1d7c6161944a581e0be7f9f6c3ef1c0aeb6"}, - {file = "pikepdf-8.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56597a0f478c89d4371cd332d580f359d85f66035c7730397bf5660ff3b16938"}, - {file = "pikepdf-8.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:52d8c24504f4d9ece15cd56bf99ccda602d4ca1cb54a4fa69c69ec1ada9add1c"}, - {file = "pikepdf-8.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2e4304287780f56f7b99ee63270ec0fc96e01c1ae9fd2b6d598cced15f56fb0"}, - {file = "pikepdf-8.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:99fd6c89b368a824faee9c968cf80626c5f6989b2e14f1bf8cd863ca68789267"}, - {file = "pikepdf-8.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9fc87f2ebe82609faa40fb29b958877fd3884d14c204fdc65f7494e4e5930ccf"}, - {file = "pikepdf-8.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eac13ce97ee6ee9fbd6bcae982bcf99a9b02335f45ce1adb08b0dc4bd36b1210"}, - {file = "pikepdf-8.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eccf53d961562ea71e834d6c2a39d0487e67b516996cb2317c6980ceceb3776"}, - {file = "pikepdf-8.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f09280adc1e9895a1052b43a5b6c83e2dd432060df06d16041bc8ff3efea8974"}, - {file = "pikepdf-8.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:8cb9436ebd61ad8a32f0135c9aa5558cc78f805298c7f03206f72713c56fb4a2"}, - {file = "pikepdf-8.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71dafd1411d09fa4a58790b8eced746fd8cec1553e1291f4dbcea334faf71b34"}, - {file = "pikepdf-8.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdce6d6993cacb0c1071685a40ffdfa038050bc8e9941532c07ea71b12d27e3d"}, - {file = "pikepdf-8.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e7b3c606f0b3f457b28da44f4ed86b17928c9fd35bf30de3a724d5669f65af98"}, - {file = "pikepdf-8.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:5fbbe154a41102a157f3fa13b4fb894353d77d798f2e7ef82fa7ec348fc7a572"}, - {file = "pikepdf-8.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7d4b6f58b7fd5f075415d66087322708ccbcf8f0a07c56d30d6ec7bfeabe8adc"}, - {file = "pikepdf-8.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bafbbddd631dd02b1aebebe76f4de9a244771e438ee84526718383d079095fcb"}, - {file = "pikepdf-8.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94d6eff63bd6ebed8e951621edb85bc8102233b1fae94b810d2b12492972a6dd"}, - {file = "pikepdf-8.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:011d06b03f8545594f1352a73dacf1f4adc3f80cfe4323131ccc85fa95df7c4a"}, - {file = "pikepdf-8.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a261190b91070f9a69943e1ca27b3ada67ed9ed43393c9720d5170db550a7dc"}, - {file = "pikepdf-8.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:efc3674cd9f2d43840fd5f32d6438cdc60c169c11e619e6b69f0446b90db0c90"}, - {file = "pikepdf-8.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b022a846aa10aaa6900b6889fa551406b496e2f893103ca6f4fd3f096def3982"}, - {file = "pikepdf-8.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff17c43eeb4bfa6e7d41fa5a353f20856f84ec9ebeca6c7468e961daf4deea15"}, - {file = "pikepdf-8.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f173a009e492426a25bf06f7be3679512d92e9c39ac4688ff1e38cad251fbd44"}, - {file = "pikepdf-8.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:f703e71a27172103fe18c580b102f24cad221932f016f22776aed5e772642dc6"}, - {file = "pikepdf-8.4.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:202b0d0a37123c2ae3cf8856e2944263351066cf95e32164d72a549f6ad1f4e2"}, - {file = "pikepdf-8.4.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:445a1a9c5d1d82828ecaf988b29bf82253e55bf80862c6529359bce42ad59bd5"}, - {file = "pikepdf-8.4.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:39f764b2283f99425c9fffdff54944bed939718789a719266127eb76705f787e"}, - {file = "pikepdf-8.4.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05a9d90372ec538898b050503670b383247c8bc0661ed6ce13304a1708ae2f17"}, - {file = "pikepdf-8.4.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f7de5c02302e880f339a7de29ee19459974b9e02218b9deed5ed87b6c1865177"}, - {file = "pikepdf-8.4.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705d64521a9896dec7eeda7a2af8ad5d985c966aca13172034cae2eb88a9a721"}, - {file = "pikepdf-8.4.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ccba19dfb26b8aa7a0c58b70916947a3a45054ff2991ffb080249447f57372e"}, - {file = "pikepdf-8.4.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:cd99b1cf5e85247e4d5dec7d8795082f51bf2be504238dfe7beb27f68b398bb7"}, - {file = "pikepdf-8.4.1.tar.gz", hash = "sha256:3f8b46875426a307585f64b97c1937c9d488982f832793387ee2836a594b8ddf"}, -] - -[package.dependencies] -deprecation = "*" -lxml = ">=4.8" -packaging = "*" -Pillow = {version = ">=9.0", markers = "platform_python_implementation != \"PyPy\" or python_version >= \"3.9\""} - -[package.extras] -dev = ["pre-commit", "typer[all]"] -docs = ["GitPython", "PyGithub", "Sphinx (>=3)", "ipython", "matplotlib", "pybind11", "requests", "sphinx-design", "sphinx-issues", "sphinx-rtd-theme", "tomli"] -mypy = ["lxml-stubs", "types-Pillow", "types-requests", "types-setuptools"] -test = ["attrs (>=20.2.0)", "coverage[toml]", "hypothesis (>=6.36)", "numpy (>=1.21.0)", "psutil (>=5.9)", "pybind11", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "pytest-timeout (>=2.1.0)", "pytest-xdist (>=2.5.0)", "python-dateutil (>=2.8.1)", "python-xmp-toolkit (>=2.0.1)", "tomli"] - [[package]] name = "pikepdf" version = "9.2.1" @@ -4483,6 +4484,44 @@ files = [ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, ] +[[package]] +name = "pycryptodomex" +version = "3.22.0" +description = "Cryptographic library for Python" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "pycryptodomex-3.22.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:41673e5cc39a8524557a0472077635d981172182c9fe39ce0b5f5c19381ffaff"}, + {file = "pycryptodomex-3.22.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:276be1ed006e8fd01bba00d9bd9b60a0151e478033e86ea1cb37447bbc057edc"}, + {file = "pycryptodomex-3.22.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:813e57da5ceb4b549bab96fa548781d9a63f49f1d68fdb148eeac846238056b7"}, + {file = "pycryptodomex-3.22.0-cp27-cp27m-win32.whl", hash = "sha256:d7beeacb5394765aa8dabed135389a11ee322d3ee16160d178adc7f8ee3e1f65"}, + {file = "pycryptodomex-3.22.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:b3746dedf74787da43e4a2f85bd78f5ec14d2469eb299ddce22518b3891f16ea"}, + {file = "pycryptodomex-3.22.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:5ebc09b7d8964654aaf8a4f5ac325f2b0cc038af9bea12efff0cd4a5bb19aa42"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:aef4590263b9f2f6283469e998574d0bd45c14fb262241c27055b82727426157"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:5ac608a6dce9418d4f300fab7ba2f7d499a96b462f2b9b5c90d8d994cd36dcad"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a24f681365ec9757ccd69b85868bbd7216ba451d0f86f6ea0eed75eeb6975db"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:259664c4803a1fa260d5afb322972813c5fe30ea8b43e54b03b7e3a27b30856b"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7127d9de3c7ce20339e06bcd4f16f1a1a77f1471bcf04e3b704306dde101b719"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee75067b35c93cc18b38af47b7c0664998d8815174cfc66dd00ea1e244eb27e6"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:1a8b0c5ba061ace4bcd03496d42702c3927003db805b8ec619ea6506080b381d"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:bfe4fe3233ef3e58028a3ad8f28473653b78c6d56e088ea04fe7550c63d4d16b"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-win32.whl", hash = "sha256:2cac9ed5c343bb3d0075db6e797e6112514764d08d667c74cb89b931aac9dddd"}, + {file = "pycryptodomex-3.22.0-cp37-abi3-win_amd64.whl", hash = "sha256:ff46212fda7ee86ec2f4a64016c994e8ad80f11ef748131753adb67e9b722ebd"}, + {file = "pycryptodomex-3.22.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:5bf3ce9211d2a9877b00b8e524593e2209e370a287b3d5e61a8c45f5198487e2"}, + {file = "pycryptodomex-3.22.0-pp27-pypy_73-win32.whl", hash = "sha256:684cb57812cd243217c3d1e01a720c5844b30f0b7b64bb1a49679f7e1e8a54ac"}, + {file = "pycryptodomex-3.22.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c8cffb03f5dee1026e3f892f7cffd79926a538c67c34f8b07c90c0bd5c834e27"}, + {file = "pycryptodomex-3.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:140b27caa68a36d0501b05eb247bd33afa5f854c1ee04140e38af63c750d4e39"}, + {file = "pycryptodomex-3.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:644834b1836bb8e1d304afaf794d5ae98a1d637bd6e140c9be7dd192b5374811"}, + {file = "pycryptodomex-3.22.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c506aba3318505dbeecf821ed7b9a9f86f422ed085e2d79c4fba0ae669920a"}, + {file = "pycryptodomex-3.22.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7cd39f7a110c1ab97ce9ee3459b8bc615920344dc00e56d1b709628965fba3f2"}, + {file = "pycryptodomex-3.22.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e4eaaf6163ff13788c1f8f615ad60cdc69efac6d3bf7b310b21e8cfe5f46c801"}, + {file = "pycryptodomex-3.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eac39e237d65981554c2d4c6668192dc7051ad61ab5fc383ed0ba049e4007ca2"}, + {file = "pycryptodomex-3.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ab0d89d1761959b608952c7b347b0e76a32d1a5bb278afbaa10a7f3eaef9a0a"}, + {file = "pycryptodomex-3.22.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e64164f816f5e43fd69f8ed98eb28f98157faf68208cd19c44ed9d8e72d33e8"}, + {file = "pycryptodomex-3.22.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f005de31efad6f9acefc417296c641f13b720be7dbfec90edeaca601c0fab048"}, + {file = "pycryptodomex-3.22.0.tar.gz", hash = "sha256:a1da61bacc22f93a91cbe690e3eb2022a03ab4123690ab16c46abb693a9df63d"}, +] + [[package]] name = "pydantic" version = "2.10.6" @@ -4778,6 +4817,27 @@ files = [ {file = "pykcs11-1.5.16.tar.gz", hash = "sha256:43d746b0677f43cc634b9f7c4dab2d9ba6b1a83b931e2598247062f8ff641e07"}, ] +[[package]] +name = "pykeepass" +version = "4.1.1.post1" +description = "Python library to interact with keepass databases (supports KDBX3 and KDBX4)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pykeepass-4.1.1.post1-py3-none-any.whl", hash = "sha256:4cfd54f376cb1f58dd8f11fbe7923282bc7dd97ffdf1bb622004a6e718bfe379"}, + {file = "pykeepass-4.1.1.post1.tar.gz", hash = "sha256:28f4927454ebe507ef7294d3ec6b5a72ee3a5c97fcc21b1080b8ddc09f2097dd"}, +] + +[package.dependencies] +argon2_cffi = ">=18.1.0" +construct = ">=2.10.53" +lxml = "*" +pycryptodomex = ">=3.6.2" +pyotp = ">=2.9.0" + +[package.extras] +test = ["pdoc", "pyotp"] + [[package]] name = "pylint" version = "3.1.0" @@ -4887,6 +4947,20 @@ six = ">=1.5.2" docs = ["sphinx", "sphinx-rtd-theme"] test = ["flaky", "pretend", "pytest (>=3.0.1)"] +[[package]] +name = "pyotp" +version = "2.9.0" +description = "Python One Time Password Library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyotp-2.9.0-py3-none-any.whl", hash = "sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612"}, + {file = "pyotp-2.9.0.tar.gz", hash = "sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63"}, +] + +[package.extras] +test = ["coverage", "mypy", "ruff", "wheel"] + [[package]] name = "pyparsing" version = "3.1.4" @@ -6636,13 +6710,13 @@ h11 = ">=0.9.0,<1" [[package]] name = "xlrd" -version = "1.2.0" +version = "1.1.0" description = "Library for developers to extract data from Microsoft Excel (tm) spreadsheet files" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "*" files = [ - {file = "xlrd-1.2.0-py2.py3-none-any.whl", hash = "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"}, - {file = "xlrd-1.2.0.tar.gz", hash = "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2"}, + {file = "xlrd-1.1.0-py2.py3-none-any.whl", hash = "sha256:83a1d2f1091078fb3f65876753b5302c5cfb6a41de64b9587b74cefa75157148"}, + {file = "xlrd-1.1.0.tar.gz", hash = "sha256:8a21885513e6d915fe33a8ee5fdfa675433b61405ba13e2a69e62ee36828d7e2"}, ] [[package]] @@ -6982,4 +7056,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.8.20" -content-hash = "4911060f04d8b21cad0ca41dcdd8d2dca4482960e3619c1fa7f91712e9102eaa" +content-hash = "fca0851b9a85783325027a2d45fa06ba0f2c359d3a155f2928efe0834c57b280" diff --git a/requirement/pyproject.odoo14.0_python3.8.20.toml b/requirement/pyproject.odoo14.0_python3.8.20.toml index 27393e9..37a4f10 100644 --- a/requirement/pyproject.odoo14.0_python3.8.20.toml +++ b/requirement/pyproject.odoo14.0_python3.8.20.toml @@ -122,6 +122,7 @@ pygments = "2.7.4" pygobject = "3.44.1" pygount = "1.5.1" pyjwt = "2.5.0" +pykeepass = "^4.1.1.post1" pylint = "3.1.0" pyopenssl = "21.0.0" pypdf = ">=3.1.0,<5.0" @@ -178,7 +179,7 @@ websocket-client = "^1.8.0" werkzeug = "0.16.1" wheel = "^0.45.1" win-unicode-console = "^0.5" -xlrd = "1.2.0" +xlrd = "1.1.0" xlsxwriter = "1.1.2" xlwt = "1.3" xmlformatter = "^0.2.8" diff --git a/requirement/requirements.odoo14.0_python3.8.20.txt b/requirement/requirements.odoo14.0_python3.8.20.txt index 272c1b7..8a90f89 100644 --- a/requirement/requirements.odoo14.0_python3.8.20.txt +++ b/requirement/requirements.odoo14.0_python3.8.20.txt @@ -10,6 +10,7 @@ colorama wheel mmg==1.0.3 selenium +pykeepass # For OSX cython diff --git a/script/selenium/selenium_lib.py b/script/selenium/selenium_lib.py index 92c33dd..c488f69 100644 --- a/script/selenium/selenium_lib.py +++ b/script/selenium/selenium_lib.py @@ -31,22 +31,35 @@ class SeleniumLib(object): self.config = config self.video_recorder = None if self.config.video_suffix: - self.filename = ( + self.filename_recording = ( f"video_{self.config.video_suffix}_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm" ) else: - self.filename = ( + self.filename_recording = ( "video_" + time.strftime("%Y_%m_%d-%H_%M_%S") + ".webm" ) + dir_path_screencast = os.path.join(".", "screencasts") + self.filename_recording = os.path.join( + dir_path_screencast, self.filename_recording + ) + if not os.path.isdir(dir_path_screencast): + os.mkdir(dir_path_screencast) self.driver = None + with open(".odoo-version") as txt: + self.odoo_version = txt.read() def do_screenshot(self): if self.config.scenario_screenshot: - self.driver.save_screenshot( - f"./screenshots/{self.config.scenario}_{str(int(time.time() * 10000))}.png" + dir_path = os.path.join(".", "screenshots") + if not os.path.isdir(dir_path): + os.mkdir(dir_path) + file_path = os.path.join( + dir_path, + f"{self.config.scenario}_{str(int(time.time() * 10000))}.png", ) + self.driver.save_screenshot(file_path) def configure(self, ignore_open_web=False): # Configuration pour lancer Firefox en mode de navigation privée @@ -102,7 +115,7 @@ class SeleniumLib(object): from script.selenium.selenium_video import VideoRecorder self.video_recorder = VideoRecorder( - self.driver, filename=self.filename + self.driver, filename=self.filename_recording ) # import vlc @@ -126,9 +139,16 @@ class SeleniumLib(object): self.click( "/html/body/div/div[2]/div/addon-list/section[1]/addon-card/div/addon-options/panel-list/panel-item[5]", ) - self.click( - "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", - ) + # Enable Run in Private Windows + try: + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input", + ) + except Exception: + # For old version before Firefox 138 + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) # Enable Odoo_debug into incognito # Back @@ -141,9 +161,16 @@ class SeleniumLib(object): self.click( "/html/body/div/div[2]/div/addon-list/section[1]/addon-card[2]/div/addon-options/panel-list/panel-item[5]", ) - self.click( - "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", - ) + # Enable Run in Private Windows + try: + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[6]/div/label[1]/input", + ) + except Exception: + # For old version before Firefox 138 + self.click( + "/html/body/div/div[2]/div/addon-card/div/addon-details/named-deck/section/div[5]/div/label[1]/input", + ) # Ouvrez la page web if not ignore_open_web: @@ -613,6 +640,13 @@ class SeleniumLib(object): self.driver.switch_to.window(self.driver.window_handles[1]) self.driver.get(url) + def switch_tab(self, index): + # Switch to the new window and open new URL + self.driver.switch_to.window(self.driver.window_handles[index]) + + def refresh(self): + self.driver.refresh() + def check_bot_chat_and_close(self): try: xpath_button = "/html/body/div[3]/div[1]/span[2]/a[2]" @@ -623,14 +657,17 @@ class SeleniumLib(object): print("Chatbot cannot be found, stop searching it.") # Website - def odoo_show_robot_message(self, msg="Ho no!"): + def odoo_show_robot_message( + self, msg="Ho no!", hide_message_after_x_seconds=0 + ): # Injecter l'animation SVG dans la page script_text = "" if msg: + msg_to_print = msg.replace("'", "\\'") script_text = f""" // Ajouter le texte const textElement = document.createElement('div'); - textElement.innerText = '{msg}'; + textElement.innerText = '{msg_to_print}'; textElement.style.color = '#FFFFFF'; textElement.style.fontSize = '24px'; textElement.style.marginBottom = '20px'; @@ -643,6 +680,7 @@ class SeleniumLib(object): (function() { // Créer un div pour l'overlay const overlay = document.createElement('div'); + overlay.id = 'uniqueOverlay'; // Ajout de l'ID overlay.style.position = 'fixed'; overlay.style.top = '0'; overlay.style.left = '0'; @@ -656,11 +694,27 @@ class SeleniumLib(object): // Contenu SVG du robot const svgContent = ` - - - - - + + + + + + + + + + + + + + + + + + + + + `; """ @@ -682,6 +736,18 @@ class SeleniumLib(object): # Exécuter le script pour injecter l'animation self.driver.execute_script(script) + if hide_message_after_x_seconds: + time.sleep(hide_message_after_x_seconds) + delete_script = """(function() { + // Sélectionner l'overlay par ses attributs de style uniques + const overlay = document.getElementById('uniqueOverlay'); + + // Vérifier si l'overlay existe et le supprimer + if (overlay) { + overlay.remove(); + } +})();""" + self.driver.execute_script(delete_script) print(f"Script inject robot svg with msg '{msg}'") def odoo_website_menu_click(self, from_text=""): @@ -709,7 +775,8 @@ class SeleniumLib(object): if self.odoo_version == "16.0": button = self.click_with_mouse_move( By.XPATH, - "//button[contains(@class, 'dropdown-toggle') and .//i[contains(@class, 'oi-apps')]]", + "//button[contains(@class, 'dropdown-toggle') and" + " .//i[contains(@class, 'oi-apps')]]", timeout=10, ) elif self.odoo_version == "14.0": @@ -737,13 +804,15 @@ class SeleniumLib(object): try: status_button = self.click_with_mouse_move( By.XPATH, - f"//button[contains(@class, 'o_arrow_button') and contains(text(), '{status_label}')]", + "//button[contains(@class, 'o_arrow_button') and" + f" contains(text(), '{status_label}')]", timeout=timeout, ) except Exception as e: status_button = self.click_with_mouse_move( By.XPATH, - f"//button[contains(@class, 'o_arrow_button') and text()='{status_label}']", + "//button[contains(@class, 'o_arrow_button') and" + f" text()='{status_label}']", timeout=timeout, ) print(f"Bouton du statusbar avec le label '{status_label}' cliqué.") @@ -754,7 +823,8 @@ class SeleniumLib(object): ): status_button = self.click_with_mouse_move( By.XPATH, - f"//span[contains(@class, 'o_arrow_button') and contains(text(), '{status_label}')]", + "//span[contains(@class, 'o_arrow_button') and contains(text()," + f" '{status_label}')]", timeout=timeout, ) print(f"Bouton du statusbar avec le label '{status_label}' cliqué.") @@ -765,7 +835,8 @@ class SeleniumLib(object): ): status_button = self.click_with_mouse_move( By.XPATH, - f"//button[contains(@class, 'o_arrow_button') and text()='{status_label}']", + "//button[contains(@class, 'o_arrow_button') and" + f" text()='{status_label}']", timeout=timeout, ) print(f"Bouton du statusbar avec le label '{status_label}' cliqué.") @@ -776,7 +847,8 @@ class SeleniumLib(object): ): status_button = self.click_with_mouse_move( By.XPATH, - f"//button[contains(@class, '{btn_class}') and contains(span, '{btn_label}')]", + f"//button[contains(@class, '{btn_class}') and contains(span," + f" '{btn_label}')]", timeout=30, ) print(f"Bouton du statusbar avec le label '{btn_label}' cliqué.") @@ -792,19 +864,28 @@ class SeleniumLib(object): return status_button def odoo_web_form_click_save_action(self): + return self.odoo_web_form_click_by_classname_action( + "o_form_button_save" + ) + + def odoo_web_form_click_web_publish_action(self): + return self.odoo_web_form_click_button_action("website_publish_button") + + def odoo_web_form_click_by_classname_action(self, custom_class_name): status_button = self.click_with_mouse_move( By.CLASS_NAME, - "o_form_button_save", + custom_class_name, timeout=30, ) - print("Bouton avec l'action 'o_form_button_save' cliqué.") + print(f"Bouton avec l'action '{custom_class_name}' cliqué.") return status_button def odoo_web_kanban_card(self, card_label): # From web view kanban, list kanban_card = self.click_with_mouse_move( By.XPATH, - f"//div[contains(@class, 'o_kanban_record')]//span[contains(text(), '{card_label}')]", + "//div[contains(@class," + f" 'o_kanban_record')]//span[contains(text(), '{card_label}')]", timeout=30, ) # kanban_card = self.driver.find_element(By.XPATH, @@ -933,10 +1014,13 @@ class SeleniumLib(object): file_name_1 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_write}" file_name_2 = f"/tmp/erplibre_sync_temp_file{self.config.sync_file_record_read}" with open(file_name_1, "w") as file: - file.write(f"Recording {self.filename}\n") + file.write(f"Recording {self.filename_recording}\n") while not os.path.exists(file_name_2): var_wait_time = 0.001 - print(f"File {self.filename} wait {var_wait_time} seconds") + print( + f"File {self.filename_recording} wait" + f" {var_wait_time} seconds" + ) time.sleep(var_wait_time) self.video_recorder.start() @@ -948,10 +1032,19 @@ class SeleniumLib(object): time.sleep(self.config.selenium_video_time_waiting_end) self.video_recorder.stop() print("End of recording video") - print(self.filename) + print(self.filename_recording) + + filename_recording_mp4 = self.filename_recording.replace( + ".webm", ".mp4" + ) + if self.config.selenium_video_auto_convert_mp4: + os.popen( + "ffmpeg -i" + f" {self.filename_recording} {filename_recording_mp4}" + ) if self.config.selenium_video_auto_play_video: - print(f"Play video {self.filename}") + print(f"Play video {self.filename_recording}") # By python-vlc # media_player = vlc.MediaPlayer(filename) # media = vlc.Media(filename) @@ -959,7 +1052,10 @@ class SeleniumLib(object): # media_player.play() # time.sleep(15) # By external process - os.popen(f"vlc {self.filename}") + if self.config.selenium_video_auto_convert_mp4: + os.popen(f"vlc {filename_recording_mp4}") + else: + os.popen(f"vlc {self.filename_recording}") def generer_code_postal_quebec(self): # Zip code from quebec canada @@ -971,7 +1067,9 @@ class SeleniumLib(object): chiffre = str(random.randint(0, 9)) troisieme_lettre = chr(random.randint(65, 90)) - code_postal = f"{premiere_lettre}{chiffre}{deuxieme_lettre} {chiffre}{troisieme_lettre}{chiffre}" + code_postal = ( + f"{premiere_lettre}{chiffre}{deuxieme_lettre} {chiffre}{troisieme_lettre}{chiffre}" + ) return code_postal @@ -1100,3 +1198,9 @@ def fill_parser(parser): action="store_true", help="Autoplay the video when done.", ) + group_record.add_argument( + "--selenium_video_auto_convert_mp4", + action="store_true", + default=True, + help="Will convert .webm to .mp4 when done.", + ) diff --git a/script/selenium/selenium_video.py b/script/selenium/selenium_video.py index c53604a..50d821a 100644 --- a/script/selenium/selenium_video.py +++ b/script/selenium/selenium_video.py @@ -26,7 +26,7 @@ class VideoRecorder(object): self, driver, filename="video.webm", - framerate="33/1", + framerate="5/1", width=None, height=None, ): diff --git a/script/todo/README.md b/script/todo/README.md index 5fdc582..983796d 100644 --- a/script/todo/README.md +++ b/script/todo/README.md @@ -1,2 +1,4 @@ TODO is an assistant robot to use ERPLibre Execute it with `./script/todo/todo.py` or `make todo`. + +For a new project, copy todo_example.json to todo_override.json and edit it. diff --git a/script/todo/todo.json b/script/todo/todo.json index eefdefa..db2f21c 100644 --- a/script/todo/todo.json +++ b/script/todo/todo.json @@ -17,7 +17,8 @@ ], "function": [ { - "prompt_description": "Ouvrir ERPLibre avec TODO \uD83E\uDD16" + "prompt_description": "Ouvrir ERPLibre avec TODO \uD83E\uDD16", + "command": "./.venv/bin/python ./script/selenium/web_login.py" } ] } diff --git a/script/todo/todo.py b/script/todo/todo.py index f028aa0..242b66d 100755 --- a/script/todo/todo.py +++ b/script/todo/todo.py @@ -47,7 +47,10 @@ class TODO: elif status == "2": self.prompt_execute() elif status == "3": - cmd = f"gnome-terminal --tab -- bash -c 'source ./.venv/bin/activate;make todo'" + cmd = ( + f"gnome-terminal --tab -- bash -c 'source" + f" ./.venv/bin/activate;make todo'" + ) self.executer_commande_live(cmd) # elif status == "3" or status == "install": # print("install") @@ -98,7 +101,8 @@ class TODO: dct_data = dct_data[param] except KeyError: _logger.error( - f"KeyError on file {config_file} with keys {lst_params}" + f"KeyError on file {config_file} with keys" + f" {lst_params}" ) return return dct_data @@ -152,15 +156,54 @@ class TODO: else: print("Commande non trouvée 🤖!") - def prompt_execute_instance(self): - lst_instance = self.get_config(["instance"]) + def execute_from_configuration( + self, dct_instance, exec_run_db=False, ignore_makefile=False + ): + # exec_run_db need argument database + kdbx_key = dct_instance.get("kdbx_key") + odoo_user = dct_instance.get("user") + odoo_password = dct_instance.get("password") + + if kdbx_key: + extra_cmd_web_login = self.kdbx_get_extra_command_user(kdbx_key) + elif odoo_user and odoo_password: + extra_cmd_web_login = ( + f" --default_email_auth {odoo_user} --default_password_auth" + f" '{odoo_password}'" + ) + else: + extra_cmd_web_login = "" + + makefile_cmd = dct_instance.get("makefile_cmd") + if makefile_cmd and not ignore_makefile: + self.executer_commande_live(f"make {makefile_cmd}") + + if exec_run_db: + db_name = dct_instance.get("database") + self.prompt_execute_selenium_and_run_db( + db_name, extra_cmd_web_login=extra_cmd_web_login + ) + + command = dct_instance.get("command") + if command: + self.prompt_execute_selenium( + command=command, extra_cmd_web_login=extra_cmd_web_login + ) + + def fill_help_info(self, lst_instance): help_info = "Commande :\n" help_end = "[0] Retour\n" for i, dct_instance in enumerate(lst_instance): + help_info += ( f"[{i + 1}] " + dct_instance["prompt_description"] + "\n" ) help_info += help_end + return help_info + + def prompt_execute_instance(self): + lst_instance = self.get_config(["instance"]) + help_info = self.fill_help_info(lst_instance) while True: status = click.prompt(help_info) @@ -176,15 +219,12 @@ class TODO: status = click.confirm( "Voulez-vous une nouvelle instance?" ) - if status: - dct_instance = lst_instance[int_cmd - 1] - makefile_cmd = dct_instance.get("makefile_cmd") - db_name = dct_instance.get("database") - self.executer_commande_live(f"make {makefile_cmd}") - kdbx_key = dct_instance.get("kdbx_key") - self.prompt_execute_selenium_and_run_db( - db_name, kdbx_key=kdbx_key - ) + dct_instance = lst_instance[int_cmd - 1] + self.execute_from_configuration( + dct_instance, + exec_run_db=True, + ignore_makefile=not bool(status), + ) except ValueError: pass if cmd_no_found: @@ -192,13 +232,7 @@ class TODO: def prompt_execute_fonction(self): lst_instance = self.get_config(["function"]) - help_info = "Commande :\n" - help_end = "[0] Retour\n" - for i, dct_instance in enumerate(lst_instance): - help_info += ( - f"[{i + 1}] " + dct_instance["prompt_description"] + "\n" - ) - help_info += help_end + help_info = self.fill_help_info(lst_instance) while True: status = click.prompt(help_info) @@ -212,11 +246,7 @@ class TODO: if 0 < int_cmd <= len(lst_instance): cmd_no_found = False dct_instance = lst_instance[int_cmd - 1] - command = dct_instance.get("command") - kdbx_key = dct_instance.get("kdbx_key") - self.prompt_execute_selenium( - command=command, kdbx_key=kdbx_key - ) + self.execute_from_configuration(dct_instance) except ValueError: pass if cmd_no_found: @@ -243,7 +273,8 @@ class TODO: except AttributeError: _logger.error(f"Cannot find password from keys {key}") lst_value.append( - f" --default_email_auth {odoo_user} --default_password_auth '{odoo_password}'" + " --default_email_auth" + f" {odoo_user} --default_password_auth '{odoo_password}'" ) if len(lst_value) == 0: return "" @@ -251,21 +282,14 @@ class TODO: return lst_value[0] return lst_value - def prompt_execute_selenium_and_run_db(self, bd, kdbx_key=None): - if kdbx_key: - extra_cmd_web_login = self.kdbx_get_extra_command_user(kdbx_key) - else: - extra_cmd_web_login = "" - - cmd = f'parallel ::: "./run.sh -d {bd}" "sleep 3;./script/selenium/web_login.py{extra_cmd_web_login}"' + def prompt_execute_selenium_and_run_db(self, bd, extra_cmd_web_login=""): + cmd = ( + f'parallel ::: "./run.sh -d {bd}" "sleep' + f' 3;./script/selenium/web_login.py{extra_cmd_web_login}"' + ) self.executer_commande_live(cmd) - def prompt_execute_selenium(self, command=None, kdbx_key=None): - if kdbx_key: - extra_cmd_web_login = self.kdbx_get_extra_command_user(kdbx_key) - else: - extra_cmd_web_login = "" - + def prompt_execute_selenium(self, command=None, extra_cmd_web_login=""): lst_cmd = [] if not command: cmd = "./script/selenium/web_login.py" @@ -314,13 +338,15 @@ class TODO: if process.returncode != 0: print( - f"La commande a retourné un code d'erreur : {process.returncode}" + "La commande a retourné un code d'erreur :" + f" {process.returncode}" ) except FileNotFoundError: if "password" in commande: print( - f"Erreur : La commande '{commande.split(' ')[0]}'[...] n'a pas été trouvée." + f"Erreur : La commande '{commande.split(' ')[0]}'[...] n'a" + " pas été trouvée." ) else: print( diff --git a/script/todo/todo_example.json b/script/todo/todo_example.json index fec4d1f..c56739c 100644 --- a/script/todo/todo_example.json +++ b/script/todo/todo_example.json @@ -14,6 +14,13 @@ "makefile_cmd": "db_restore_erplibre_base_db_test", "database": "test", "kdbx_key": "default_user_odoo" + }, + { + "prompt_description": "Test 2 - Instance de base minimale", + "makefile_cmd": "db_restore_erplibre_base_db_test", + "database": "test", + "user": "test", + "password": "test" } ], "function": [