lr-gladiator 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.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.
Potentially problematic release.
This version of lr-gladiator might be problematic. Click here for more details.
- gladiator/arena.py +42 -7
- gladiator/cli.py +48 -1
- {lr_gladiator-0.3.0.dist-info → lr_gladiator-0.5.0.dist-info}/METADATA +1 -1
- lr_gladiator-0.5.0.dist-info/RECORD +10 -0
- lr_gladiator-0.3.0.dist-info/RECORD +0 -10
- {lr_gladiator-0.3.0.dist-info → lr_gladiator-0.5.0.dist-info}/WHEEL +0 -0
- {lr_gladiator-0.3.0.dist-info → lr_gladiator-0.5.0.dist-info}/entry_points.txt +0 -0
- {lr_gladiator-0.3.0.dist-info → lr_gladiator-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {lr_gladiator-0.3.0.dist-info → lr_gladiator-0.5.0.dist-info}/top_level.txt +0 -0
gladiator/arena.py
CHANGED
|
@@ -185,7 +185,45 @@ class ArenaClient:
|
|
|
185
185
|
edition=edition,
|
|
186
186
|
)
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
def get_bom(self, item_number: str, revision: Optional[str] = None) -> List[Dict]:
|
|
189
|
+
"""
|
|
190
|
+
Return a normalized list of BOM lines for the given item.
|
|
191
|
+
|
|
192
|
+
By default this fetches the EFFECTIVE (approved) revision's BOM.
|
|
193
|
+
Use revision="WORKING" or a specific label (e.g., "B2") to override.
|
|
194
|
+
"""
|
|
195
|
+
# 1) Resolve the exact revision GUID we want the BOM for
|
|
196
|
+
target_guid = self._api_resolve_revision_guid(item_number, revision or "EFFECTIVE")
|
|
197
|
+
|
|
198
|
+
# 2) GET /items/{guid}/bom
|
|
199
|
+
url = f"{self._api_base()}/items/{target_guid}/bom"
|
|
200
|
+
self._log(f"GET {url}")
|
|
201
|
+
r = self.session.get(url)
|
|
202
|
+
r.raise_for_status()
|
|
203
|
+
data = self._ensure_json(r)
|
|
204
|
+
|
|
205
|
+
rows = data.get("results", data if isinstance(data, list) else [])
|
|
206
|
+
norm: List[Dict] = []
|
|
207
|
+
for row in rows:
|
|
208
|
+
itm = row.get("item", {}) if isinstance(row, dict) else {}
|
|
209
|
+
norm.append({
|
|
210
|
+
# association/line
|
|
211
|
+
"guid": row.get("guid"),
|
|
212
|
+
"lineNumber": row.get("lineNumber"),
|
|
213
|
+
"notes": row.get("notes"),
|
|
214
|
+
"quantity": row.get("quantity"),
|
|
215
|
+
"refDes": row.get("refDes") or row.get("referenceDesignators") or "",
|
|
216
|
+
# child item
|
|
217
|
+
"itemGuid": itm.get("guid") or itm.get("id"),
|
|
218
|
+
"itemNumber": itm.get("number"),
|
|
219
|
+
"itemName": itm.get("name"),
|
|
220
|
+
"itemRevision": itm.get("revisionNumber"),
|
|
221
|
+
"itemRevisionStatus": itm.get("revisionStatus"),
|
|
222
|
+
"itemUrl": (itm.get("url") or {}).get("api"),
|
|
223
|
+
"itemAppUrl": (itm.get("url") or {}).get("app"),
|
|
224
|
+
})
|
|
225
|
+
return norm
|
|
226
|
+
|
|
189
227
|
def _api_base(self) -> str:
|
|
190
228
|
return self.cfg.base_url.rstrip("/")
|
|
191
229
|
|
|
@@ -242,7 +280,7 @@ class ArenaClient:
|
|
|
242
280
|
file_guid = f.get("guid") or f.get("id")
|
|
243
281
|
norm.append({
|
|
244
282
|
"id": row.get("guid") or row.get("id"), # association id
|
|
245
|
-
"fileGuid": file_guid,
|
|
283
|
+
"fileGuid": file_guid, # actual file id
|
|
246
284
|
"name": f.get("name") or f.get("title"),
|
|
247
285
|
"filename": f.get("name") or f.get("title"),
|
|
248
286
|
"size": f.get("size"),
|
|
@@ -287,7 +325,7 @@ class ArenaClient:
|
|
|
287
325
|
# Prefer the one not superseded
|
|
288
326
|
eff = [rv for rv in revs if (rv.get("revisionStatus") or "").upper() == "EFFECTIVE" or rv.get("status") == 1]
|
|
289
327
|
if not eff:
|
|
290
|
-
raise ArenaError("No approved/effective revision exists for this item.")
|
|
328
|
+
raise ArenaError("No approved/effective revision exists for this item. Try using revision 'WORKING'.")
|
|
291
329
|
current = next((rv for rv in eff if not rv.get("supersededDateTime")), eff[-1])
|
|
292
330
|
return current.get("guid")
|
|
293
331
|
|
|
@@ -431,14 +469,11 @@ class ArenaClient:
|
|
|
431
469
|
title = title or file_path.stem
|
|
432
470
|
file_format = file_format or (file_path.suffix[1:].lower() if file_path.suffix else "bin")
|
|
433
471
|
description = description or "Uploaded via gladiator"
|
|
472
|
+
files = {"content": (file_path.name, open(file_path, "rb"), "application/octet-stream")}
|
|
434
473
|
|
|
435
|
-
files = {
|
|
436
|
-
"content": (file_path.name, open(file_path, "rb"), "application/octet-stream"),
|
|
437
|
-
}
|
|
438
474
|
# NOTE: nested field names are sent in `data`, not `files`
|
|
439
475
|
data_form = {
|
|
440
476
|
"file.title": title,
|
|
441
|
-
"file.name": filename,
|
|
442
477
|
"file.description": description,
|
|
443
478
|
"file.category.guid": cat_guid,
|
|
444
479
|
"file.format": file_format,
|
gladiator/cli.py
CHANGED
|
@@ -83,6 +83,9 @@ def latest_approved(
|
|
|
83
83
|
sys.stdout.write("\n")
|
|
84
84
|
else:
|
|
85
85
|
print(rev)
|
|
86
|
+
except requests.HTTPError as e:
|
|
87
|
+
typer.secho(f"Arena request failed: {e}", fg=typer.colors.RED, err=True)
|
|
88
|
+
raise typer.Exit(2)
|
|
86
89
|
except ArenaError as e:
|
|
87
90
|
typer.secho(str(e), fg=typer.colors.RED, err=True)
|
|
88
91
|
raise typer.Exit(2)
|
|
@@ -108,10 +111,48 @@ def list_files(
|
|
|
108
111
|
for f in files:
|
|
109
112
|
table.add_row(str(f.get("filename")), str(f.get("size")), str(f.get("checksum")))
|
|
110
113
|
print(table)
|
|
114
|
+
except requests.HTTPError as e:
|
|
115
|
+
typer.secho(f"Arena request failed: {e}", fg=typer.colors.RED, err=True)
|
|
116
|
+
raise typer.Exit(2)
|
|
111
117
|
except ArenaError as e:
|
|
112
118
|
typer.secho(str(e), fg=typer.colors.RED, err=True)
|
|
113
119
|
raise typer.Exit(2)
|
|
114
120
|
|
|
121
|
+
@app.command("bom")
|
|
122
|
+
def bom(
|
|
123
|
+
item: str = typer.Argument(..., help="Item/article number (e.g., 890-1001)"),
|
|
124
|
+
revision: Optional[str] = typer.Option(None, "--rev", help='Revision selector: WORKING, EFFECTIVE (default), or label (e.g., "B2")'),
|
|
125
|
+
output: str = typer.Option("table", "--output", help='Output format: "table" (default) or "json"'),
|
|
126
|
+
):
|
|
127
|
+
"""List the BOM lines for an item revision."""
|
|
128
|
+
try:
|
|
129
|
+
lines = _client().get_bom(item, revision)
|
|
130
|
+
if output.lower() == "json":
|
|
131
|
+
print(json.dumps({"count": len(lines), "results": lines}, indent=2))
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
title_rev = revision or "(latest approved)"
|
|
135
|
+
table = Table(title=f"BOM for {item} rev {title_rev}")
|
|
136
|
+
table.add_column("Line", justify="right")
|
|
137
|
+
table.add_column("Qty", justify="right")
|
|
138
|
+
table.add_column("Number")
|
|
139
|
+
table.add_column("Name")
|
|
140
|
+
table.add_column("RefDes")
|
|
141
|
+
for ln in lines:
|
|
142
|
+
table.add_row(
|
|
143
|
+
str(ln.get("lineNumber") or ""),
|
|
144
|
+
str(ln.get("quantity") or ""),
|
|
145
|
+
str(ln.get("itemNumber") or ""),
|
|
146
|
+
str(ln.get("itemName") or ""),
|
|
147
|
+
str(ln.get("refDes") or ""),
|
|
148
|
+
)
|
|
149
|
+
print(table)
|
|
150
|
+
except requests.HTTPError as e:
|
|
151
|
+
typer.secho(f"Arena request failed: {e}", fg=typer.colors.RED, err=True)
|
|
152
|
+
raise typer.Exit(2)
|
|
153
|
+
except ArenaError as e:
|
|
154
|
+
typer.secho(str(e), fg=typer.colors.RED, err=True)
|
|
155
|
+
raise typer.Exit(2)
|
|
115
156
|
|
|
116
157
|
@app.command("get-files")
|
|
117
158
|
def get_files(
|
|
@@ -123,6 +164,9 @@ def get_files(
|
|
|
123
164
|
paths = _client().download_files(item, revision, out_dir=out)
|
|
124
165
|
for p in paths:
|
|
125
166
|
print(str(p))
|
|
167
|
+
except requests.HTTPError as e:
|
|
168
|
+
typer.secho(f"Arena request failed: {e}", fg=typer.colors.RED, err=True)
|
|
169
|
+
raise typer.Exit(2)
|
|
126
170
|
except ArenaError as e:
|
|
127
171
|
typer.secho(str(e), fg=typer.colors.RED, err=True)
|
|
128
172
|
raise typer.Exit(2)
|
|
@@ -137,7 +181,7 @@ def upload_file(
|
|
|
137
181
|
category: str = typer.Option("CAD Data", "--category", help='File category name (default: "CAD Data")'),
|
|
138
182
|
file_format: Optional[str] = typer.Option(None, "--format", help="File format (default: file extension)"),
|
|
139
183
|
description: Optional[str] = typer.Option(None, "--desc", help="Optional description"),
|
|
140
|
-
primary: bool = typer.Option(
|
|
184
|
+
primary: bool = typer.Option(False, "--primary/--no-primary", help="Mark association as primary"),
|
|
141
185
|
edition: str = typer.Option("1", "--edition", help="Edition number when creating a new association (default: 1)"),
|
|
142
186
|
):
|
|
143
187
|
"""If a file with the same filename exists: update its content (new edition).
|
|
@@ -149,6 +193,9 @@ def upload_file(
|
|
|
149
193
|
description=description, primary=primary, edition=edition
|
|
150
194
|
)
|
|
151
195
|
print(json.dumps(result, indent=2))
|
|
196
|
+
except requests.HTTPError as e:
|
|
197
|
+
typer.secho(f"Arena request failed: {e}", fg=typer.colors.RED, err=True)
|
|
198
|
+
raise typer.Exit(2)
|
|
152
199
|
except ArenaError as e:
|
|
153
200
|
typer.secho(str(e), fg=typer.colors.RED, err=True)
|
|
154
201
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lr-gladiator
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: CLI and Python client for Arena PLM (app.bom.com): login, get revisions, list/download attachments, and upload to working revisions.
|
|
5
5
|
Author-email: Jonas Estberger <jonas.estberger@lumenradio.com>
|
|
6
6
|
License: MIT
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
gladiator/__init__.py,sha256=kVgJiGDD6714tJ3SN6mdao3rdVO57jlMvLMHAFjHX4A,207
|
|
2
|
+
gladiator/arena.py,sha256=Dr6FVDrcsxI98KVPzQY1LaZS2Ixch0BU4qe1qqqez60,23297
|
|
3
|
+
gladiator/cli.py,sha256=EqoIjmnoSPzjckgeiUXjJBt6rEU723bbYOIiEsbhMSY,8530
|
|
4
|
+
gladiator/config.py,sha256=pnuVrcW8yafxMB7RU9wyi_4jS_oMBIuNryfet203Wng,1738
|
|
5
|
+
lr_gladiator-0.5.0.dist-info/licenses/LICENSE,sha256=2CEtbEagerjoU3EDSk-eTM5LKgI_RpiVIOh3_CV4kms,1069
|
|
6
|
+
lr_gladiator-0.5.0.dist-info/METADATA,sha256=Pikc_vdgYG1KFYss8y4pLTsflM7W6d5wgZ5TvDIckC0,1912
|
|
7
|
+
lr_gladiator-0.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
+
lr_gladiator-0.5.0.dist-info/entry_points.txt,sha256=SLka4w7iGS2B8HrbeZyNk5mxaIC6QKcv93us1OaWNwQ,48
|
|
9
|
+
lr_gladiator-0.5.0.dist-info/top_level.txt,sha256=tfrcAmK7_7Lf63w7kWy0wv_Qg9RrcFWGoins1-jGUF4,10
|
|
10
|
+
lr_gladiator-0.5.0.dist-info/RECORD,,
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
gladiator/__init__.py,sha256=kVgJiGDD6714tJ3SN6mdao3rdVO57jlMvLMHAFjHX4A,207
|
|
2
|
-
gladiator/arena.py,sha256=GUexGV7aSnOKXM86MSh6hp05S5qfnAgRAt7hX4gGV_4,21652
|
|
3
|
-
gladiator/cli.py,sha256=K5qM5rTlz4EXZ_7kc4EjOGrGzj_-4E4HXFCrt-BTCxU,6444
|
|
4
|
-
gladiator/config.py,sha256=pnuVrcW8yafxMB7RU9wyi_4jS_oMBIuNryfet203Wng,1738
|
|
5
|
-
lr_gladiator-0.3.0.dist-info/licenses/LICENSE,sha256=2CEtbEagerjoU3EDSk-eTM5LKgI_RpiVIOh3_CV4kms,1069
|
|
6
|
-
lr_gladiator-0.3.0.dist-info/METADATA,sha256=xuB5t1e8lBt86agY-L7jb63qm3K5YEa7be1ZxWNFu0w,1912
|
|
7
|
-
lr_gladiator-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
8
|
-
lr_gladiator-0.3.0.dist-info/entry_points.txt,sha256=SLka4w7iGS2B8HrbeZyNk5mxaIC6QKcv93us1OaWNwQ,48
|
|
9
|
-
lr_gladiator-0.3.0.dist-info/top_level.txt,sha256=tfrcAmK7_7Lf63w7kWy0wv_Qg9RrcFWGoins1-jGUF4,10
|
|
10
|
-
lr_gladiator-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|