diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index d2c41ae..0000000 --- a/.coveragerc +++ /dev/null @@ -1,14 +0,0 @@ -[run] -omit = - */lib/* - build/* - dist/* - __pycache__/* - django_drip_campaigns.egg-info/* - env-* - env-django-drip/* - *__pycache__* - */migrations/* - *__init__.py - */virtualenv/* - diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 89e5891..0000000 --- a/.flake8 +++ /dev/null @@ -1,3 +0,0 @@ -[flake8] - -exclude = *migrations/*.py, env*, __pycache__, docs, legacy_docs diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41485ae..9647aa1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,37 +1,32 @@ -exclude: 'docs|node_modules|migrations|.git|.tox' +exclude: | + ^(venv|env|\.tox|django_drip_campaigns\.egg-info|__pycache__|docs|legacy_docs|.*/migrations/.*\.py)$ default_stages: [commit] fail_fast: true default_language_version: - python: python3.8 + python: python3.12 repos: - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.2.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - - repo: https://github.com/psf/black - rev: 22.3.0 - hooks: - - id: black - - - repo: https://github.com/timothycrosley/isort - rev: 5.7.0 + - repo: https://github.com/pycqa/isort + rev: 5.13.2 hooks: - id: isort + args: ["--settings-path=setup.cfg"] - - repo: https://gitlab.com/pycqa/flake8 - rev: 4.0.1 + - repo: https://github.com/pycqa/flake8 + rev: 7.1.1 hooks: - id: flake8 - args: ['--config=setup.cfg'] - additional_dependencies: [flake8-isort] + args: ["--config=setup.cfg"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.942 + rev: v1.11.2 hooks: - id: mypy - args: ['--namespace-packages', '--explicit-package-bases', '--ignore-missing-imports', '--no-warn-unused-ignores'] - additional_dependencies: [django-stubs, six, types-six] + args: ["--config-file=setup.cfg"] + additional_dependencies: [django-stubs, six] + + - repo: https://github.com/psf/black + rev: 24.8.0 + hooks: + - id: black + args: ["--config=pyproject.toml"] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d3f2d28..ed95cd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -100,6 +100,30 @@ with older versions of Python. from the `test-requirements.txt` file that has the list of the needed dev libraries. - You will see the tests execution for each version of Python. - You can run `tox -v` to see more details. +8. Run `pre-commit install` so pre-commit is configured. This will make that some dev tools are run when making a git commit. The tools are + explained in the next section. + +### Use of Dev tools + +If you want to develop in Django Drip, you will need to use these dev tools: + +- isort: to automatically sort imports in Python files, ensuring a consistent and organized format. Before the commit, run `isort .`, this will sort the imports. +- black: to automatically format Python code by enforcing a consistent style, improving readability while adhering to PEP 8 guidelines. Before the commit, run `black .`. This will format the files. +- flake8: to enforce coding style guidelines and check for code quality issues in Python, including PEP 8 compliance, syntax errors, and potential bugs. Before the commit, run `flake8 .`. This will show errors if any of the used guidelines are not being met. +- mypy: used for static type checking in Python, ensuring that variables, functions, and return types match the expected types specified in type hints. Before commit, run `mypy .`. This will show errors if there is any typing error. + +All these tools are configured in the setup.cfg file, except black, that can't use that file and uses pyproject.toml. +It's important to make sure these four tools are executed successfuly before making any git commit. If any of them +shows any errors, you need to fix all of them before making the commit. + +### Test Coverage + +If you add new code, make sure you create tests for it and make sure you don't decrease the percentage of test coverage. + +1. You can run: `coverage run -m pytest .` +2. Now run: `coverage report -m` + +This way you will see a complete report of the tests. The percentage coverage should be equal or greater to the current one: 94%. ## Use a Consistent Coding Style diff --git a/Pipfile b/Pipfile index 261f018..004f321 100644 --- a/Pipfile +++ b/Pipfile @@ -1,24 +1,32 @@ [[source]] +name = "pypi" url = "https://pypi.org/simple" verify_ssl = true -name = "pypi" [packages] -django = "==4.2.16" apscheduler = "==3.10.4" celery = "==5.4.0" +django = "==4.2.16" typing-extensions = "==4.12.2" [dev-packages] +black = "==24.8.0" +coverage = "==7.6.1" +django-coverage-plugin = "==3.1.0" +django-stubs = "==5.1.0" +factory-boy = "==3.3.1" +faker = "==29.0.0" +flake8 = "==7.1.1" +isort = "==5.13.2" +mypy = "==1.11.2" pytest = "==8.3.3" -pytest-sugar = "==1.0.0" -pytest-django = "==4.9.0" pytest-celery = "==0.0.0" -faker = "==29.0.0" -factory-boy = "==3.3.1" +pytest-django = "==4.9.0" +pytest-sugar = "==1.0.0" tox = "==4.20.0" -coverage = "==7.6.1" +types-six = "==1.16.21.20240513" +pre-commit = "==3.8.0" [requires] -python_version = "3.12" python_full_version = "3.12.4" +python_version = "3.12" diff --git a/Pipfile.lock b/Pipfile.lock index ffce856..a2d6386 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "9cf13ac549aacf2b984af43526ab154dd9827e7ccf31a5316b3963ddafbbefbe" + "sha256": "7e2f553830ea4f3b8e9e3a7ab47819dcfa3b19380a2ab1b20e76d787440b90d3" }, "pipfile-spec": 6, "requires": { @@ -44,11 +44,11 @@ }, "billiard": { "hashes": [ - "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d", - "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c" + "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", + "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" }, "celery": { "hashes": [ @@ -109,11 +109,11 @@ }, "prompt-toolkit": { "hashes": [ - "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", - "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360" + "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", + "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.47" + "version": "==3.0.48" }, "python-dateutil": { "hashes": [ @@ -157,11 +157,11 @@ }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "tzlocal": { "hashes": [ @@ -196,13 +196,50 @@ "markers": "python_version >= '3.6'", "version": "==5.2.0" }, + "asgiref": { + "hashes": [ + "sha256:3e1e3ecc849832fe52ccf2cb6686b7a55f82bb1d6aee72a58826471390335e47", + "sha256:c343bd80a0bec947a9860adb4c432ffa7db769836c64238fc34bdc3fec84d590" + ], + "markers": "python_version >= '3.8'", + "version": "==3.8.1" + }, "billiard": { "hashes": [ - "sha256:07aa978b308f334ff8282bd4a746e681b3513db5c9a514cbdd810cbbdc19714d", - "sha256:9a3c3184cb275aa17a732f93f65b20c525d3d9f253722d26a82194803ade5a2c" + "sha256:12b641b0c539073fc8d3f5b8b7be998956665c4233c7c1fcd66a7e677c4fb36f", + "sha256:40b59a4ac8806ba2c2369ea98d876bc6108b051c227baffd928c644d15d8f3cb" ], "markers": "python_version >= '3.7'", - "version": "==4.2.0" + "version": "==4.2.1" + }, + "black": { + "hashes": [ + "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6", + "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e", + "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", + "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018", + "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e", + "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd", + "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4", + "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed", + "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2", + "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42", + "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af", + "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb", + "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368", + "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb", + "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af", + "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed", + "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47", + "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2", + "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a", + "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c", + "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920", + "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==24.8.0" }, "cachetools": { "hashes": [ @@ -221,6 +258,14 @@ "markers": "python_version >= '3.8'", "version": "==5.4.0" }, + "cfgv": { + "hashes": [ + "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", + "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560" + ], + "markers": "python_version >= '3.8'", + "version": "==3.4.0" + }, "chardet": { "hashes": [ "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", @@ -354,6 +399,40 @@ ], "version": "==0.3.8" }, + "django": { + "hashes": [ + "sha256:1ddc333a16fc139fd253035a1606bb24261951bbc3a6ca256717fa06cc41a898", + "sha256:6f1616c2786c408ce86ab7e10f792b8f15742f7b7b7460243929cb371e7f1dad" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.2.16" + }, + "django-coverage-plugin": { + "hashes": [ + "sha256:223d34bf92bebadcb8b7b89932480e41c7bd98b44a8156934488fbe7f4a71f99", + "sha256:eb0ea8ffdb0db11a02994fc99be6500550efb496c350d709f418ff3d8e553a67" + ], + "index": "pypi", + "version": "==3.1.0" + }, + "django-stubs": { + "hashes": [ + "sha256:86128c228b65e6c9a85e5dc56eb1c6f41125917dae0e21e6cfecdf1b27e630c5", + "sha256:b98d49a80aa4adf1433a97407102d068de26c739c405431d93faad96dd282c40" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==5.1.0" + }, + "django-stubs-ext": { + "hashes": [ + "sha256:a455fc222c90b30b29ad8c53319559f5b54a99b4197205ddbb385aede03b395d", + "sha256:ed7d51c0b731651879fc75f331fb0806d98b67bfab464e96e2724db6b46ef926" + ], + "markers": "python_version >= '3.8'", + "version": "==5.1.0" + }, "factory-boy": { "hashes": [ "sha256:7b1113c49736e1e9995bc2a18f4dbf2c52cf0f841103517010b1d825712ce3ca", @@ -380,6 +459,23 @@ "markers": "python_version >= '3.8'", "version": "==3.16.1" }, + "flake8": { + "hashes": [ + "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38", + "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.1'", + "version": "==7.1.1" + }, + "identify": { + "hashes": [ + "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0", + "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98" + ], + "markers": "python_version >= '3.8'", + "version": "==2.6.1" + }, "iniconfig": { "hashes": [ "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", @@ -388,6 +484,15 @@ "markers": "python_version >= '3.7'", "version": "==2.0.0" }, + "isort": { + "hashes": [ + "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", + "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6" + ], + "index": "pypi", + "markers": "python_full_version >= '3.8.0'", + "version": "==5.13.2" + }, "kombu": { "hashes": [ "sha256:14212f5ccf022fc0a70453bb025a1dcc32782a588c49ea866884047d66e14763", @@ -396,6 +501,64 @@ "markers": "python_version >= '3.8'", "version": "==5.4.2" }, + "mccabe": { + "hashes": [ + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + ], + "markers": "python_version >= '3.6'", + "version": "==0.7.0" + }, + "mypy": { + "hashes": [ + "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36", + "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce", + "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6", + "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b", + "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca", + "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24", + "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383", + "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7", + "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86", + "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d", + "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4", + "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8", + "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987", + "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385", + "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79", + "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef", + "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6", + "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70", + "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca", + "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70", + "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12", + "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104", + "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a", + "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318", + "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1", + "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b", + "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.11.2" + }, + "mypy-extensions": { + "hashes": [ + "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", + "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782" + ], + "markers": "python_version >= '3.5'", + "version": "==1.0.0" + }, + "nodeenv": { + "hashes": [ + "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", + "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==1.9.1" + }, "packaging": { "hashes": [ "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", @@ -404,6 +567,14 @@ "markers": "python_version >= '3.8'", "version": "==24.1" }, + "pathspec": { + "hashes": [ + "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", + "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712" + ], + "markers": "python_version >= '3.8'", + "version": "==0.12.1" + }, "platformdirs": { "hashes": [ "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", @@ -420,13 +591,38 @@ "markers": "python_version >= '3.8'", "version": "==1.5.0" }, + "pre-commit": { + "hashes": [ + "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", + "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f" + ], + "index": "pypi", + "markers": "python_version >= '3.9'", + "version": "==3.8.0" + }, "prompt-toolkit": { "hashes": [ - "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", - "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360" + "sha256:d6623ab0477a80df74e646bdbc93621143f5caf104206aa29294d53de1a03d90", + "sha256:f49a827f90062e411f1ce1f854f2aedb3c23353244f8108b89283587397ac10e" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.0.47" + "version": "==3.0.48" + }, + "pycodestyle": { + "hashes": [ + "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", + "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521" + ], + "markers": "python_version >= '3.8'", + "version": "==2.12.1" + }, + "pyflakes": { + "hashes": [ + "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", + "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a" + ], + "markers": "python_version >= '3.8'", + "version": "==3.2.0" }, "pyproject-api": { "hashes": [ @@ -479,6 +675,65 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==2.9.0.post0" }, + "pyyaml": { + "hashes": [ + "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff", + "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", + "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", + "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e", + "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", + "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", + "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", + "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", + "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", + "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", + "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a", + "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", + "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", + "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8", + "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", + "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19", + "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", + "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a", + "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", + "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", + "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", + "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631", + "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d", + "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", + "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", + "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", + "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", + "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", + "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", + "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706", + "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", + "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", + "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", + "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083", + "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", + "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", + "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", + "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f", + "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725", + "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", + "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", + "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", + "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", + "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", + "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5", + "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d", + "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290", + "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", + "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", + "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", + "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", + "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12", + "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.2" + }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", @@ -487,6 +742,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, + "sqlparse": { + "hashes": [ + "sha256:773dcbf9a5ab44a090f3441e2180efe2560220203dc2f8c0b0fa141e18b505e4", + "sha256:bb6b4df465655ef332548e24f08e205afc81b9ab86cb1c45657a7ff173a3a00e" + ], + "markers": "python_version >= '3.8'", + "version": "==0.5.1" + }, "termcolor": { "hashes": [ "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63", @@ -504,13 +767,39 @@ "markers": "python_version >= '3.8'", "version": "==4.20.0" }, + "types-pyyaml": { + "hashes": [ + "sha256:392b267f1c0fe6022952462bf5d6523f31e37f6cea49b14cee7ad634b6301570", + "sha256:d1405a86f9576682234ef83bcb4e6fff7c9305c8b1fbad5e0bcd4f7dbdc9c587" + ], + "markers": "python_version >= '3.8'", + "version": "==6.0.12.20240917" + }, + "types-six": { + "hashes": [ + "sha256:af2a105be6d504339bfed81319cc8e8697865f0ee5c6baa63658f127b33b9e63", + "sha256:cdf445b5161bf17753500713a475ab79a45bd0d87728b8bfcecd86e2fbf66402" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==1.16.21.20240513" + }, + "typing-extensions": { + "hashes": [ + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==4.12.2" + }, "tzdata": { "hashes": [ - "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd", - "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252" + "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc", + "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd" ], "markers": "python_version >= '2'", - "version": "==2024.1" + "version": "==2024.2" }, "vine": { "hashes": [ @@ -522,11 +811,11 @@ }, "virtualenv": { "hashes": [ - "sha256:4f3ac17b81fba3ce3bd6f4ead2749a72da5929c01774948e243db9ba41df4ff6", - "sha256:ce489cac131aa58f4b25e321d6d186171f78e6cb13fafbf32a840cee67733ff4" + "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48", + "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2" ], "markers": "python_version >= '3.7'", - "version": "==20.26.5" + "version": "==20.26.6" }, "wcwidth": { "hashes": [ diff --git a/__init__.py b/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/drip/admin.py b/drip/admin.py index b6ad7c1..cf6084a 100644 --- a/drip/admin.py +++ b/drip/admin.py @@ -151,7 +151,7 @@ def add_view(self, request: HttpRequest, form_url: str = "", extra_context: Any return super(DripAdmin, self).add_view( request, form_url=form_url, - extra_context=self.build_extra_context(extra_context), # type: ignore + extra_context=self.build_extra_context(extra_context), ) def change_view(self, request: HttpRequest, object_id: str, form_url="", extra_context: Any = None) -> HttpResponse: diff --git a/drip/campaigns/models.py b/drip/campaigns/models.py index be4f248..7c736e9 100644 --- a/drip/campaigns/models.py +++ b/drip/campaigns/models.py @@ -5,7 +5,7 @@ class Campaign(models.Model): name = models.CharField(max_length=256) delete_drips = models.BooleanField(default=True) - unsubscribed_users = models.ManyToManyField( + unsubscribed_users = models.ManyToManyField( # type: ignore getattr(settings, "AUTH_USER_MODEL", "auth.User"), through="UserUnsubscribeCampaign", related_name="campaign_unsubscribed_users", diff --git a/drip/models.py b/drip/models.py index 367dd23..5bfa115 100644 --- a/drip/models.py +++ b/drip/models.py @@ -60,7 +60,7 @@ class AbstractDrip(models.Model): on_delete=models.SET_DEFAULT, help_text="If set, this is the campaign to which this Drip belongs to.", ) - unsubscribed_users = models.ManyToManyField( + unsubscribed_users = models.ManyToManyField( # type: ignore getattr(settings, "AUTH_USER_MODEL", "auth.User"), through="UserUnsubscribeDrip", related_name="drips_unsubscribed", @@ -253,7 +253,7 @@ def set_time_deltas_and_dates(self, now: Callable, field_value: str) -> TimeDelt def set_f_expressions(self, field_value: str) -> FExpressionOrStr: """ - If field_value starts with the substring 'F\_', returns an instance + If field_value starts with the substring 'F_', returns an instance of models.F within the field_value expression, otherwise returns field_value unchanged. """ # noqa: W605 @@ -302,9 +302,9 @@ def filter_kwargs( field_value: FieldValue = self.set_time_deltas_and_dates(now, self.field_value) - field_value = self.set_f_expressions(field_value) if type(field_value) == str else field_value + field_value = self.set_f_expressions(field_value) if isinstance(field_value, str) else field_value - field_value = self.set_booleans(field_value) if type(field_value) == str else field_value + field_value = self.set_booleans(field_value) if isinstance(field_value, str) else field_value kwargs = {field_name: field_value} diff --git a/drip/tests/test_drips.py b/drip/tests/test_drips.py index d15b364..1e0a03e 100644 --- a/drip/tests/test_drips.py +++ b/drip/tests/test_drips.py @@ -505,7 +505,7 @@ def test_apply_annotations_with_count(self): ) qs = qsr.apply_any_annotation(model_drip.drip.get_queryset()) - assert list(qs.query.annotation_select.keys()) == ["num_profile_user_groups"] # type: ignore + assert list(qs.query.annotation_select.keys()) == ["num_profile_user_groups"] def test_apply_multiple_rules_with_aggregation(self): diff --git a/drip/tests/test_rules.py b/drip/tests/test_rules.py index 3c038a8..9be7a16 100644 --- a/drip/tests/test_rules.py +++ b/drip/tests/test_rules.py @@ -28,7 +28,7 @@ def _get_field_value(self, field_type: str) -> Optional[str]: field_types = { "AutoField": self.faker.pyint(min_value=1), "CharField": self.faker.word(), - "DateTimeField": f"now-{self.faker.pyint(min_value= 1, max_value=60)} days", + "DateTimeField": f"now-{self.faker.pyint(min_value=1, max_value=60)} days", "BooleanField": self.faker.pybool(), "EmailField": self.faker.email(), "TextField": self.faker.word(), diff --git a/drip/tokens.py b/drip/tokens.py index 5d12eee..b67818f 100644 --- a/drip/tokens.py +++ b/drip/tokens.py @@ -1,11 +1,11 @@ from typing import Optional, Tuple +from django.conf import settings from django.contrib.auth.models import AbstractBaseUser from django.contrib.auth.tokens import PasswordResetTokenGenerator from django.utils.crypto import constant_time_compare from django.utils.encoding import force_bytes, force_str from django.utils.http import base36_to_int, urlsafe_base64_decode, urlsafe_base64_encode -from django.conf import settings from drip.models import Campaign, Drip from drip.utils import get_user_model @@ -46,7 +46,10 @@ def check_token(self, user: Optional[AbstractBaseUser], token: Optional[str]) -> return False # Check that the timestamp/uid has not been tampered with - if not constant_time_compare(self._make_token_with_timestamp(user, ts, settings.SECRET_KEY), token): + if not constant_time_compare( + self._make_token_with_timestamp(user, ts, settings.SECRET_KEY), # type: ignore + token, + ): # Ignore line because Mypy doesn't recognice the argument legacy if not constant_time_compare( self._make_token_with_timestamp(user, ts, settings.SECRET_KEY), # type: ignore @@ -74,14 +77,14 @@ def _get_token(self) -> str: """ Generate token using custom token generator class for user """ - return custom_token_generator.make_token(self.user) + return custom_token_generator.make_token(self.user) # type: ignore def _get_uidb64(self, data_id: int) -> str: """ Generate uidb64 string for ids with url encode """ # Mypy is not getting the result of force_bytes as bytes - return urlsafe_base64_encode(force_bytes(data_id)) # type: ignore + return urlsafe_base64_encode(force_bytes(data_id)) def get_uidb64_token(self, object_id: int) -> Tuple[str, str, str]: """ diff --git a/drip/types.py b/drip/types.py index 88d3bc8..e3d39dd 100644 --- a/drip/types.py +++ b/drip/types.py @@ -1,5 +1,6 @@ """Defines the types to be used within the type annotations all along the system""" + from datetime import timedelta from typing import TypeVar, Union diff --git a/drip/utils.py b/drip/utils.py index 0664181..5375b84 100644 --- a/drip/utils.py +++ b/drip/utils.py @@ -65,12 +65,12 @@ def get_full_field(parent_field: str, field_name: str) -> str: def get_rel_model(field: FieldType, RelatedObject: RelatedObject) -> Type[models.Model]: - if not is_valid_instance(field): # type: ignore + if not is_valid_instance(field): RelModel = field.model # field_names.extend(get_fields(RelModel, full_field, True)) else: RelModel = field.related_model # type: ignore - return RelModel # type: ignore + return RelModel def is_valid_instance(field: FieldType) -> bool: @@ -133,7 +133,7 @@ def get_fields( # github.com/omab/python-social-auth/commit/d8637cec02422374e4102231488481170dc51057 if isinstance(Model, six.string_types): app_label, model_name = Model.split(".") - Model = models.get_model(app_label, model_name) # type: ignore + Model = models.get_model(app_label, model_name) fields = Model._meta.fields + Model._meta.many_to_many + Model._meta.get_fields() # type: ignore model_stack.append(Model) @@ -171,7 +171,7 @@ def give_model_field(full_field: str, Model: Type[models.Model]) -> tuple: return full_key, name, _Model, _ModelField message_exception = "Field key `{field}` not found on `{model}`.".format( field=full_field, - model=Model.__name__, # type: ignore + model=Model.__name__, ) raise Exception(message_exception) diff --git a/pyproject.toml b/pyproject.toml index 32b411c..500d6f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,4 +1,15 @@ [tool.black] skip_string_normalization = false line-length = 120 -exclude = '.*\/(migrations|settings)\/.*' +exclude = ''' +/( + venv + | env + | \.tox + | django_drip_campaigns\.egg-info + | __pycache__ + | .+/migrations + | docs + | legacy_docs +)/ +''' diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index cfd4385..0000000 --- a/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -addopts = --ds=testsettings --reuse-db -python_files = tests.py test_*.py diff --git a/setup.cfg b/setup.cfg index 359e9fc..f75510b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,41 +1,52 @@ [flake8] max-line-length = 120 -exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv/* +exclude = venv/, env/, .tox/, django_drip_campaigns.egg-info/, __pycache__, docs/, legacy_docs/, **/migrations/*.py extend-ignore = E203, W503 -[pycodestyle] -max-line-length = 120 -exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules,venv - [isort] line_length = 120 known_first_party = drip,config multi_line_output = 3 default_section = THIRDPARTY -skip = venv/ +skip = venv/, env/, .tox/, django_drip_campaigns.egg-info/, __pycache__, docs/, legacy_docs/ skip_glob = **/migrations/*.py include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true +; [black]: black is configured in pyproject.toml, because it doesn't use this file + [mypy] -python_version = 3.8 +python_version = 3.12 check_untyped_defs = True ignore_missing_imports = True warn_unused_ignores = True warn_redundant_casts = True warn_unused_configs = True plugins = mypy_django_plugin.main +exclude = ^(venv|env|\.tox|django_drip_campaigns\.egg-info|__pycache__|.*/migrations|docs|legacy_docs) [mypy.plugins.django-stubs] django_settings_module = testsettings -[mypy-*.migrations.*] -# Django migrations should not produce any errors: -ignore_errors = True +[tool:pytest] +addopts = --ds=testsettings --reuse-db +python_files = tests.py test_*.py [coverage:run] include = drip/* -omit = *migrations*, *tests* +omit = + */lib/* + build/* + dist/* + __pycache__/* + django_drip_campaigns.egg-info/* + env-* + env-django-drip/* + *__pycache__* + */migrations/* + *__init__.py + */virtualenv/* + *tests* plugins = django_coverage_plugin diff --git a/testsettings.py b/testsettings.py index 9f0ece9..d469f17 100755 --- a/testsettings.py +++ b/testsettings.py @@ -52,6 +52,7 @@ "django.contrib.messages.context_processors.messages", "django.template.context_processors.request", ], + "debug": DEBUG, }, }, ]