{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cell-23-13-00",
   "metadata": {},
   "source": [
    "# 23-13 · Перемещаем файлы во временном каталоге\n",
    "\n",
    "Практика к разделу [«Безопасно перемещаем файлы»](../../site/chapters/glava-23/23-13-peremeshaem-fajly.html). Использует настоящий пакет `safesort`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "setup-23-13",
   "metadata": {},
   "source": [
    "## Reproducible local environment\n",
    "\n",
    "```bash\n",
    "git clone https://github.com/Cartesian-School/safesort.git\n",
    "cd safesort\n",
    "python3.14 -m venv .venv\n",
    "source .venv/bin/activate\n",
    "# Windows PowerShell: .venv\\Scripts\\Activate.ps1\n",
    "python -m pip install -U pip\n",
    "python -m pip install -e \".[dev]\"\n",
    "python -m pip install jupyter ipykernel\n",
    "python -m ipykernel install --user --name safesort-py314 --display-name \"SafeSort Python 3.14\"\n",
    "jupyter lab\n",
    "```\n",
    "\n",
    "Select the **SafeSort Python 3.14** kernel. The diagnostic cell below must\n",
    "point into this `.venv` and the cloned `src/safesort` tree."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "diagnostic-23-13",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import safesort\n",
    "\n",
    "print(sys.executable)\n",
    "print(safesort.__file__)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-03",
   "metadata": {},
   "source": [
    "## Цель\n",
    "\n",
    "Вызвать настоящую `safesort.executor.apply_plan()` во временном каталоге и убедиться, что она перемещает файлы и отказывается перезаписывать уже занятое место назначения."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-04",
   "metadata": {},
   "source": [
    "## Example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-13-05",
   "metadata": {},
   "outputs": [],
   "source": [
    "import tempfile\n",
    "from pathlib import Path\n",
    "\n",
    "from safesort.executor import apply_plan\n",
    "from safesort.models import MoveOperation, SortPlan\n",
    "\n",
    "tmpdir = tempfile.TemporaryDirectory()\n",
    "koren = Path(tmpdir.name)\n",
    "\n",
    "istochnik = koren / \"otchet.pdf\"\n",
    "istochnik.write_text(\"содержимое отчёта\", encoding=\"utf-8\")\n",
    "\n",
    "naznachenie = koren / \"Sorted\" / \"documents\" / \"otchet.pdf\"\n",
    "plan = SortPlan(root=koren, operations=(MoveOperation(source=istochnik, destination=naznachenie),))\n",
    "\n",
    "rezultaty = apply_plan(plan)\n",
    "print(rezultaty)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-06",
   "metadata": {},
   "source": [
    "## Проверка результата"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-13-07",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert rezultaty[0].completed is True\n",
    "assert not istochnik.exists()\n",
    "assert naznachenie.exists()\n",
    "assert naznachenie.read_text(encoding=\"utf-8\") == \"содержимое отчёта\"\n",
    "print(\"Верно: файл перемещён, содержимое не повреждено, исходное место пусто.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-08",
   "metadata": {},
   "source": [
    "## Эксперимент — существующий файл в месте назначения не перезаписывается"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cell-23-13-09",
   "metadata": {},
   "outputs": [],
   "source": [
    "istochnik2 = koren / \"zametka.txt\"\n",
    "istochnik2.write_text(\"новый текст\", encoding=\"utf-8\")\n",
    "\n",
    "naznachenie2 = koren / \"Sorted\" / \"documents\" / \"zametka.txt\"\n",
    "naznachenie2.parent.mkdir(parents=True, exist_ok=True)\n",
    "naznachenie2.write_text(\"уже лежавший здесь текст\", encoding=\"utf-8\")\n",
    "\n",
    "plan2 = SortPlan(root=koren, operations=(MoveOperation(source=istochnik2, destination=naznachenie2),))\n",
    "rezultaty2 = apply_plan(plan2)\n",
    "\n",
    "assert rezultaty2[0].completed is False\n",
    "assert \"already exists\" in rezultaty2[0].error\n",
    "assert istochnik2.exists()\n",
    "assert naznachenie2.read_text(encoding=\"utf-8\") == \"уже лежавший здесь текст\"\n",
    "print(\"Верно: apply_plan отказался перезаписать существующий файл.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-10",
   "metadata": {},
   "source": [
    "## Starter\n",
    "\n",
    "Заполните отмеченное место. Неизменённый starter не проходит tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "task-23-13",
   "metadata": {
    "tags": [
     "exercise",
     "starter"
    ]
   },
   "outputs": [],
   "source": [
    "def peremestit_dva(root: Path):\n",
    "    # TODO: create two files, build one SortPlan, call apply_plan().\n",
    "    raise NotImplementedError\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-12",
   "metadata": {},
   "source": [
    "## Task\n",
    "\n",
    "Напишите `peremestit_dva(root)`: создайте a.txt и b.txt, выполните один SortPlan и верните результаты."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-13",
   "metadata": {},
   "source": [
    "## Tests\n",
    "\n",
    "Запустите после task cell: есть основной пример и хотя бы один крайний случай."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "tests-23-13",
   "metadata": {
    "tags": [
     "exercise-tests"
    ]
   },
   "outputs": [],
   "source": [
    "with tempfile.TemporaryDirectory() as tmp:\n",
    "    test_root = Path(tmp)\n",
    "    rezultaty3 = peremestit_dva(test_root)\n",
    "    assert len(rezultaty3) == 2 and all(r.completed for r in rezultaty3)\n",
    "    assert (test_root / \"Sorted/documents/a.txt\").read_text() == \"A\"\n",
    "    assert (test_root / \"Sorted/documents/b.txt\").read_text() == \"B\"\n",
    "print(\"Tests passed\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-15",
   "metadata": {},
   "source": [
    "## Hint\n",
    "\n",
    "Обе `MoveOperation` поместите в один tuple `SortPlan.operations`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cell-23-13-16",
   "metadata": {},
   "source": [
    "## Solution\n",
    "\n",
    "<details><summary>Показать решение после собственной попытки</summary>\n",
    "\n",
    "```python\n",
    "def peremestit_dva(root: Path):\n",
    "    source_a = root / \"a.txt\"\n",
    "    source_b = root / \"b.txt\"\n",
    "    source_a.write_text(\"A\", encoding=\"utf-8\")\n",
    "    source_b.write_text(\"B\", encoding=\"utf-8\")\n",
    "    destination = root / \"Sorted\" / \"documents\"\n",
    "    plan = SortPlan(\n",
    "        root=root,\n",
    "        operations=(\n",
    "            MoveOperation(source_a, destination / \"a.txt\"),\n",
    "            MoveOperation(source_b, destination / \"b.txt\"),\n",
    "        ),\n",
    "    )\n",
    "    return apply_plan(plan)\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
}
