Skip to content

Commit 1c62ee9

Browse files
committed
Update docs
1 parent 8f46136 commit 1c62ee9

File tree

8 files changed

+300
-112
lines changed

8 files changed

+300
-112
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.PHONY: all setup build test coverage pep8 mypy fmt docs open-docs bench
22

3-
all: setup test pep8 mypy
3+
all: setup test pep8 mypy docs
44

55
setup:
66
pipenv install --dev

docs/de.html

+38-16
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,11 @@ <h1 class="title">Module <code>serde.de</code></h1>
4545
parts of pyserde.
4646
&#34;&#34;&#34;
4747
import abc
48+
import functools
4849
from dataclasses import dataclass, fields, is_dataclass
4950
from typing import Any, Dict, List, Optional, Tuple, Type, Union
5051

52+
import jinja2
5153
import stringcase
5254

5355
from .compat import assert_type, is_dict, is_list, is_opt, is_tuple, is_union, iter_types, type_args, typename
@@ -95,8 +97,8 @@ <h1 class="title">Module <code>serde.de</code></h1>
9597
def wrap(cls) -&gt; Type:
9698
if not hasattr(cls, HIDDEN_NAME):
9799
setattr(cls, HIDDEN_NAME, Hidden())
98-
cls = de_func(cls, FROM_ITER, args_from_iter(cls))
99-
cls = de_func(cls, FROM_DICT, args_from_dict(cls, case=rename_all))
100+
cls = de_func(cls, FROM_ITER, render_from_iter(cls))
101+
cls = de_func(cls, FROM_DICT, render_from_dict(cls, case=rename_all))
100102
return cls
101103

102104
if _cls is None:
@@ -131,7 +133,7 @@ <h1 class="title">Module <code>serde.de</code></h1>
131133
&#34;&#34;&#34;
132134

133135
@abc.abstractclassmethod
134-
def deserialize(self, data, **opts):
136+
def deserialize(cls, data, **opts):
135137
&#34;&#34;&#34;
136138
deserialize `data` into an object typically `dict`, `list` or `tuple`.
137139

@@ -180,7 +182,7 @@ <h1 class="title">Module <code>serde.de</code></h1>
180182
&gt;&gt;&gt;
181183
&#34;&#34;&#34;
182184
if de:
183-
o = de().deserialize(o, **opts)
185+
o = de.deserialize(o, **opts)
184186
if o is None:
185187
v = None
186188
if is_deserializable(c):
@@ -439,12 +441,32 @@ <h1 class="title">Module <code>serde.de</code></h1>
439441
return s
440442

441443

442-
def de_func(cls: Type[T], funcname: str, params: str) -&gt; Type[T]:
444+
def render_from_iter(cls: Type) -&gt; str:
445+
template = &#34;&#34;&#34;
446+
def {{func}}(data):
447+
return cls({{cls|args}})
443448
&#34;&#34;&#34;
444-
Generate function to deserialize into an instance of `deserialize` class.
449+
450+
env = jinja2.Environment(loader=jinja2.DictLoader({&#39;iter&#39;: template}))
451+
env.filters.update({&#39;args&#39;: args_from_iter})
452+
return env.get_template(&#39;iter&#39;).render(func=FROM_ITER, cls=cls)
453+
454+
455+
def render_from_dict(cls: Type, case: Optional[str] = None) -&gt; str:
456+
template = &#34;&#34;&#34;
457+
def {{func}}(data):
458+
return cls({{cls|args}})
445459
&#34;&#34;&#34;
446-
body = f&#39;def {funcname}(data):\n&#39; f&#39; return cls({params})&#39;
447460

461+
env = jinja2.Environment(loader=jinja2.DictLoader({&#39;dict&#39;: template}))
462+
env.filters.update({&#39;args&#39;: functools.partial(args_from_dict, case=case)})
463+
return env.get_template(&#39;dict&#39;).render(func=FROM_DICT, cls=cls)
464+
465+
466+
def de_func(cls: Type[T], func: str, code: str) -&gt; Type[T]:
467+
&#34;&#34;&#34;
468+
Generate function to deserialize into an instance of `deserialize` class.
469+
&#34;&#34;&#34;
448470
# Collect types to be used in the `exec` scope.
449471
g: Dict[str, Any] = globals().copy()
450472
for typ in iter_types(cls):
@@ -458,11 +480,11 @@ <h1 class="title">Module <code>serde.de</code></h1>
458480
g[&#39;NoneType&#39;] = type(None)
459481

460482
# Generate deserialize function.
461-
code = gen(body, g, cls=cls)
462-
setattr(cls, funcname, staticmethod(g[funcname]))
483+
code = gen(code, g, cls=cls)
484+
setattr(cls, func, staticmethod(g[func]))
463485
if SETTINGS[&#39;debug&#39;]:
464486
hidden = getattr(cls, HIDDEN_NAME)
465-
hidden.code[funcname] = code
487+
hidden.code[func] = code
466488

467489
return cls</code></pre>
468490
</details>
@@ -690,8 +712,8 @@ <h2 class="section-title" id="header-functions">Functions</h2>
690712
def wrap(cls) -&gt; Type:
691713
if not hasattr(cls, HIDDEN_NAME):
692714
setattr(cls, HIDDEN_NAME, Hidden())
693-
cls = de_func(cls, FROM_ITER, args_from_iter(cls))
694-
cls = de_func(cls, FROM_DICT, args_from_dict(cls, case=rename_all))
715+
cls = de_func(cls, FROM_ITER, render_from_iter(cls))
716+
cls = de_func(cls, FROM_DICT, render_from_dict(cls, case=rename_all))
695717
return cls
696718

697719
if _cls is None:
@@ -778,7 +800,7 @@ <h3 id="containers">Containers</h3>
778800
&gt;&gt;&gt;
779801
&#34;&#34;&#34;
780802
if de:
781-
o = de().deserialize(o, **opts)
803+
o = de.deserialize(o, **opts)
782804
if o is None:
783805
v = None
784806
if is_deserializable(c):
@@ -872,7 +894,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
872894
&#34;&#34;&#34;
873895

874896
@abc.abstractclassmethod
875-
def deserialize(self, data, **opts):
897+
def deserialize(cls, data, **opts):
876898
&#34;&#34;&#34;
877899
deserialize `data` into an object typically `dict`, `list` or `tuple`.
878900

@@ -883,10 +905,10 @@ <h2 class="section-title" id="header-classes">Classes</h2>
883905
</details>
884906
<h3>Subclasses</h3>
885907
<ul class="hlist">
908+
<li><a title="serde.toml.TomlDeserializer" href="toml.html#serde.toml.TomlDeserializer">TomlDeserializer</a></li>
886909
<li><a title="serde.msgpack.MsgPackDeserializer" href="msgpack.html#serde.msgpack.MsgPackDeserializer">MsgPackDeserializer</a></li>
887910
<li><a title="serde.yaml.YamlDeserializer" href="yaml.html#serde.yaml.YamlDeserializer">YamlDeserializer</a></li>
888911
<li><a title="serde.json.JsonDeserializer" href="json.html#serde.json.JsonDeserializer">JsonDeserializer</a></li>
889-
<li><a title="serde.toml.TomlDeserializer" href="toml.html#serde.toml.TomlDeserializer">TomlDeserializer</a></li>
890912
</ul>
891913
<h3>Static methods</h3>
892914
<dl>
@@ -901,7 +923,7 @@ <h3>Static methods</h3>
901923
<details class="source">
902924
<summary>Source code</summary>
903925
<pre><code class="python">@abc.abstractclassmethod
904-
def deserialize(self, data, **opts):
926+
def deserialize(cls, data, **opts):
905927
&#34;&#34;&#34;
906928
deserialize `data` into an object typically `dict`, `list` or `tuple`.
907929

docs/index.html

+65-2
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,67 @@ <h2 id="features">Features</h2>
7070
</ul>
7171
</li>
7272
<li>Class attributes<ul>
73-
<li>Case conversion e.g. camelCase, kebab-case</li>
73+
<li><a href="#case-conversion">Case conversion</a> e.g. camelCase, kebab-case</li>
7474
</ul>
7575
</li>
76+
<li>Field attributes<ul>
77+
<li><a href="#rename-field">Rename</a></li>
78+
<li><a href="#skip-field">Skip</a></li>
79+
<li><a href="#skip-if-value-is-evaluated-as-false">Skip if value is evaluated as False</a></li>
7680
</ul>
81+
</li>
82+
</ul>
83+
<h3 id="case-conversion">Case conversion</h3>
84+
<pre><code class="python">&gt;&gt;&gt; @serialize(rename_all = 'camelcase')
85+
... @dataclass
86+
... class Hoge:
87+
... int_field: int
88+
... str_field: str
89+
&gt;&gt;&gt;
90+
&gt;&gt;&gt; to_json(Hoge(int_field=10, str_field='hoge'))
91+
'{&quot;intField&quot;: 10, &quot;strField&quot;: &quot;hoge&quot;}'
92+
</code></pre>
93+
<h3 id="rename-field">Rename field</h3>
94+
<pre><code class="python">&gt;&gt;&gt; @serialize
95+
... @dataclass
96+
... class Hoge:
97+
... # Use 'class_name' because 'class' is a keyword.
98+
... class_name: str = field(metadata={'serde_rename': 'class'})
99+
&gt;&gt;&gt; to_json(Hoge(class_name='Hoge'))
100+
'{&quot;class&quot;: &quot;Hoge&quot;}'
101+
</code></pre>
102+
<p>For complete example, please see <a href="./examples/rename.py">./examples/rename.py</a></p>
103+
<h3 id="skip-field">Skip field</h3>
104+
<pre><code class="python">&gt;&gt;&gt; @serialize
105+
... @dataclass
106+
... class Resource:
107+
... name: str
108+
... hash: str
109+
... metadata: Dict[str, str] = field(default_factory=dict, metadata={'serde_skip': True})
110+
111+
&gt;&gt;&gt; resources = [
112+
... Resource(&quot;Stack Overflow&quot;, &quot;b6469c3f31653d281bbbfa6f94d60fea130abe38&quot;),
113+
... Resource(&quot;GitHub&quot;, &quot;5cb7a0c47e53854cd00e1a968de5abce1c124601&quot;, metadata={&quot;headquarters&quot;: &quot;San Francisco&quot;}) ]
114+
&gt;&gt;&gt; to_json(resources)
115+
'[{&quot;name&quot;: &quot;Stack Overflow&quot;, &quot;hash&quot;: &quot;b6469c3f31653d281bbbfa6f94d60fea130abe38&quot;}, {&quot;name&quot;: &quot;GitHub&quot;, &quot;hash&quot;: &quot;5cb7a0c47e53854cd00e1a968de5abce1c124601&quot;}]'
116+
</code></pre>
117+
<p>For complete example, please see <a href="./examples/skip.py">./examples/skip.py</a></p>
118+
<h3 id="skip-if-value-is-evaluated-as-false">Skip if value is evaluated as False</h3>
119+
<pre><code class="python">&gt;&gt;&gt; @serialize
120+
... @dataclass
121+
... class World:
122+
... player: str
123+
... enemies: List[str] = field(default_factory=list, metadata={'serde_skip_if_false': True})
124+
125+
&gt;&gt;&gt; world = World('satoshi', ['Rattata', 'Pidgey'])
126+
&gt;&gt;&gt; to_json(world)
127+
'{&quot;player&quot;: &quot;satoshi&quot;, &quot;enemies&quot;: [&quot;Rattata&quot;, &quot;Pidgey&quot;]}'
128+
129+
&gt;&gt;&gt; world = World('green', [])
130+
&gt;&gt;&gt; print(to_json(world))
131+
'{&quot;player&quot;: &quot;green&quot;}'
132+
</code></pre>
133+
<p>For complete example, please see <a href="./examples/skip.py">./examples/skip.py</a></p>
77134
<h2 id="documentation">Documentation</h2>
78135
<p><a href="https://yukinarit.github.io/pyserde/">https://yukinarit.github.io/pyserde/</a></p>
79136
<details class="source">
@@ -144,7 +201,13 @@ <h1>Index</h1>
144201
<li><a href="#pyserde">pyserde</a><ul>
145202
<li><a href="#installation">Installation</a></li>
146203
<li><a href="#quickstart">QuickStart</a></li>
147-
<li><a href="#features">Features</a></li>
204+
<li><a href="#features">Features</a><ul>
205+
<li><a href="#case-conversion">Case conversion</a></li>
206+
<li><a href="#rename-field">Rename field</a></li>
207+
<li><a href="#skip-field">Skip field</a></li>
208+
<li><a href="#skip-if-value-is-evaluated-as-false">Skip if value is evaluated as False</a></li>
209+
</ul>
210+
</li>
148211
<li><a href="#documentation">Documentation</a></li>
149212
</ul>
150213
</li>

docs/json.html

+18-19
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,23 @@ <h1 class="title">Module <code>serde.json</code></h1>
2727

2828
from .core import T
2929
from .de import Deserializer, from_obj
30-
from .se import Serializer, is_serializable, asdict
30+
from .se import Serializer, asdict, is_serializable
3131

3232

3333
class JsonSerializer(Serializer):
34-
def serialize(self, obj: Any, **opts) -&gt; str:
34+
@classmethod
35+
def serialize(cls, obj: Any, **opts) -&gt; str:
3536
return json.dumps(asdict(obj), **opts)
3637

3738

3839
class JsonDeserializer(Deserializer):
39-
def deserialize(self, s, **opts):
40+
@classmethod
41+
def deserialize(cls, s, **opts):
4042
return json.loads(s, **opts)
4143

4244

43-
def to_json(obj: Any, serializer=JsonSerializer) -&gt; str:
44-
if is_serializable(obj):
45-
return obj.__serde_serialize__(serializer)
46-
else:
47-
return json.dumps(obj)
45+
def to_json(obj: Any, cls: Type[JsonSerializer] = JsonSerializer) -&gt; str:
46+
return cls.serialize(obj)
4847

4948

5049
def from_json(c: Type[T], s: str, de: Type[Deserializer] = JsonDeserializer, **opts) -&gt; T:
@@ -70,17 +69,14 @@ <h2 class="section-title" id="header-functions">Functions</h2>
7069
</details>
7170
</dd>
7271
<dt id="serde.json.to_json"><code class="name flex">
73-
<span>def <span class="ident">to_json</span></span>(<span>obj, serializer=<class 'serde.json.JsonSerializer'>)</span>
72+
<span>def <span class="ident">to_json</span></span>(<span>obj, cls=<class 'serde.json.JsonSerializer'>)</span>
7473
</code></dt>
7574
<dd>
7675
<section class="desc"></section>
7776
<details class="source">
7877
<summary>Source code</summary>
79-
<pre><code class="python">def to_json(obj: Any, serializer=JsonSerializer) -&gt; str:
80-
if is_serializable(obj):
81-
return obj.__serde_serialize__(serializer)
82-
else:
83-
return json.dumps(obj)</code></pre>
78+
<pre><code class="python">def to_json(obj: Any, cls: Type[JsonSerializer] = JsonSerializer) -&gt; str:
79+
return cls.serialize(obj)</code></pre>
8480
</details>
8581
</dd>
8682
</dl>
@@ -98,7 +94,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
9894
<details class="source">
9995
<summary>Source code</summary>
10096
<pre><code class="python">class JsonDeserializer(Deserializer):
101-
def deserialize(self, s, **opts):
97+
@classmethod
98+
def deserialize(cls, s, **opts):
10299
return json.loads(s, **opts)</code></pre>
103100
</details>
104101
<h3>Ancestors</h3>
@@ -124,23 +121,25 @@ <h3>Inherited members</h3>
124121
<details class="source">
125122
<summary>Source code</summary>
126123
<pre><code class="python">class JsonSerializer(Serializer):
127-
def serialize(self, obj: Any, **opts) -&gt; str:
124+
@classmethod
125+
def serialize(cls, obj: Any, **opts) -&gt; str:
128126
return json.dumps(asdict(obj), **opts)</code></pre>
129127
</details>
130128
<h3>Ancestors</h3>
131129
<ul class="hlist">
132130
<li><a title="serde.se.Serializer" href="se.html#serde.se.Serializer">Serializer</a></li>
133131
</ul>
134-
<h3>Methods</h3>
132+
<h3>Static methods</h3>
135133
<dl>
136134
<dt id="serde.json.JsonSerializer.serialize"><code class="name flex">
137-
<span>def <span class="ident">serialize</span></span>(<span>self, obj, **opts)</span>
135+
<span>def <span class="ident">serialize</span></span>(<span>obj, **opts)</span>
138136
</code></dt>
139137
<dd>
140138
<section class="desc"></section>
141139
<details class="source">
142140
<summary>Source code</summary>
143-
<pre><code class="python">def serialize(self, obj: Any, **opts) -&gt; str:
141+
<pre><code class="python">@classmethod
142+
def serialize(cls, obj: Any, **opts) -&gt; str:
144143
return json.dumps(asdict(obj), **opts)</code></pre>
145144
</details>
146145
</dd>

docs/msgpack.html

+12-7
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ <h1 class="title">Module <code>serde.msgpack</code></h1>
3333

3434

3535
class MsgPackSerializer(Serializer):
36-
def serialize(self, obj: Any, **opts) -&gt; str:
36+
@classmethod
37+
def serialize(cls, obj: Any, **opts) -&gt; str:
3738
return msgpack.packb(astuple(obj), **opts)
3839

3940

4041
class MsgPackDeserializer(Deserializer):
41-
def deserialize(self, s, **opts):
42+
@classmethod
43+
def deserialize(cls, s, **opts):
4244
unp = msgpack.unpackb(s, raw=False, use_list=False, **opts)
4345
logger.debug(&#39;unpack from msgpack: {unp}&#39;)
4446
return unp
@@ -96,7 +98,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
9698
<details class="source">
9799
<summary>Source code</summary>
98100
<pre><code class="python">class MsgPackDeserializer(Deserializer):
99-
def deserialize(self, s, **opts):
101+
@classmethod
102+
def deserialize(cls, s, **opts):
100103
unp = msgpack.unpackb(s, raw=False, use_list=False, **opts)
101104
logger.debug(&#39;unpack from msgpack: {unp}&#39;)
102105
return unp</code></pre>
@@ -124,23 +127,25 @@ <h3>Inherited members</h3>
124127
<details class="source">
125128
<summary>Source code</summary>
126129
<pre><code class="python">class MsgPackSerializer(Serializer):
127-
def serialize(self, obj: Any, **opts) -&gt; str:
130+
@classmethod
131+
def serialize(cls, obj: Any, **opts) -&gt; str:
128132
return msgpack.packb(astuple(obj), **opts)</code></pre>
129133
</details>
130134
<h3>Ancestors</h3>
131135
<ul class="hlist">
132136
<li><a title="serde.se.Serializer" href="se.html#serde.se.Serializer">Serializer</a></li>
133137
</ul>
134-
<h3>Methods</h3>
138+
<h3>Static methods</h3>
135139
<dl>
136140
<dt id="serde.msgpack.MsgPackSerializer.serialize"><code class="name flex">
137-
<span>def <span class="ident">serialize</span></span>(<span>self, obj, **opts)</span>
141+
<span>def <span class="ident">serialize</span></span>(<span>obj, **opts)</span>
138142
</code></dt>
139143
<dd>
140144
<section class="desc"></section>
141145
<details class="source">
142146
<summary>Source code</summary>
143-
<pre><code class="python">def serialize(self, obj: Any, **opts) -&gt; str:
147+
<pre><code class="python">@classmethod
148+
def serialize(cls, obj: Any, **opts) -&gt; str:
144149
return msgpack.packb(astuple(obj), **opts)</code></pre>
145150
</details>
146151
</dd>

0 commit comments

Comments
 (0)