reliafy-client 0.1.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.
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: reliafy-client
3
+ Version: 0.1.0
4
+ Summary: Push SurPyval models to Reliafy — shareable, trackable, citable reliability analyses.
5
+ Author: Reliafy
6
+ License: AGPL-3.0-or-later
7
+ Project-URL: Homepage, https://reliafy.com
8
+ Project-URL: Source, https://github.com/Reliafy/reliafy
9
+ Project-URL: Documentation, https://github.com/Reliafy/reliafy/blob/main/python/README.md
10
+ Keywords: reliability,survival-analysis,weibull,surpyval,maintenance
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # reliafy — push SurPyval models to Reliafy
15
+
16
+ Fit a model anywhere with [SurPyval](https://github.com/derrynknife/SurPyval),
17
+ then make it a shareable, trackable, citable artifact in
18
+ [Reliafy](https://reliafy.com) with one call. The notebook is the lab;
19
+ Reliafy is the plant.
20
+
21
+ ```bash
22
+ pip install reliafy-client
23
+ ```
24
+
25
+ (The package installs as `reliafy-client`; you import it as `reliafy`.)
26
+
27
+ ## Quick start
28
+
29
+ ```python
30
+ import surpyval as sp
31
+ import reliafy
32
+
33
+ # Fit however you like — censored data, offsets, whatever.
34
+ model = sp.Weibull.fit(x=failures, c=censoring_flags)
35
+
36
+ reliafy.configure(token="rlf_...") # from Reliafy → API access (Pro)
37
+ url = reliafy.push(model, name="Pump bearings — 2026 refit", unit="hours")
38
+ print(url) # open it in Reliafy
39
+ ```
40
+
41
+ `push()` uploads the model **and its fitted data** by default, so Reliafy
42
+ shows the full probability plot with confidence bounds — and the model stays
43
+ editable and refittable in the app, and can be cited as RCM evidence, used in
44
+ RBD blocks, or tracked against a fleet.
45
+
46
+ Offset / limited-failure-population / zero-inflated fits are detected
47
+ automatically from the model and reproduced.
48
+
49
+ ## Options
50
+
51
+ ```python
52
+ # Parameters only (no data upload): functions & life metrics, no plot.
53
+ reliafy.push(model, name="From a report", data=False)
54
+
55
+ # No SurPyval object — just numbers:
56
+ reliafy.push_params("weibull", [1200.0, 2.3], name="Handbook value", unit="hours")
57
+
58
+ # Self-hosted instance:
59
+ reliafy.configure(token="rlf_...", base_url="https://reliafy.mycompany.com")
60
+ ```
61
+
62
+ Configuration also reads `RELIAFY_TOKEN` and `RELIAFY_BASE_URL` from the
63
+ environment.
64
+
65
+ ## Notes
66
+
67
+ - The token is a personal API token, created on the **API access** page in
68
+ Reliafy. On Reliafy Cloud this is a Pro feature; self-hosted instances have
69
+ it unconditionally.
70
+ - Supported distributions: Weibull, Exponential, Normal, LogNormal, Gamma,
71
+ LogLogistic, Exponentiated Weibull, Gumbel, Logistic.
72
+ - Pure standard library — no dependencies. You bring SurPyval to do the fit.
@@ -0,0 +1,59 @@
1
+ # reliafy — push SurPyval models to Reliafy
2
+
3
+ Fit a model anywhere with [SurPyval](https://github.com/derrynknife/SurPyval),
4
+ then make it a shareable, trackable, citable artifact in
5
+ [Reliafy](https://reliafy.com) with one call. The notebook is the lab;
6
+ Reliafy is the plant.
7
+
8
+ ```bash
9
+ pip install reliafy-client
10
+ ```
11
+
12
+ (The package installs as `reliafy-client`; you import it as `reliafy`.)
13
+
14
+ ## Quick start
15
+
16
+ ```python
17
+ import surpyval as sp
18
+ import reliafy
19
+
20
+ # Fit however you like — censored data, offsets, whatever.
21
+ model = sp.Weibull.fit(x=failures, c=censoring_flags)
22
+
23
+ reliafy.configure(token="rlf_...") # from Reliafy → API access (Pro)
24
+ url = reliafy.push(model, name="Pump bearings — 2026 refit", unit="hours")
25
+ print(url) # open it in Reliafy
26
+ ```
27
+
28
+ `push()` uploads the model **and its fitted data** by default, so Reliafy
29
+ shows the full probability plot with confidence bounds — and the model stays
30
+ editable and refittable in the app, and can be cited as RCM evidence, used in
31
+ RBD blocks, or tracked against a fleet.
32
+
33
+ Offset / limited-failure-population / zero-inflated fits are detected
34
+ automatically from the model and reproduced.
35
+
36
+ ## Options
37
+
38
+ ```python
39
+ # Parameters only (no data upload): functions & life metrics, no plot.
40
+ reliafy.push(model, name="From a report", data=False)
41
+
42
+ # No SurPyval object — just numbers:
43
+ reliafy.push_params("weibull", [1200.0, 2.3], name="Handbook value", unit="hours")
44
+
45
+ # Self-hosted instance:
46
+ reliafy.configure(token="rlf_...", base_url="https://reliafy.mycompany.com")
47
+ ```
48
+
49
+ Configuration also reads `RELIAFY_TOKEN` and `RELIAFY_BASE_URL` from the
50
+ environment.
51
+
52
+ ## Notes
53
+
54
+ - The token is a personal API token, created on the **API access** page in
55
+ Reliafy. On Reliafy Cloud this is a Pro feature; self-hosted instances have
56
+ it unconditionally.
57
+ - Supported distributions: Weibull, Exponential, Normal, LogNormal, Gamma,
58
+ LogLogistic, Exponentiated Weibull, Gumbel, Logistic.
59
+ - Pure standard library — no dependencies. You bring SurPyval to do the fit.
@@ -0,0 +1,24 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ # Distribution name is reliafy-client (the bare `reliafy` name is taken on
7
+ # PyPI by an unrelated project); the import package stays `import reliafy`.
8
+ name = "reliafy-client"
9
+ version = "0.1.0"
10
+ description = "Push SurPyval models to Reliafy — shareable, trackable, citable reliability analyses."
11
+ readme = "README.md"
12
+ requires-python = ">=3.8"
13
+ license = { text = "AGPL-3.0-or-later" }
14
+ authors = [{ name = "Reliafy" }]
15
+ keywords = ["reliability", "survival-analysis", "weibull", "surpyval", "maintenance"]
16
+ dependencies = [] # stdlib only; SurPyval is optional (yours to fit with)
17
+
18
+ [project.urls]
19
+ Homepage = "https://reliafy.com"
20
+ Source = "https://github.com/Reliafy/reliafy"
21
+ Documentation = "https://github.com/Reliafy/reliafy/blob/main/python/README.md"
22
+
23
+ [tool.setuptools]
24
+ packages = ["reliafy"]
@@ -0,0 +1,173 @@
1
+ """reliafy — push SurPyval models to Reliafy.
2
+
3
+ Build a model in a notebook with SurPyval, then make it a shareable,
4
+ trackable, citable artifact in Reliafy with one call:
5
+
6
+ import surpyval as sp
7
+ import reliafy
8
+
9
+ model = sp.Weibull.fit(x=my_data)
10
+
11
+ reliafy.configure(token="rlf_...") # from the API access page
12
+ url = reliafy.push(model, name="Pump bearings")
13
+ print(url) # open it in the app
14
+
15
+ The token is a personal API token (Reliafy Cloud → API access; a Pro
16
+ feature). Self-hosted instances pass ``base_url`` to point at your server.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import json
22
+ import os
23
+ import urllib.error
24
+ import urllib.request
25
+
26
+ __all__ = ["configure", "push", "push_params", "ReliafyError"]
27
+
28
+ _DEFAULT_BASE = "https://reliafy.com"
29
+
30
+ # SurPyval distribution name -> Reliafy id (the server also resolves these,
31
+ # but mapping here gives a clear error before the network call).
32
+ _DIST_MAP = {
33
+ "Weibull": "weibull",
34
+ "Exponential": "exponential",
35
+ "Normal": "normal",
36
+ "LogNormal": "lognormal",
37
+ "Gamma": "gamma",
38
+ "LogLogistic": "loglogistic",
39
+ "ExpoWeibull": "expo_weibull",
40
+ "Gumbel": "gumbel",
41
+ "Logistic": "logistic",
42
+ }
43
+
44
+ _config = {
45
+ "token": os.environ.get("RELIAFY_TOKEN"),
46
+ "base_url": os.environ.get("RELIAFY_BASE_URL", _DEFAULT_BASE),
47
+ }
48
+
49
+
50
+ class ReliafyError(RuntimeError):
51
+ pass
52
+
53
+
54
+ def configure(token: str | None = None, base_url: str | None = None) -> None:
55
+ """Set the API token and (optionally) the base URL for later calls.
56
+
57
+ Both also read from ``RELIAFY_TOKEN`` / ``RELIAFY_BASE_URL`` in the
58
+ environment.
59
+ """
60
+ if token is not None:
61
+ _config["token"] = token
62
+ if base_url is not None:
63
+ _config["base_url"] = base_url.rstrip("/")
64
+
65
+
66
+ def _dist_name(model) -> str:
67
+ dist = getattr(model, "dist", None)
68
+ name = getattr(dist, "name", None) or type(dist).__name__.rstrip("_")
69
+ if name not in _DIST_MAP:
70
+ raise ReliafyError(
71
+ f"Distribution {name!r} isn't supported by Reliafy import. "
72
+ f"Supported: {', '.join(sorted(_DIST_MAP))}."
73
+ )
74
+ return _DIST_MAP[name]
75
+
76
+
77
+ def _extract(model, include_data: bool):
78
+ """Pull distribution, params, data, and extras off a fitted SurPyval model."""
79
+ body = {
80
+ "distribution": _dist_name(model),
81
+ "params": [{"value": float(v)} for v in list(model.params)],
82
+ }
83
+ extras = {}
84
+ for attr, default in (("gamma", 0.0), ("p", 1.0), ("f0", 0.0)):
85
+ val = getattr(model, attr, None)
86
+ if val is not None and float(val) != default:
87
+ extras[attr] = float(val)
88
+ if extras:
89
+ body["extras"] = extras
90
+ # Also flag the equivalent options so a data-backed refit reproduces them.
91
+ body["options"] = {
92
+ "offset": "gamma" in extras, "lfp": "p" in extras, "zi": "f0" in extras,
93
+ }
94
+
95
+ data = getattr(model, "data", None)
96
+ if include_data and data is not None and data.get("x") is not None:
97
+ out = {"x": [float(v) for v in data["x"]]}
98
+ c = data.get("c")
99
+ if c is not None and any(int(v) != 0 for v in c):
100
+ out["c"] = [int(v) for v in c]
101
+ n = data.get("n")
102
+ if n is not None and any(int(v) != 1 for v in n):
103
+ out["n"] = [int(v) for v in n]
104
+ body["data"] = out
105
+ return body
106
+
107
+
108
+ def _post(payload: dict) -> dict:
109
+ token = _config.get("token")
110
+ if not token:
111
+ raise ReliafyError(
112
+ "No API token. Call reliafy.configure(token='rlf_...') or set "
113
+ "RELIAFY_TOKEN. Create a token on the API access page (Pro)."
114
+ )
115
+ url = _config["base_url"].rstrip("/") + "/api/import/models"
116
+ req = urllib.request.Request(
117
+ url,
118
+ data=json.dumps(payload).encode(),
119
+ headers={"Authorization": f"Bearer {token}", "Content-Type": "application/json"},
120
+ method="POST",
121
+ )
122
+ try:
123
+ with urllib.request.urlopen(req, timeout=60) as resp:
124
+ result = json.loads(resp.read())
125
+ except urllib.error.HTTPError as exc:
126
+ try:
127
+ detail = json.loads(exc.read()).get("detail", exc.reason)
128
+ except Exception:
129
+ detail = exc.reason
130
+ raise ReliafyError(f"Reliafy returned {exc.code}: {detail}") from None
131
+ except urllib.error.URLError as exc:
132
+ raise ReliafyError(f"Couldn't reach Reliafy at {url}: {exc.reason}") from None
133
+ return result
134
+
135
+
136
+ def push(model, name: str, *, data: bool = True, unit: str | None = None) -> str:
137
+ """Push a fitted SurPyval model to Reliafy; return the URL to open it.
138
+
139
+ ``data=True`` (default) uploads the model's fitted observations too, so
140
+ Reliafy shows the full probability plot and the model stays editable and
141
+ refittable. ``data=False`` uploads parameters only.
142
+ """
143
+ if not name or not str(name).strip():
144
+ raise ReliafyError("A name is required.")
145
+ body = _extract(model, include_data=data)
146
+ body["name"] = str(name).strip()
147
+ if unit:
148
+ body["unit"] = unit
149
+ result = _post(body)
150
+ return _config["base_url"].rstrip("/") + result["url"]
151
+
152
+
153
+ def push_params(distribution: str, params, name: str, *, unit: str | None = None,
154
+ extras: dict | None = None) -> str:
155
+ """Push a model by distribution + parameter values (no SurPyval object).
156
+
157
+ ``params`` is a sequence of numbers in the distribution's natural order,
158
+ or a list of ``{"name": ..., "value": ...}`` dicts. ``extras`` may hold
159
+ ``gamma``/``p``/``f0`` for offset/LFP/zero-inflated models.
160
+ """
161
+ norm = []
162
+ for p in params:
163
+ if isinstance(p, dict):
164
+ norm.append({"value": float(p["value"]), **({"name": p["name"]} if "name" in p else {})})
165
+ else:
166
+ norm.append({"value": float(p)})
167
+ body = {"name": str(name).strip(), "distribution": distribution, "params": norm}
168
+ if unit:
169
+ body["unit"] = unit
170
+ if extras:
171
+ body["extras"] = {k: float(v) for k, v in extras.items()}
172
+ result = _post(body)
173
+ return _config["base_url"].rstrip("/") + result["url"]
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: reliafy-client
3
+ Version: 0.1.0
4
+ Summary: Push SurPyval models to Reliafy — shareable, trackable, citable reliability analyses.
5
+ Author: Reliafy
6
+ License: AGPL-3.0-or-later
7
+ Project-URL: Homepage, https://reliafy.com
8
+ Project-URL: Source, https://github.com/Reliafy/reliafy
9
+ Project-URL: Documentation, https://github.com/Reliafy/reliafy/blob/main/python/README.md
10
+ Keywords: reliability,survival-analysis,weibull,surpyval,maintenance
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # reliafy — push SurPyval models to Reliafy
15
+
16
+ Fit a model anywhere with [SurPyval](https://github.com/derrynknife/SurPyval),
17
+ then make it a shareable, trackable, citable artifact in
18
+ [Reliafy](https://reliafy.com) with one call. The notebook is the lab;
19
+ Reliafy is the plant.
20
+
21
+ ```bash
22
+ pip install reliafy-client
23
+ ```
24
+
25
+ (The package installs as `reliafy-client`; you import it as `reliafy`.)
26
+
27
+ ## Quick start
28
+
29
+ ```python
30
+ import surpyval as sp
31
+ import reliafy
32
+
33
+ # Fit however you like — censored data, offsets, whatever.
34
+ model = sp.Weibull.fit(x=failures, c=censoring_flags)
35
+
36
+ reliafy.configure(token="rlf_...") # from Reliafy → API access (Pro)
37
+ url = reliafy.push(model, name="Pump bearings — 2026 refit", unit="hours")
38
+ print(url) # open it in Reliafy
39
+ ```
40
+
41
+ `push()` uploads the model **and its fitted data** by default, so Reliafy
42
+ shows the full probability plot with confidence bounds — and the model stays
43
+ editable and refittable in the app, and can be cited as RCM evidence, used in
44
+ RBD blocks, or tracked against a fleet.
45
+
46
+ Offset / limited-failure-population / zero-inflated fits are detected
47
+ automatically from the model and reproduced.
48
+
49
+ ## Options
50
+
51
+ ```python
52
+ # Parameters only (no data upload): functions & life metrics, no plot.
53
+ reliafy.push(model, name="From a report", data=False)
54
+
55
+ # No SurPyval object — just numbers:
56
+ reliafy.push_params("weibull", [1200.0, 2.3], name="Handbook value", unit="hours")
57
+
58
+ # Self-hosted instance:
59
+ reliafy.configure(token="rlf_...", base_url="https://reliafy.mycompany.com")
60
+ ```
61
+
62
+ Configuration also reads `RELIAFY_TOKEN` and `RELIAFY_BASE_URL` from the
63
+ environment.
64
+
65
+ ## Notes
66
+
67
+ - The token is a personal API token, created on the **API access** page in
68
+ Reliafy. On Reliafy Cloud this is a Pro feature; self-hosted instances have
69
+ it unconditionally.
70
+ - Supported distributions: Weibull, Exponential, Normal, LogNormal, Gamma,
71
+ LogLogistic, Exponentiated Weibull, Gumbel, Logistic.
72
+ - Pure standard library — no dependencies. You bring SurPyval to do the fit.
@@ -0,0 +1,7 @@
1
+ README.md
2
+ pyproject.toml
3
+ reliafy/__init__.py
4
+ reliafy_client.egg-info/PKG-INFO
5
+ reliafy_client.egg-info/SOURCES.txt
6
+ reliafy_client.egg-info/dependency_links.txt
7
+ reliafy_client.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+