[build-system]
requires = ["setuptools~=62.3", "wheel~=0.37.1"]
build-backend = "setuptools.build_meta"

[project]
name        = "homeassistant"
version     = "2023.3.0.dev0"
license     = {text = "Apache-2.0"}
description = "Open-source home automation platform running on Python 3."
readme      = "README.rst"
authors     = [
    {name = "The Home Assistant Authors", email = "hello@home-assistant.io"}
]
keywords    = ["home", "automation"]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Intended Audience :: End Users/Desktop",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: Apache Software License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3.10",
    "Topic :: Home Automation",
]
requires-python = ">=3.10.0"
dependencies    = [
    "aiohttp==3.8.1",
    "astral==2.2",
    "async_timeout==4.0.2",
    "attrs==22.2.0",
    "atomicwrites-homeassistant==1.4.1",
    "awesomeversion==22.9.0",
    "bcrypt==4.0.1",
    "certifi>=2021.5.30",
    "ciso8601==2.3.0",
    # When bumping httpx, please check the version pins of
    # httpcore, anyio, and h11 in gen_requirements_all
    "httpx==0.23.3",
    "home-assistant-bluetooth==1.9.2",
    "ifaddr==0.1.7",
    "jinja2==3.1.2",
    "lru-dict==1.1.8",
    "PyJWT==2.5.0",
    # PyJWT has loose dependency. We want the latest one.
    "cryptography==39.0.0",
    # pyOpenSSL 23.0.0 is required to work with cryptography 39+
    "pyOpenSSL==23.0.0",
    "orjson==3.8.5",
    "pip>=21.0,<23.1",
    "python-slugify==4.0.1",
    "pyyaml==6.0",
    "requests==2.28.1",
    "typing-extensions>=4.4.0,<5.0",
    "voluptuous==0.13.1",
    "voluptuous-serialize==2.5.0",
    "yarl==1.8.1",
]

[project.urls]
"Source Code" = "https://github.com/home-assistant/core"
"Bug Reports" = "https://github.com/home-assistant/core/issues"
"Docs: Dev"   = "https://developers.home-assistant.io/"
"Discord"     = "https://www.home-assistant.io/join-chat/"
"Forum"       = "https://community.home-assistant.io/"

[project.scripts]
hass = "homeassistant.__main__:main"

[tool.setuptools]
platforms = ["any"]
zip-safe  = false
include-package-data = true

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

[tool.black]
target-version = ["py310"]
extend-exclude = "/generated/"

[tool.isort]
# https://github.com/PyCQA/isort/wiki/isort-Settings
profile = "black"
# will group `import x` and `from x import` of the same module.
force_sort_within_sections = true
known_first_party = [
    "homeassistant",
    "tests",
]
forced_separate = [
    "tests",
]
combine_as_imports = true

[tool.pylint.MAIN]
py-version = "3.10"
ignore = [
    "tests",
]
# Use a conservative default here; 2 should speed up most setups and not hurt
# any too bad. Override on command line as appropriate.
jobs = 2
init-hook = """\
    from pathlib import Path; \
    import sys; \

    from pylint.config import find_default_config_files; \

    sys.path.append( \
        str(Path(next(find_default_config_files())).parent.joinpath('pylint/plugins'))
    ) \
    """
load-plugins = [
    "pylint.extensions.code_style",
    "pylint.extensions.typing",
    "hass_enforce_type_hints",
    "hass_imports",
    "hass_logger",
    "pylint_per_file_ignores",
]
persistent = false
extension-pkg-allow-list = [
    "av.audio.stream",
    "av.stream",
    "ciso8601",
    "orjson",
    "cv2",
]
fail-on = [
    "I",
]

[tool.pylint.BASIC]
class-const-naming-style = "any"
good-names = [
    "_",
    "ev",
    "ex",
    "fp",
    "i",
    "id",
    "j",
    "k",
    "Run",
    "ip",
]

[tool.pylint."MESSAGES CONTROL"]
# Reasons disabled:
# format - handled by black
# locally-disabled - it spams too much
# duplicate-code - unavoidable
# cyclic-import - doesn't test if both import on load
# abstract-class-little-used - prevents from setting right foundation
# unused-argument - generic callbacks and setup methods create a lot of warnings
# too-many-* - are not enforced for the sake of readability
# too-few-* - same as too-many-*
# abstract-method - with intro of async there are always methods missing
# inconsistent-return-statements - doesn't handle raise
# too-many-ancestors - it's too strict.
# wrong-import-order - isort guards this
# consider-using-f-string - str.format sometimes more readable
# ---
# Pylint CodeStyle plugin
# consider-using-namedtuple-or-dataclass - too opinionated
# consider-using-assignment-expr - decision to use := better left to devs
# ---
# Temporary for the Python 3.10 update, remove with mypy v1.0
# consider-alternative-union-syntax
disable = [
    "format",
    "abstract-method",
    "cyclic-import",
    "duplicate-code",
    "inconsistent-return-statements",
    "locally-disabled",
    "not-context-manager",
    "too-few-public-methods",
    "too-many-ancestors",
    "too-many-arguments",
    "too-many-branches",
    "too-many-instance-attributes",
    "too-many-lines",
    "too-many-locals",
    "too-many-public-methods",
    "too-many-return-statements",
    "too-many-statements",
    "too-many-boolean-expressions",
    "unused-argument",
    "wrong-import-order",
    "consider-using-f-string",
    "consider-using-namedtuple-or-dataclass",
    "consider-using-assignment-expr",
    "consider-alternative-union-syntax",
]
enable = [
    #"useless-suppression",  # temporarily every now and then to clean them up
    "use-symbolic-message-instead",
]

[tool.pylint.REPORTS]
score = false

[tool.pylint.TYPECHECK]
ignored-classes = [
    "_CountingAttr",  # for attrs
]
mixin-class-rgx = ".*[Mm]ix[Ii]n"

[tool.pylint.FORMAT]
expected-line-ending-format = "LF"

[tool.pylint.EXCEPTIONS]
overgeneral-exceptions = [
    "builtins.BaseException",
    "builtins.Exception",
    # "homeassistant.exceptions.HomeAssistantError",  # too many issues
]

[tool.pylint.TYPING]
runtime-typing = false

[tool.pylint.CODE_STYLE]
max-line-length-suggestions = 72

[tool.pylint-per-file-ignores]
# hass-component-root-import: Tests test non-public APIs
# protected-access: Tests do often test internals a lot
# redefined-outer-name: Tests reference fixtures in the test function
"/tests/"="hass-component-root-import,protected-access,redefined-outer-name"

[tool.pytest.ini_options]
testpaths = [
    "tests",
]
norecursedirs = [
    ".git",
    "testing_config",
]
log_format = "%(asctime)s.%(msecs)03d %(levelname)-8s %(threadName)s %(name)s:%(filename)s:%(lineno)s %(message)s"
log_date_format = "%Y-%m-%d %H:%M:%S"
asyncio_mode = "auto"

[tool.ruff]
target-version = "py310"

select = [
    "C",  # complexity
    "D",  # docstrings
    "E",  # pycodestyle
    "F",  # pyflakes/autoflake
    "PGH004",  # Use specific rule codes when using noqa
    "PLC0414", # Useless import alias. Import alias does not rename original package.
    "SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass
    "SIM117", # Merge with-statements that use the same scope
    "SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'.
    "SIM401", # Use get from dict with default instead of an if block
    "T20",  # flake8-print
    "TRY004", # Prefer TypeError exception for invalid type
    "UP",  # pyupgrade
    "W",  # pycodestyle
]

ignore = [
    "D202",  # No blank lines allowed after function docstring
    "D203",  # 1 blank line required before class docstring
    "D213",  # Multi-line docstring summary should start at the second line
    "D404",  # First word of the docstring should not be This
    "D406",  # Section name should end with a newline
    "D407",  # Section name underlining
    "D411",  # Missing blank line before section
    "E501",  # line too long
    "E731",  # do not assign a lambda expression, use a def
]

[tool.ruff.flake8-pytest-style]
fixture-parentheses = false

[tool.ruff.pyupgrade]
keep-runtime-typing = true

[tool.ruff.per-file-ignores]

# TODO: these files have functions that are too complex, but flake8's and ruff's
#       complexity (and/or nested-function) handling differs; trying to add a noqa doesn't work
#       because the flake8-noqa plugin then disagrees on whether there should be a C901 noqa
#       on that line.  So, for now, we just ignore C901s on these files as far as ruff is concerned.

"homeassistant/components/light/__init__.py" = ["C901"]
"homeassistant/components/mqtt/discovery.py" = ["C901"]
"homeassistant/components/websocket_api/http.py" = ["C901"]

# Allow for main entry & scripts to write to stdout
"homeassistant/__main__.py" = ["T201"]
"homeassistant/scripts/*" = ["T201"]
"script/*" = ["T20"]

[tool.ruff.mccabe]
max-complexity = 25