[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "integreat-cms"
description = "Content Management System for the Integreat App"
version = "2024.7.1"
authors = [{name = "Tür an Tür – Digitalfabrik gGmbH", email = "tech@integreat-app.de"}]
readme = "README.md"
requires-python = ">=3.11"
keywords = [
    "integreat",
    "cms",
    "django",
    "e-government",
    "newcomers",
    "refugees",
    "multilingual",
]
license = {text = "Apache2 2.0 License"}
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Environment :: Web Environment",
    "Framework :: Django",
    "Framework :: Django :: 3.2",
    "Intended Audience :: Developers",
    "Intended Audience :: System Administrators",
    "License :: OSI Approved :: Apache Software License",
    "Natural Language :: English",
    "Natural Language :: German",
    "Operating System :: POSIX :: Linux",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Topic :: Internet :: WWW/HTTP :: Dynamic Content :: Content Management System",
    "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
]
dependencies = [
    "aiohttp",
    "argon2-cffi",
    "bcrypt",
    "cffi",
    "deepl",
    "Django>=4.2,<5.0",
    "django-cacheops",
    "django-cors-headers",
    "django-db-mutex",
    "django-debug-toolbar",
    "django-import-export==3.3.9",
    "django-linkcheck",
    "django-polymorphic",
    "django-redis",
    "django-treebeard",
    "django-webpack-loader",
    "django-widget-tweaks",
    "feedparser",
    "geopy",
    "google-auth",
    "google-cloud-translate",
    "idna",
    "ipython",
    "jsonschema",
    "lxml",
    "natsort",
    "Pillow",
    "psycopg[binary]",
    "pyotp",
    "python-dateutil",
    "python-magic",
    "pyyaml",
    "qrcode",
    "requests",
    "rules",
    "six",
    "webauthn",
    "xhtml2pdf==0.2.8",
    "reportlab<4.0.0",
    "zammad-py",
]

[project.optional-dependencies]
dev = [
    "black",
    "build",
    "bumpver",
    "djlint",
    "freezegun",
    "isort",
    "mypy",
    "pre-commit",
    "pyjwt",
    "pylint",
    "pylint-django",
    "pylint-per-file-ignores",
    "pytest-circleci-parallelized",
    "pytest-cov",
    "pytest-django",
    "pytest-httpserver",
    "pytest-icdiff",
    "pytest-order",
    "pytest-testmon<=1.4.5",
    "pytest-xdist",
    "requests-mock",
    "ruff",
    "shellcheck-py",
    "sphinx",
    "sphinx-last-updated-by-git",
    "sphinx-rtd-theme",
    "sphinxcontrib-django",
    "twine",
    "types-python-dateutil",
    "types-PyYAML",
    "types-requests",
]
pinned = [
    "aiohttp==3.9.5",
    "aiosignal==1.3.1",
    "arabic-reshaper==3.0.0",
    "argon2-cffi==23.1.0",
    "argon2-cffi-bindings==21.2.0",
    "asgiref==3.8.1",
    "asn1crypto==1.5.1",
    "asttokens==2.4.1",
    "attrs==23.2.0",
    "bcrypt==4.1.3",
    "cachetools==5.3.3",
    "cbor2==5.6.3",
    "certifi==2024.6.2",
    "cffi==1.16.0",
    "charset-normalizer==3.3.2",
    "click==8.1.7",
    "cryptography==42.0.8",
    "cssselect2==0.7.0",
    "decorator==5.1.1",
    "deepl==1.18.0",
    "defusedxml==0.7.1",
    "diff-match-patch==20230430",
    "Django==4.2.13",
    "django-cacheops==7.0.2",
    "django-cors-headers==4.3.1",
    "django-db-mutex==3.1.0",
    "django-debug-toolbar==4.4.2",
    "django-import-export==3.3.9",
    "django-linkcheck==2.3.0",
    "django-polymorphic==3.1.0",
    "django-redis==5.4.0",
    "django-treebeard==4.7.1",
    "django-webpack-loader==3.1.0",
    "django-widget-tweaks==1.5.0",
    "et-xmlfile==1.1.0",
    "executing==2.0.1",
    "feedparser==6.0.11",
    "frozenlist==1.4.1",
    "funcy==2.0",
    "geographiclib==2.0",
    "geopy==2.4.1",
    "google-api-core==2.19.0",
    "googleapis-common-protos==1.63.1",
    "google-auth==2.29.0",
    "google-cloud-core==2.4.1",
    "google-cloud-translate==3.15.3",
    "grpcio==1.64.1",
    "grpcio-status==1.62.2",
    "html5lib==1.1",
    "idna==3.7",
    "ipython==8.25.0",
    "jedi==0.19.1",
    "jsonschema==4.22.0",
    "jsonschema-specifications==2023.12.1",
    "lxml==5.2.2",
    "MarkupPy==1.14",
    "matplotlib-inline==0.1.7",
    "multidict==6.0.5",
    "natsort==8.4.0",
    "odfpy==1.4.1",
    "openpyxl==3.1.3",
    "oscrypto==1.3.0",
    "parso==0.8.4",
    "pexpect==4.9.0",
    "pillow==10.3.0",
    "pip==24.0",
    "prompt_toolkit==3.0.46",
    "protobuf==4.25.3",
    "proto-plus==1.23.0",
    "psycopg==3.1.19",
    "psycopg-binary==3.1.19",
    "ptyprocess==0.7.0",
    "pure-eval==0.2.2",
    "pyasn1==0.6.0",
    "pyasn1_modules==0.4.0",
    "pycparser==2.22",
    "Pygments==2.18.0",
    "pyHanko==0.25.0",
    "pyhanko-certvalidator==0.26.3",
    "pyOpenSSL==24.1.0",
    "pyotp==2.9.0",
    "PyPDF3==1.0.6",
    "pypng==0.20220715.0",
    "python-bidi==0.4.2",
    "python-dateutil==2.9.0.post0",
    "python-magic==0.4.27",
    "PyYAML==6.0.1",
    "qrcode==7.4.2",
    "redis==5.0.4",
    "referencing==0.35.1",
    "reportlab==3.6.13",
    "requests==2.32.3",
    "rpds-py==0.18.1",
    "rsa==4.9",
    "rules==3.4",
    "setuptools==65.5.0",
    "sgmllib3k==1.0.0",
    "six==1.16.0",
    "sqlparse==0.5.0",
    "stack-data==0.6.3",
    "svglib==1.5.1",
    "tablib==3.5.0",
    "tinycss2==1.3.0",
    "tqdm==4.66.4",
    "traitlets==5.14.3",
    "typing_extensions==4.12.1",
    "tzlocal==5.2",
    "uritools==4.0.3",
    "urllib3==2.2.1",
    "wcwidth==0.2.13",
    "webauthn==2.1.0",
    "webencodings==0.5.1",
    "xhtml2pdf==0.2.8",
    "xlrd==2.0.1",
    "xlwt==1.3.0",
    "yarl==1.9.4",
    "zammad-py==3.0.0",
]
dev-pinned = [
    "alabaster==0.7.16",
    "astroid==3.2.2",
    "Babel==2.15.0",
    "backports.tarfile==1.2.0",
    "black==24.4.2",
    "build==1.2.1",
    "bumpver==2023.1129",
    "cfgv==3.4.0",
    "colorama==0.4.6",
    "coverage==7.5.3",
    "cssbeautifier==1.15.1",
    "dill==0.3.8",
    "distlib==0.3.8",
    "djlint==1.34.1",
    "docutils==0.20.1",
    "EditorConfig==0.12.4",
    "execnet==2.1.1",
    "filelock==3.14.0",
    "freezegun==1.5.1",
    "html-tag-names==0.1.2",
    "html-void-elements==0.1.0",
    "icdiff==2.0.7",
    "identify==2.5.36",
    "imagesize==1.4.1",
    "importlib_metadata==7.1.0",
    "iniconfig==2.0.0",
    "jaraco.classes==3.4.0",
    "jaraco.context==5.3.0",
    "jaraco.functools==4.0.1",
    "jeepney==0.8.0",
    "Jinja2==3.1.4",
    "jsbeautifier==1.15.1",
    "json5==0.9.25",
    "keyring==25.2.1",
    "lexid==2021.1006",
    "looseversion==1.3.0",
    "markdown-it-py==3.0.0",
    "MarkupSafe==2.1.5",
    "mccabe==0.7.0",
    "mdurl==0.1.2",
    "more-itertools==10.2.0",
    "mypy==1.10.0",
    "mypy-extensions==1.0.0",
    "nh3==0.2.17",
    "nodeenv==1.9.1",
    "packaging==24.0",
    "pathspec==0.12.1",
    "pkginfo==1.11.0",
    "platformdirs==4.2.2",
    "pluggy==1.5.0",
    "pprintpp==0.4.0",
    "pre-commit==3.7.1",
    "PyJWT==2.8.0",
    "pylint==3.2.2",
    "pylint-django==2.5.5",
    "pylint-per-file-ignores==1.3.2",
    "pylint-plugin-utils==0.8.2",
    "pyproject_hooks==1.1.0",
    "pytest==7.4.4",
    "pytest-circleci-parallelized==0.1.0",
    "pytest-cov==5.0.0",
    "pytest-django==4.8.0",
    "pytest_httpserver==1.0.10",
    "pytest-icdiff==0.9",
    "pytest-order==1.2.1",
    "pytest-testmon==1.4.5",
    "pytest-xdist==3.6.1",
    "readme_renderer==43.0",
    "regex==2023.12.25",
    "requests-mock==1.12.1",
    "requests-toolbelt==1.0.0",
    "rfc3986==2.0.0",
    "rich==13.7.1",
    "ruff==0.4.8",
    "SecretStorage==3.3.3",
    "shellcheck-py==0.10.0.1",
    "snowballstemmer==2.2.0",
    "Sphinx==7.3.7",
    "sphinxcontrib-applehelp==1.0.8",
    "sphinxcontrib-devhelp==1.0.6",
    "sphinxcontrib-django==2.5",
    "sphinxcontrib-htmlhelp==2.0.5",
    "sphinxcontrib-jquery==4.1",
    "sphinxcontrib-jsmath==1.0.1",
    "sphinxcontrib-qthelp==1.0.7",
    "sphinxcontrib-serializinghtml==1.1.10",
    "sphinx-last-updated-by-git==0.3.7",
    "sphinx-rtd-theme==2.0.0",
    "toml==0.10.2",
    "tomlkit==0.12.5",
    "twine==5.1.0",
    "types-python-dateutil==2.9.0.20240316",
    "types-PyYAML==6.0.12.20240311",
    "types-requests==2.32.0.20240602",
    "virtualenv==20.26.2",
    "Werkzeug==3.0.3",
    "zipp==3.19.2",
]

[project.urls]
"Homepage" = "https://integreat-app.de/en/"
"Source Code" = "https://github.com/digitalfabrik/integreat-cms"
"Issues" = "https://github.com/digitalfabrik/integreat-cms/issues"
"Release Notes" = "https://digitalfabrik.github.io/integreat-cms/release-notes.html"
"Documentation" = "https://digitalfabrik.github.io/integreat-cms/"
"Funding" = "https://integreat-app.de/en/donation/"

[tool.setuptools]
script-files = ["integreat_cms/integreat-cms-cli"]
license-files = ["LICENSE", "NOTICE.md"]

[tool.setuptools.packages.find]
include = ["integreat_cms*"]

[tool.bumpver]
current_version = "2024.7.1"
version_pattern = "YYYY.MM.INC0[-TAG]"
commit_message = """
Bump version to {new_version}

[skip ci]
"""
commit = true
tag = false
push = false

[tool.bumpver.file_patterns]
"pyproject.toml" = [
    'current_version = "{version}"',
    'version = "{version}"',
]
"integreat_cms/__init__.py" = [
    '__version__ = "{version}"',
]
"docs/src/conf.py" = [
    'release = "{version}"',
]

[tool.coverage.report]
exclude_also = [
    "def __repr__",
    "if TYPE_CHECKING:",
    "raise NotImplementedError",
]

[tool.djlint]
profile="django"
line_break_after_multiline_tag=true
# exclude invalid html files until this is resolved https://github.com/djlint/djLint/issues/703
exclude = "integreat_cms/api/v3/templates/"

[tool.pylint.main]
jobs = 0
load-plugins = [
    "pylint_django",
    "pylint_per_file_ignores",
    "pylint.extensions.code_style",
    "pylint.extensions.comparison_placement",
    "pylint.extensions.consider_ternary_expression",
    "pylint.extensions.docparams",
    "pylint.extensions.for_any_all",
]
recursive = true
ignore-paths = [
  ".venv",
  "node_modules",
  "build",
]
fail-on = "I"
extension-pkg-whitelist = ["lxml"]
django-settings-module="integreat_cms.core.settings"

[tool.pylint.design]
max-args = 7
max-attributes = 7
max-branches = 12
max-locals = 15
max-parents = 8

[tool.pylint.messages_control]
disable = [
    "consider-using-namedtuple-or-dataclass",
    "consider-using-tuple",
    "duplicate-code",
    "invalid-name",
    "line-too-long",
    "missing-module-docstring",
    "no-member",
    "too-many-lines",
    "ungrouped-imports",
    "unsupported-binary-operation",
    "wrong-import-position",
]
enable = [
    "consider-using-augmented-assign",
    "use-implicit-booleaness-not-comparison-to-string",
    "use-implicit-booleaness-not-comparison-to-zero",
    "useless-suppression",
]

[tool.pylint.reports]
output-format = "colorized"

[tool.pylint-per-file-ignores]
"/tests/"="unused-argument,missing-function-docstring"

[tool.mypy]
disallow_untyped_defs = true
ignore_missing_imports = true
warn_redundant_casts = true
strict_equality = true

[tool.ruff]
line-length = 279
target-version = "py311"

[tool.ruff.lint]
select = [
  "I",      # isort
  "A",      # flake8-builtins
  "AIR",    # Airflow
  "ASYNC",  # flake8-async
  "BLE",    # flake8-blind-except
  "C4",   # flake8-comprehensions
  "C90",    # McCabe cyclomatic complexity
  "DJ",     # flake8-django
  "E",      # pycodestyle
  "EXE",    # flake8-executable
  "F",      # Pyflakes
  "FA",     # flake8-future-annotations
  "FIX",    # flake8-fixme
  "FLY",    # flynt
  "G",      # flake8-logging-format
  "ICN",    # flake8-import-conventions
  "INP",    # flake8-no-pep420
  "INT",    # flake8-gettext
  "ISC",    # flake8-implicit-str-concat
  "LOG",    # flake8-logging
  "NPY",    # NumPy-specific rules
  "PD",     # pandas-vet
  "PERF",   # Perflint
  "PGH",    # pygrep-hooks
  "PIE",    # flake8-pie
  "PL",     # Pylint
  "PYI",    # flake8-pyi
  "RSE",    # flake8-raise
  "SLOT",   # flake8-slots
  "T10",    # flake8-debugger
  "TRIO",   # flake8-trio
  "W",      # pycodestyle
  "YTT",    # flake8-2020
  # "ANN",  # flake8-annotations
  # "ARG",  # flake8-unused-arguments
  # "B",    # flake8-bugbear
  # "COM",  # flake8-commas
  # "CPY",  # flake8-copyright
  # "D",    # pydocstyle
  # "DTZ",  # flake8-datetimez
  # "EM",   # flake8-errmsg
  # "ERA",  # eradicate
  # "FBT",  # flake8-boolean-trap
  # "FURB", # refurb
  # "N",    # pep8-naming
  # "PT",   # flake8-pytest-style
  # "PTH",  # flake8-use-pathlib
  # "Q",    # flake8-quotes
  # "RET",  # flake8-return
  # "RUF",  # Ruff-specific rules
  # "S",    # flake8-bandit
  # "SIM",  # flake8-simplify
  # "SLF",  # flake8-self
  # "T20",  # flake8-print
  # "TCH",  # flake8-type-checking
  # "TD",   # flake8-todos
  # "TID",  # flake8-tidy-imports
  # "TRY",  # tryceratops
  # "UP",   # pyupgrade
]
ignore = [
  "F401",
  "INP001",
]

[tool.ruff.lint.mccabe]
max-complexity = 23  # default is 10

[tool.ruff.lint.isort]
order-by-type = false

[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401", "F403"]
"docs/src/conf.py" = ["A001"]
"integreat_cms/api/v3/*" = ["PERF401"]
"integreat_cms/api/v3/social_media_headers.py" = ["FIX002"]
"integreat_cms/cms/forms/custom_model_form.py" = ["G003", "PERF401"]
"integreat_cms/cms/forms/linkcheck/link_replace_form.py" = ["W605"]
"integreat_cms/cms/forms/pages/page_form.py" = ["PLR5501"]
"integreat_cms/cms/forms/regions/region_form.py" = ["FIX002"]
"integreat_cms/cms/models/abstract_base_model.py" = ["BLE001", "DJ012"]
"integreat_cms/cms/models/poi_categories/poi_category.py" = ["DJ001"]
"integreat_cms/cms/models/push_notifications/push_notification.py" = ["DJ001"]
"integreat_cms/cms/models/users/user.py" = ["DJ001"]
"integreat_cms/cms/views/*" = ["PIE804"]
"integreat_cms/cms/views/analytics/app_size_view.py" = ["FIX002"]
"integreat_cms/core/*_settings.py" = ["F403"]
"integreat_cms/core/circleci_settings.py" = ["F405"]
"integreat_cms/core/management/commands/find_large_files.py" = ["G004"]
"integreat_cms/core/sphinx_settings.py" = ["F405"]
"integreat_cms/google_translate_api/apps.py" = ["BLE001"]
"integreat_cms/google_translate_api/google_translate_api_client.py" = ["BLE001"]
"integreat_cms/nominatim_api/nominatim_api_client.py" = ["PERF401"]
"tests/*" = ["S101"]
"tests/core/management/commands/test_summ_ai_bulk.py" = ["FIX002"]
"tests/deepl_api/deepl_api_test.py" = ["PIE804"]
"tests/pdf/test_pdf_export.py" = ["PLW2901"]
"tests/summ_ai_api/summ_ai_test.py" = ["PLW0603"]
"tests/textlab_api/textlab_api_test.py" = ["A002"]

[tool.ruff.lint.pylint]
allow-magic-value-types = ["float", "int", "str"]
max-args = 8  # default is 5
max-bool-expr = 5  # default is 5
max-branches = 22  # default is 12
max-locals = 15  # default is 15
max-positional-args = 5  # default is 5
max-returns = 12  # default is 6
max-statements = 64  # default is 50
