python-datamodel 0.10.1__cp313-cp313-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datamodel/__init__.py +13 -0
- datamodel/abstract.py +383 -0
- datamodel/adaptive/__init__.py +0 -0
- datamodel/adaptive/models.py +598 -0
- datamodel/aliases/__init__.py +26 -0
- datamodel/base.py +180 -0
- datamodel/converters.c +43471 -0
- datamodel/converters.cp313-win32.pyd +0 -0
- datamodel/converters.html +17387 -0
- datamodel/converters.pyx +1489 -0
- datamodel/exceptions.c +13455 -0
- datamodel/exceptions.cp313-win32.pyd +0 -0
- datamodel/exceptions.html +1261 -0
- datamodel/exceptions.pxd +13 -0
- datamodel/exceptions.pyx +50 -0
- datamodel/fields.cp313-win32.pyd +0 -0
- datamodel/fields.cpp +17401 -0
- datamodel/fields.html +3912 -0
- datamodel/fields.pyx +309 -0
- datamodel/functions.cp313-win32.pyd +0 -0
- datamodel/functions.cpp +9068 -0
- datamodel/functions.html +1766 -0
- datamodel/functions.pxd +9 -0
- datamodel/functions.pyx +82 -0
- datamodel/jsonld/__init__.py +45 -0
- datamodel/jsonld/models.py +500 -0
- datamodel/libs/__init__.py +1 -0
- datamodel/libs/mapping.c +15067 -0
- datamodel/libs/mapping.cp313-win32.pyd +0 -0
- datamodel/libs/mapping.html +2618 -0
- datamodel/libs/mapping.pxd +11 -0
- datamodel/libs/mapping.pyx +135 -0
- datamodel/libs/mutables.py +127 -0
- datamodel/models.py +814 -0
- datamodel/parsers/__init__.py +0 -0
- datamodel/parsers/encoders.py +15 -0
- datamodel/parsers/json.cp313-win32.pyd +0 -0
- datamodel/parsers/json.cpp +17004 -0
- datamodel/parsers/json.html +3365 -0
- datamodel/parsers/json.pyx +250 -0
- datamodel/profiler.py +21 -0
- datamodel/py.typed +0 -0
- datamodel/rs_core/Cargo.toml +17 -0
- datamodel/rs_core/src/lib.rs +294 -0
- datamodel/rs_parsers/Cargo.toml +22 -0
- datamodel/rs_parsers/src/lib.rs +571 -0
- datamodel/rs_parsers.cp313-win32.pyd +0 -0
- datamodel/rs_validators/Cargo.toml +17 -0
- datamodel/rs_validators/src/lib.rs +0 -0
- datamodel/typedefs/__init__.py +9 -0
- datamodel/typedefs/singleton.c +9169 -0
- datamodel/typedefs/singleton.cp313-win32.pyd +0 -0
- datamodel/typedefs/singleton.html +629 -0
- datamodel/typedefs/singleton.pxd +9 -0
- datamodel/typedefs/singleton.pyx +24 -0
- datamodel/typedefs/types.c +11716 -0
- datamodel/typedefs/types.cp313-win32.pyd +0 -0
- datamodel/typedefs/types.html +732 -0
- datamodel/typedefs/types.pxd +11 -0
- datamodel/typedefs/types.pyx +39 -0
- datamodel/types.c +7165 -0
- datamodel/types.cp313-win32.pyd +0 -0
- datamodel/types.html +716 -0
- datamodel/types.pyx +100 -0
- datamodel/validation.cp313-win32.pyd +0 -0
- datamodel/validation.cpp +17085 -0
- datamodel/validation.html +4769 -0
- datamodel/validation.pyx +315 -0
- datamodel/version.py +13 -0
- examples/nn/examples.py +311 -0
- examples/nn/stores.py +151 -0
- examples/tests/sp_types.py +294 -0
- examples/tests/speed_dates.py +26 -0
- python_datamodel-0.10.1.dist-info/LICENSE +29 -0
- python_datamodel-0.10.1.dist-info/METADATA +320 -0
- python_datamodel-0.10.1.dist-info/RECORD +78 -0
- python_datamodel-0.10.1.dist-info/WHEEL +5 -0
- python_datamodel-0.10.1.dist-info/top_level.txt +7 -0
datamodel/functions.pxd
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# function.pxd
|
|
2
|
+
from libcpp cimport bool as bool_t
|
|
3
|
+
|
|
4
|
+
cpdef bool_t is_iterable(object value)
|
|
5
|
+
cpdef bool_t is_primitive(object value)
|
|
6
|
+
cpdef bool_t is_dataclass(object obj)
|
|
7
|
+
cpdef bool_t is_function(object value)
|
|
8
|
+
cpdef bool_t is_callable(object value)
|
|
9
|
+
cpdef bool_t is_empty(object value)
|
datamodel/functions.pyx
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# cython: language_level=3, embedsignature=True, boundscheck=False, wraparound=True, initializedcheck=False
|
|
2
|
+
# Copyright (C) 2018-present Jesus Lara
|
|
3
|
+
#
|
|
4
|
+
from typing import get_args, get_origin, Union, Optional
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from libcpp cimport bool as bool_t
|
|
7
|
+
from cpython.object cimport (
|
|
8
|
+
PyObject_IsInstance,
|
|
9
|
+
PyObject_IsSubclass,
|
|
10
|
+
PyObject_HasAttr,
|
|
11
|
+
)
|
|
12
|
+
from uuid import UUID
|
|
13
|
+
import asyncpg.pgproto.pgproto as pgproto
|
|
14
|
+
from decimal import Decimal
|
|
15
|
+
import datetime
|
|
16
|
+
import types
|
|
17
|
+
from functools import partial
|
|
18
|
+
from dataclasses import _MISSING_TYPE
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
cpdef bool_t is_iterable(object value):
|
|
22
|
+
"""Returns True if value is an iterable."""
|
|
23
|
+
if isinstance(value, Iterable) and not isinstance(value, (str, bytes)):
|
|
24
|
+
return True
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
cpdef bool_t is_primitive(object value):
|
|
29
|
+
"""Returns True if value is a primitive type."""
|
|
30
|
+
return value in (
|
|
31
|
+
int,
|
|
32
|
+
float,
|
|
33
|
+
str,
|
|
34
|
+
UUID,
|
|
35
|
+
pgproto.UUID,
|
|
36
|
+
Decimal,
|
|
37
|
+
bool,
|
|
38
|
+
bytes,
|
|
39
|
+
datetime.date,
|
|
40
|
+
datetime.datetime,
|
|
41
|
+
datetime.time,
|
|
42
|
+
datetime.timedelta
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
cpdef bool_t is_dataclass(object obj):
|
|
47
|
+
"""Returns True if obj is a dataclass or an instance of a
|
|
48
|
+
dataclass."""
|
|
49
|
+
cls = obj if isinstance(obj, type) and not isinstance(obj, types.GenericAlias) else type(obj)
|
|
50
|
+
return PyObject_HasAttr(cls, '__dataclass_fields__')
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
cpdef bool_t is_function(object value):
|
|
54
|
+
"""Returns True if value is a function."""
|
|
55
|
+
return isinstance(value, (types.BuiltinFunctionType, types.FunctionType, partial))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
cpdef bool_t is_callable(object value):
|
|
59
|
+
"""Returns True if value is a callable object."""
|
|
60
|
+
if value is None or value == _MISSING_TYPE:
|
|
61
|
+
return False
|
|
62
|
+
if is_function(value):
|
|
63
|
+
return callable(value)
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
cpdef bool_t is_empty(object value):
|
|
67
|
+
cdef bool_t result = False
|
|
68
|
+
if value is None:
|
|
69
|
+
return True
|
|
70
|
+
if isinstance(value, _MISSING_TYPE) or value == _MISSING_TYPE:
|
|
71
|
+
result = True
|
|
72
|
+
elif isinstance(value, str) and value == '':
|
|
73
|
+
result = True
|
|
74
|
+
elif isinstance(value, (int, float)) and value == 0:
|
|
75
|
+
result = False
|
|
76
|
+
elif isinstance(value, dict) and value == {}:
|
|
77
|
+
result = False
|
|
78
|
+
elif isinstance(value, (list, tuple, set)) and value == []:
|
|
79
|
+
result = False
|
|
80
|
+
elif not value:
|
|
81
|
+
result = True
|
|
82
|
+
return result
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from .models import (
|
|
2
|
+
URL,
|
|
3
|
+
JobTitle,
|
|
4
|
+
PostalAddress,
|
|
5
|
+
GeoCoordinates,
|
|
6
|
+
Person,
|
|
7
|
+
ImageObject,
|
|
8
|
+
Recipe,
|
|
9
|
+
NutritionInformation,
|
|
10
|
+
Organization,
|
|
11
|
+
AggregateRating,
|
|
12
|
+
Rating,
|
|
13
|
+
Product,
|
|
14
|
+
Review,
|
|
15
|
+
VideoObject,
|
|
16
|
+
AdministrativeArea,
|
|
17
|
+
Audience,
|
|
18
|
+
Place,
|
|
19
|
+
QuantitativeValue,
|
|
20
|
+
MonetaryAmount,
|
|
21
|
+
JobPosting,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
JSON_MODEL_MAP = {
|
|
25
|
+
"URL": URL,
|
|
26
|
+
"JobTitle": JobTitle,
|
|
27
|
+
"PostalAddress": PostalAddress,
|
|
28
|
+
"GeoCoordinates": GeoCoordinates,
|
|
29
|
+
"Person": Person,
|
|
30
|
+
"ImageObject": ImageObject,
|
|
31
|
+
"Recipe": Recipe,
|
|
32
|
+
"NutritionInformation": NutritionInformation,
|
|
33
|
+
"Organization": Organization,
|
|
34
|
+
"AggregateRating": AggregateRating,
|
|
35
|
+
"Rating": Rating,
|
|
36
|
+
"Product": Product,
|
|
37
|
+
"Review": Review,
|
|
38
|
+
"VideoObject": VideoObject,
|
|
39
|
+
"AdministrativeArea": AdministrativeArea,
|
|
40
|
+
"Audience": Audience,
|
|
41
|
+
"Place": Place,
|
|
42
|
+
"QuantitativeValue": QuantitativeValue,
|
|
43
|
+
"MonetaryAmount": MonetaryAmount,
|
|
44
|
+
"JobPosting": JobPosting,
|
|
45
|
+
}
|
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
from typing import Any, List, Optional, Union
|
|
2
|
+
from html import escape
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from ..base import BaseModel, Field, register_renderer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class URL(BaseModel):
|
|
8
|
+
"""
|
|
9
|
+
Corresponds to the JSON-LD "URL" type.
|
|
10
|
+
https://schema.org/URL
|
|
11
|
+
"""
|
|
12
|
+
url: str
|
|
13
|
+
|
|
14
|
+
class Meta:
|
|
15
|
+
schema_type: str = "URL"
|
|
16
|
+
|
|
17
|
+
class JobTitle(BaseModel):
|
|
18
|
+
"""
|
|
19
|
+
The job title of the person (for example, Financial Manager).
|
|
20
|
+
http://schema.org/jobTitle
|
|
21
|
+
|
|
22
|
+
Example:
|
|
23
|
+
"jobTitle": {
|
|
24
|
+
"@type": "DefinedTerm",
|
|
25
|
+
"inDefinedTermSet": "https://targetjobs.co.uk/careers-advice/job-descriptions",
|
|
26
|
+
"termCode": "277133-aid-workerhumanitarian-worker-job-description",
|
|
27
|
+
"name": "Aid worker/humanitarian worker",
|
|
28
|
+
"url": "https://targetjobs.co.uk/careers-advice/job-descriptions/277133-aid-workerhumanitarian-worker-job-description"
|
|
29
|
+
}
|
|
30
|
+
""" # noqa
|
|
31
|
+
name: str
|
|
32
|
+
url: str
|
|
33
|
+
inDefinedTermSet: str
|
|
34
|
+
termCode: str
|
|
35
|
+
|
|
36
|
+
class Meta:
|
|
37
|
+
schema_type: str = "JobTitle"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class PostalAddress(BaseModel):
|
|
41
|
+
"""
|
|
42
|
+
Corresponds to the JSON-LD "Address" type.
|
|
43
|
+
https://schema.org/PostalAddress
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
"address": {
|
|
47
|
+
"@type": "PostalAddress",
|
|
48
|
+
"addressLocality": "Seattle",
|
|
49
|
+
"addressRegion": "WA",
|
|
50
|
+
"postalCode": "98052",
|
|
51
|
+
"streetAddress": "20341 Whitworth Institute 405 N. Whitworth"
|
|
52
|
+
}
|
|
53
|
+
"""
|
|
54
|
+
streetAddress: str
|
|
55
|
+
addressLocality: str
|
|
56
|
+
addressRegion: str
|
|
57
|
+
postalCode: str
|
|
58
|
+
addressCountry: str
|
|
59
|
+
postOfficeBoxNumber: Optional[str]
|
|
60
|
+
telephone: Optional[str]
|
|
61
|
+
|
|
62
|
+
class Meta:
|
|
63
|
+
schema_type: str = "PostalAddress"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class GeoCoordinates(BaseModel):
|
|
67
|
+
"""
|
|
68
|
+
Corresponds to the JSON-LD "GeoCoordinates" type.
|
|
69
|
+
https://schema.org/GeoCoordinates
|
|
70
|
+
|
|
71
|
+
Properties:
|
|
72
|
+
latitude: The latitude of a location. For example 37.42242 (WGS 84).
|
|
73
|
+
longitude: The longitude of a location. For example -122.08585 (WGS 84).
|
|
74
|
+
elevation: The elevation of a location (WGS 84).
|
|
75
|
+
Values may be of the form 'NUMBER UNIT_OF_MEASUREMENT' (e.g., '1,000 m')
|
|
76
|
+
while numbers alone should be assumed to be a value in meters.
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
"geo": {
|
|
80
|
+
"@type": "GeoCoordinates",
|
|
81
|
+
"latitude": "47.603",
|
|
82
|
+
"longitude": "-122.329"
|
|
83
|
+
}
|
|
84
|
+
"""
|
|
85
|
+
latitude: float
|
|
86
|
+
longitude: float
|
|
87
|
+
elevation: Optional[float]
|
|
88
|
+
|
|
89
|
+
class Meta:
|
|
90
|
+
schema_type: str = "GeoCoordinates"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class Person(BaseModel):
|
|
94
|
+
"""
|
|
95
|
+
Corresponds to the JSON-LD "Person" type.
|
|
96
|
+
https://schema.org/Person
|
|
97
|
+
|
|
98
|
+
example:
|
|
99
|
+
{
|
|
100
|
+
"@context": "http://schema.org/",
|
|
101
|
+
"@type": "Person",
|
|
102
|
+
"name": "Jane Doe",
|
|
103
|
+
"jobTitle": "Professor",
|
|
104
|
+
"telephone": "(425) 123-4567",
|
|
105
|
+
"url": "http://www.janedoe.com"
|
|
106
|
+
}
|
|
107
|
+
"""
|
|
108
|
+
name: str = Field(required=True)
|
|
109
|
+
image: Union["ImageObject", str, None] = None
|
|
110
|
+
jobTitle: Optional[JobTitle]
|
|
111
|
+
telephone: Optional[str] = None
|
|
112
|
+
url: Optional[str] = None
|
|
113
|
+
sameAs: Optional[str] = None
|
|
114
|
+
|
|
115
|
+
class Meta:
|
|
116
|
+
schema_type: str = "Person"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class ImageObject(BaseModel):
|
|
120
|
+
"""
|
|
121
|
+
Corresponds to the JSON-LD "ImageObject" type.
|
|
122
|
+
https://schema.org/ImageObject
|
|
123
|
+
"""
|
|
124
|
+
name: str
|
|
125
|
+
url: str = Field(required=True)
|
|
126
|
+
width: int = 0
|
|
127
|
+
height: int = 0
|
|
128
|
+
caption: str = ""
|
|
129
|
+
|
|
130
|
+
class Meta:
|
|
131
|
+
schema_type: str = "ImageObject"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Recipe(BaseModel):
|
|
135
|
+
"""
|
|
136
|
+
Corresponds to the JSON-LD "Recipe" type.
|
|
137
|
+
https://schema.org/Recipe
|
|
138
|
+
"""
|
|
139
|
+
name: str
|
|
140
|
+
image: Union["ImageObject", str, None] = None
|
|
141
|
+
datePublished: Optional[str] = None
|
|
142
|
+
description: Optional[str] = None
|
|
143
|
+
prepTime: Optional[str] = None
|
|
144
|
+
cookTime: Optional[str] = None
|
|
145
|
+
totalTime: Optional[str] = None
|
|
146
|
+
recipeIngredient: List[str] = Field(default_factory=list)
|
|
147
|
+
recipeInstructions: List[Any] = Field(default_factory=list)
|
|
148
|
+
recipeCategory: List[str] = Field(default_factory=list)
|
|
149
|
+
recipeCuisine: List[str] = Field(default_factory=list)
|
|
150
|
+
|
|
151
|
+
class Meta:
|
|
152
|
+
schema_type: str = "Recipe"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class NutritionInformation(BaseModel):
|
|
156
|
+
"""
|
|
157
|
+
Example of a NutritionInformation data model.
|
|
158
|
+
"nutrition": {
|
|
159
|
+
"@type": "NutritionInformation",
|
|
160
|
+
"calories": "512.2 calories",
|
|
161
|
+
"carbohydrateContent": "67.8 g",
|
|
162
|
+
"cholesterolContent": "30.5 mg",
|
|
163
|
+
"fatContent": "26.7 g",
|
|
164
|
+
"fiberContent": "5 g",
|
|
165
|
+
"proteinContent": "3.6 g",
|
|
166
|
+
"saturatedFatContent": "11.1 g",
|
|
167
|
+
"servingSize": null,
|
|
168
|
+
"sodiumContent": "240.8 mg",
|
|
169
|
+
"sugarContent": "40.3 g",
|
|
170
|
+
"transFatContent": null,
|
|
171
|
+
"unsaturatedFatContent": null
|
|
172
|
+
},
|
|
173
|
+
"""
|
|
174
|
+
calories: str
|
|
175
|
+
carbohydrateContent: str
|
|
176
|
+
cholesterolContent: str
|
|
177
|
+
fatContent: str
|
|
178
|
+
fiberContent: str
|
|
179
|
+
proteinContent: str
|
|
180
|
+
saturatedFatContent: str
|
|
181
|
+
servingSize: str
|
|
182
|
+
sodiumContent: str
|
|
183
|
+
sugarContent: str
|
|
184
|
+
transFatContent: str
|
|
185
|
+
unsaturatedFatContent: str
|
|
186
|
+
|
|
187
|
+
class Meta:
|
|
188
|
+
schema_type: str = "NutritionInformation"
|
|
189
|
+
|
|
190
|
+
class Organization(BaseModel):
|
|
191
|
+
name: str = Field(required=True)
|
|
192
|
+
url: str
|
|
193
|
+
sameAs: Optional[List[str]] = None
|
|
194
|
+
logo: Optional[ImageObject] = None
|
|
195
|
+
|
|
196
|
+
class Meta:
|
|
197
|
+
schema_type = "Organization"
|
|
198
|
+
|
|
199
|
+
class Rating(BaseModel):
|
|
200
|
+
"""
|
|
201
|
+
Corresponds to the JSON-LD "Rating" type.
|
|
202
|
+
https://schema.org/Rating
|
|
203
|
+
"""
|
|
204
|
+
ratingValue: str = Field(required=True)
|
|
205
|
+
bestRating: str
|
|
206
|
+
worstRating: str
|
|
207
|
+
|
|
208
|
+
class Meta:
|
|
209
|
+
schema_type = "Rating"
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class AggregateRating(BaseModel):
|
|
213
|
+
"""
|
|
214
|
+
Corresponds to the JSON-LD "AggregateRating" type.
|
|
215
|
+
https://schema.org/AggregateRating
|
|
216
|
+
"""
|
|
217
|
+
ratingValue: str = Field(required=True)
|
|
218
|
+
reviewCount: str
|
|
219
|
+
|
|
220
|
+
class Meta:
|
|
221
|
+
schema_type = "AggregateRating"
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class Product(BaseModel):
|
|
225
|
+
"""
|
|
226
|
+
Corresponds to the JSON-LD "Product" type.
|
|
227
|
+
https://schema.org/Product
|
|
228
|
+
|
|
229
|
+
Example:
|
|
230
|
+
{
|
|
231
|
+
"@context": "https://schema.org",
|
|
232
|
+
"@type": "Product",
|
|
233
|
+
"aggregateRating": {
|
|
234
|
+
"@type": "AggregateRating",
|
|
235
|
+
"ratingValue": "3.5",
|
|
236
|
+
"reviewCount": "11"
|
|
237
|
+
},
|
|
238
|
+
"description": "0.7 cubic feet countertop microwave.",
|
|
239
|
+
"name": "Kenmore White 17\" Microwave",
|
|
240
|
+
"image": "kenmore-microwave-17in.jpg",
|
|
241
|
+
"offers": {
|
|
242
|
+
"@type": "Offer",
|
|
243
|
+
"availability": "https://schema.org/InStock",
|
|
244
|
+
"price": "55.00",
|
|
245
|
+
"priceCurrency": "USD"
|
|
246
|
+
},
|
|
247
|
+
}
|
|
248
|
+
"""
|
|
249
|
+
name: str = Field(required=True)
|
|
250
|
+
brand: str
|
|
251
|
+
manufacturer: str
|
|
252
|
+
material: str
|
|
253
|
+
model: str
|
|
254
|
+
award: str
|
|
255
|
+
category: str
|
|
256
|
+
gtin: str
|
|
257
|
+
sku: str
|
|
258
|
+
aggregateRating: Optional[AggregateRating]
|
|
259
|
+
|
|
260
|
+
class Meta:
|
|
261
|
+
schema_type = "Product"
|
|
262
|
+
|
|
263
|
+
class Review(BaseModel):
|
|
264
|
+
"""
|
|
265
|
+
Corresponds to the JSON-LD "Review" type.
|
|
266
|
+
https://schema.org/Review
|
|
267
|
+
|
|
268
|
+
Example:
|
|
269
|
+
{
|
|
270
|
+
"@type": "Review",
|
|
271
|
+
"datePublished": "2009-10-15T16:20:23.473Z",
|
|
272
|
+
"reviewBody": "My words from 2008 still hold true today.",
|
|
273
|
+
"reviewRating": {
|
|
274
|
+
"@type": "Rating",
|
|
275
|
+
"worstRating": "1",
|
|
276
|
+
"bestRating": "5",
|
|
277
|
+
"ratingValue": 5
|
|
278
|
+
},
|
|
279
|
+
"author": {
|
|
280
|
+
"@type": "Person",
|
|
281
|
+
"name": "RCLYMA",
|
|
282
|
+
"image": null,
|
|
283
|
+
"sameAs": "https://www.allrecipes.com/cook/575406/"
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
"""
|
|
287
|
+
itemReviewed: Optional[Product]
|
|
288
|
+
reviewRating: Rating
|
|
289
|
+
reviewBody: str = Field(default='')
|
|
290
|
+
author: Person
|
|
291
|
+
datePublished: datetime
|
|
292
|
+
publisher: Organization
|
|
293
|
+
|
|
294
|
+
class Meta:
|
|
295
|
+
schema_type = "Review"
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class VideoObject(BaseModel):
|
|
299
|
+
"""
|
|
300
|
+
Corresponds to the JSON-LD "VideoObject" type.
|
|
301
|
+
https://schema.org/VideoObject
|
|
302
|
+
|
|
303
|
+
Example:
|
|
304
|
+
"video": {
|
|
305
|
+
"@context": "http://schema.org",
|
|
306
|
+
"@type": "VideoObject",
|
|
307
|
+
"name": "Apple Pie by Grandma Ople",
|
|
308
|
+
"description": "Learn how to make Grandma Ople's apple pie.",
|
|
309
|
+
"uploadDate": "2012-05-09T09:07:12.148Z",
|
|
310
|
+
"duration": "PT4M4.744S",
|
|
311
|
+
"thumbnailUrl": "https://imagesvc.meredithcorp.io/v3/mm/image?url=https%3A%2F%2Fcf-images.us-east-1.prod.boltdns.net%2Fv1%2Fstatic%2F1033249144001%2F571fbd8d-66c7-4521-b002-cbb53ace86e9%2Ff253b5d1-edaf-4dc7-8f0c-954a4259d97f%2F160x90%2Fmatch%2Fimage.jpg",
|
|
312
|
+
"publisher": {
|
|
313
|
+
"@type": "Organization",
|
|
314
|
+
"name": "Allrecipes",
|
|
315
|
+
"url": "https://www.allrecipes.com",
|
|
316
|
+
"logo": {
|
|
317
|
+
"@type": "ImageObject",
|
|
318
|
+
"url": "https://www.allrecipes.com/img/logo.png",
|
|
319
|
+
"width": 209,
|
|
320
|
+
"height": 60
|
|
321
|
+
},
|
|
322
|
+
"sameAs": [
|
|
323
|
+
"https://www.facebook.com/allrecipes",
|
|
324
|
+
"https://twitter.com/Allrecipes",
|
|
325
|
+
"https://www.pinterest.com/allrecipes/",
|
|
326
|
+
"https://www.instagram.com/allrecipes/"
|
|
327
|
+
]
|
|
328
|
+
},
|
|
329
|
+
"embedUrl": "https://players.brightcove.net/1033249144001/default_default/index.html?videoId=1629100183001"
|
|
330
|
+
}
|
|
331
|
+
""" # noqa
|
|
332
|
+
name: str = Field(required=True)
|
|
333
|
+
description: str = ''
|
|
334
|
+
uploadDate: datetime
|
|
335
|
+
duration: str
|
|
336
|
+
thumbnailUrl: str
|
|
337
|
+
publisher: Organization
|
|
338
|
+
embedUrl: str
|
|
339
|
+
|
|
340
|
+
class Meta:
|
|
341
|
+
schema_type = "VideoObject"
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class AdministrativeArea(BaseModel):
|
|
345
|
+
"""
|
|
346
|
+
Corresponds to the JSON-LD "AdministrativeArea" type.
|
|
347
|
+
https://schema.org/AdministrativeArea
|
|
348
|
+
"""
|
|
349
|
+
name: str = Field(required=True)
|
|
350
|
+
geo: Optional[GeoCoordinates]
|
|
351
|
+
branchCode: Optional[str]
|
|
352
|
+
|
|
353
|
+
class Meta:
|
|
354
|
+
schema_type: str = "AdministrativeArea"
|
|
355
|
+
|
|
356
|
+
class Audience(BaseModel):
|
|
357
|
+
"""
|
|
358
|
+
Corresponds to the JSON-LD "Audience" type.
|
|
359
|
+
https://schema.org/Audience
|
|
360
|
+
"""
|
|
361
|
+
name: str = Field(required=True)
|
|
362
|
+
audienceType: str
|
|
363
|
+
geographicArea: Optional[AdministrativeArea]
|
|
364
|
+
|
|
365
|
+
class Meta:
|
|
366
|
+
schema_type: str = "Audience"
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class Place(BaseModel):
|
|
370
|
+
address: PostalAddress
|
|
371
|
+
|
|
372
|
+
class Meta:
|
|
373
|
+
schema_type = "Place"
|
|
374
|
+
|
|
375
|
+
class QuantitativeValue(BaseModel):
|
|
376
|
+
value: float
|
|
377
|
+
unitText: str
|
|
378
|
+
|
|
379
|
+
class Meta:
|
|
380
|
+
schema_type = "QuantitativeValue"
|
|
381
|
+
|
|
382
|
+
class MonetaryAmount(BaseModel):
|
|
383
|
+
currency: Union[str, float]
|
|
384
|
+
value: QuantitativeValue
|
|
385
|
+
|
|
386
|
+
class Meta:
|
|
387
|
+
schema_type = "MonetaryAmount"
|
|
388
|
+
|
|
389
|
+
class JobPosting(BaseModel):
|
|
390
|
+
title: str
|
|
391
|
+
description: str
|
|
392
|
+
hiringOrganization: Organization
|
|
393
|
+
datePosted: str
|
|
394
|
+
validThrough: str
|
|
395
|
+
jobLocation: Optional[Place]
|
|
396
|
+
baseSalary: Optional[MonetaryAmount]
|
|
397
|
+
qualifications: str
|
|
398
|
+
skills: List[str]
|
|
399
|
+
responsibilities: str
|
|
400
|
+
educationRequirements: str
|
|
401
|
+
experienceRequirements: str
|
|
402
|
+
|
|
403
|
+
class Meta:
|
|
404
|
+
schema_type = "JobPosting"
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
@register_renderer("ImageObject")
|
|
408
|
+
def render_imageobject(model: "BaseModel", top_level: bool) -> str:
|
|
409
|
+
"""
|
|
410
|
+
Render an ImageObject in a custom way:
|
|
411
|
+
<div typeof="ImageObject">
|
|
412
|
+
<h2 property="name">...</h2>
|
|
413
|
+
<img src="..." alt="..." property="contentUrl"/>
|
|
414
|
+
...
|
|
415
|
+
</div>
|
|
416
|
+
"""
|
|
417
|
+
# You can read fields from the model (like name, url, caption, etc.).
|
|
418
|
+
# If you used 'url' as the field that is the image's src, we can do:
|
|
419
|
+
name = getattr(model, "name", None) # or None if not present
|
|
420
|
+
url = getattr(model, "url", None)
|
|
421
|
+
caption = getattr(model, "caption", None)
|
|
422
|
+
width = getattr(model, "width", None)
|
|
423
|
+
height = getattr(model, "height", None)
|
|
424
|
+
|
|
425
|
+
schema_type = getattr(model.Meta, 'schema_type', model.__class__.__name__)
|
|
426
|
+
|
|
427
|
+
container_open = ""
|
|
428
|
+
if top_level:
|
|
429
|
+
container_open = f'<div vocab="https://schema.org/" typeof="{escape(schema_type)}">' # noqa
|
|
430
|
+
else:
|
|
431
|
+
# when nested, we might do property="image" or property=schema_type
|
|
432
|
+
container_open = f'<div property="{escape(schema_type)}" typeof="{escape(schema_type)}">' # noqa
|
|
433
|
+
|
|
434
|
+
pieces = [container_open]
|
|
435
|
+
|
|
436
|
+
# Render name as <h2 property="name">Name</h2> if present
|
|
437
|
+
if name:
|
|
438
|
+
name_esc = escape(str(name))
|
|
439
|
+
pieces.append(f'<h2 property="name">{name_esc}</h2>')
|
|
440
|
+
|
|
441
|
+
# Now create an <img> that has property="contentUrl" or "url"
|
|
442
|
+
if url:
|
|
443
|
+
url_esc = escape(str(url))
|
|
444
|
+
caption_esc = escape(str(caption or ""))
|
|
445
|
+
# alt can come from caption
|
|
446
|
+
snippet = f'<img property="contentUrl" src="{url_esc}" alt="{caption_esc}"'
|
|
447
|
+
if width:
|
|
448
|
+
snippet += f' width="{escape(str(width))}"'
|
|
449
|
+
if height:
|
|
450
|
+
snippet += f' height="{escape(str(height))}"'
|
|
451
|
+
snippet += ' />'
|
|
452
|
+
pieces.append(snippet)
|
|
453
|
+
|
|
454
|
+
# If we have other fields not individually handled, we could do a fallback
|
|
455
|
+
# to the normal field iteration. But for brevity, let's omit that here.
|
|
456
|
+
# E.g. leftover = model.render_remaining_fields(…)
|
|
457
|
+
# pieces.append(leftover)
|
|
458
|
+
|
|
459
|
+
pieces.append('</div>')
|
|
460
|
+
return "\n".join(pieces)
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@register_renderer("GeoCoordinates")
|
|
464
|
+
def render_geocoordinates(model: "BaseModel", top_level: bool) -> str:
|
|
465
|
+
"""
|
|
466
|
+
Custom renderer for GeoCoordinates:
|
|
467
|
+
<div property="geo" typeof="GeoCoordinates">
|
|
468
|
+
<meta property="latitude" content="40.75"/>
|
|
469
|
+
<meta property="longitude" content="-73.98"/>
|
|
470
|
+
...
|
|
471
|
+
</div>
|
|
472
|
+
"""
|
|
473
|
+
lat = getattr(model, "latitude", None)
|
|
474
|
+
lng = getattr(model, "longitude", None)
|
|
475
|
+
elevation = getattr(model, "elevation", None)
|
|
476
|
+
|
|
477
|
+
schema_type = getattr(model.Meta, 'schema_type', model.__class__.__name__)
|
|
478
|
+
if top_level:
|
|
479
|
+
container_open = f'<div vocab="https://schema.org/" typeof="{escape(schema_type)}">' # noqa
|
|
480
|
+
else:
|
|
481
|
+
container_open = f'<div property="{escape(schema_type)}" typeof="{escape(schema_type)}">' # noqa
|
|
482
|
+
|
|
483
|
+
pieces = [container_open]
|
|
484
|
+
|
|
485
|
+
# For numeric fields, we might prefer <meta ... content="..."/>
|
|
486
|
+
if lat is not None:
|
|
487
|
+
pieces.append(
|
|
488
|
+
f'<meta property="latitude" content="{escape(str(lat))}" />'
|
|
489
|
+
)
|
|
490
|
+
if lng is not None:
|
|
491
|
+
pieces.append(
|
|
492
|
+
f'<meta property="longitude" content="{escape(str(lng))}" />'
|
|
493
|
+
)
|
|
494
|
+
if elevation is not None:
|
|
495
|
+
pieces.append(
|
|
496
|
+
f'<meta property="elevation" content="{escape(str(elevation))}" />'
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
pieces.append('</div>')
|
|
500
|
+
return "\n".join(pieces)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .mapping import ClassDict, ClassDictConfig
|