{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-23-15-00",
   "metadata": {},
   "source": [
    "#23-15 · Manifest jako regularny JSON\n",
    "\n",
    "Praktyka do sekcji [„Dziennik wykonanych operacji”](/pl/chapters/rozdzial-23/23-15-zhurnal-operacij.html). Prawdziwy plik — `projects/python/safesort/src/safesort/manifest.py`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-01",
   "metadata": {},
   "source": [
    "## Cel\n",
    "\n",
    "Sporządzić manifest w tej samej formie co prawdziwy `write_manifest()`i upewnij się, że się martwi `json.dumps()`/`json.loads()` bez strat."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-02",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-15-03",
   "metadata": {},
   "outputs": [],
   "source": [
    "import json\n",
    "from pathlib import Path\n",
    "\n",
    "operation_id = \"20260824T011640800152\"\n",
    "moves = [\n",
    "    {\n",
    "        \"source\": str(Path(\"/home/anna/Downloads/otchet.pdf\")),\n",
    "        \"destination\": str(Path(\"/home/anna/Downloads/Sorted/documents/otchet.pdf\")),\n",
    "        \"completed\": True,\n",
    "        \"error\": None,\n",
    "    },\n",
    "    {\n",
    "        \"source\": str(Path(\"/home/anna/Downloads/zametka.txt\")),\n",
    "        \"destination\": str(Path(\"/home/anna/Downloads/Sorted/documents/zametka.txt\")),\n",
    "        \"completed\": False,\n",
    "        \"error\": \"destination already exists: ...\",\n",
    "    },\n",
    "]\n",
    "\n",
    "manifest = {\n",
    "    \"operation_id\": operation_id,\n",
    "    \"root\": str(Path(\"/home/anna/Downloads\")),\n",
    "    \"timestamp\": \"2026-08-24T01:16:40\",\n",
    "    \"moves\": moves,\n",
    "}\n",
    "\n",
    "tekst_json = json.dumps(manifest, indent=2)\n",
    "print(tekst_json)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-04",
   "metadata": {},
   "source": [
    "## Sprawdzenie wyniku"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-15-05",
   "metadata": {},
   "outputs": [],
   "source": [
    "zagruzhennyj = json.loads(tekst_json)\n",
    "\n",
    "assert zagruzhennyj == manifest\n",
    "assert zagruzhennyj[\"operation_id\"] == operation_id\n",
    "assert len(zagruzhennyj[\"moves\"]) == 2\n",
    "assert zagruzhennyj[\"moves\"][0][\"completed\"] is True\n",
    "assert zagruzhennyj[\"moves\"][1][\"error\"] is not None\n",
    "print(\"Верно: структура манифеста пережила dumps()/loads() без потерь.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-06",
   "metadata": {},
   "source": [
    "## Starter\n",
    "\n",
    "Wypełnij zaznaczone miejsce. Niezmieniony starter nie przechodzi tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "task-23-15",
   "metadata": {
    "tags": [
     "exercise",
     "starter"
    ]
   },
   "outputs": [],
   "source": [
    "def poschitat_uspeshnye(moves):\n",
    "    # TODO: count completed moves without changing the list.\n",
    "    raise NotImplementedError\n",
    "\n",
    "\n",
    "uspeshnyh = poschitat_uspeshnye(zagruzhennyj[\"moves\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-08",
   "metadata": {},
   "source": [
    "## Task\n",
    "\n",
    "Zapisz funkcję liczenia rekordów z `completed=True`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-09",
   "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-15",
   "metadata": {
    "tags": [
     "exercise-tests"
    ]
   },
   "outputs": [],
   "source": [
    "assert uspeshnyh == 1\n",
    "assert poschitat_uspeshnye([]) == 0\n",
    "assert poschitat_uspeshnye([{\"completed\": True}, {\"completed\": True}]) == 2\n",
    "print(\"Tests passed\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-11",
   "metadata": {},
   "source": [
    "## Hint\n",
    "\n",
    "Odpowiednie generator expression wewnątrz `sum()`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-15-12",
   "metadata": {},
   "source": [
    "## Solution\n",
    "\n",
    "Pokaż rozwiązanie po własnej próbie</summary>\n",
    "\n",
    "```python\n",
    "def poschitat_uspeshnye(moves):\n",
    "    return sum(1 for move in moves if move[\"completed\"])\n",
    "\n",
    "\n",
    "uspeshnyh = poschitat_uspeshnye(zagruzhennyj[\"moves\"])\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
}
