PyObservability 0.0.0a2__py3-none-any.whl → 0.0.1__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.
@@ -0,0 +1,6 @@
1
+ from enum import StrEnum
2
+
3
+
4
+ class APIEndpoints(StrEnum):
5
+ root = "/"
6
+ ws = "/ws"
@@ -1,10 +1,12 @@
1
1
  import json
2
+ import os
2
3
  import pathlib
3
4
  import socket
4
5
  from typing import List
5
6
 
6
7
  import yaml
7
- from pydantic import BaseModel, HttpUrl, PositiveInt
8
+ from pydantic import BaseModel, Field, HttpUrl, PositiveInt
9
+ from pydantic.aliases import AliasChoices
8
10
  from pydantic_settings import BaseSettings
9
11
 
10
12
 
@@ -34,6 +36,19 @@ class MonitorTarget(BaseModel):
34
36
  apikey: str
35
37
 
36
38
 
39
+ def alias_choices(variable: str) -> AliasChoices:
40
+ """Custom alias choices for environment variables for GitHub.
41
+
42
+ Args:
43
+ variable: Variable name.
44
+
45
+ Returns:
46
+ AliasChoices:
47
+ Returns the alias choices for the variable.
48
+ """
49
+ return AliasChoices(variable, f"MONITOR_{variable}")
50
+
51
+
37
52
  class EnvConfig(PydanticEnvConfig):
38
53
  """Configuration settings for the server.
39
54
 
@@ -41,11 +56,14 @@ class EnvConfig(PydanticEnvConfig):
41
56
 
42
57
  """
43
58
 
44
- host: str = socket.gethostbyname("localhost") or "0.0.0.0"
45
- port: PositiveInt = 8080
59
+ host: str = Field(socket.gethostbyname("localhost") or "0.0.0.0", validation_alias=alias_choices("HOST"))
60
+ port: PositiveInt = Field(8080, validation_alias=alias_choices("PORT"))
61
+
62
+ targets: List[MonitorTarget] = Field(..., validation_alias=alias_choices("TARGETS"))
63
+ interval: PositiveInt = Field(3, validation_alias=alias_choices("INTERVAL"))
46
64
 
47
- monitor_targets: List[MonitorTarget]
48
- poll_interval: PositiveInt = 3
65
+ username: str | None = Field(None, validation_alias=alias_choices("USERNAME"))
66
+ password: str | None = Field(None, validation_alias=alias_choices("PASSWORD"))
49
67
 
50
68
  class Config:
51
69
  """Environment variables configuration."""
@@ -79,28 +97,27 @@ def env_loader(**kwargs) -> EnvConfig:
79
97
  if not kwargs:
80
98
  return EnvConfig.from_env_file(".env")
81
99
  # Look for the kwarg env_file and process accordingly
82
- if env_file := kwargs.get("env_file"):
100
+ if env_file := kwargs.get("env_file") or os.getenv("env_file"):
83
101
  env_file = pathlib.Path(env_file)
84
102
  assert env_file.is_file(), f"\n\tenv_file: [{env_file.resolve()!r}] does not exist"
85
103
  if env_file.suffix.lower() == ".json":
86
104
  with env_file.open() as stream:
87
105
  env_data = json.load(stream)
88
106
  return EnvConfig(**{k.lower(): v for k, v in env_data.items()})
89
- elif env_file.suffix.lower() in (".yaml", ".yml"):
107
+ if env_file.suffix.lower() in (".yaml", ".yml"):
90
108
  with env_file.open() as stream:
91
109
  env_data = yaml.load(stream, yaml.FullLoader)
92
110
  return EnvConfig(**{k.lower(): v for k, v in env_data.items()})
93
- elif not env_file.suffix or env_file.suffix.lower() in (
111
+ if not env_file.suffix or env_file.suffix.lower() in (
94
112
  ".text",
95
113
  ".txt",
96
114
  ".env",
97
115
  "",
98
116
  ):
99
117
  return EnvConfig.from_env_file(env_file)
100
- else:
101
- raise ValueError(
102
- f"\n\tUnsupported format for {env_file!r}, " "can be one of (.json, .yaml, .yml, .txt, .text, .env)"
103
- )
118
+ raise ValueError(
119
+ f"\n\tUnsupported format for {env_file!r}, " "can be one of (.json, .yaml, .yml, .txt, .text, .env)"
120
+ )
104
121
  # Load env config with regular kwargs
105
122
  return EnvConfig(**kwargs)
106
123
 
pyobservability/main.py CHANGED
@@ -1,13 +1,15 @@
1
1
  import logging
2
2
  import pathlib
3
+ import warnings
3
4
 
5
+ import uiauth
4
6
  import uvicorn
5
7
  from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
6
8
  from fastapi.routing import APIRoute, APIWebSocketRoute
7
9
  from fastapi.staticfiles import StaticFiles
8
10
  from fastapi.templating import Jinja2Templates
9
11
 
10
- from pyobservability.config import settings
12
+ from pyobservability.config import enums, settings
11
13
  from pyobservability.monitor import Monitor
12
14
 
13
15
  LOGGER = logging.getLogger("uvicorn.default")
@@ -59,20 +61,41 @@ async def websocket_endpoint(websocket: WebSocket):
59
61
  await monitor.stop()
60
62
 
61
63
 
62
- PyObservability.routes.append(
63
- APIRoute(
64
- path="/", # enums.APIEndpoints.root,
65
- endpoint=index,
66
- methods=["GET"],
67
- include_in_schema=False,
68
- ),
69
- )
70
- PyObservability.routes.append(
71
- APIWebSocketRoute(
72
- path="/ws",
73
- endpoint=websocket_endpoint,
74
- )
75
- )
64
+ def include_routes():
65
+ if all((settings.env.username, settings.env.password)):
66
+ uiauth.protect(
67
+ app=PyObservability,
68
+ username=settings.env.username,
69
+ password=settings.env.password,
70
+ params=[
71
+ uiauth.Parameters(
72
+ path=enums.APIEndpoints.root,
73
+ function=index,
74
+ methods=["GET"],
75
+ ),
76
+ uiauth.Parameters(
77
+ path=enums.APIEndpoints.ws,
78
+ function=websocket_endpoint,
79
+ route=APIWebSocketRoute,
80
+ ),
81
+ ],
82
+ )
83
+ else:
84
+ warnings.warn("\n\tRunning PyObservability without any protection.", UserWarning)
85
+ PyObservability.routes.append(
86
+ APIRoute(
87
+ path=enums.APIEndpoints.root,
88
+ endpoint=index,
89
+ methods=["GET"],
90
+ include_in_schema=False,
91
+ ),
92
+ )
93
+ PyObservability.routes.append(
94
+ APIWebSocketRoute(
95
+ path=enums.APIEndpoints.ws,
96
+ endpoint=websocket_endpoint,
97
+ )
98
+ )
76
99
 
77
100
 
78
101
  def start(**kwargs):
@@ -80,6 +103,7 @@ def start(**kwargs):
80
103
  settings.env.monitor_targets = [
81
104
  {k: str(v) for k, v in target.model_dump().items()} for target in settings.env.monitor_targets
82
105
  ]
106
+ include_routes()
83
107
  uvicorn_args = dict(
84
108
  host=settings.env.host,
85
109
  port=settings.env.port,
@@ -1 +1 @@
1
- __version__ = "0.0.0a2"
1
+ __version__ = "0.0.1"
@@ -0,0 +1,163 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyObservability
3
+ Version: 0.0.1
4
+ Summary: Lightweight OS-agnostic observability UI for PyNinja
5
+ Author-email: Vignesh Rao <svignesh1793@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 TheVickypedia
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/thevickypedia/PyObservability
29
+ Project-URL: Docs, https://thevickypedia.github.io/PyObservability
30
+ Project-URL: Source, https://github.com/thevickypedia/PyObservability
31
+ Project-URL: Bug Tracker, https://github.com/thevickypedia/PyObservability/issues
32
+ Project-URL: Release Notes, https://github.com/thevickypedia/PyObservability/blob/main/release_notes.rst
33
+ Keywords: PyObservability,observability,system-monitor,PyNinja
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Development Status :: 3 - Alpha
37
+ Classifier: Operating System :: MacOS :: MacOS X
38
+ Classifier: Operating System :: Microsoft :: Windows
39
+ Classifier: Operating System :: POSIX :: Linux
40
+ Classifier: Topic :: System :: Monitoring
41
+ Requires-Python: >=3.11
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: aiohttp==3.13.*
45
+ Requires-Dist: fastapi==0.122.*
46
+ Requires-Dist: FastAPI-UI-Auth==0.2.1
47
+ Requires-Dist: Jinja2==3.1.*
48
+ Requires-Dist: pydantic==2.12.*
49
+ Requires-Dist: pydantic-settings==2.12.*
50
+ Requires-Dist: python-dotenv==1.2.*
51
+ Requires-Dist: uvicorn[standard]==0.38.*
52
+ Provides-Extra: dev
53
+ Requires-Dist: sphinx==5.1.1; extra == "dev"
54
+ Requires-Dist: pre-commit; extra == "dev"
55
+ Requires-Dist: recommonmark; extra == "dev"
56
+ Requires-Dist: gitverse; extra == "dev"
57
+ Dynamic: license-file
58
+
59
+ # PyObservability
60
+
61
+ ![Python][label-pyversion]
62
+
63
+ **Platform Supported**
64
+
65
+ ![Platform][label-platform]
66
+
67
+ **Deployments**
68
+
69
+ [![pypi][label-actions-pypi]][gha_pypi]
70
+ [![notes][label-actions-notes]][gha_notes]
71
+ [![release][label-actions-release]][gha_release]
72
+
73
+ [![Pypi][label-pypi]][pypi]
74
+ [![Pypi-format][label-pypi-format]][pypi-files]
75
+ [![Pypi-status][label-pypi-status]][pypi]
76
+
77
+ ## Kick off
78
+
79
+ **Recommendations**
80
+
81
+ - Install `python` [3.11] or above
82
+ - Use a dedicated [virtual environment]
83
+
84
+ **Install PyObservability**
85
+ ```shell
86
+ python -m pip install pyobservability
87
+ ```
88
+
89
+ **Initiate - IDE**
90
+ ```python
91
+ import pyobservability
92
+
93
+
94
+ if __name__ == '__main__':
95
+ pyobservability.start()
96
+ ```
97
+
98
+ **Initiate - CLI**
99
+ ```shell
100
+ pyobservability start
101
+ ```
102
+
103
+ > Use `pyobservability --help` for usage instructions.
104
+
105
+ ## Environment Variables
106
+
107
+ <details>
108
+ <summary><strong>Sourcing environment variables from an env file</strong></summary>
109
+
110
+ > _By default, `PyObservability` will look for a `.env` file in the current working directory._
111
+ > _Other file options are supported with a custom kwarg or env var `env_file` pointing to the filepath._
112
+ </details>
113
+
114
+ **Mandatory**
115
+ - **TARGETS** - Target URLs running `PyNinja` in the following format.
116
+ - `TARGETS='[{"name":"node1","base_url":"http://192.168.1.10:8000","apikey":"token1"},{"name":"node2","base_url":"http://192.168.1.11:8000"}]'`
117
+
118
+ **Defaults**
119
+ - **HOST** - Host IP to run PyObservability. Defaults to `127.0.0.1` or `0.0.0.0`
120
+ - **PORT** - Port number to run PyObservability. Defaults to `8080`
121
+ - **INTERVAL** - Polling interval to retrieve server information.
122
+
123
+ **Optional**
124
+ - **USERNAME** - Username to authenticate the monitoring page.
125
+ - **PASSWORD** - Password to authenticate the monitoring page.
126
+
127
+ ## License & copyright
128
+
129
+ &copy; Vignesh Rao
130
+
131
+ Licensed under the [MIT License][license]
132
+
133
+ [//]: # (Labels)
134
+
135
+ [label-pypi-package]: https://img.shields.io/badge/Pypi%20Package-pyobservability-blue?style=for-the-badge&logo=Python
136
+ [label-sphinx-doc]: https://img.shields.io/badge/Made%20with-Sphinx-blue?style=for-the-badge&logo=Sphinx
137
+ [label-pyversion]: https://img.shields.io/badge/python-3.11%20%7C%203.12-blue
138
+ [label-platform]: https://img.shields.io/badge/Platform-Linux|macOS|Windows-1f425f.svg
139
+ [label-actions-pypi]: https://github.com/thevickypedia/PyObservability/actions/workflows/python-publish.yml/badge.svg
140
+ [label-pypi]: https://img.shields.io/pypi/v/PyObservability
141
+ [label-pypi-format]: https://img.shields.io/pypi/format/PyObservability
142
+ [label-pypi-status]: https://img.shields.io/pypi/status/PyObservability
143
+ [label-actions-notes]: https://github.com/thevickypedia/PyObservability/actions/workflows/notes.yml/badge.svg
144
+ [label-actions-release]: https://github.com/thevickypedia/PyObservability/actions/workflows/release.yml/badge.svg
145
+
146
+ [3.11]: https://docs.python.org/3/whatsnew/3.11.html
147
+ [virtual environment]: https://docs.python.org/3/tutorial/venv.html
148
+ [release-notes]: https://github.com/thevickypedia/PyObservability/blob/main/release_notes.rst
149
+ [gha_pypi]: https://github.com/thevickypedia/PyObservability/actions/workflows/python-publish.yml
150
+ [gha_notes]: https://github.com/thevickypedia/PyObservability/actions/workflows/notes.yml
151
+ [gha_release]: https://github.com/thevickypedia/PyObservability/actions/workflows/release.yml
152
+ [google-docs]: https://google.github.io/styleguide/pyguide.html#38-comments-and-docstrings
153
+ [pep8]: https://www.python.org/dev/peps/pep-0008/
154
+ [isort]: https://pycqa.github.io/isort/
155
+ [sphinx]: https://www.sphinx-doc.org/en/master/man/sphinx-autogen.html
156
+ [pypi]: https://pypi.org/project/PyObservability
157
+ [pypi-files]: https://pypi.org/project/PyObservability/#files
158
+ [pypi-repo]: https://packaging.python.org/tutorials/packaging-projects/
159
+ [license]: https://github.com/thevickypedia/PyObservability/blob/main/LICENSE
160
+ [runbook]: https://thevickypedia.github.io/PyObservability/
161
+ [samples]: https://github.com/thevickypedia/PyObservability/tree/main/samples
162
+ [PyUdisk]: https://github.com/thevickypedia/PyUdisk
163
+ [PyArchitecture]: https://github.com/thevickypedia/PyArchitecture
@@ -0,0 +1,15 @@
1
+ pyobservability/__init__.py,sha256=rr4udGMbbNPl3yo7l8R3FUUVVahBtYVaW6vSWWgXlv0,2617
2
+ pyobservability/main.py,sha256=5_c4Q2D5EgUTQgs6kULBpn0O8dF_k7LacdQhPq1qHnk,3451
3
+ pyobservability/monitor.py,sha256=s2sVp97sLjkkdtL6be82bX5ydu_gBdMSoWxDlmUtpgE,6613
4
+ pyobservability/version.py,sha256=sXLh7g3KC4QCFxcZGBTpG2scR7hmmBsMjq6LqRptkRg,22
5
+ pyobservability/config/enums.py,sha256=iMIOpa8LYSszkPIYBhupX--KrEXVTTsBurinpAxLvMA,86
6
+ pyobservability/config/settings.py,sha256=3nPvA-GsmtunUIGcroHqwgSvQ24TmIdINs-QRD_dg2s,3737
7
+ pyobservability/static/app.js,sha256=poc7eReoiRUbyI5JKnPwxSqmSNCuOge4aZKCITFy7eo,13494
8
+ pyobservability/static/styles.css,sha256=t6r1C0ueBanipgRRjdu18nmq6RbSGLK5bhpf0BdMOpQ,3245
9
+ pyobservability/templates/index.html,sha256=PsN3aq-7Q6RzGeshoNH5v37G3sHoI2saJq6mfuA6JYs,3977
10
+ pyobservability-0.0.1.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
11
+ pyobservability-0.0.1.dist-info/METADATA,sha256=BQ4Z6EbkaRWOaY1oc4rf3wpulGoYtUhIfEPDBdCDYBU,6822
12
+ pyobservability-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
13
+ pyobservability-0.0.1.dist-info/entry_points.txt,sha256=DSGIr_VA8Tb3FYa2iNUYpf55eAvuFCAoInNS4ngXaME,57
14
+ pyobservability-0.0.1.dist-info/top_level.txt,sha256=p20T0EmihDYW1uMintRXr7X9bg3XWYKyoSbBHOVC1xI,16
15
+ pyobservability-0.0.1.dist-info/RECORD,,
@@ -1,58 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: PyObservability
3
- Version: 0.0.0a2
4
- Summary: Lightweight OS-agnostic observability UI for PyNinja
5
- Author-email: Vignesh Rao <svignesh1793@gmail.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2025 TheVickypedia
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Project-URL: Homepage, https://github.com/thevickypedia/PyObservability
29
- Project-URL: Docs, https://thevickypedia.github.io/PyObservability
30
- Project-URL: Source, https://github.com/thevickypedia/PyObservability
31
- Project-URL: Bug Tracker, https://github.com/thevickypedia/PyObservability/issues
32
- Project-URL: Release Notes, https://github.com/thevickypedia/PyObservability/blob/main/release_notes.rst
33
- Keywords: PyObservability,observability,system-monitor,PyNinja
34
- Classifier: License :: OSI Approved :: MIT License
35
- Classifier: Programming Language :: Python :: 3
36
- Classifier: Development Status :: 3 - Alpha
37
- Classifier: Operating System :: MacOS :: MacOS X
38
- Classifier: Operating System :: Microsoft :: Windows
39
- Classifier: Operating System :: POSIX :: Linux
40
- Classifier: Topic :: System :: Monitoring
41
- Requires-Python: >=3.11
42
- Description-Content-Type: text/markdown
43
- License-File: LICENSE
44
- Requires-Dist: aiohttp==3.13.*
45
- Requires-Dist: fastapi==0.122.*
46
- Requires-Dist: Jinja2==3.1.*
47
- Requires-Dist: pydantic==2.12.*
48
- Requires-Dist: pydantic-settings==2.12.*
49
- Requires-Dist: python-dotenv==1.2.*
50
- Requires-Dist: uvicorn[standard]==0.38.*
51
- Provides-Extra: dev
52
- Requires-Dist: sphinx==5.1.1; extra == "dev"
53
- Requires-Dist: pre-commit; extra == "dev"
54
- Requires-Dist: recommonmark; extra == "dev"
55
- Requires-Dist: gitverse; extra == "dev"
56
- Dynamic: license-file
57
-
58
- # PyObservability
@@ -1,14 +0,0 @@
1
- pyobservability/__init__.py,sha256=rr4udGMbbNPl3yo7l8R3FUUVVahBtYVaW6vSWWgXlv0,2617
2
- pyobservability/main.py,sha256=m3jNBQ7B495d1Pk_Fcdy3AQbNts2K8iFwDQDKV1pB0M,2527
3
- pyobservability/monitor.py,sha256=s2sVp97sLjkkdtL6be82bX5ydu_gBdMSoWxDlmUtpgE,6613
4
- pyobservability/version.py,sha256=za-UuO_D1PzxYCprpyh75AnwaFhntPuAZpHRqS1fIxc,24
5
- pyobservability/config/settings.py,sha256=53dYdfO5SbmHQ4cLzPM2JQvrU2Lw70vBghlhiLy28ZI,3013
6
- pyobservability/static/app.js,sha256=poc7eReoiRUbyI5JKnPwxSqmSNCuOge4aZKCITFy7eo,13494
7
- pyobservability/static/styles.css,sha256=t6r1C0ueBanipgRRjdu18nmq6RbSGLK5bhpf0BdMOpQ,3245
8
- pyobservability/templates/index.html,sha256=PsN3aq-7Q6RzGeshoNH5v37G3sHoI2saJq6mfuA6JYs,3977
9
- pyobservability-0.0.0a2.dist-info/licenses/LICENSE,sha256=_sOIKJWdD2o1WwwDIwYB2qTP2nlSWqT5Tyg9jr1Xa4w,1070
10
- pyobservability-0.0.0a2.dist-info/METADATA,sha256=y74dxaDkt1pTwgqFmkNj7bemJqOPqKUjfHBHPwWh0UA,2775
11
- pyobservability-0.0.0a2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
- pyobservability-0.0.0a2.dist-info/entry_points.txt,sha256=DSGIr_VA8Tb3FYa2iNUYpf55eAvuFCAoInNS4ngXaME,57
13
- pyobservability-0.0.0a2.dist-info/top_level.txt,sha256=p20T0EmihDYW1uMintRXr7X9bg3XWYKyoSbBHOVC1xI,16
14
- pyobservability-0.0.0a2.dist-info/RECORD,,