content: [build-system]
  requires = ["setuptools>=77.0"]
  build-backend = "setuptools.build_meta"
  
  [project]
  name = "cookidoo-api"
  dynamic = ["version", "readme"]
  description = "Unofficial package to access Cookidoo."
  authors = [
    { name = "Cyrill Raccaud", email = "cyrill.raccaud+pypi@gmail.com" },
  ]
  dependencies = [
    "aiohttp",
    "aiofiles",
    "isodate",
  ]
  requires-python = ">=3.12"
  
  classifiers = [
    "Programming Language :: Python :: 3",
    "Operating System :: OS Independent",
    "Intended Audience :: Information Technology",
    "Topic :: System :: Monitoring",
    "Topic :: System :: Logging",
    "Topic :: System :: Systems Administration",
  ]
  license = "MIT"
  keywords = ["cookidoo", "todo", "home-assistant", "iot"]
  
  [tool.setuptools]
  
  [tool.setuptools.packages.find]
  include = ["cookidoo_api*"]
  
  [tool.setuptools.package-data]
  cookidoo_api = ["py.typed", '*.json']
  
  [tool.setuptools.dynamic]
  version = {attr = "cookidoo_api.__version__"}
  readme = {file = ["README.md"], content-type = "text/markdown"}
  
  [project.urls]
  Documentation = "https://miaucl.github.io/cookidoo-api/"
  Source = "https://github.com/miaucl/cookidoo-api"
  Issues = "https://github.com/miaucl/cookidoo-api/issues"
  "Release notes" = "https://github.com/miaucl/cookidoo-api/releases"
  
  
  [tool.ruff]
  
  target-version = "py312"
  
  [tool.ruff.lint]
  select = [
      "B002", # Python does not support the unary prefix increment
      "B007", # Loop control variable {name} not used within loop body
      "B014", # Exception handler with duplicate exception
      "B023", # Function definition does not bind loop variable {name}
      "B026", # Star-arg unpacking after a keyword argument is strongly discouraged
      "C",  # complexity
      "COM818", # Trailing comma on bare tuple prohibited
      "D",  # docstrings
      "DTZ003",  # Use datetime.now(tz=) instead of datetime.utcnow()
      "DTZ004",  # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts)
      "E",  # pycodestyle
      "F",  # pyflakes/autoflake
      "G", # flake8-logging-format
      "I",  # isort
      "ICN001", # import concentions; {name} should be imported as {asname}
      "N804", # First argument of a class method should be named cls
      "N805", # First argument of a method should be named self
      "N815", # Variable {name} in class scope should not be mixedCase
      "S307", # No builtin eval() allowed
      "PGH004",  # Use specific rule codes when using noqa
      "PLC0414", # Useless import alias. Import alias does not rename original package.
      "PLC", # pylint
      "PLE", # pylint
      "PLR", # pylint
      "PLW", # pylint
      "Q000", # Double quotes found but single quotes preferred
      "RUF006", # Store a reference to the return value of asyncio.create_task
      "S102", # Use of exec detected
      "S103",  # bad-file-permissions
      "S108",  # hardcoded-temp-file
      "S306",  # suspicious-mktemp-usage
      "S307",  # suspicious-eval-usage
      "S313",  # suspicious-xmlc-element-tree-usage
      "S314",  # suspicious-xml-element-tree-usage
      "S315",  # suspicious-xml-expat-reader-usage
      "S316",  # suspicious-xml-expat-builder-usage
      "S317",  # suspicious-xml-sax-usage
      "S318",  # suspicious-xml-mini-dom-usage
      "S319",  # suspicious-xml-pull-dom-usage
      "S601",  # paramiko-call
      "S602",  # subprocess-popen-with-shell-equals-true
      "S604",  # call-with-shell-equals-true
      "S608",  # hardcoded-sql-expression
      "S609",  # unix-command-wildcard-injection
      "SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass
      "SIM117", # Merge with-statements that use the same scope
      "SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys()
      "SIM201", # Use {left} != {right} instead of not {left} == {right}
      "SIM208", # Use {expr} instead of not (not {expr})
      "SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a}
      "SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'.
      "SIM401", # Use get from dict with default instead of an if block
      "T100", # Trace found: {name} used
      "T20",  # flake8-print
      "TID251", # Banned imports
      "TRY004", # Prefer TypeError exception for invalid type
      "B904", # Use raise from to specify exception cause
      "TRY", # tryceratops
      "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
      "D406",  # Section name should end with a newline
      "D407",  # Section name underlining
      "E501",  # line too long
      "E731",  # do not assign a lambda expression, use a def
  
      # Ignore ignored, as the rule is now back in preview/nursery, which cannot
      # be ignored anymore without warnings.
      # https://github.com/astral-sh/ruff/issues/7491
      # "PLC1901", # Lots of false positives
  
      # False positives https://github.com/astral-sh/ruff/issues/5386
      "PLC0208", # Use a sequence type instead of a `set` when iterating over values
      "PLR0911", # Too many return statements ({returns} > {max_returns})
      "PLR0912", # Too many branches ({branches} > {max_branches})
      "PLR0913", # Too many arguments to function call ({c_args} > {max_args})
      "PLR0915", # Too many statements ({statements} > {max_statements})
      "PLR2004",  # Magic value used in comparison, consider replacing {value} with a constant variable
      "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target
      "TRY003", # Avoid specifying long messages outside the exception class
  
      # May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
      "W191",
      "E111",
      "E114",
      "E117",
      "D206",
      "D300",
      "Q000",
      "Q001",
      "Q002",
      "Q003",
      "COM812",
      "COM819",
      "ISC001",
      "ISC002",
  
      # Disabled because ruff does not understand type of __all__ generated by a function
      "PLE0605",
  ]
  
  [tool.ruff.lint.flake8-pytest-style]
  fixture-parentheses = false
  
  [tool.ruff.lint.flake8-tidy-imports.banned-api]
  "async_timeout".msg = "use asyncio.timeout instead"
  "pytz".msg = "use zoneinfo instead"
  
  [tool.ruff.lint.isort]
  force-sort-within-sections = true
  known-first-party = [
      "cookidoo_api",
  ]
  combine-as-imports = true
  split-on-trailing-comma = false
  
  [tool.ruff.lint.per-file-ignores]
  
  # Allow for main entry & scripts to write to stdout
  "cookidoo_api/__main__.py" = ["T201"]
  "cookidoo_api/scripts/*" = ["T201"]
  "scripts/*" = ["T20"]
  "tests/*" = ["T20"]
  "smoke_test/*" = ["T20"]
  
  [tool.ruff.lint.mccabe]
  max-complexity = 25
  
  [tool.pytest.ini_options]
  asyncio_mode = "auto"
  testpaths = [
      "tests",
  ]
  log_cli = true
  # log_cli_level = "DEBUG"
  log_cli_format = "%(asctime)s%(msecs)03d [%(levelname)8s] %(name)s:%(lineno)s %(message)s"
  log_cli_date_format = "%Y%m%dT%H%M%S."
  
  [tool.coverage.run]
  branch = true
  source = ["tests"]
  
  [tool.coverage.report]
  format="text"
  show_missing = true
  
  # Regexes for lines to exclude from consideration
  exclude_also = [
    # Don't complain about missing debug-only code:
    "def __repr__",
    "if self\\.debug",
  
    # Don't complain if tests don't hit defensive assertion code:
    "raise AssertionError",
    "raise NotImplementedError",
  
    # Don't complain if non-runnable code isn't run:
    "if 0:",
    "if __name__ == .__main__.:",
  
    # Don't complain about abstract methods, they aren't run:
    "@(abc\\.)?abstractmethod",
  ]
  
  [tool.coverage.html]
  directory = "coverage_html_report"
  
  [tool.mypy]
  python_version = "3.12"
  plugins = "pydantic.mypy"
  show_error_codes = true
  follow_imports = "normal"
  local_partial_types = true
  strict_equality = true
  no_implicit_optional = true
  warn_incomplete_stub = true
  warn_redundant_casts = true
  warn_unused_configs = true
  warn_unused_ignores = true
  enable_error_code = ["ignore-without-code", "redundant-self", "truthy-iterable"]
  disable_error_code = ["annotation-unchecked", "import-not-found", "import-untyped"]
  extra_checks = false
  check_untyped_defs = true
  disallow_incomplete_defs = true
  disallow_subclassing_any = true
  disallow_untyped_calls = true
  disallow_untyped_decorators = true
  disallow_untyped_defs = true
  warn_return_any = true
  warn_unreachable = true
  