[project] name = "frappe" authors = [ { name = "Frappe Technologies Pvt Ltd", email = "developers@frappe.io"} ] description = "Metadata driven, full-stack low code web framework" requires-python = ">=3.10,<3.14" readme = "README.md" dynamic = ["version"] dependencies = [ # core dependencies "Babel~=2.16.0", "Click~=8.2.0", "filelock~=3.18.0", "filetype~=1.2.0", "GitPython~=3.1.44", "Jinja2~=3.1.6", "Pillow~=11.3.0", "PyJWT~=2.10.1", # We depend on internal attributes, # do NOT add loose requirements on PyMySQL versions. "PyMySQL==1.1.1", "pypdf~=6.0.0", "PyPika @ git+https://github.com/frappe/pypika@093984977ce157d35e048c51d9ff55a1f0f44570", "mysqlclient==2.2.7", "PyQRCode~=1.2.1", "PyYAML~=6.0.2", "RestrictedPython~=8.0", "WeasyPrint==66.0", "pydyf==0.11.0", "Werkzeug==3.1.3", "Whoosh~=2.7.4", "beautifulsoup4~=4.13.4", "bleach-allowlist~=1.0.3", "bleach[css]~=6.2.0", "chardet~=5.2.0", "croniter~=6.0.0", "cryptography~=45.0.4", "cssutils~=2.11.1", "email-reply-parser~=0.5.12", "gunicorn @ git+https://github.com/frappe/gunicorn@bb554053bb87218120d76ab6676af7015680e8b6", "html5lib~=1.1", "ipython~=8.37.0", "ldap3~=2.9", "markdown2~=2.5.3", "MarkupSafe~=3.0.2", "num2words~=0.5.14", "oauthlib~=3.2.2", "openpyxl~=3.1.5", "orjson~=3.10.18", "passlib~=1.7.4", "pdfkit~=1.0.0", "phonenumbers~=9.0.7", "premailer~=3.10.0", "psutil~=7.0.0", "psycopg2-binary~=2.9.1", "pyOpenSSL~=25.1.0", "pydantic~=2.11.7", "pyotp~=2.9.0", "python-dateutil~=2.9.0", "pytz==2025.2", "rauth~=0.7.3", "redis~=6.2.0", "hiredis~=3.2.1", "requests-oauthlib~=2.0.0", "requests~=2.32.4", # We depend on internal attributes of RQ. # Do NOT add loose requirements on RQ versions. # Audit the code changes w.r.t. background_jobs.py before updating. "rq==2.4.0", "rsa~=4.9", "semantic-version~=2.10.0", "sentry-sdk~=1.45.1", "sqlparse~=0.5.0", "sql_metadata~=2.17.0", "tenacity~=9.1.2", "terminaltables~=3.1.10", "traceback-with-variables~=2.2.0", "typing_extensions>=4.6.1,<5", "tomli~=2.2.1", "uuid-utils~=0.11.0", "xlrd~=2.0.2", "zxcvbn~=4.5.0", "markdownify~=1.1.0", # integration dependencies "google-api-python-client~=2.172.0", "google-auth-oauthlib~=1.2.2", "google-auth~=2.40.3", "posthog~=5.0.0", "vobject~=0.9.9", "pycountry~=24.6.1", "websockets" ] [project.urls] Homepage = "https://frappeframework.com/" Repository = "https://github.com/frappe/frappe.git" "Bug Reports" = "https://github.com/frappe/frappe/issues" [project.optional-dependencies] dev = [ "pyngrok~=6.0.0", "watchdog~=3.0.0", "responses==0.23.1", # typechecking "basedmypy", "types-PyMySQL", "types-PyYAML", "types-Pygments", "types-beautifulsoup4", "types-bleach", "types-cffi", "types-colorama", "types-croniter", "types-decorator", "types-ldap3", "types-oauthlib", "types-openpyxl", "types-passlib", "types-psutil", "types-psycopg2", "types-python-dateutil", "types-pytz", "types-requests", "types-six", "types-vobject", "types-zxcvbn", "pypika-stubs", # contributed ] test = [ "unittest-xml-reporting~=3.2.0", "coverage~=7.10.0", "Faker~=18.10.1", "hypothesis~=6.77.0", "freezegun~=1.5.1", ] [build-system] requires = ["flit_core >=3.4,<4"] build-backend = "flit_core.buildapi" [tool.frappe.testing.function_type_validation] max_module_depth = 0 skip_namespaces = [ "frappe.deprecation_dumpster", "frappe.utils.typing_validations", ] [tool.bench.dev-dependencies] coverage = "~=7.10.0" Faker = "~=18.10.1" pyngrok = "~=6.0.0" unittest-xml-reporting = "~=3.2.0" watchdog = "~=3.0.0" hypothesis = "~=6.77.0" responses = "==0.23.1" freezegun = "~=1.2.2" [tool.ruff] line-length = 110 target-version = "py310" exclude = [ "**/doctype/*/boilerplate/*.py" # boilerplate are template strings, not valid python ] [tool.ruff.lint] select = [ "F", "E", "W", "I", "UP", "B", "RUF", ] ignore = [ "B017", # assertRaises(Exception) - should be more specific "B018", # useless expression, not assigned to anything "B023", # function doesn't bind loop variable - will have last iteration's value "B904", # raise inside except without from "E101", # indentation contains mixed spaces and tabs "E402", # module level import not at top of file "E501", # line too long "E741", # ambiguous variable name "F401", # "unused" imports "F403", # can't detect undefined names from * import "F405", # can't detect undefined names from * import "F722", # syntax error in forward type annotation "W191", # indentation contains tabs "UP030", # Use implicit references for positional format fields (translations) "UP031", # Use format specifiers instead of percent format "UP032", # Use f-string instead of `format` call (translations) ] typing-modules = ["frappe.types.DF"] [tool.ruff.format] quote-style = "double" indent-style = "tab" docstring-code-format = true [tool.frappix] # use identifier from https://search.nixos.org/packages nixpkgs-deps = [ "mariadb", "restic", "wkhtmltopdf-bin", "which", "gzip", "bash", "redis", "nodejs_20", "python312", ] [tool.mypy] strict = false pretty = true incremental = true sqlite_cache = true files = [ # start small, with a lot of multiplication potential "frappe/types/__init__.py", "frappe/types/DF.py", "frappe/types/frappedict.py", "frappe/types/filter.py", ] exclude = [ # permanent excludes "^frappe/patches", '/test_.+\.py$', "^frappe/tests/ui_test_helpers.py", "^frappe/parallel_test_runner.py", "^frappe/deprecation_dumpster.py", ] disable_error_code = [ ] [[tool.mypy.overrides]] module = "frappe" # Too many for a start disable_error_code = [ "no-any-expr", "no-untyped-def", "no-untyped-call", "no-untyped-usage", ] # External libraries without types [[tool.mypy.overrides]] module = [ "bleach_allowlist", "cssutils", "cups", "email_reply_parser", "filetype", "google", "googleapiclient.discovery", "googleapiclient.errors", "google.oauth2", "google.oauth2.credentials", "markdown2", "markdownify", "num2words", "pdfkit", "premailer", "pyngrok", "pypika", "pypika.dialects", "pypika.functions", "pypika.queries", "pypika.terms", "pypika.utils", "pyqrcode", "rauth", "requests_oauthlib", "RestrictedPython", "RestrictedPython.Guards", "RestrictedPython.transformer", "semantic_version", "sql_metadata", "sqlparse", "terminaltables", "traceback_with_variables", "weasyprint", "whoosh.fields", "whoosh.index", "whoosh.qparser", "whoosh.query", "whoosh.writing", "xlrd", "xmlrunner", ] ignore_missing_imports = true