{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-23-19-00",
   "metadata": {},
   "source": [
    "# 23-19 · Czytanie i sprawdzanie ustawień TOML-\n",
    "\n",
    "Praktyka do sekcji [„Ustawienia projektu”](/pl/chapters/rozdzial-23/23-22-nastrojki-proekta.html). Ten plik — `projects/python/safesort/src/safesort/config.py`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-01",
   "metadata": {},
   "source": [
    "## Cel\n",
    "\n",
    "Rozłóż `safesort.toml`tekst przypominający `tomllib` i zbudować z niego `Config`-podobny obiekt – z tymi samymi domyślnymi wartościami co rzeczywisty `load_config()`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-02",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-19-03",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tomllib\n",
    "from dataclasses import dataclass, field\n",
    "\n",
    "DEFAULT_DESTINATION = \"Sorted\"\n",
    "DEFAULT_EXCLUDE = (\".git\", \".venv\")\n",
    "DEFAULT_EXTENSIONS = {\n",
    "    \"documents\": [\".pdf\", \".docx\", \".txt\", \".odt\"],\n",
    "    \"images\": [\".jpg\", \".jpeg\", \".png\", \".webp\"],\n",
    "}\n",
    "\n",
    "\n",
    "@dataclass(frozen=True)\n",
    "class Config:\n",
    "    destination: str = DEFAULT_DESTINATION\n",
    "    exclude: tuple = field(default_factory=lambda: DEFAULT_EXCLUDE)\n",
    "    extensions: dict = field(default_factory=lambda: {k: list(v) for k, v in DEFAULT_EXTENSIONS.items()})\n",
    "\n",
    "\n",
    "TEKST_TOML = \"\"\"\n",
    "destination = \"Archive\"\n",
    "exclude = [\".git\", \".venv\", \"node_modules\"]\n",
    "\n",
    "[extensions]\n",
    "documents = [\".pdf\", \".docx\", \".txt\"]\n",
    "images = [\".jpg\", \".jpeg\", \".png\", \".webp\"]\n",
    "\"\"\"\n",
    "\n",
    "raw = tomllib.loads(TEKST_TOML)\n",
    "print(raw)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-04",
   "metadata": {},
   "source": [
    "## Sprawdzanie wyniku – TOML rozłożony na zwykły słownik Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-19-05",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert raw[\"destination\"] == \"Archive\"\n",
    "assert raw[\"exclude\"] == [\".git\", \".venv\", \"node_modules\"]\n",
    "assert raw[\"extensions\"][\"documents\"] == [\".pdf\", \".docx\", \".txt\"]\n",
    "print(\"Верно: tomllib.loads() вернул обычный словарь с ожидаемой структурой.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-06",
   "metadata": {},
   "source": [
    "## Budynek Config z rozebranych TOML"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-19-07",
   "metadata": {},
   "outputs": [],
   "source": [
    "def config_from_raw(raw):\n",
    "    extensions = {k: list(v) for k, v in DEFAULT_EXTENSIONS.items()}\n",
    "    extensions.update(raw.get(\"extensions\", {}))\n",
    "    return Config(\n",
    "        destination=raw.get(\"destination\", DEFAULT_DESTINATION),\n",
    "        exclude=tuple(raw.get(\"exclude\", list(DEFAULT_EXCLUDE))),\n",
    "        extensions=extensions,\n",
    "    )\n",
    "\n",
    "\n",
    "nastrojki = config_from_raw(raw)\n",
    "print(nastrojki)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-08",
   "metadata": {},
   "source": [
    "## Starter\n",
    "\n",
    "Wypełnij zaznaczone miejsce. Niezmieniony starter nie przechodzi tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "task-23-19",
   "metadata": {
    "tags": [
     "exercise",
     "starter"
    ]
   },
   "outputs": [],
   "source": [
    "def config_iz_toml(text: str) -> Config:\n",
    "    # TODO: parse text and apply defaults + category-specific overrides.\n",
    "    raise NotImplementedError\n",
    "\n",
    "\n",
    "nastrojki_minimalnye = config_iz_toml('destination = \"Sorted2\"\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-10",
   "metadata": {},
   "source": [
    "## Task\n",
    "\n",
    "Write `config_iz_toml(text)`. Nowe kategorie powinny być dodawane na defaults, a nazwa wbudowana kategoria powinna zostać zastąpiona."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-11",
   "metadata": {},
   "source": [
    "## Tests\n",
    "\n",
    "Run After task cell: jest podstawowy przykład i przynajmniej jeden skrajny przypadek."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "tests-23-19",
   "metadata": {
    "tags": [
     "exercise-tests"
    ]
   },
   "outputs": [],
   "source": [
    "assert nastrojki_minimalnye.destination == \"Sorted2\"\n",
    "assert nastrojki_minimalnye.extensions == DEFAULT_EXTENSIONS\n",
    "with_books = config_iz_toml('[extensions]\\nbooks = [\".epub\"]\\n')\n",
    "assert with_books.extensions[\"books\"] == [\".epub\"]\n",
    "assert with_books.extensions[\"documents\"] == DEFAULT_EXTENSIONS[\"documents\"]\n",
    "overridden = config_iz_toml('[extensions]\\ndocuments = [\".md\"]\\n')\n",
    "assert overridden.extensions[\"documents\"] == [\".md\"]\n",
    "print(\"Tests passed\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-13",
   "metadata": {},
   "source": [
    "## Hint\n",
    "\n",
    "Najpierw skopiuj każdy lista DEFAULT_EXTENSIONS, potem wywołaj `.update()` z niestandardowym stołem."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-19-14",
   "metadata": {},
   "source": [
    "## Solution\n",
    "\n",
    "Pokaż rozwiązanie po własnej próbie</summary>\n",
    "\n",
    "```python\n",
    "def config_iz_toml(text: str) -> Config:\n",
    "    raw = tomllib.loads(text)\n",
    "    extensions = {k: list(v) for k, v in DEFAULT_EXTENSIONS.items()}\n",
    "    extensions.update(raw.get(\"extensions\", {}))\n",
    "    return Config(\n",
    "        destination=raw.get(\"destination\", DEFAULT_DESTINATION),\n",
    "        exclude=tuple(raw.get(\"exclude\", DEFAULT_EXCLUDE)),\n",
    "        extensions=extensions,\n",
    "    )\n",
    "\n",
    "\n",
    "nastrojki_minimalnye = config_iz_toml('destination = \"Sorted2\"\\n')\n",
    "```\n",
    "\n",
    "</details>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Cartesian Python 3.14",
   "language": "python",
   "name": "cartesian-python314"
  },
  "language_info": {
   "name": "python",
   "version": "3.14.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
