diff --git a/pydantic.ipynb b/pydantic.ipynb new file mode 100644 index 0000000..0578fde --- /dev/null +++ b/pydantic.ipynb @@ -0,0 +1,470 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "##**Pydantic is the most widely used data validation library for Python.**" + ], + "metadata": { + "id": "b5xvKVzKijGE" + } + }, + { + "cell_type": "markdown", + "source": [ + "##**Pydantic has many advantages, such as:**\n", + "\n", + "##**Type safety:** Pydantic enforces type hints at runtime, ensuring that your data conforms to the expected types and formats. It also supports custom data types, such as enums, UUIDs, IP addresses, etc.\n", + "##**User-friendly errors:** Pydantic provides informative and readable error messages when validation fails, including the location, type, and input of the error. It also provides links to the documentation for each error type.\n", + "##**Performance:** Pydantic’s core validation logic is written in Rust, making it one of the fastest data validation libraries for Python. It also supports lazy validation and caching for improved efficiency.\n", + "##**Ease of use:** Pydantic is simple and intuitive to use, requiring minimal boilerplate code and configuration. It works well with many popular IDEs and static analysis tools, such as PyCharm, VS Code, mypy, etc." + ], + "metadata": { + "id": "whq-1VYUnGEV" + } + }, + { + "cell_type": "markdown", + "source": [ + "###pip install pydantic" + ], + "metadata": { + "id": "sbKSKVXIoEXf" + } + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "id": "aNZP7cqToGJO" + } + }, + { + "cell_type": "markdown", + "source": [ + "###\"pedantic\" refer's to the library's meticulous approach to **data validation** and **type enforcement.**" + ], + "metadata": { + "id": "zZK4PX9ui0tz" + } + }, + { + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "from typing import Tuple\n", + "\n", + "from pydantic import BaseModel\n", + "\n", + "\n", + "class Delivery(BaseModel):\n", + " timestamp: datetime\n", + " dimensions: Tuple[int, int]\n", + "\n", + "\n", + "m = Delivery(timestamp='2020-01-02T03:04:05Z', dimensions=['10', '20'])\n", + "print(repr(m.timestamp))\n", + "#> datetime.datetime(2020, 1, 2, 3, 4, 5, tzinfo=TzInfo(UTC))\n", + "print(m.dimensions)\n", + "#> (10, 20)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "agkQkGMailw1", + "outputId": "2e23b577-4471-42da-eb2e-c940d634e9cf" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "datetime.datetime(2020, 1, 2, 3, 4, 5, tzinfo=TzInfo(UTC))\n", + "(10, 20)\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###**Creating a custom class that inherits from BaseModel:**" + ], + "metadata": { + "id": "7E2yq7sKjzWa" + } + }, + { + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "\n", + "from pydantic import BaseModel, PositiveInt\n", + "\n", + "\n", + "class User(BaseModel):\n", + " id: int\n", + " name: str = 'John Doe'\n", + " signup_ts: datetime | None\n", + " tastes: dict[str, PositiveInt]\n", + "\n", + "\n", + "external_data = {\n", + " 'id': 123,\n", + " 'signup_ts': '2019-06-01 12:22',\n", + " 'tastes': {\n", + " 'wine': 9,\n", + " b'cheese': 7,\n", + " 'cabbage': '1',\n", + " },\n", + "}\n", + "\n", + "user = User(**external_data)\n", + "\n", + "print(user.id)\n", + "#> 123\n", + "print(user.model_dump())\n", + "\"\"\"\n", + "{\n", + " 'id': 123,\n", + " 'name': 'John Doe',\n", + " 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),\n", + " 'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},\n", + "}\n", + "\"\"\"" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 88 + }, + "id": "kLbbNJGzjv97", + "outputId": "ee0904b9-ea18-4d1b-f333-612dad3d1838" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "123\n", + "{'id': 123, 'name': 'John Doe', 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22), 'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1}}\n" + ] + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "\"\\n{\\n 'id': 123,\\n 'name': 'John Doe',\\n 'signup_ts': datetime.datetime(2019, 6, 1, 12, 22),\\n 'tastes': {'wine': 9, 'cheese': 7, 'cabbage': 1},\\n}\\n\"" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + } + }, + "metadata": {}, + "execution_count": 3 + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###**If validation fails, Pydantic will raise an error with a breakdown of what was wrong:**\n", + "\n" + ], + "metadata": { + "id": "paXvRKt3kDTL" + } + }, + { + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "from pydantic import ValidationError\n", + "\n", + "from pydantic import BaseModel, PositiveInt\n", + "\n", + "\n", + "class User(BaseModel):\n", + " id: int\n", + " name: str = 'samim'\n", + " signup_ts: datetime | None\n", + " tastes: dict[str, PositiveInt]\n", + "\n", + "external_data = {\n", + " \"id\": 0,\n", + " \"name\": \"lisa\",\n", + " \"signup_ts\": \"2019-06-01 12:22\",\n", + " \"tastes\": {\n", + " \"fish\": \"9\",\n", + " \"tomato\": \"7\",\n", + " \"cabbage\": \"1\"\n", + " }\n", + "}\n", + "user = User(**external_data)\n", + "print(user.id)" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7Qbe2gL7kE2t", + "outputId": "a776c37f-88d2-4b9b-b9a8-90dbde265fd4" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "0\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "from pydantic import ValidationError\n", + "\n", + "from pydantic import BaseModel, PositiveInt\n", + "\n", + "\n", + "class User(BaseModel):\n", + " id: int\n", + " name: str = 'samim'\n", + " signup_ts: datetime | None\n", + " tastes: dict[str, PositiveInt]\n", + "\n", + "external_data = {'id': 'not an int', 'tastes': {}}\n", + "\n", + "try:\n", + " user = User(**external_data)\n", + " print(user.id)\n", + "except ValidationError as e:\n", + " print(e.errors())\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "nfm1faf4lgl8", + "outputId": "d0850281-1e4d-471c-b9c5-0a1293b6aef0" + }, + "execution_count": 9, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[{'type': 'int_parsing', 'loc': ('id',), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'not an int', 'url': 'https://errors.pydantic.dev/2.7/v/int_parsing'}, {'type': 'missing', 'loc': ('signup_ts',), 'msg': 'Field required', 'input': {'id': 'not an int', 'tastes': {}}, 'url': 'https://errors.pydantic.dev/2.7/v/missing'}]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###The main way to use Pydantic is to **create custom classes** that **inherit from BaseModel,** which is the base class for all Pydantic models. You can then define the attributes of your model using type annotations, and optionally provide default values or validators.\n", + "\n", + "###For example, let’s create a simple model for a user:" + ], + "metadata": { + "id": "9ThA6Ag-oNnk" + } + }, + { + "cell_type": "code", + "source": [ + "from datetime import datetime\n", + "from typing import List, Optional\n", + "from pydantic import BaseModel\n", + "\n", + "class User(BaseModel):\n", + " id: int\n", + " name: str = 'John Doe'\n", + " signup_ts: Optional[datetime] = None\n", + " friends: List[int] = []" + ], + "metadata": { + "id": "FTxxWbO-oWi-" + }, + "execution_count": 10, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "###This model defines four attributes: id, name, signup_ts, and friends. The id attribute is required and must be an integer. The name attribute has a default value of 'John Doe' and must be a string. The signup_ts attribute is optional and can be either a datetime object or None. The friends attribute has an empty list as the default value and must be a list of integers.\n", + "\n", + "###To **create an instance** of this model, you can **pass a dictionary of values** to the constructor:" + ], + "metadata": { + "id": "_Ja2MfxYou4k" + } + }, + { + "cell_type": "code", + "source": [ + "external_data = {\n", + " 'id': 123,\n", + " 'signup_ts': '2019-06-01 12:22',\n", + " 'friends': [1, '2', b'3'],\n", + "}\n", + "\n", + "user = User(**external_data)" + ], + "metadata": { + "id": "pUXD9GLboxBU" + }, + "execution_count": 11, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "###Pydantic will **automatically validate and parse** the input data according to the type annotations. It will also coerce the data to the correct type where appropriate. For example, it will convert the string '2019-06-01 12:22' to a datetime object, and the bytes b'3' to an integer.\n", + "\n", + "###You can access the attributes of the model as normal:" + ], + "metadata": { + "id": "nD_Obzg-pCeF" + } + }, + { + "cell_type": "code", + "source": [ + "print(user.id) # 123\n", + "print(user.name) # John Doe\n", + "print(user.signup_ts) # 2019-06-01 12:22:00\n", + "print(user.friends) # [1, 2, 3]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "OFm5vMVrpB2_", + "outputId": "0e0f48c6-b707-42b4-ddcc-653fce7d86d8" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "123\n", + "John Doe\n", + "2019-06-01 12:22:00\n", + "[1, 2, 3]\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###Or as a JSON string using the json() method:" + ], + "metadata": { + "id": "hF4k2r8DpNKM" + } + }, + { + "cell_type": "code", + "source": [ + "print(user.json())\n", + "# {\"id\": 123, \"name\": \"John Doe\", \"signup_ts\": \"2019-06-01T12:22:00\", \"friends\": [1, 2, 3]}" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hXwK4mw8pOP8", + "outputId": "2f648b98-ca2a-4c74-9cca-8aadc62faba2" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "{\"id\":123,\"name\":\"John Doe\",\"signup_ts\":\"2019-06-01T12:22:00\",\"friends\":[1,2,3]}\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "###If the input data is invalid or missing some required values, Pydantic will **raise a ValidationError** with a **detailed breakdown** of what went wrong:" + ], + "metadata": { + "id": "i-sPHlCMpU4E" + } + }, + { + "cell_type": "code", + "source": [ + "external_data = {\n", + " 'id': 'not an int',\n", + " 'tastes': {},\n", + "}\n", + "\n", + "try:\n", + " user = User(**external_data)\n", + "except ValidationError as e:\n", + " print(e.errors())\n", + "# [\n", + "# {\n", + "# 'type': 'int_parsing',\n", + "# 'loc': ('id',),\n", + "# 'msg': 'Input should be a valid integer, unable to parse string as an integer',\n", + "# 'input': 'not an int',\n", + "# 'url': 'https://errors.pydantic.dev/2/v/int_parsing',\n", + "# },\n", + "# {\n", + "# 'type': 'missing',\n", + "# 'loc': ('signup_ts',),\n", + "# 'msg': 'Field required',\n", + "# 'input': {'id': 'not an int', 'tastes': {}},\n", + "# 'url': 'https://errors.pydantic.dev/2/v/missing',\n", + "# },\n", + "# ]" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yMv4lzugpeG-", + "outputId": "bbd60f6b-c0c8-4cb3-a407-63bd7c8e5cc0" + }, + "execution_count": 14, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[{'type': 'int_parsing', 'loc': ('id',), 'msg': 'Input should be a valid integer, unable to parse string as an integer', 'input': 'not an int', 'url': 'https://errors.pydantic.dev/2.7/v/int_parsing'}]\n" + ] + } + ] + } + ] +} \ No newline at end of file