Skip to content

Commit 66b1a3a

Browse files
add pydantic validation
1 parent 89e5142 commit 66b1a3a

File tree

4 files changed

+239
-3
lines changed

4 files changed

+239
-3
lines changed

Chapter2/dataclasses.ipynb

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,88 @@
365365
"dogs = Dogs(names, ages)\n",
366366
"dogs.info "
367367
]
368+
},
369+
{
370+
"cell_type": "code",
371+
"execution_count": 6,
372+
"id": "2f084dad",
373+
"metadata": {},
374+
"outputs": [
375+
{
376+
"ename": "ValueError",
377+
"evalue": "Dog's age must be an integer.",
378+
"output_type": "error",
379+
"traceback": [
380+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
381+
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
382+
"Cell \u001b[0;32mIn[6], line 12\u001b[0m\n\u001b[1;32m 10\u001b[0m dog \u001b[38;5;241m=\u001b[39m Dog(names\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mBim\u001b[39m\u001b[38;5;124m\"\u001b[39m, age\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mten\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(dog\u001b[38;5;241m.\u001b[39mage, \u001b[38;5;28mint\u001b[39m):\n\u001b[0;32m---> 12\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDog\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124ms age must be an integer.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n",
383+
"\u001b[0;31mValueError\u001b[0m: Dog's age must be an integer."
384+
]
385+
}
386+
],
387+
"source": [
388+
"from dataclasses import dataclass\n",
389+
"\n",
390+
"\n",
391+
"@dataclass\n",
392+
"class Dog:\n",
393+
" names: str\n",
394+
" age: int\n",
395+
"\n",
396+
"\n",
397+
"dog = Dog(names=\"Bim\", age=\"ten\")\n",
398+
"if not isinstance(dog.age, int):\n",
399+
" raise ValueError(\"Dog's age must be an integer.\")"
400+
]
401+
},
402+
{
403+
"cell_type": "markdown",
404+
"id": "addd6347",
405+
"metadata": {},
406+
"source": [
407+
"### Simplify Data Validation with Pydantic"
408+
]
409+
},
410+
{
411+
"cell_type": "markdown",
412+
"id": "e4bb3a40",
413+
"metadata": {},
414+
"source": [
415+
"Dataclasses require manual implementation of validation.\n",
416+
"\n",
417+
"On the other hand, Pydantic offers built-in validation that automatically validates data and provides informative error messages. This makes Pydantic particularly useful when working with data from external sources.\n"
418+
]
419+
},
420+
{
421+
"cell_type": "code",
422+
"execution_count": 3,
423+
"id": "3aaa4b09",
424+
"metadata": {},
425+
"outputs": [
426+
{
427+
"ename": "ValidationError",
428+
"evalue": "1 validation error for Dog\nage\n Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='ten', input_type=str]\n For further information visit https://errors.pydantic.dev/2.5/v/int_parsing",
429+
"output_type": "error",
430+
"traceback": [
431+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
432+
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
433+
"Cell \u001b[0;32mIn[3], line 9\u001b[0m\n\u001b[1;32m 5\u001b[0m names: \u001b[38;5;28mstr\u001b[39m\n\u001b[1;32m 6\u001b[0m age: \u001b[38;5;28mint\u001b[39m\n\u001b[0;32m----> 9\u001b[0m dog \u001b[38;5;241m=\u001b[39m \u001b[43mDog\u001b[49m\u001b[43m(\u001b[49m\u001b[43mnames\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mBim\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mten\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
434+
"File \u001b[0;32m~/book/venv/lib/python3.11/site-packages/pydantic/main.py:164\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[0;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[1;32m 162\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[1;32m 163\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m--> 164\u001b[0m \u001b[43m__pydantic_self__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__pydantic_validator__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_python\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mself_instance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m__pydantic_self__\u001b[49m\u001b[43m)\u001b[49m\n",
435+
"\u001b[0;31mValidationError\u001b[0m: 1 validation error for Dog\nage\n Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='ten', input_type=str]\n For further information visit https://errors.pydantic.dev/2.5/v/int_parsing"
436+
]
437+
}
438+
],
439+
"source": [
440+
"from pydantic import BaseModel\n",
441+
"\n",
442+
"\n",
443+
"class Dog(BaseModel):\n",
444+
" names: str\n",
445+
" age: int\n",
446+
"\n",
447+
"\n",
448+
"dog = Dog(names=\"Bim\", age=\"ten\")"
449+
]
368450
}
369451
],
370452
"metadata": {
@@ -383,7 +465,7 @@
383465
"name": "python",
384466
"nbconvert_exporter": "python",
385467
"pygments_lexer": "ipython3",
386-
"version": "3.8.9"
468+
"version": "3.11.6"
387469
},
388470
"toc": {
389471
"base_numbering": 1,

docs/Chapter2/dataclasses.html

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ <h2> Contents </h2>
516516
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#frozen-true-make-your-data-classes-read-only">3.7.2. frozen=True: Make Your Data Classes Read-Only</a></li>
517517
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#compare-between-two-data-classes">3.7.3. Compare Between Two Data Classes</a></li>
518518
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#post-init-add-init-method-to-a-data-class">3.7.4. Post-init: Add Init Method to a Data Class</a></li>
519+
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#simplify-data-validation-with-pydantic">3.7.5. Simplify Data Validation with Pydantic</a></li>
519520
</ul>
520521
</nav>
521522
</div>
@@ -720,6 +721,76 @@ <h2><span class="section-number">3.7.4. </span>Post-init: Add Init Method to a D
720721
</div>
721722
</div>
722723
</div>
724+
<div class="cell docutils container">
725+
<div class="cell_input docutils container">
726+
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>
727+
728+
729+
<span class="nd">@dataclass</span>
730+
<span class="k">class</span> <span class="nc">Dog</span><span class="p">:</span>
731+
<span class="n">names</span><span class="p">:</span> <span class="nb">str</span>
732+
<span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
733+
734+
735+
<span class="n">dog</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="n">names</span><span class="o">=</span><span class="s2">&quot;Bim&quot;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="s2">&quot;ten&quot;</span><span class="p">)</span>
736+
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dog</span><span class="o">.</span><span class="n">age</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
737+
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Dog&#39;s age must be an integer.&quot;</span><span class="p">)</span>
738+
</pre></div>
739+
</div>
740+
</div>
741+
<div class="cell_output docutils container">
742+
<div class="output traceback highlight-ipythontb notranslate"><div class="highlight"><pre><span></span><span class="gt">---------------------------------------------------------------------------</span>
743+
<span class="ne">ValueError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
744+
<span class="n">Cell</span> <span class="n">In</span><span class="p">[</span><span class="mi">6</span><span class="p">],</span> <span class="n">line</span> <span class="mi">12</span>
745+
<span class="g g-Whitespace"> </span><span class="mi">10</span> <span class="n">dog</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="n">names</span><span class="o">=</span><span class="s2">&quot;Bim&quot;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="s2">&quot;ten&quot;</span><span class="p">)</span>
746+
<span class="g g-Whitespace"> </span><span class="mi">11</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">dog</span><span class="o">.</span><span class="n">age</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
747+
<span class="ne">---&gt; </span><span class="mi">12</span> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Dog&#39;s age must be an integer.&quot;</span><span class="p">)</span>
748+
749+
<span class="ne">ValueError</span>: Dog&#39;s age must be an integer.
750+
</pre></div>
751+
</div>
752+
</div>
753+
</div>
754+
</section>
755+
<section id="simplify-data-validation-with-pydantic">
756+
<h2><span class="section-number">3.7.5. </span>Simplify Data Validation with Pydantic<a class="headerlink" href="#simplify-data-validation-with-pydantic" title="Permalink to this heading">#</a></h2>
757+
<p>Dataclasses require manual implementation of validation.</p>
758+
<p>On the other hand, Pydantic offers built-in validation that automatically validates data and provides informative error messages. This makes Pydantic particularly useful when working with data from external sources.</p>
759+
<div class="cell docutils container">
760+
<div class="cell_input docutils container">
761+
<div class="highlight-ipython3 notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">pydantic</span> <span class="kn">import</span> <span class="n">BaseModel</span>
762+
763+
764+
<span class="k">class</span> <span class="nc">Dog</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
765+
<span class="n">names</span><span class="p">:</span> <span class="nb">str</span>
766+
<span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
767+
768+
769+
<span class="n">dog</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="n">names</span><span class="o">=</span><span class="s2">&quot;Bim&quot;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="s2">&quot;ten&quot;</span><span class="p">)</span>
770+
</pre></div>
771+
</div>
772+
</div>
773+
<div class="cell_output docutils container">
774+
<div class="output traceback highlight-ipythontb notranslate"><div class="highlight"><pre><span></span><span class="gt">---------------------------------------------------------------------------</span>
775+
<span class="ne">ValidationError</span><span class="g g-Whitespace"> </span>Traceback (most recent call last)
776+
<span class="n">Cell</span> <span class="n">In</span><span class="p">[</span><span class="mi">3</span><span class="p">],</span> <span class="n">line</span> <span class="mi">9</span>
777+
<span class="g g-Whitespace"> </span><span class="mi">5</span> <span class="n">names</span><span class="p">:</span> <span class="nb">str</span>
778+
<span class="g g-Whitespace"> </span><span class="mi">6</span> <span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
779+
<span class="ne">----&gt; </span><span class="mi">9</span> <span class="n">dog</span> <span class="o">=</span> <span class="n">Dog</span><span class="p">(</span><span class="n">names</span><span class="o">=</span><span class="s2">&quot;Bim&quot;</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="s2">&quot;ten&quot;</span><span class="p">)</span>
780+
781+
<span class="nn">File ~/book/venv/lib/python3.11/site-packages/pydantic/main.py:164,</span> in <span class="ni">BaseModel.__init__</span><span class="nt">(__pydantic_self__, **data)</span>
782+
<span class="g g-Whitespace"> </span><span class="mi">162</span> <span class="c1"># `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks</span>
783+
<span class="g g-Whitespace"> </span><span class="mi">163</span> <span class="n">__tracebackhide__</span> <span class="o">=</span> <span class="kc">True</span>
784+
<span class="ne">--&gt; </span><span class="mi">164</span> <span class="n">__pydantic_self__</span><span class="o">.</span><span class="n">__pydantic_validator__</span><span class="o">.</span><span class="n">validate_python</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">self_instance</span><span class="o">=</span><span class="n">__pydantic_self__</span><span class="p">)</span>
785+
786+
<span class="ne">ValidationError</span>: 1 validation error for Dog
787+
<span class="n">age</span>
788+
<span class="n">Input</span> <span class="n">should</span> <span class="n">be</span> <span class="n">a</span> <span class="n">valid</span> <span class="n">integer</span><span class="p">,</span> <span class="n">unable</span> <span class="n">to</span> <span class="n">parse</span> <span class="n">string</span> <span class="k">as</span> <span class="n">an</span> <span class="n">integer</span> <span class="p">[</span><span class="nb">type</span><span class="o">=</span><span class="n">int_parsing</span><span class="p">,</span> <span class="n">input_value</span><span class="o">=</span><span class="s1">&#39;ten&#39;</span><span class="p">,</span> <span class="n">input_type</span><span class="o">=</span><span class="nb">str</span><span class="p">]</span>
789+
<span class="n">For</span> <span class="n">further</span> <span class="n">information</span> <span class="n">visit</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">errors</span><span class="o">.</span><span class="n">pydantic</span><span class="o">.</span><span class="n">dev</span><span class="o">/</span><span class="mf">2.5</span><span class="o">/</span><span class="n">v</span><span class="o">/</span><span class="n">int_parsing</span>
790+
</pre></div>
791+
</div>
792+
</div>
793+
</div>
723794
</section>
724795
</section>
725796

@@ -790,6 +861,7 @@ <h2><span class="section-number">3.7.4. </span>Post-init: Add Init Method to a D
790861
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#frozen-true-make-your-data-classes-read-only">3.7.2. frozen=True: Make Your Data Classes Read-Only</a></li>
791862
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#compare-between-two-data-classes">3.7.3. Compare Between Two Data Classes</a></li>
792863
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#post-init-add-init-method-to-a-data-class">3.7.4. Post-init: Add Init Method to a Data Class</a></li>
864+
<li class="toc-h2 nav-item toc-entry"><a class="reference internal nav-link" href="#simplify-data-validation-with-pydantic">3.7.5. Simplify Data Validation with Pydantic</a></li>
793865
</ul>
794866
</nav></div>
795867

0 commit comments

Comments
 (0)