workwire 0.4.0__tar.gz → 0.5.0__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.
- {workwire-0.4.0 → workwire-0.5.0}/CHANGELOG.md +7 -0
- {workwire-0.4.0 → workwire-0.5.0}/PKG-INFO +32 -8
- {workwire-0.4.0 → workwire-0.5.0}/README.md +31 -7
- {workwire-0.4.0 → workwire-0.5.0}/pyproject.toml +1 -1
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/_client.py +1 -5
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/_coverage.py +1 -1
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/_models.py +25 -10
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/jobs.py +2 -2
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/locations.py +20 -6
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/projects.py +7 -4
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/wires.py +2 -5
- {workwire-0.4.0 → workwire-0.5.0}/.gitignore +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/LICENSE +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/SECURITY.md +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/__init__.py +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/_version.py +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/errors.py +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/py.typed +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/__init__.py +0 -0
- {workwire-0.4.0 → workwire-0.5.0}/src/workwire/resources/partnerships.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0](https://github.com/workwire/workwire-python/compare/v0.4.0...v0.5.0) (2026-10-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **WOR-511:** backend v1.62.0's spec — unit_type on locations and jobs, the kind_rank reason ([#24](https://github.com/workwire/workwire-python/issues/24)) ([c97d486](https://github.com/workwire/workwire-python/commit/c97d4860acfe7a73598c6c3407ccc9dc5d666be2))
|
|
9
|
+
|
|
3
10
|
## [0.4.0](https://github.com/workwire/workwire-python/compare/v0.3.0...v0.4.0) (2026-10-18)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: workwire
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Official Python SDK for the Workwire API
|
|
5
5
|
Project-URL: Homepage, https://github.com/workwire/workwire-python
|
|
6
6
|
Project-URL: Changelog, https://github.com/workwire/workwire-python/blob/main/CHANGELOG.md
|
|
@@ -107,15 +107,28 @@ shown to the other side.
|
|
|
107
107
|
```python
|
|
108
108
|
from workwire import LocationNode, Party
|
|
109
109
|
|
|
110
|
-
project = client.projects.create(
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
project = client.projects.create(
|
|
111
|
+
name="Elm St. Townhomes",
|
|
112
|
+
template="development",
|
|
113
|
+
locations=[
|
|
114
|
+
LocationNode("building", "Bldg A", children=[LocationNode("floor", "Level 1")]),
|
|
115
|
+
],
|
|
116
|
+
)
|
|
113
117
|
tree = client.projects.locations.list(project.id).data # the site root first
|
|
114
118
|
level_1 = next(loc for loc in tree if loc.name == "Level 1")
|
|
115
|
-
client.wires.create(
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
+
client.wires.create(
|
|
120
|
+
project_id=project.id,
|
|
121
|
+
title="Drywall — Level 1",
|
|
122
|
+
parties=[
|
|
123
|
+
Party.partnered(
|
|
124
|
+
partnership_id=partnership.id,
|
|
125
|
+
trade="Drywall",
|
|
126
|
+
scope_text="Level 1.",
|
|
127
|
+
contract_value="40000.00",
|
|
128
|
+
scope_location_ids=[level_1.id], # one Job per scope location
|
|
129
|
+
)
|
|
130
|
+
],
|
|
131
|
+
)
|
|
119
132
|
page = client.jobs.list(project=project.id) # page.quantity_unit is your org's unit
|
|
120
133
|
client.jobs.update(page.data[0].id, your_reference="PO-4471-A", quantity="12.5", checked=True)
|
|
121
134
|
```
|
|
@@ -125,6 +138,17 @@ one `client.jobs.update` returns — carries `location_name`, `location_kind` an
|
|
|
125
138
|
`location_path` (the ancestors, root first), so a sub reads its scope without
|
|
126
139
|
the GC's tree; `client.jobs.list` rows had them already.
|
|
127
140
|
|
|
141
|
+
A tree only descends: `site` › `building`/`house` › `floor` ›
|
|
142
|
+
`unit`/`common_area` › `room`, levels skippable but never repeated or
|
|
143
|
+
reversed. A node that breaks the rank raises `InvalidRequestError` with code
|
|
144
|
+
`invalid_parent` and `details` `{"reason": "kind_rank", "child_kind": ...,
|
|
145
|
+
"parent_kind": ...}`.
|
|
146
|
+
|
|
147
|
+
`LocationNode(..., unit_type="C1.1 (2 Bedroom)")` (or
|
|
148
|
+
`locations.create(..., unit_type=...)`) labels a unit's plan; every
|
|
149
|
+
`Location` reads it back as `unit_type`, and a Job as `location_unit_type` —
|
|
150
|
+
`None` when unset.
|
|
151
|
+
|
|
128
152
|
Leave `scope_location_ids` out to scope a party to the whole project.
|
|
129
153
|
`client.jobs.update` sends only the fields you pass: leave one out to keep
|
|
130
154
|
it, pass `None` to clear it. Add to a tree later with
|
|
@@ -84,15 +84,28 @@ shown to the other side.
|
|
|
84
84
|
```python
|
|
85
85
|
from workwire import LocationNode, Party
|
|
86
86
|
|
|
87
|
-
project = client.projects.create(
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
project = client.projects.create(
|
|
88
|
+
name="Elm St. Townhomes",
|
|
89
|
+
template="development",
|
|
90
|
+
locations=[
|
|
91
|
+
LocationNode("building", "Bldg A", children=[LocationNode("floor", "Level 1")]),
|
|
92
|
+
],
|
|
93
|
+
)
|
|
90
94
|
tree = client.projects.locations.list(project.id).data # the site root first
|
|
91
95
|
level_1 = next(loc for loc in tree if loc.name == "Level 1")
|
|
92
|
-
client.wires.create(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
+
client.wires.create(
|
|
97
|
+
project_id=project.id,
|
|
98
|
+
title="Drywall — Level 1",
|
|
99
|
+
parties=[
|
|
100
|
+
Party.partnered(
|
|
101
|
+
partnership_id=partnership.id,
|
|
102
|
+
trade="Drywall",
|
|
103
|
+
scope_text="Level 1.",
|
|
104
|
+
contract_value="40000.00",
|
|
105
|
+
scope_location_ids=[level_1.id], # one Job per scope location
|
|
106
|
+
)
|
|
107
|
+
],
|
|
108
|
+
)
|
|
96
109
|
page = client.jobs.list(project=project.id) # page.quantity_unit is your org's unit
|
|
97
110
|
client.jobs.update(page.data[0].id, your_reference="PO-4471-A", quantity="12.5", checked=True)
|
|
98
111
|
```
|
|
@@ -102,6 +115,17 @@ one `client.jobs.update` returns — carries `location_name`, `location_kind` an
|
|
|
102
115
|
`location_path` (the ancestors, root first), so a sub reads its scope without
|
|
103
116
|
the GC's tree; `client.jobs.list` rows had them already.
|
|
104
117
|
|
|
118
|
+
A tree only descends: `site` › `building`/`house` › `floor` ›
|
|
119
|
+
`unit`/`common_area` › `room`, levels skippable but never repeated or
|
|
120
|
+
reversed. A node that breaks the rank raises `InvalidRequestError` with code
|
|
121
|
+
`invalid_parent` and `details` `{"reason": "kind_rank", "child_kind": ...,
|
|
122
|
+
"parent_kind": ...}`.
|
|
123
|
+
|
|
124
|
+
`LocationNode(..., unit_type="C1.1 (2 Bedroom)")` (or
|
|
125
|
+
`locations.create(..., unit_type=...)`) labels a unit's plan; every
|
|
126
|
+
`Location` reads it back as `unit_type`, and a Job as `location_unit_type` —
|
|
127
|
+
`None` when unset.
|
|
128
|
+
|
|
105
129
|
Leave `scope_location_ids` out to scope a party to the whole project.
|
|
106
130
|
`client.jobs.update` sends only the fields you pass: leave one out to keep
|
|
107
131
|
it, pass `None` to clear it. Add to a tree later with
|
|
@@ -96,9 +96,7 @@ class BaseClient:
|
|
|
96
96
|
return {
|
|
97
97
|
"Authorization": f"Bearer {self._api_key}",
|
|
98
98
|
"Accept": "application/json",
|
|
99
|
-
"User-Agent": (
|
|
100
|
-
f"workwire-python/{__version__} python/{platform.python_version()}"
|
|
101
|
-
),
|
|
99
|
+
"User-Agent": (f"workwire-python/{__version__} python/{platform.python_version()}"),
|
|
102
100
|
"X-Workwire-Client-User-Agent": telemetry,
|
|
103
101
|
}
|
|
104
102
|
|
|
@@ -248,5 +246,3 @@ class BaseClient:
|
|
|
248
246
|
headers={k.lower(): v for k, v in response.headers.items()},
|
|
249
247
|
body=body,
|
|
250
248
|
)
|
|
251
|
-
|
|
252
|
-
|
|
@@ -66,7 +66,7 @@ OPERATIONS: dict[str, dict[str, object]] = {
|
|
|
66
66
|
"createProjectLocation": {
|
|
67
67
|
"method": "POST",
|
|
68
68
|
"path": "/v1/projects/{id}/locations",
|
|
69
|
-
"request_fields": {"parent_id", "kind", "name"},
|
|
69
|
+
"request_fields": {"parent_id", "kind", "name", "unit_type"},
|
|
70
70
|
"query_params": set(),
|
|
71
71
|
"response_model": _models.Location,
|
|
72
72
|
},
|
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
from collections.abc import Iterator, Mapping, Sequence
|
|
21
21
|
from collections.abc import Set as AbstractSet
|
|
22
|
-
from dataclasses import dataclass
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
23
|
from typing import Any, Literal
|
|
24
24
|
|
|
25
25
|
__all__ = [
|
|
@@ -186,7 +186,8 @@ class PartyJob(WorkwireObject):
|
|
|
186
186
|
(the ancestors, root first; empty at the site root) are the server's
|
|
187
187
|
description of where the Job sits in the GC's tree; ``your_reference``,
|
|
188
188
|
``quantity`` and ``checked_at`` are **your org's own** fields, never the
|
|
189
|
-
other side's.
|
|
189
|
+
other side's. ``location_unit_type`` is the location's ``unit_type`` — the
|
|
190
|
+
label a builder gives a unit's plan, ``None`` when unset."""
|
|
190
191
|
|
|
191
192
|
_nested = {"location_path": JobPathLocation}
|
|
192
193
|
|
|
@@ -195,6 +196,7 @@ class PartyJob(WorkwireObject):
|
|
|
195
196
|
location_id: str
|
|
196
197
|
location_name: str
|
|
197
198
|
location_kind: str
|
|
199
|
+
location_unit_type: str | None
|
|
198
200
|
location_path: list[JobPathLocation]
|
|
199
201
|
your_reference: str | None
|
|
200
202
|
quantity: str | None
|
|
@@ -313,13 +315,16 @@ class PartnershipListItem(WorkwireObject):
|
|
|
313
315
|
|
|
314
316
|
class Location(WorkwireObject):
|
|
315
317
|
"""One location of a project's tree. ``path`` is the ancestor ids, root
|
|
316
|
-
first (empty on the root, whose ``parent_id`` is ``None``).
|
|
318
|
+
first (empty on the root, whose ``parent_id`` is ``None``). ``unit_type``
|
|
319
|
+
is the label a builder gives a unit's plan — ``None`` when unset; always
|
|
320
|
+
``None`` on a split."""
|
|
317
321
|
|
|
318
322
|
id: str
|
|
319
323
|
project_id: str
|
|
320
324
|
parent_id: str | None
|
|
321
325
|
kind: str
|
|
322
326
|
name: str
|
|
327
|
+
unit_type: str | None
|
|
323
328
|
path: list[str]
|
|
324
329
|
archived_at: str | None
|
|
325
330
|
created_at: str
|
|
@@ -361,7 +366,9 @@ class JobMilestones(WorkwireObject):
|
|
|
361
366
|
class JobRow(WorkwireObject):
|
|
362
367
|
"""One row of :meth:`Jobs.list`: the Job with its party, wire, project,
|
|
363
368
|
location and counterparty context. ``your_reference``, ``quantity`` and
|
|
364
|
-
``checked_at`` are your org's own fields, never the other side's.
|
|
369
|
+
``checked_at`` are your org's own fields, never the other side's.
|
|
370
|
+
``location_unit_type`` is the location's ``unit_type`` — the label a
|
|
371
|
+
builder gives a unit's plan, ``None`` when unset."""
|
|
365
372
|
|
|
366
373
|
_nested = {"location_path": JobPathLocation, "milestones": JobMilestones}
|
|
367
374
|
|
|
@@ -380,6 +387,7 @@ class JobRow(WorkwireObject):
|
|
|
380
387
|
location_id: str
|
|
381
388
|
location_name: str
|
|
382
389
|
location_kind: str
|
|
390
|
+
location_unit_type: str | None
|
|
383
391
|
location_path: list[JobPathLocation]
|
|
384
392
|
counterparty_org_id: str | None
|
|
385
393
|
counterparty_name: str | None
|
|
@@ -453,13 +461,20 @@ class ColdInvite:
|
|
|
453
461
|
|
|
454
462
|
@dataclass(frozen=True)
|
|
455
463
|
class LocationNode:
|
|
456
|
-
"""One location of a tree being created — its ``kind``, its ``name``,
|
|
457
|
-
|
|
458
|
-
|
|
464
|
+
"""One location of a tree being created — its ``kind``, its ``name``, its
|
|
465
|
+
optional ``unit_type`` (the label a builder gives a unit's plan, "C1.1
|
|
466
|
+
(2 Bedroom)"), and the ``children`` nested beneath it. A tree only
|
|
467
|
+
descends — each kind ranks strictly below its parent's, ``site`` ›
|
|
468
|
+
``building``/``house`` › ``floor`` › ``unit``/``common_area`` › ``room``,
|
|
469
|
+
levels skippable but never repeated or reversed, else
|
|
470
|
+
``InvalidRequestError`` code ``invalid_parent`` with
|
|
471
|
+
``details["reason"] == "kind_rank"``. At most 500 locations per request,
|
|
459
472
|
counted over every level."""
|
|
460
473
|
|
|
461
474
|
kind: LocationKind
|
|
462
475
|
name: str
|
|
476
|
+
# Keyword-only, so a positional third argument is still ``children``.
|
|
477
|
+
unit_type: str | None = field(default=None, kw_only=True)
|
|
463
478
|
children: Sequence[LocationNode] | None = None
|
|
464
479
|
|
|
465
480
|
def __post_init__(self) -> None:
|
|
@@ -475,6 +490,8 @@ class LocationNode:
|
|
|
475
490
|
|
|
476
491
|
def to_payload(self) -> dict[str, Any]:
|
|
477
492
|
payload: dict[str, Any] = {"kind": self.kind, "name": self.name}
|
|
493
|
+
if self.unit_type is not None: # absent, never null: the bytes stay as before
|
|
494
|
+
payload["unit_type"] = self.unit_type
|
|
478
495
|
if self.children is not None:
|
|
479
496
|
payload["children"] = [child.to_payload() for child in self.children]
|
|
480
497
|
return payload
|
|
@@ -524,9 +541,7 @@ class Party:
|
|
|
524
541
|
|
|
525
542
|
def __init__(self, payload: dict[str, Any], *, _guard: object = None) -> None:
|
|
526
543
|
if _guard is not _PARTY_GUARD:
|
|
527
|
-
raise TypeError(
|
|
528
|
-
"Construct with Party.partnered(...) or Party.cold_invite(...)"
|
|
529
|
-
)
|
|
544
|
+
raise TypeError("Construct with Party.partnered(...) or Party.cold_invite(...)")
|
|
530
545
|
self._payload = payload
|
|
531
546
|
|
|
532
547
|
@classmethod
|
|
@@ -43,11 +43,11 @@ def _quantity(value: str | Decimal | None) -> str | None:
|
|
|
43
43
|
return format(value, "f")
|
|
44
44
|
if isinstance(value, float):
|
|
45
45
|
raise TypeError(
|
|
46
|
-
|
|
46
|
+
'quantity must be a decimal string ("12.5") or a decimal.Decimal, '
|
|
47
47
|
"never a float: a binary float is not an exact quantity"
|
|
48
48
|
)
|
|
49
49
|
raise TypeError(
|
|
50
|
-
|
|
50
|
+
'quantity must be a decimal string ("12.5") or a decimal.Decimal, '
|
|
51
51
|
f"not {type(value).__name__} — pass str(n) or Decimal(n)"
|
|
52
52
|
)
|
|
53
53
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
Every project has one ``site`` root, created with the project
|
|
5
5
|
(``Project.root_location_id``), and beneath it houses, buildings, floors,
|
|
6
|
-
units, rooms and common areas,
|
|
6
|
+
units, rooms and common areas, each kind ranked below its parent's (see
|
|
7
|
+
:class:`~workwire.LocationNode`). Locations have stable ids —
|
|
7
8
|
nothing references one by name or path. Seed a tree when you create the
|
|
8
9
|
project (``projects.create(locations=...)``) or add to it here; renames,
|
|
9
10
|
moves and archives happen in the Workwire app.
|
|
@@ -76,6 +77,7 @@ class ProjectLocations:
|
|
|
76
77
|
*,
|
|
77
78
|
kind: LocationKind,
|
|
78
79
|
name: str,
|
|
80
|
+
unit_type: str | None = None,
|
|
79
81
|
parent_id: str | None = None,
|
|
80
82
|
idempotency_key: str | None = None,
|
|
81
83
|
timeout: float | None = None,
|
|
@@ -83,13 +85,22 @@ class ProjectLocations:
|
|
|
83
85
|
"""Add one location beneath ``parent_id`` — absent, the project's
|
|
84
86
|
root. Requires ``projects:write``.
|
|
85
87
|
|
|
88
|
+
``unit_type`` is the label a builder gives a unit's plan ("C1.1
|
|
89
|
+
(2 Bedroom)"); left ``None``, it is not sent.
|
|
90
|
+
|
|
86
91
|
A parent that is not an unarchived location of this project's tree
|
|
87
|
-
raises ``InvalidRequestError`` (code ``invalid_parent``)
|
|
88
|
-
``kind``
|
|
89
|
-
|
|
90
|
-
|
|
92
|
+
raises ``InvalidRequestError`` (code ``invalid_parent``), and so does
|
|
93
|
+
a ``kind`` that does not rank below the parent's (``site`` ›
|
|
94
|
+
``building``/``house`` › ``floor`` › ``unit``/``common_area`` ›
|
|
95
|
+
``room``) — that refusal's ``details`` are ``{"reason": "kind_rank",
|
|
96
|
+
"child_kind": ..., "parent_kind": ...}``. An unknown ``kind`` is
|
|
97
|
+
checked with the body here — ``InvalidRequestError`` code
|
|
98
|
+
``validation_error``, ``fields["kind"]``. An archived project's tree
|
|
99
|
+
is read-only (``ConflictError``, code ``project_archived``).
|
|
91
100
|
"""
|
|
92
101
|
body: dict[str, Any] = {"kind": kind, "name": name}
|
|
102
|
+
if unit_type is not None:
|
|
103
|
+
body["unit_type"] = unit_type
|
|
93
104
|
if parent_id is not None:
|
|
94
105
|
body["parent_id"] = parent_id
|
|
95
106
|
data, request_id = self._client._request(
|
|
@@ -117,7 +128,10 @@ class ProjectLocations:
|
|
|
117
128
|
At most 500 locations, counted over every level: more raises
|
|
118
129
|
``InvalidRequestError`` (code ``too_many_locations``, with
|
|
119
130
|
``details["limit"]``), as does an unknown ``kind``
|
|
120
|
-
(``invalid_location_kind``)
|
|
131
|
+
(``invalid_location_kind``) and a node whose kind does not rank below
|
|
132
|
+
its own parent's (``invalid_parent``, with ``details`` ``{"reason":
|
|
133
|
+
"kind_rank", "child_kind": ..., "parent_kind": ...}``); a refused
|
|
134
|
+
node creates nothing. Returns
|
|
121
135
|
a :class:`LocationBatch` — a plain list of the created locations,
|
|
122
136
|
flat, every parent before its children, so you have every id; each
|
|
123
137
|
carries the response's ``request_id``.
|
|
@@ -45,10 +45,13 @@ class Projects:
|
|
|
45
45
|
(``root_location_id``). ``locations`` seeds a tree beneath the root
|
|
46
46
|
in the same transaction — at most 500 locations counted over every
|
|
47
47
|
level (``too_many_locations``), each of a known kind
|
|
48
|
-
(``invalid_location_kind``)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
(``invalid_location_kind``) ranked below its parent's
|
|
49
|
+
(``invalid_parent``, with ``details`` ``{"reason": "kind_rank",
|
|
50
|
+
"child_kind": ..., "parent_kind": ...}`` — see :class:`LocationNode`);
|
|
51
|
+
a refused node creates nothing, the project included. ``template``
|
|
52
|
+
(``development``, ``single_home``, ``renovation``) records the Project
|
|
53
|
+
Type your tree follows in the project's history only — the server
|
|
54
|
+
seeds nothing from it.
|
|
52
55
|
"""
|
|
53
56
|
body: dict[str, Any] = {"name": name}
|
|
54
57
|
if address is not None:
|
|
@@ -46,8 +46,7 @@ class Wires:
|
|
|
46
46
|
for party in parties:
|
|
47
47
|
if not isinstance(party, Party):
|
|
48
48
|
raise TypeError(
|
|
49
|
-
"parties must be built with Party.partnered(...) or "
|
|
50
|
-
"Party.cold_invite(...)"
|
|
49
|
+
"parties must be built with Party.partnered(...) or Party.cold_invite(...)"
|
|
51
50
|
)
|
|
52
51
|
body: dict[str, Any] = {
|
|
53
52
|
"project_id": project_id,
|
|
@@ -70,9 +69,7 @@ class Wires:
|
|
|
70
69
|
def retrieve(self, wire_id: str, *, timeout: float | None = None) -> Wire:
|
|
71
70
|
"""Fetch one wire with embedded parties, milestones, and POs.
|
|
72
71
|
Requires ``wires:read``."""
|
|
73
|
-
data, request_id = self._client._request(
|
|
74
|
-
"GET", f"/v1/wires/{wire_id}", timeout=timeout
|
|
75
|
-
)
|
|
72
|
+
data, request_id = self._client._request("GET", f"/v1/wires/{wire_id}", timeout=timeout)
|
|
76
73
|
return Wire(data, request_id=request_id)
|
|
77
74
|
|
|
78
75
|
def go_live(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|