Merge branch 'develop'
- fix docker-compose.yml - fix selenium with new version firefox - improve screencast with selenium - upgrade poetry odoo 14 - support custom makefile with Common.Makefile
This commit is contained in:
commit
d237ce4696
12 changed files with 372 additions and 153 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -42,4 +42,5 @@ pyproject.toml
|
|||
requirements.txt
|
||||
requirement/ignore_requirements.txt
|
||||
screenshots
|
||||
screencasts
|
||||
script/todo/todo_override.json
|
||||
|
|
|
|||
2
Makefile
2
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ colorama
|
|||
wheel
|
||||
mmg==1.0.3
|
||||
selenium
|
||||
pykeepass
|
||||
|
||||
# For OSX
|
||||
cython
|
||||
|
|
|
|||
|
|
@ -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 = `
|
||||
<svg class="robot-animation" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" style="width: 150px; cursor: pointer;">
|
||||
<circle cx="32" cy="32" r="30" fill="#FF5252"/>
|
||||
<path fill="#FFF" d="M20 27h24l-6-12h-12z"/>
|
||||
<circle cx="24" cy="44" r="4" fill="#FFF"/>
|
||||
<circle cx="40" cy="44" r="4" fill="#FFF"/>
|
||||
<svg class="cute-robot" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 150" style="width: 150px; cursor: pointer;">
|
||||
<!-- Corps du robot -->
|
||||
<rect x="25" y="50" width="50" height="70" rx="10" ry="10" fill="#4CAF50"/>
|
||||
|
||||
<!-- Tête du robot -->
|
||||
<circle cx="50" cy="30" r="20" fill="#4CAF50"/>
|
||||
|
||||
<!-- Yeux du robot -->
|
||||
<circle cx="42" cy="25" r="3" fill="#FFFFFF"/>
|
||||
<circle cx="58" cy="25" r="3" fill="#FFFFFF"/>
|
||||
|
||||
<!-- Bouche du robot -->
|
||||
<path d="M44 38 Q 50 42 56 38" stroke="#FFFFFF" stroke-width="2" fill="transparent"/>
|
||||
|
||||
<!-- Bras du robot -->
|
||||
<rect x="15" y="60" width="15" height="50" rx="5" ry="5" fill="#388E3C"/>
|
||||
<rect x="70" y="60" width="15" height="50" rx="5" ry="5" fill="#388E3C"/>
|
||||
|
||||
<!-- Jambes du robot -->
|
||||
<rect x="35" y="120" width="15" height="30" rx="5" ry="5" fill="#388E3C"/>
|
||||
<rect x="50" y="120" width="15" height="30" rx="5" ry="5" fill="#388E3C"/>
|
||||
</svg>
|
||||
`;
|
||||
"""
|
||||
|
|
@ -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.",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class VideoRecorder(object):
|
|||
self,
|
||||
driver,
|
||||
filename="video.webm",
|
||||
framerate="33/1",
|
||||
framerate="5/1",
|
||||
width=None,
|
||||
height=None,
|
||||
):
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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": [
|
||||
|
|
|
|||
Loading…
Reference in a new issue