cs-tagged 20260912__tar.gz
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.
- cs_tagged-20260912/PKG-INFO +652 -0
- cs_tagged-20260912/pyproject.toml +676 -0
- cs_tagged-20260912/src/cs/tagged.py +967 -0
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cs-tagged
|
|
3
|
+
Version: 20260912
|
|
4
|
+
Summary: Tagged information entities, built on `TagSet`s for representation and typically an `SQLTags` for storage. I use these to persist and mediate knowledge, including my interactions with web sites, APIs, and third party databases.
|
|
5
|
+
Keywords: python3
|
|
6
|
+
Author-email: Cameron Simpson <cs@cskk.id.au>
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
Classifier: Programming Language :: Python
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
16
|
+
Requires-Dist: cs.cmdutils>=20260912
|
|
17
|
+
Requires-Dist: cs.context>=20250528
|
|
18
|
+
Requires-Dist: cs.deco>=20260912
|
|
19
|
+
Requires-Dist: cs.lex>=20260912
|
|
20
|
+
Requires-Dist: cs.logutils>=20260912
|
|
21
|
+
Requires-Dist: cs.obj>=20260912
|
|
22
|
+
Requires-Dist: cs.pfx>=20260912
|
|
23
|
+
Requires-Dist: cs.progress>=20260531
|
|
24
|
+
Requires-Dist: cs.tagset>=20260912
|
|
25
|
+
Requires-Dist: cs.trace
|
|
26
|
+
Requires-Dist: icontract
|
|
27
|
+
Requires-Dist: typeguard
|
|
28
|
+
Project-URL: MonoRepo Commits, https://bitbucket.org/cameron_simpson/css/commits/branch/main
|
|
29
|
+
Project-URL: Monorepo Git Mirror, https://github.com/cameron-simpson/css
|
|
30
|
+
Project-URL: Monorepo Hg/Mercurial Mirror, https://hg.sr.ht/~cameron-simpson/css
|
|
31
|
+
Project-URL: Source, https://github.com/cameron-simpson/css/blob/main/lib/python/cs/tagged.py
|
|
32
|
+
|
|
33
|
+
Tagged information entities, built on `TagSet`s for representation
|
|
34
|
+
and typically an `SQLTags` for storage.
|
|
35
|
+
I use these to persist and mediate knowledge, including my interactions
|
|
36
|
+
with web sites, APIs, and third party databases.
|
|
37
|
+
|
|
38
|
+
*Latest release 20260912*:
|
|
39
|
+
First PyPI release: Entity, Entities, ScanData.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
Short summary:
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
* `Entities`: A mixin to support classes which use a `.tagsets:BaseTagSets` attribute to store their data.
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
* `Entity`: A base class for classes which have a `.tags:TagSet` attribute and a `.tags_db:BaseTagSets` containing other `Tagset`s.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
* `ScanData`: A class to manage data obtained about `SiteEntity` instances, for example from an API or scanning a web page.
|
|
53
|
+
|
|
54
|
+
# Classes
|
|
55
|
+
|
|
56
|
+
## class Entities
|
|
57
|
+
|
|
58
|
+
A mixin to support classes which use a `.tagsets:BaseTagSets` attribute to store their data.
|
|
59
|
+
|
|
60
|
+
Subclasses may define the following class attributes:
|
|
61
|
+
- `EntityClass`: a subclass of `Entity` which represents data entities;
|
|
62
|
+
the default is `Entity` which should be enough if there is no `.tYPE_ZONE`
|
|
63
|
+
- `TYPE_ZONE`: the type zone identifying entities in the
|
|
64
|
+
larger `BaseTagSets` data; if this is not supplied it is
|
|
65
|
+
obtained from `EntityClass.TYPE_ZONE`, if defined
|
|
66
|
+
|
|
67
|
+
A typical use subclasses `cs.sqltags.UsesSQLTags`, a subclass
|
|
68
|
+
of this which uses an `SQLTags` as the storage backend.
|
|
69
|
+
|
|
70
|
+
If there is a `.TYPE_ZONE`, the meaning of the type *zone*,
|
|
71
|
+
*subname* and *key* are as described for the `ZonedTypes`
|
|
72
|
+
class.
|
|
73
|
+
|
|
74
|
+
### `Entities.EntityClass`
|
|
75
|
+
|
|
76
|
+
A base class for classes which have a `.tags:TagSet` attribute
|
|
77
|
+
and a `.tags_db:BaseTagSets` containing other `Tagset`s.
|
|
78
|
+
|
|
79
|
+
Usually these are considered part of a "zone" - a group of
|
|
80
|
+
entities in a particular applicaiton domain.
|
|
81
|
+
|
|
82
|
+
The subclass may itself define its `.tags` instance attribute
|
|
83
|
+
or rely on the default cached property `.tags`, which will return
|
|
84
|
+
`self.tags_db[self.tags_entity_key]`.
|
|
85
|
+
(`self.tags_entity_key` is `self.tags.name` by default.)
|
|
86
|
+
|
|
87
|
+
Note that this mixin brings its own `__new__` method which
|
|
88
|
+
can choose a subclass based on the subclass' `.TYPE_SUBNAME`
|
|
89
|
+
attribute. See the `__new__` docstring.
|
|
90
|
+
|
|
91
|
+
This also provides some behaviour based around updating
|
|
92
|
+
entities based on some kind of API call; the direct values
|
|
93
|
+
from the API call land on attributes named `{zone}.{key}` -
|
|
94
|
+
the `.type_zone_update(mapping)` provides a convenient call
|
|
95
|
+
for this.
|
|
96
|
+
|
|
97
|
+
`Entity` instances are designed as representing entities in
|
|
98
|
+
some "zone", a set of entities in some domain or organised
|
|
99
|
+
grouping; typical examples include entities describes by some
|
|
100
|
+
API like MusicBrainzNG or objects presented by some website.
|
|
101
|
+
As such, they subclass `ZonedTypes`, which expects the entity's
|
|
102
|
+
`.name` to be of the form *zone*`.`*subname*`.`*key*; the
|
|
103
|
+
*zone* partitions entities off into their own domain, the
|
|
104
|
+
*subname* is in effect the entity's type within that domain
|
|
105
|
+
and the *key* is the entity id within that type.
|
|
106
|
+
|
|
107
|
+
On this basis, entities updated with data from the zone,
|
|
108
|
+
for example from an API call or by scraping a web page,
|
|
109
|
+
normally update tag keys named *zone*`.`*field* where the *field*
|
|
110
|
+
is the top level field from the data.
|
|
111
|
+
|
|
112
|
+
The `ZonedTypes.__getattr__(attr)` method looks first for a
|
|
113
|
+
direct tag named `attr` but falls back to a tag named
|
|
114
|
+
*zone*`.`*attr*. This allows entities to be tagged with the
|
|
115
|
+
data from an API, but to be overridden by the direct tag if
|
|
116
|
+
the API data are considered incorrect or unsuitable.
|
|
117
|
+
|
|
118
|
+
The `ScanData.apply()` method follows this principle,
|
|
119
|
+
applying the scanned data to tags named *zone*`.`*field*.
|
|
120
|
+
|
|
121
|
+
We relate entities using attributes named *field*`_id`,
|
|
122
|
+
which may be a single key for another entity or a list of keys.
|
|
123
|
+
|
|
124
|
+
Various derived attributes are also provided, see the
|
|
125
|
+
`__getattr__` docstring for details:
|
|
126
|
+
- *field*`_ent`: the related `Entity` named *zone*`.`*field*`.`*key*
|
|
127
|
+
where *key* comes from the `.`*field*`_id` attribute
|
|
128
|
+
- *field*`_ents`: multiple related `Entity` named
|
|
129
|
+
*zone*`.`*field*`.`*key* where *key* comes from the `.`*field*`_id` attribute
|
|
130
|
+
|
|
131
|
+
### `Entities.TagsetsClass`
|
|
132
|
+
|
|
133
|
+
The type of the None singleton.
|
|
134
|
+
|
|
135
|
+
### `Entities.__class_getitem__(index)`
|
|
136
|
+
|
|
137
|
+
An `Entities` subclass may be indexed with a string.
|
|
138
|
+
|
|
139
|
+
If there is no `cls.TYPE_ZONE` the string is treated either as:
|
|
140
|
+
- if the string ha no dots, a `TYPE_ZONE` value - the
|
|
141
|
+
`Entities` instance for that zone is returned
|
|
142
|
+
- if the string has dots, as an `Entity.name` and looked
|
|
143
|
+
up with `cls.by_entity_id(index)`.
|
|
144
|
+
|
|
145
|
+
If there is a `cls.TYPE_ZONE`, such as with a `SiteMap`,
|
|
146
|
+
the string is treated as a `ZonedTypes.type_zone_key` and
|
|
147
|
+
looked up as by indexing that zone's `Entities` instance.
|
|
148
|
+
|
|
149
|
+
Example using `TheTVDBAPI`, which has a `TYPE_ZONE`:
|
|
150
|
+
|
|
151
|
+
# fetch the TV series entity with id 1234
|
|
152
|
+
# there is a TheTVDBAPI.TYPE_ZONE
|
|
153
|
+
series = TheTVDBAPI['series.1234']
|
|
154
|
+
|
|
155
|
+
# fetch an arbtrary Entity
|
|
156
|
+
# the value of `TheTVDBAPI.TYPE_ZONE` is "tvdb"
|
|
157
|
+
series = Entities['tvdb.series.1234']
|
|
158
|
+
|
|
159
|
+
Example using `SiteMap`, the base class for site maps, and
|
|
160
|
+
which has no `.TYPE_ZONE`:
|
|
161
|
+
|
|
162
|
+
smh_map = SiteMap['smh']
|
|
163
|
+
smh_topic = SiteMap['smh.topic.technology']
|
|
164
|
+
smh_article = SiteMap['smh']['article.abcd']
|
|
165
|
+
|
|
166
|
+
### `Entities.__dict__`
|
|
167
|
+
|
|
168
|
+
Read-only proxy of a mapping.
|
|
169
|
+
|
|
170
|
+
### `Entities.__firstlineno__`
|
|
171
|
+
|
|
172
|
+
int([x]) -> integer
|
|
173
|
+
int(x, base=10) -> integer
|
|
174
|
+
|
|
175
|
+
Convert a number or string to an integer, or return 0 if no arguments
|
|
176
|
+
are given. If x is a number, return x.__int__(). For floating-point
|
|
177
|
+
numbers, this truncates towards zero.
|
|
178
|
+
|
|
179
|
+
If x is not a number or if base is given, then x must be a string,
|
|
180
|
+
bytes, or bytearray instance representing an integer literal in the
|
|
181
|
+
given base. The literal can be preceded by '+' or '-' and be surrounded
|
|
182
|
+
by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.
|
|
183
|
+
Base 0 means to interpret the base from the string as an integer literal.
|
|
184
|
+
>>> int('0b100', base=0)
|
|
185
|
+
4
|
|
186
|
+
|
|
187
|
+
### `Entities.__getitem__(self, index: str | tuple[str, str | int] | tuple[str, str, str | int]) -> cs.tagged.Entity`
|
|
188
|
+
|
|
189
|
+
`self.__getitem__(index)` calls `self.entity(index)`.
|
|
190
|
+
|
|
191
|
+
### `Entities.__init_subclass__(**kw)`
|
|
192
|
+
|
|
193
|
+
Inititialise a subclass by defining `.TYPE_ZNE` if already present.
|
|
194
|
+
|
|
195
|
+
### `Entities.__static_attributes__`
|
|
196
|
+
|
|
197
|
+
Built-in immutable sequence.
|
|
198
|
+
|
|
199
|
+
If no argument is given, the constructor returns an empty tuple.
|
|
200
|
+
If iterable is specified the tuple is initialized from iterable's items.
|
|
201
|
+
|
|
202
|
+
If the argument is a tuple, the return value is the same object.
|
|
203
|
+
|
|
204
|
+
### `Entities.as_zone(self, zone=None)`
|
|
205
|
+
|
|
206
|
+
Push this `Entities` instance as the default mapping for
|
|
207
|
+
`zone`, whose default is `self.__class__.TYPE_ZONE`.
|
|
208
|
+
Yields the zone, or `None` if there is no
|
|
209
|
+
|
|
210
|
+
### `Entities.by_entity_id(entity_id: str) -> cs.tagged.Entity`
|
|
211
|
+
|
|
212
|
+
Return the `Entity` instance corresponding to `entity_id`
|
|
213
|
+
from the full tb
|
|
214
|
+
Raise `ValueError` if `entity_id` cannot be parsed by
|
|
215
|
+
`ZonedTypes.type_parts_of`.
|
|
216
|
+
Raise `KeyError` if there is no `Entities` instance for the zone
|
|
217
|
+
and we cannot make a default instance.
|
|
218
|
+
|
|
219
|
+
### `Entities.by_type_zone`
|
|
220
|
+
|
|
221
|
+
Mapping class that references values weakly.
|
|
222
|
+
|
|
223
|
+
Entries in the dictionary will be discarded when no strong
|
|
224
|
+
reference to the value exists anymore
|
|
225
|
+
|
|
226
|
+
### `Entities.class_by_type_zone`
|
|
227
|
+
|
|
228
|
+
dict() -> new empty dictionary
|
|
229
|
+
dict(mapping) -> new dictionary initialized from a mapping object's
|
|
230
|
+
(key, value) pairs
|
|
231
|
+
dict(iterable) -> new dictionary initialized as if via:
|
|
232
|
+
d = {}
|
|
233
|
+
for k, v in iterable:
|
|
234
|
+
d[k] = v
|
|
235
|
+
dict(**kwargs) -> new dictionary initialized with the name=value pairs
|
|
236
|
+
in the keyword argument list. For example: dict(one=1, two=2)
|
|
237
|
+
|
|
238
|
+
### `Entities.default(zone: str | None = None) -> 'Entities'`
|
|
239
|
+
|
|
240
|
+
Return the default `Entities` instance for `zone`.
|
|
241
|
+
If `zone` is not defined it is taken from `cls.TYPE_ZONE`.
|
|
242
|
+
Raise `KeyError` for an unregistered `zone`.
|
|
243
|
+
Raise `TypeError` if there is no registered default
|
|
244
|
+
and the class for `zone` cannot be instantiated with `entcls()`.
|
|
245
|
+
|
|
246
|
+
### `Entities.entity(self, index: str | tuple[str, str | int] | tuple[str, str, str | int], zone=None) -> cs.tagged.Entity`
|
|
247
|
+
|
|
248
|
+
Fetch the `Entity` instance for the supplied `index`.
|
|
249
|
+
This underlies the `__getitem__` method.
|
|
250
|
+
|
|
251
|
+
The meaning of the type *zone*, *subname* and *key* are as
|
|
252
|
+
described for the `ZonedTypes` class.
|
|
253
|
+
|
|
254
|
+
The `index` may take the following forms:
|
|
255
|
+
- `str`: a string which will be split into *subname* and *key*
|
|
256
|
+
for use in `self.TYPE_ZONE`
|
|
257
|
+
- `(subname,key)`: a 2-tuple of the type *subname* and *key*
|
|
258
|
+
in `self.TYPE_ZONE`
|
|
259
|
+
the subname make also be a subclass of `self.EntityClass`
|
|
260
|
+
- `(zone,subname,key)`: a 3-tuple of the type zone, subname and key
|
|
261
|
+
The *subname* may also be a class (normally a subclass of
|
|
262
|
+
`Entity`, usually a subclass of `type(self).EntityClass`);
|
|
263
|
+
in this case the *subname* will be taken from `type(self).TYPE_SUBNAME`
|
|
264
|
+
attribute.
|
|
265
|
+
The *key* may also be an `int` or a `uuid.UUID`, in which
|
|
266
|
+
case it will be used as `str(key)`.
|
|
267
|
+
|
|
268
|
+
Examples:
|
|
269
|
+
|
|
270
|
+
# the Entity subclass Artist, and the Entities
|
|
271
|
+
# subclass MBDB which hold MusicbrainzNG information
|
|
272
|
+
from cs.cdrip import Artist, MBDB
|
|
273
|
+
mbdb = MBDB()
|
|
274
|
+
|
|
275
|
+
# Various indices obtaining the record for Jon Cleary,
|
|
276
|
+
# whose key is 'mbdb.artist.a417f0e5-2c14-445a-9a07-5a7ad2bdeafa'
|
|
277
|
+
|
|
278
|
+
# the subname.key as a single string
|
|
279
|
+
artist = mbdb['artist.a417f0e5-2c14-445a-9a07-5a7ad2bdeafa']
|
|
280
|
+
|
|
281
|
+
# the subname and key in a 2-tuple
|
|
282
|
+
artist = mbdb['artist', 'a417f0e5-2c14-445a-9a07-5a7ad2bdeafa']
|
|
283
|
+
|
|
284
|
+
# the record but not from the default MBDB zonne
|
|
285
|
+
artist = mbdb['mbdb2', 'artist', 'a417f0e5-2c14-445a-9a07-5a7ad2bdeafa']
|
|
286
|
+
|
|
287
|
+
# the preferred way to obtain it, using the entity type
|
|
288
|
+
artist = mbdb[Artist, 'a417f0e5-2c14-445a-9a07-5a7ad2bdeafa']
|
|
289
|
+
|
|
290
|
+
# or if you're working with UUIDs
|
|
291
|
+
artist_uuid = UUID('a417f0e5-2c14-445a-9a07-5a7ad2bdeafa')
|
|
292
|
+
artist = mbdb[Artist, artist_uuid]
|
|
293
|
+
|
|
294
|
+
### `Entities.find(self, *criteria, **crit_kw) -> list[cs.tagged.Entity]`
|
|
295
|
+
|
|
296
|
+
Find entities in the database.
|
|
297
|
+
|
|
298
|
+
This calls `self.tagsets.find()` and returns the associated
|
|
299
|
+
`Entity` instances.
|
|
300
|
+
|
|
301
|
+
### `Entities.keys(self, subname=None)`
|
|
302
|
+
|
|
303
|
+
Return the keys from `self.tagsets` as `(subname,type_key)` 2-tuples
|
|
304
|
+
suitable as indices of `self`.
|
|
305
|
+
If `subname` is not `None`, restrict the keys to those with that subname.
|
|
306
|
+
|
|
307
|
+
### `Entities.set_as_zone(self, zone: str, if_unset=False)`
|
|
308
|
+
|
|
309
|
+
Set this `Entities` instance as the one handling entities in `zone`.
|
|
310
|
+
|
|
311
|
+
### `Entities.zone_entity(self, zone: str) -> 'Entity'`
|
|
312
|
+
|
|
313
|
+
Return the `Entity` entity associated with a per-type-zone key.
|
|
314
|
+
For example, `self.zone_entity('tvdb')` would return the entity
|
|
315
|
+
for `tvdb.`*tvdb_id* where `tvdb_id` comes from `self['id.tvdb']`.
|
|
316
|
+
|
|
317
|
+
## class Entity(cs.tagset.ZonedTypes, cs.obj.Refreshable, cs.deco.Promotable, cs.lex.FormatableMixin, cs.obj.NoAttrs)
|
|
318
|
+
|
|
319
|
+
A base class for classes which have a `.tags:TagSet` attribute
|
|
320
|
+
and a `.tags_db:BaseTagSets` containing other `Tagset`s.
|
|
321
|
+
|
|
322
|
+
Usually these are considered part of a "zone" - a group of
|
|
323
|
+
entities in a particular applicaiton domain.
|
|
324
|
+
|
|
325
|
+
The subclass may itself define its `.tags` instance attribute
|
|
326
|
+
or rely on the default cached property `.tags`, which will return
|
|
327
|
+
`self.tags_db[self.tags_entity_key]`.
|
|
328
|
+
(`self.tags_entity_key` is `self.tags.name` by default.)
|
|
329
|
+
|
|
330
|
+
Note that this mixin brings its own `__new__` method which
|
|
331
|
+
can choose a subclass based on the subclass' `.TYPE_SUBNAME`
|
|
332
|
+
attribute. See the `__new__` docstring.
|
|
333
|
+
|
|
334
|
+
This also provides some behaviour based around updating
|
|
335
|
+
entities based on some kind of API call; the direct values
|
|
336
|
+
from the API call land on attributes named `{zone}.{key}` -
|
|
337
|
+
the `.type_zone_update(mapping)` provides a convenient call
|
|
338
|
+
for this.
|
|
339
|
+
|
|
340
|
+
`Entity` instances are designed as representing entities in
|
|
341
|
+
some "zone", a set of entities in some domain or organised
|
|
342
|
+
grouping; typical examples include entities describes by some
|
|
343
|
+
API like MusicBrainzNG or objects presented by some website.
|
|
344
|
+
As such, they subclass `ZonedTypes`, which expects the entity's
|
|
345
|
+
`.name` to be of the form *zone*`.`*subname*`.`*key*; the
|
|
346
|
+
*zone* partitions entities off into their own domain, the
|
|
347
|
+
*subname* is in effect the entity's type within that domain
|
|
348
|
+
and the *key* is the entity id within that type.
|
|
349
|
+
|
|
350
|
+
On this basis, entities updated with data from the zone,
|
|
351
|
+
for example from an API call or by scraping a web page,
|
|
352
|
+
normally update tag keys named *zone*`.`*field* where the *field*
|
|
353
|
+
is the top level field from the data.
|
|
354
|
+
|
|
355
|
+
The `ZonedTypes.__getattr__(attr)` method looks first for a
|
|
356
|
+
direct tag named `attr` but falls back to a tag named
|
|
357
|
+
*zone*`.`*attr*. This allows entities to be tagged with the
|
|
358
|
+
data from an API, but to be overridden by the direct tag if
|
|
359
|
+
the API data are considered incorrect or unsuitable.
|
|
360
|
+
|
|
361
|
+
The `ScanData.apply()` method follows this principle,
|
|
362
|
+
applying the scanned data to tags named *zone*`.`*field*.
|
|
363
|
+
|
|
364
|
+
We relate entities using attributes named *field*`_id`,
|
|
365
|
+
which may be a single key for another entity or a list of keys.
|
|
366
|
+
|
|
367
|
+
Various derived attributes are also provided, see the
|
|
368
|
+
`__getattr__` docstring for details:
|
|
369
|
+
- *field*`_ent`: the related `Entity` named *zone*`.`*field*`.`*key*
|
|
370
|
+
where *key* comes from the `.`*field*`_id` attribute
|
|
371
|
+
- *field*`_ents`: multiple related `Entity` named
|
|
372
|
+
*zone*`.`*field*`.`*key* where *key* comes from the `.`*field*`_id` attribute
|
|
373
|
+
|
|
374
|
+
### `Entity.__annotations__`
|
|
375
|
+
|
|
376
|
+
dict() -> new empty dictionary
|
|
377
|
+
dict(mapping) -> new dictionary initialized from a mapping object's
|
|
378
|
+
(key, value) pairs
|
|
379
|
+
dict(iterable) -> new dictionary initialized as if via:
|
|
380
|
+
d = {}
|
|
381
|
+
for k, v in iterable:
|
|
382
|
+
d[k] = v
|
|
383
|
+
dict(**kwargs) -> new dictionary initialized with the name=value pairs
|
|
384
|
+
in the keyword argument list. For example: dict(one=1, two=2)
|
|
385
|
+
|
|
386
|
+
### `Entity.__delitem__(self, tag_name: str)`
|
|
387
|
+
|
|
388
|
+
Remove an entry from `self.tags`.
|
|
389
|
+
|
|
390
|
+
### `Entity.__firstlineno__`
|
|
391
|
+
|
|
392
|
+
int([x]) -> integer
|
|
393
|
+
int(x, base=10) -> integer
|
|
394
|
+
|
|
395
|
+
Convert a number or string to an integer, or return 0 if no arguments
|
|
396
|
+
are given. If x is a number, return x.__int__(). For floating-point
|
|
397
|
+
numbers, this truncates towards zero.
|
|
398
|
+
|
|
399
|
+
If x is not a number or if base is given, then x must be a string,
|
|
400
|
+
bytes, or bytearray instance representing an integer literal in the
|
|
401
|
+
given base. The literal can be preceded by '+' or '-' and be surrounded
|
|
402
|
+
by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.
|
|
403
|
+
Base 0 means to interpret the base from the string as an integer literal.
|
|
404
|
+
>>> int('0b100', base=0)
|
|
405
|
+
4
|
|
406
|
+
|
|
407
|
+
### `Entity.__getattr__(self, attr)`
|
|
408
|
+
|
|
409
|
+
Try `ZonedTypes.__getattr__` (which lokks up `[attr]` then `[f'{zone}.{attr}']`)
|
|
410
|
+
then fall back to suffix based synthetic attributes where
|
|
411
|
+
an attribute ending in `_`*suffix* is implemented by the
|
|
412
|
+
`suffix_`*suffix*`(attr)` method if it exists.
|
|
413
|
+
|
|
414
|
+
The following synthetic attibutes are implemented:
|
|
415
|
+
- *attr0*`_or_none`: return `.attr0` or `None` if that does not exist
|
|
416
|
+
- *subtype*`_ent`: the entity with name
|
|
417
|
+
*type_zone*`.`*subtype*`.`*id* or `None` where `id` comes
|
|
418
|
+
from the `.`*attr*`_id` value;
|
|
419
|
+
see the `suffix_ent` method.
|
|
420
|
+
- *subtype*`_ents`: the entities with name
|
|
421
|
+
*type_zone*`.`*subtype*`.`*id* or `None` where each `id` comes
|
|
422
|
+
from the `.`*attr*`_id` values;
|
|
423
|
+
see the `suffix_ents` method.
|
|
424
|
+
|
|
425
|
+
### `Entity.__getitem__(self, tag_name: str)`
|
|
426
|
+
|
|
427
|
+
Index `self.tags`.
|
|
428
|
+
|
|
429
|
+
### `Entity.__setitem__(self, tag_name, value, *, verbose=False)`
|
|
430
|
+
|
|
431
|
+
Set a tag value.
|
|
432
|
+
|
|
433
|
+
### `Entity.__static_attributes__`
|
|
434
|
+
|
|
435
|
+
Built-in immutable sequence.
|
|
436
|
+
|
|
437
|
+
If no argument is given, the constructor returns an empty tuple.
|
|
438
|
+
If iterable is specified the tuple is initialized from iterable's items.
|
|
439
|
+
|
|
440
|
+
If the argument is a tuple, the return value is the same object.
|
|
441
|
+
|
|
442
|
+
### `Entity.as_dict(self)`
|
|
443
|
+
|
|
444
|
+
Proxy `.as_dict()` to `self.tags`.
|
|
445
|
+
|
|
446
|
+
### `Entity.entity`
|
|
447
|
+
|
|
448
|
+
The `.entity` attribute space, whose attributes map to
|
|
449
|
+
entities which are `UsesTags` instances from the appropriate
|
|
450
|
+
`Entities` instances according to their zone.
|
|
451
|
+
|
|
452
|
+
Example:
|
|
453
|
+
|
|
454
|
+
tags = TagSet({'id.playon':'recording.1234567'})
|
|
455
|
+
playon_recording = tags.entity.playon
|
|
456
|
+
|
|
457
|
+
### `Entity.entity_`
|
|
458
|
+
|
|
459
|
+
The `.entity_` attribute space, whose attributes map to
|
|
460
|
+
entities which are `UsesTags` instances from the appropriate
|
|
461
|
+
`Entities` instances according to their zone.
|
|
462
|
+
Unlike `.entity`, a missing `id.` tag returns `None` instead
|
|
463
|
+
of raising `AttributeError`.
|
|
464
|
+
|
|
465
|
+
Example:
|
|
466
|
+
|
|
467
|
+
tags = TagSet({'id.playon':'recording.1234567'})
|
|
468
|
+
playon_recording = tags.entity.playon
|
|
469
|
+
|
|
470
|
+
### `Entity.format_attributes`
|
|
471
|
+
|
|
472
|
+
dict() -> new empty dictionary
|
|
473
|
+
dict(mapping) -> new dictionary initialized from a mapping object's
|
|
474
|
+
(key, value) pairs
|
|
475
|
+
dict(iterable) -> new dictionary initialized as if via:
|
|
476
|
+
d = {}
|
|
477
|
+
for k, v in iterable:
|
|
478
|
+
d[k] = v
|
|
479
|
+
dict(**kwargs) -> new dictionary initialized with the name=value pairs
|
|
480
|
+
in the keyword argument list. For example: dict(one=1, two=2)
|
|
481
|
+
|
|
482
|
+
### `Entity.format_kwargs(self)`
|
|
483
|
+
|
|
484
|
+
A `format_kwargs` method to support `cs.lex.FormatableMixin`.
|
|
485
|
+
|
|
486
|
+
### `Entity.get(self, tag_name: str, default=None)`
|
|
487
|
+
|
|
488
|
+
Call `.tags.get(tag_name)`.
|
|
489
|
+
|
|
490
|
+
### `Entity.items(self)`
|
|
491
|
+
|
|
492
|
+
The tags items.
|
|
493
|
+
|
|
494
|
+
### `Entity.prefix_in(self, attr) -> collections.abc.Sequence[typing.Self]`
|
|
495
|
+
|
|
496
|
+
Resolve `in_`*subtype*[`_`*field* to the `Entity` instance
|
|
497
|
+
of subtype *subtype* whose *field*`_id` attribute contains
|
|
498
|
+
`self.type_key`.
|
|
499
|
+
The default *field* is `self.type_subname`.
|
|
500
|
+
|
|
501
|
+
For example, if `self.name` is `"tvdb.episode.1234"` then
|
|
502
|
+
`self.in_season` would return a list of all the `tvdb.season`
|
|
503
|
+
entities whose `episode_id` attributes referred to `1234`.
|
|
504
|
+
|
|
505
|
+
Where the
|
|
506
|
+
|
|
507
|
+
### `Entity.print(self)`
|
|
508
|
+
|
|
509
|
+
The default `print()` runs `self.printt()`.
|
|
510
|
+
This is intended to be a nice print of important stuff.
|
|
511
|
+
|
|
512
|
+
### `Entity.refresh_key(self)`
|
|
513
|
+
|
|
514
|
+
The unique key identifying this object for use in recursive refreshes.
|
|
515
|
+
|
|
516
|
+
### `Entity.refresh_last_update`
|
|
517
|
+
|
|
518
|
+
The last time a refresh update time.
|
|
519
|
+
|
|
520
|
+
### `Entity.setdefault(self, key, default_value)`
|
|
521
|
+
|
|
522
|
+
Set `self[key]=default_value` if `key` is not present.
|
|
523
|
+
|
|
524
|
+
### `Entity.suffix_ent(self, attr) -> Optional[Self]`
|
|
525
|
+
|
|
526
|
+
Resolve *subtype*`_ent` to `self[type_zone.`*subtype*`.id]`
|
|
527
|
+
or `None` if no `self[`*subtype*`_id]`
|
|
528
|
+
|
|
529
|
+
### `Entity.suffix_ents(self, attr) -> collections.abc.Sequence[typing.Self]`
|
|
530
|
+
|
|
531
|
+
Resolve *subtype*`_ents` to [self[type_zone.`*subtype*`.id]]`
|
|
532
|
+
or `()` if no `self[`*subtype*`_id]]`.
|
|
533
|
+
|
|
534
|
+
### `Entity.tags`
|
|
535
|
+
|
|
536
|
+
A default `.tags` property which obtains a `TagSet` from `self.tags_db`
|
|
537
|
+
via using the `TagSet` name `self.tags_entity_key`.
|
|
538
|
+
This is for subclasses which might fetch the `.tags` on demand.
|
|
539
|
+
|
|
540
|
+
Subclasses typically set `.tags` during `__init__` and
|
|
541
|
+
therefore have no need for a `.tags_entity_key` property.
|
|
542
|
+
|
|
543
|
+
### `Entity.tags_entity_key`
|
|
544
|
+
|
|
545
|
+
Our tagged entity key, `self.tags.name`.
|
|
546
|
+
|
|
547
|
+
This is only really needed by the `.tags` cached
|
|
548
|
+
property; most subclasses of `Entity` set `.tags` during
|
|
549
|
+
`__init__`.
|
|
550
|
+
If you have an "on demand" subclass you should override
|
|
551
|
+
this method to compute the entity key without relying on
|
|
552
|
+
the (missing) `.tags` attribute.
|
|
553
|
+
|
|
554
|
+
### `Entity.type_zone_update(self, mapping, prefix=None, *, lc_=False)`
|
|
555
|
+
|
|
556
|
+
Update `self` with `mapping`, using `prefix`.
|
|
557
|
+
The default `prefix` is self.type_zone`.
|
|
558
|
+
|
|
559
|
+
### `Entity.update(self, *update_a, **update_kw)`
|
|
560
|
+
|
|
561
|
+
Update the tags, tupically from a mapping or keyword arguments.
|
|
562
|
+
|
|
563
|
+
### `Entity.values(self)`
|
|
564
|
+
|
|
565
|
+
The tags values.
|
|
566
|
+
|
|
567
|
+
## class ScanData
|
|
568
|
+
|
|
569
|
+
A class to manage data obtained about `SiteEntity` instances,
|
|
570
|
+
for example from an API or scanning a web page.
|
|
571
|
+
|
|
572
|
+
The data for an `SiteEntity` can be obtained by indexing the
|
|
573
|
+
`ScanData` instance with a `SiteEntity` instance or
|
|
574
|
+
a `(ent_cls,type_key)` 2-tuple
|
|
575
|
+
|
|
576
|
+
### `ScanData.__dict__`
|
|
577
|
+
|
|
578
|
+
Read-only proxy of a mapping.
|
|
579
|
+
|
|
580
|
+
### `ScanData.__firstlineno__`
|
|
581
|
+
|
|
582
|
+
int([x]) -> integer
|
|
583
|
+
int(x, base=10) -> integer
|
|
584
|
+
|
|
585
|
+
Convert a number or string to an integer, or return 0 if no arguments
|
|
586
|
+
are given. If x is a number, return x.__int__(). For floating-point
|
|
587
|
+
numbers, this truncates towards zero.
|
|
588
|
+
|
|
589
|
+
If x is not a number or if base is given, then x must be a string,
|
|
590
|
+
bytes, or bytearray instance representing an integer literal in the
|
|
591
|
+
given base. The literal can be preceded by '+' or '-' and be surrounded
|
|
592
|
+
by whitespace. The base defaults to 10. Valid bases are 0 and 2-36.
|
|
593
|
+
Base 0 means to interpret the base from the string as an integer literal.
|
|
594
|
+
>>> int('0b100', base=0)
|
|
595
|
+
4
|
|
596
|
+
|
|
597
|
+
### `ScanData.__getitem__(self, ent: Union[tuple, ForwardRef('Entity')])`
|
|
598
|
+
|
|
599
|
+
The data for the supplied `ent`.
|
|
600
|
+
|
|
601
|
+
### `ScanData.__iter__(self)`
|
|
602
|
+
|
|
603
|
+
Iteration yields `(Entity,datadict)` 2-tuples.
|
|
604
|
+
|
|
605
|
+
### `ScanData.__static_attributes__`
|
|
606
|
+
|
|
607
|
+
Built-in immutable sequence.
|
|
608
|
+
|
|
609
|
+
If no argument is given, the constructor returns an empty tuple.
|
|
610
|
+
If iterable is specified the tuple is initialized from iterable's items.
|
|
611
|
+
|
|
612
|
+
If the argument is a tuple, the return value is the same object.
|
|
613
|
+
|
|
614
|
+
### `ScanData.apply(self, *refresh_ents)`
|
|
615
|
+
|
|
616
|
+
Apply the scanned data to its entities.
|
|
617
|
+
|
|
618
|
+
If an entity `ent` is a member of `refresh_ents` then call
|
|
619
|
+
`ent.refresh(data=data)` on the basis that the data are
|
|
620
|
+
complete enough to consider the entity refreshed, otherwise
|
|
621
|
+
call `ent.type_zone_update(data)`.
|
|
622
|
+
|
|
623
|
+
The purpose of the call to `ent.refresh()` is to exercise
|
|
624
|
+
the refresh machinery. On a `Refreshable` object `ent` this
|
|
625
|
+
marks the object as current with the new data; the data are
|
|
626
|
+
applied with `Refreshable._refresh()`, the zone specific
|
|
627
|
+
method, which typically _also_ uses `ent.type_zone_update(data)`.
|
|
628
|
+
|
|
629
|
+
This follows the tag name design outlined in the `Entity` docstring,
|
|
630
|
+
where API/site data are stored with tags named *zone*`.`*field*.
|
|
631
|
+
|
|
632
|
+
### `ScanData.conv(self, ent: Union[tuple, ForwardRef('Entity')], mapping, key, conv=None)`
|
|
633
|
+
|
|
634
|
+
Update the data for `ent` from `mapping[key]` if present.
|
|
635
|
+
If `conv` is not `None` it should be a callable accepting
|
|
636
|
+
the value from `mapping[key]` and returning a converted
|
|
637
|
+
value to store in the entity data.
|
|
638
|
+
|
|
639
|
+
### `ScanData.printt(self, title=None)`
|
|
640
|
+
|
|
641
|
+
Call `cs.lex.printt()` to print the scanned data.
|
|
642
|
+
|
|
643
|
+
### `ScanData.update(self, ent: Union[tuple[type, int | str], ForwardRef('Entity')], **data_kw)`
|
|
644
|
+
|
|
645
|
+
Update the data for `ent` from `data_kw`.
|
|
646
|
+
|
|
647
|
+
# Release Log
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
*Release 20260912*:
|
|
652
|
+
First PyPI release: Entity, Entities, ScanData.
|