Nexom 0.1.4__py3-none-any.whl → 1.0.2__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.
Files changed (67) hide show
  1. nexom/__init__.py +2 -2
  2. nexom/__main__.py +111 -17
  3. nexom/app/__init__.py +62 -0
  4. nexom/app/auth.py +322 -0
  5. nexom/{web → app}/cookie.py +4 -2
  6. nexom/app/db.py +88 -0
  7. nexom/app/path.py +195 -0
  8. nexom/app/request.py +267 -0
  9. nexom/{web → app}/response.py +13 -3
  10. nexom/{web → app}/template.py +1 -1
  11. nexom/app/user.py +31 -0
  12. nexom/assets/app/__init__.py +0 -0
  13. nexom/assets/app/__pycache__/__init__.cpython-313.pyc +0 -0
  14. nexom/assets/app/config.py +28 -0
  15. nexom/assets/app/gunicorn.conf.py +5 -0
  16. nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc +0 -0
  17. nexom/assets/app/pages/_templates.py +7 -0
  18. nexom/assets/{server → app}/pages/default.py +2 -2
  19. nexom/assets/{server → app}/pages/document.py +2 -2
  20. nexom/assets/app/router.py +12 -0
  21. nexom/assets/app/wsgi.py +64 -0
  22. nexom/assets/auth/__init__.py +0 -0
  23. nexom/assets/auth/__pycache__/__init__.cpython-313.pyc +0 -0
  24. nexom/assets/auth/config.py +27 -0
  25. nexom/assets/auth/gunicorn.conf.py +5 -0
  26. nexom/assets/auth/wsgi.py +62 -0
  27. nexom/assets/auth_page/login.html +95 -0
  28. nexom/assets/auth_page/signup.html +106 -0
  29. nexom/assets/error_page/error.html +3 -3
  30. nexom/assets/gateway/apache_app.conf +16 -0
  31. nexom/assets/gateway/nginx_app.conf +21 -0
  32. nexom/buildTools/__init__.py +1 -0
  33. nexom/buildTools/build.py +274 -54
  34. nexom/buildTools/run.py +185 -0
  35. nexom/core/__init__.py +2 -1
  36. nexom/core/error.py +81 -3
  37. nexom/core/log.py +111 -0
  38. nexom/{engine → core}/object_html_render.py +4 -1
  39. nexom/templates/__init__.py +0 -0
  40. nexom/templates/auth.py +72 -0
  41. {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/METADATA +76 -50
  42. nexom-1.0.2.dist-info/RECORD +56 -0
  43. {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/WHEEL +1 -1
  44. nexom/assets/server/config.py +0 -27
  45. nexom/assets/server/gunicorn.conf.py +0 -16
  46. nexom/assets/server/pages/__pycache__/__init__.cpython-313.pyc +0 -0
  47. nexom/assets/server/pages/_templates.py +0 -11
  48. nexom/assets/server/router.py +0 -18
  49. nexom/assets/server/wsgi.py +0 -30
  50. nexom/engine/__init__.py +0 -1
  51. nexom/web/__init__.py +0 -5
  52. nexom/web/path.py +0 -125
  53. nexom/web/request.py +0 -62
  54. nexom-0.1.4.dist-info/RECORD +0 -39
  55. /nexom/{web → app}/http_status_codes.py +0 -0
  56. /nexom/{web → app}/middleware.py +0 -0
  57. /nexom/assets/{server → app}/pages/__init__.py +0 -0
  58. /nexom/assets/{server → app}/static/dog.jpeg +0 -0
  59. /nexom/assets/{server → app}/static/style.css +0 -0
  60. /nexom/assets/{server → app}/templates/base.html +0 -0
  61. /nexom/assets/{server → app}/templates/default.html +0 -0
  62. /nexom/assets/{server → app}/templates/document.html +0 -0
  63. /nexom/assets/{server → app}/templates/footer.html +0 -0
  64. /nexom/assets/{server → app}/templates/header.html +0 -0
  65. {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/entry_points.txt +0 -0
  66. {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/licenses/LICENSE +0 -0
  67. {nexom-0.1.4.dist-info → nexom-1.0.2.dist-info}/top_level.txt +0 -0
nexom/core/log.py ADDED
@@ -0,0 +1,111 @@
1
+ from __future__ import annotations
2
+
3
+ import traceback
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+
7
+
8
+ # =========================
9
+ # App Logger
10
+ # =========================
11
+
12
+ class AppLogger:
13
+ """
14
+ Application-level logger.
15
+
16
+ Used for:
17
+ - info
18
+ - warn
19
+ - error
20
+ - access
21
+ """
22
+
23
+ def __init__(
24
+ self,
25
+ *,
26
+ info: str | Path | None = None,
27
+ warn: str | Path | None = None,
28
+ error: str | Path | None = None,
29
+ access: str | Path | None = None,
30
+ ) -> None:
31
+ self.info_path = self._norm(info)
32
+ self.warn_path = self._norm(warn)
33
+ self.error_path = self._norm(error)
34
+ self.access_path = self._norm(access)
35
+
36
+ def info(self, msg: str) -> None:
37
+ self._write(self.info_path, "INFO", msg)
38
+
39
+ def warn(self, msg: str) -> None:
40
+ self._write(self.warn_path, "WARN", msg)
41
+
42
+ def error(self, err: Exception | str) -> None:
43
+ if isinstance(err, Exception):
44
+ msg = "".join(traceback.format_exception(err))
45
+ else:
46
+ msg = str(err)
47
+ self._write(self.error_path, "ERROR", msg)
48
+
49
+ def access(self, msg: str) -> None:
50
+ self._write(self.access_path, "ACCESS", msg)
51
+
52
+ # ---------- internal ----------
53
+
54
+ def _norm(self, path: str | Path | None) -> Path | None:
55
+ if not path:
56
+ return None
57
+ p = Path(path)
58
+ p.parent.mkdir(parents=True, exist_ok=True)
59
+ return p
60
+
61
+ def _write(self, path: Path | None, level: str, msg: str) -> None:
62
+ if path is None:
63
+ return
64
+
65
+ ts = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
66
+ line = f"[{ts}] [{level}] {msg}\n"
67
+
68
+ with path.open("a", encoding="utf-8") as f:
69
+ f.write(line)
70
+
71
+
72
+ # =========================
73
+ # Auth Logger
74
+ # =========================
75
+
76
+ class AuthLogger:
77
+ """
78
+ Authentication / Security logger.
79
+
80
+ Used for:
81
+ - login success / failure
82
+ - signup
83
+ - token verification failure
84
+ """
85
+
86
+ def __init__(self, path: str | Path) -> None:
87
+ self.path = Path(path)
88
+ self.path.parent.mkdir(parents=True, exist_ok=True)
89
+
90
+ def login_success(self, *, user_id: str, ip: str | None = None) -> None:
91
+ self._write("LOGIN_OK", user_id, ip)
92
+
93
+ def login_failed(self, *, user_id: str, ip: str | None = None) -> None:
94
+ self._write("LOGIN_NG", user_id, ip)
95
+
96
+ def signup(self, *, user_id: str, ip: str | None = None) -> None:
97
+ self._write("SIGNUP", user_id, ip)
98
+
99
+ def token_invalid(self, *, token: str | None, ip: str | None = None) -> None:
100
+ t = token[:8] + "..." if token else "none"
101
+ self._write("TOKEN_INVALID", t, ip)
102
+
103
+ # ---------- internal ----------
104
+
105
+ def _write(self, action: str, subject: str, ip: str | None) -> None:
106
+ ts = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")
107
+ ip_txt = ip or "-"
108
+ line = f"[{ts}] [{action}] subject={subject} ip={ip_txt}\n"
109
+
110
+ with self.path.open("a", encoding="utf-8") as f:
111
+ f.write(line)
@@ -17,11 +17,12 @@ import re
17
17
  from collections import UserList
18
18
  from typing import Final
19
19
 
20
- from ..core.error import (
20
+ from .error import (
21
21
  HTMLDocLibNotFoundError,
22
22
  ObjectHTMLImportError,
23
23
  ObjectHTMLInsertValueError,
24
24
  ObjectHTMLExtendsError,
25
+ ObjectHTMLTypeError
25
26
  )
26
27
 
27
28
 
@@ -90,6 +91,8 @@ class ObjectHTML:
90
91
  self._set_doc(doc)
91
92
 
92
93
  def _set_doc(self, doc: HTMLDoc) -> None:
94
+ if not isinstance(doc, HTMLDoc):
95
+ raise ObjectHTMLTypeError()
93
96
  def _call(**kwargs: str) -> str:
94
97
  return self.render(doc.name, **kwargs)
95
98
 
File without changes
@@ -0,0 +1,72 @@
1
+ # src/nexom/templates/auth.py
2
+ from __future__ import annotations
3
+
4
+ from importlib import resources
5
+
6
+ from ..app.auth import AuthClient
7
+ from ..app.request import Request
8
+ from ..app.response import HtmlResponse, JsonResponse
9
+ from ..core.object_html_render import HTMLDoc, ObjectHTML
10
+
11
+ from ..core.error import NexomError
12
+
13
+ # --------------------
14
+ # Object HTML
15
+ # --------------------
16
+
17
+ _OHTML: ObjectHTML = ObjectHTML(
18
+ HTMLDoc(
19
+ "signup",
20
+ resources.files("nexom.assets.auth_page").joinpath("signup.html").read_text(encoding="utf-8"),
21
+ ),
22
+ HTMLDoc(
23
+ "login",
24
+ resources.files("nexom.assets.auth_page").joinpath("login.html").read_text(encoding="utf-8"),
25
+ ),
26
+ )
27
+
28
+
29
+ # --------------------
30
+ # Pages
31
+ # --------------------
32
+
33
+ class LoginPage:
34
+ def __init__(self, auth_server: str) -> None:
35
+ self.client = AuthClient(auth_server)
36
+
37
+ def page(self, req: Request, args: dict) -> HtmlResponse | JsonResponse:
38
+ if req.method == "GET":
39
+ return HtmlResponse(_OHTML.render("login"))
40
+
41
+ try:
42
+ data = req.json() or {}
43
+ token, user_id, exp = self.client.login(
44
+ user_id=data.get("user_id", ""),
45
+ password=data.get("password", ""),
46
+ )
47
+ return JsonResponse({"ok": True, "user_id": user_id, "token": token, "expires_at": exp})
48
+ except NexomError as e:
49
+ return JsonResponse({"error": e.code}, status=401)
50
+ except Exception:
51
+ return JsonResponse({"error": "Internal Server Error"}, status=401)
52
+
53
+ class SignupPage:
54
+ def __init__(self, auth_server: str) -> None:
55
+ self.client = AuthClient(auth_server)
56
+
57
+ def page(self, req: Request, args: dict) -> HtmlResponse | JsonResponse:
58
+ if req.method == "GET":
59
+ return HtmlResponse(_OHTML.render("signup"))
60
+
61
+ try:
62
+ data = req.json() or {}
63
+ ok = self.client.signup(
64
+ user_id=data.get("user_id", ""),
65
+ public_name=data.get("public_name", ""),
66
+ password=data.get("password", ""),
67
+ )
68
+ return JsonResponse({"ok": ok})
69
+ except NexomError as e:
70
+ return JsonResponse({"error": e.code}, status=401)
71
+ except Exception:
72
+ return JsonResponse({"error": "Internal Server Error"}, status=401)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: Nexom
3
- Version: 0.1.4
3
+ Version: 1.0.2
4
4
  Summary: Lightweight Python Web Framework (WSGI)
5
5
  Author: TouriAida
6
6
  License: MIT License
@@ -32,6 +32,7 @@ Keywords: wsgi,web,framework
32
32
  Requires-Python: >=3.10
33
33
  Description-Content-Type: text/markdown
34
34
  License-File: LICENSE
35
+ Requires-Dist: typing-extensions; python_version < "3.12"
35
36
  Dynamic: license-file
36
37
 
37
38
 
@@ -44,64 +45,96 @@ Nexomは短いコードで最低限動作し、シンプルで理解のしやす
44
45
  ## はじめる
45
46
  最初のサーバーを起動するには、3つの手順が必要です。
46
47
 
47
- 1. ディレクトリを作成
48
- 2. nexomをpipでインストール、サーバーのビルド
48
+ 1. プロジェクトディレクトリを作成
49
+ 2. nexomをpipでインストール、プロジェクトのビルド
49
50
  3. 起動
50
51
 
51
- ### 1.ディレクトリの作成
52
+ ### 1.プロジェクトディレクトリの作成
52
53
  **準備**
53
- 用意していない場合はディレクトリを作成し、仮想環境も準備てください
54
+
55
+ 用意していない場合はディレクトリを作成し、仮想環境も準備してください
54
56
  ```
55
- mkdir sample
56
- cd sample
57
+ mkdir banana_project
58
+ cd banana_project
57
59
 
58
60
  python -m venv venv
59
61
  source venv/bin/activate
60
62
  ```
61
- ### 2.npipでインストール、サーバーのビルド
63
+ ### 2. pipでインストール、サーバーのビルド
62
64
  **インストール**
65
+
63
66
  nexomをインストールします。
64
- ※まだベータ版のため、最新のバージョンを確認してください。
65
67
  ```
66
- pip install nexom==0.1.4
68
+ pip install
67
69
  ```
68
- **テンプレートサーバーのビルド**
69
- サーバーを置きたいディレクトリ上で、以下のコマンドを実行してください(sampleは自由)
70
+ **プロジェクトのビルド**
71
+
72
+ プロジェクトディレクトリ上で、以下のコマンドを実行してください(名前は自由)
73
+ もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
74
+
75
+ ```
76
+ $ python -m nexom start-project
77
+ ```
78
+
79
+ 以下の構成でプロジェクトが生成されます。
80
+
70
81
  ```
71
- python -m nexom build-server sample
82
+ banana_project/
83
+ ├─ app/
84
+ │ ├─ pages/
85
+ │ │ ├─ __init__.py
86
+ │ │ ├─ _templates.py
87
+ │ │ └─ * pages *
88
+ │ ├─ static/
89
+ │ │ └─ * static items *
90
+ │ ├─ templates/
91
+ │ │ └─ * html files *
92
+ │ ├─ __init__.py
93
+ │ ├─ config.py
94
+ │ ├─ gunicorn.conf.py
95
+ │ ├─ router.py
96
+ │ └─ wsgi.py
97
+ ├─ auth/
98
+ │ ├─ __init__.py
99
+ │ ├─ config.py
100
+ │ ├─ gunicorn.conf.py
101
+ │ └─ wsgi.py
102
+ └─ data/
103
+ ├─ log/
104
+ │ └─ * app logs *
105
+ ├─ db/
106
+ │ └─ * app db *
107
+ └─ gateway/
108
+ ├─ app.nginx.conf
109
+ └─ app.apache.conf
72
110
  ```
73
111
 
74
112
  ### 3.起動
75
113
  以下のコマンドを起動します。
76
114
  ```
77
- gunicorn wsgi:app
115
+ $ python -m nexom run
78
116
  ```
79
117
  ブラウザからアクセスできるようになります。
80
118
  デフォルトのポートは8080です。
81
- [httpls://localhost:8080](httpls://localhost:8080)
119
+
120
+ [https://localhost:8080](https://localhost:8080)
121
+
82
122
  ポートなどの設定は `config.py` から変更してください。
83
123
 
84
124
  ## Nginx等使用して外部公開する
85
- `config.py` で指定したポートにプロキシしてください。
125
+ gatewayディレクトリにある設定を読み込んでください
86
126
  ```
87
- server {
88
- listen 443 ssl;
89
- server_name nexom.ceez7.com;
90
-
91
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
-
93
- location / {
94
- proxy_pass http://localhost:8080;
95
- }
127
+ http {
128
+ include /home/ubuntu/banana_project/gateway/*.conf;
96
129
  }
97
130
  ```
98
131
 
99
132
  ## Systemdに登録して自動起動する
100
133
  **Ubuntuの場合**
101
- 1. `/etc/systemd/system` に、 `your_server_name.service` を作成します。
102
- 2. `your_server_name.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
134
+ 1. `/etc/systemd/system` に、 `banana_sample.service` を作成します。
135
+ 2. `banana_sample.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
103
136
 
104
- サーバーのディレクトリが `/home/ubuntu/nexom` にある場合
137
+ サーバーのディレクトリが `/home/ubuntu/banana_project` にある場合
105
138
  ```
106
139
  [Unit]
107
140
  Description=Nexom Web Freamework
@@ -110,9 +143,11 @@ After=network.target
110
143
  [Service]
111
144
  User=www-data
112
145
  Group=www-data
113
- WorkingDirectory=/home/ubuntu/nexom
114
- Environment="/home/ubuntu/nexom/venv/bin"
115
- ExecStart=/home/ubuntu/nexom/venv/bin/gunicorn wsgi:app
146
+ WorkingDirectory=/home/ubuntu/banana_project
147
+ Environment="PYTHONPATH=/home/ubuntu/banana_project"
148
+ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn sample.wsgi:app --config sample/gunicorn.conf.py
149
+ Restart=always
150
+ RestartSec=3
116
151
  [Install]
117
152
  WantedBy=multi-user.target
118
153
  ```
@@ -120,23 +155,12 @@ WantedBy=multi-user.target
120
155
  以下のコマンドを実行します
121
156
  ```
122
157
  sudo systemd daemon-reload
123
- sudo systemd enable your_server_name
124
- sudo systemd start your_server_name
158
+ sudo systemd enable banana_sample
159
+ sudo systemd start banana_sample
125
160
  ```
126
161
 
127
- ### テンプレートユニットを活用して複数のサーバーを効率的に管理
128
- 以下の構成でサーバーが建てられていたとします。
129
- ```
130
- /home/ubuntu/BananaProject/
131
- └─ web/
132
- ├─ banana1 (Nexomサーバー)/
133
- │ └─ wsgi.py
134
- ├─ banana2 (Nexomサーバー)/
135
- │ └─ wsgi.py
136
- └─ banana3 (Nexomサーバー)/
137
- └─ wsgi.py
138
- ```
139
- この構成の場合、テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
162
+ ### テンプレートユニットを活用して複数のアプリを効率的に管理
163
+ テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
140
164
 
141
165
  `/etc/systemd/system/banana-project@.service`
142
166
  ```
@@ -147,9 +171,11 @@ After=network.target
147
171
  [Service]
148
172
  User=www-data
149
173
  Group=www-data
150
- WorkingDirectory=/home/ubuntu/BananaProject/web/%i
151
- Environment="/home/ubuntu/BananaProject/web/%i/venv/bin"
152
- ExecStart=/home/ubuntu/BananaProject/web/%i/venv/bin/gunicorn wsgi:app
174
+ WorkingDirectory=/home/ubuntu/banana_project
175
+ Environment="PYTHONPATH=/home/ubuntu/banana_project"
176
+ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn %iwsgi:app --config %i/gunicorn.conf.py
177
+ Restart=always
178
+ RestartSec=3
153
179
  [Install]
154
180
  WantedBy=multi-user.target
155
181
  ```
@@ -165,4 +191,4 @@ sudo systemd start banana-project@banana2
165
191
  sudo systemd start banana-project@banana3
166
192
  ```
167
193
 
168
- 2026 1/24
194
+ 2026 1/25
@@ -0,0 +1,56 @@
1
+ nexom/__init__.py,sha256=V6US1i4gO-EOWsoHEgxzwbkrLPnzPhSn6TYue3uVsBA,367
2
+ nexom/__main__.py,sha256=VKT7WSe6552_mzwLwJqa55tfag5Olr28eYVhVnf9kWY,6196
3
+ nexom/app/__init__.py,sha256=meq2MgHUNgcjVn4V3dzm52EIlrGeIdNS-09sGLhita4,1090
4
+ nexom/app/auth.py,sha256=DQ8xM1xhHFMcZf22ZYAqItyT1quAz8mR2pJu-FdBHXI,10028
5
+ nexom/app/cookie.py,sha256=VCau9i8z6QlkaE_s8gKZXjcFtrV2bX1T4xssNtpJ5A0,2026
6
+ nexom/app/db.py,sha256=gUJOlUJqDaHCYU5JkzGV_wf_OTvFlqDWvM7vJDNVulY,2816
7
+ nexom/app/http_status_codes.py,sha256=R4ka3n4rijqvfahF5n5kS-Qrg8bZSsrvF8lGnpKWAgY,1934
8
+ nexom/app/middleware.py,sha256=7bHGtEem92QhgULOvTFDFlZ4K719CQgu9RKj1g7XOW8,1429
9
+ nexom/app/path.py,sha256=o7HUr_p4oRLhXo7YAD8jqgXVkrrRW6KUoY2unAI7s1Y,6007
10
+ nexom/app/request.py,sha256=4dvcfrrS9gKzVFtoizRw5eFvP7eHRXsavh21zEHXX2U,8867
11
+ nexom/app/response.py,sha256=qmLm8wCcexLjUIj8DaOBxt0cK3_J4Rn6DuWn6wkE7cE,4299
12
+ nexom/app/template.py,sha256=4V4YSaZ92Gq76lj6HgPaF7obvvzmM42Gh8f0e5oAIzM,3587
13
+ nexom/app/user.py,sha256=6KLLsb08Ma39CnLBbq5y290o33tfxtHFWu9lu1kT0NM,623
14
+ nexom/assets/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ nexom/assets/app/config.py,sha256=Ltpj40PE1--s0eRPTHiJNFqG8pFA7Lb6x02C39kwoYA,765
16
+ nexom/assets/app/gunicorn.conf.py,sha256=0kAQ7ddfpnPpqLAZxIXqYPF6EuUzkjIC9aOTqfxn6rc,149
17
+ nexom/assets/app/router.py,sha256=6VplXBlyvdsN144zy165sA3NZuvguMy6oO-mR0ebM2U,320
18
+ nexom/assets/app/wsgi.py,sha256=o-GtCPPHKiavTOmr8qxqCY95iUFU_IvRmwLqLK3ecwU,1743
19
+ nexom/assets/app/__pycache__/__init__.cpython-313.pyc,sha256=4WFkUYDuBZdpaXyXHrp3g5nTjc1XtExGRIyTPUyCFGM,195
20
+ nexom/assets/app/pages/__init__.py,sha256=DlX9iwM39JaMKfzK4mbgjE2uVMX3ax0wd2mCVnpg0b4,61
21
+ nexom/assets/app/pages/_templates.py,sha256=3lz42xOzHodOhFnujMhOuMX6IBJjMXGQKmOZ8SVhgE4,190
22
+ nexom/assets/app/pages/default.py,sha256=Kmm8ud8Uh1BAIba28Zp3Wz6WsTTx7cQ6-t6RMkuL9qU,257
23
+ nexom/assets/app/pages/document.py,sha256=JI9ChJ2BTXFyOiCnm4PRUnOY1xaLHeOI1ZEqHMQ7zPI,245
24
+ nexom/assets/app/pages/__pycache__/__init__.cpython-313.pyc,sha256=p0AGZjUdMtwO8e3cnmA3_R0rz1G5UFZNvVNICSHK8g0,273
25
+ nexom/assets/app/static/dog.jpeg,sha256=qGEhcg48FxRLRISzbmXvw1qvfbdluC_ukM8ZrHg7_XE,6559
26
+ nexom/assets/app/static/style.css,sha256=mDKNWue0uRLdWB0w1RsMSn6h3tHsuTVLuk3xOOJl7X8,566
27
+ nexom/assets/app/templates/base.html,sha256=RVW_63gA1sr7pqNkfB6Djk5an_VFpowahDIHGjfV-Wk,349
28
+ nexom/assets/app/templates/default.html,sha256=EKG9NTYkXngdCiDodSI1Kuic_ZwVwdeRc3VLq6fX5UI,167
29
+ nexom/assets/app/templates/document.html,sha256=16ClimpeqhLnXFNa8nMdMOlXUu8JOw7XxfpjU9DdIFs,6243
30
+ nexom/assets/app/templates/footer.html,sha256=1NZbbarU-CQhs1OPs2MTzhnWu0h7YYiEKDIP_cgIl9I,98
31
+ nexom/assets/app/templates/header.html,sha256=VgkCtCVE1J-eGEYvbBgWSUU-QauEf6xuvweOE-84U9c,75
32
+ nexom/assets/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
+ nexom/assets/auth/config.py,sha256=YgwEDhTsaxOxaOhUVSw6meay8Nc50A3GXafzmSdnhWo,804
34
+ nexom/assets/auth/gunicorn.conf.py,sha256=PbCWHG-A2OCfL71G04XS9xr78aH_gg-1UpH2tJhTWUk,141
35
+ nexom/assets/auth/wsgi.py,sha256=sMTj_ei0w1skoR_-xBNpveGAhRKWANfd1UaAItXQFO8,1698
36
+ nexom/assets/auth/__pycache__/__init__.cpython-313.pyc,sha256=dRCVl1pZMRjC5NpwgaW4uanJl9l4J8u4gcLhOzVXOEk,196
37
+ nexom/assets/auth_page/login.html,sha256=dMF098lsctmpDWHZL_wSDcqaBSLquiSXzcBZrtc5Phg,3536
38
+ nexom/assets/auth_page/signup.html,sha256=1fjw5R02EDFk2pyxqaa7eDU83uKegnXAOVaBLgbfOd0,4014
39
+ nexom/assets/error_page/error.html,sha256=JFi47UVxcxef_TTt1hDOuo93_45uSWCfixOJCUQVTs4,1230
40
+ nexom/assets/gateway/apache_app.conf,sha256=_QeZ0BqpuZaJfBONurNTW1FqJ7-PmunPrfbzAJRP3Qg,370
41
+ nexom/assets/gateway/nginx_app.conf,sha256=PaHRPGjJEyNiUU9OZiXS9HQhGwSe1oosSZp-6lnlQO0,521
42
+ nexom/buildTools/__init__.py,sha256=FbaFEMRjOKHNqNR-KuEatZjwPhmJf1CDZmR2hSH7YGk,19
43
+ nexom/buildTools/build.py,sha256=DSmHUIHNrXCdLUogmfHvnl9PtO1QOfQyRU15F-HLztk,10782
44
+ nexom/buildTools/run.py,sha256=HpSlkrNPFW961qgHjzedjGogdIYRQddhL95g3PcbM5s,5384
45
+ nexom/core/__init__.py,sha256=_ohRDLTerW9deZyh0WEp-ZB2LExkLvM9f26MhEdcp8g,52
46
+ nexom/core/error.py,sha256=1xwAynes65OEjhO8ZFC2lm_u_LGOAm4-nfGK-IedKOo,6199
47
+ nexom/core/log.py,sha256=q0FYz1-kkTUHvNkEBW5V1zvUv1phMYchOqwAfUXGHQI,3016
48
+ nexom/core/object_html_render.py,sha256=4yT3Aihia4oG62gr1rqZd757wEXsu78mTCCpjpVE7JM,7027
49
+ nexom/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
+ nexom/templates/auth.py,sha256=eWThgPR4E7y7YFcQ6rFZaO6yPKGL2zIbBC4SuzQ5M44,2332
51
+ nexom-1.0.2.dist-info/licenses/LICENSE,sha256=YbcHyxYLJ5jePeMS_NXpR9yiZjP5skhn32LvcKeknJw,1066
52
+ nexom-1.0.2.dist-info/METADATA,sha256=Zk1zoBzcVBX5btwcMJm1D6jAlkoCWGt9RVj3-byZCng,5914
53
+ nexom-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
54
+ nexom-1.0.2.dist-info/entry_points.txt,sha256=0r1egKZmF1MUo25AKPt-2d55sk5Q_EIBOQwD3JC8RgI,46
55
+ nexom-1.0.2.dist-info/top_level.txt,sha256=mTyUruscL3rqXvYJRo8KGwDM6PWXRzgf4CamLr8LSX4,6
56
+ nexom-1.0.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.10.1)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,27 +0,0 @@
1
- """
2
- Nexom server settings.
3
-
4
- This file is generated by Nexom buildTools.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- from pathlib import Path
10
-
11
-
12
- # ======== module ========
13
- # Project root directory
14
- directory: str = "{pwd_dir}"
15
-
16
- # ======== gunicorn ========
17
- _address: str = "{g_address}"
18
- _port: int = {g_port}
19
- _workers: int = {g_workers}
20
- _reload: bool = {g_reload}
21
-
22
-
23
- def project_path(*parts: str) -> str:
24
- """
25
- Build an absolute path under the project directory.
26
- """
27
- return str(Path(directory, *parts))
@@ -1,16 +0,0 @@
1
-
2
- from __future__ import annotations
3
-
4
- import sys
5
- from pathlib import Path
6
-
7
- # Ensure config.py in the same directory is importable
8
- ROOT = Path(__file__).resolve().parent
9
- if str(ROOT) not in sys.path:
10
- sys.path.insert(0, str(ROOT))
11
-
12
- from config import _address, _port, _workers, _reload # noqa: E402
13
-
14
- bind = f"{_address}:{_port}"
15
- workers = int(_workers)
16
- reload = bool(_reload)
@@ -1,11 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from pathlib import Path
4
-
5
- from nexom.web.template import ObjectHTMLTemplates
6
-
7
-
8
- # templates/ directory is located at: <project_root>/templates
9
- TEMPLATES_DIR = (Path(__file__).resolve().parent.parent / "templates").resolve()
10
-
11
- templates = ObjectHTMLTemplates(base_dir=str(TEMPLATES_DIR))
@@ -1,18 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import pathlib as plib
4
-
5
- from nexom.web.path import Path, Static, Pathlib
6
-
7
- from pages import default, document
8
-
9
-
10
- # Project root directory (where this file exists)
11
- ROOT = plib.Path(__file__).resolve().parent
12
-
13
-
14
- routing = Pathlib(
15
- Path("", default.main, "DefaultPage"),
16
- Path("doc/", document.main, "DocumentPage"),
17
- Static("static/", str(ROOT / "static"), "StaticFiles"),
18
- )
@@ -1,30 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Callable, Iterable
4
-
5
- from nexom.web.request import Request
6
- from nexom.web.response import Response, ErrorResponse
7
- from nexom.core.error import PathNotFoundError
8
-
9
- # Project-local router
10
- from router import routing
11
-
12
-
13
- def app(environ: dict, start_response: Callable) -> Iterable[bytes]:
14
- """
15
- WSGI application entrypoint.
16
- """
17
- try:
18
- request = Request(environ)
19
- path = request.path
20
-
21
- p = routing.get(path)
22
- res = p.call_handler(request)
23
-
24
- except PathNotFoundError as e:
25
- res = ErrorResponse(404, str(e))
26
- except Exception as e:
27
- res = ErrorResponse(500, str(e))
28
-
29
- start_response(res.status_text, res.headers)
30
- return [res.body]
nexom/engine/__init__.py DELETED
@@ -1 +0,0 @@
1
- from . import object_html_render
nexom/web/__init__.py DELETED
@@ -1,5 +0,0 @@
1
- from . import request
2
- from . import response
3
- from . import path
4
- from . import cookie
5
- from . import template