Nexom 0.1.3__py3-none-any.whl → 1.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.
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.3.dist-info → nexom-1.0.1.dist-info}/METADATA +75 -50
  42. nexom-1.0.1.dist-info/RECORD +56 -0
  43. {nexom-0.1.3.dist-info → nexom-1.0.1.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.3.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.3.dist-info → nexom-1.0.1.dist-info}/entry_points.txt +0 -0
  66. {nexom-0.1.3.dist-info → nexom-1.0.1.dist-info}/licenses/LICENSE +0 -0
  67. {nexom-0.1.3.dist-info → nexom-1.0.1.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.3
3
+ Version: 1.0.1
4
4
  Summary: Lightweight Python Web Framework (WSGI)
5
5
  Author: TouriAida
6
6
  License: MIT License
@@ -44,64 +44,96 @@ Nexomは短いコードで最低限動作し、シンプルで理解のしやす
44
44
  ## はじめる
45
45
  最初のサーバーを起動するには、3つの手順が必要です。
46
46
 
47
- 1. ディレクトリを作成
48
- 2. nexomをpipでインストール、サーバーのビルド
47
+ 1. プロジェクトディレクトリを作成
48
+ 2. nexomをpipでインストール、プロジェクトのビルド
49
49
  3. 起動
50
50
 
51
- ### 1.ディレクトリの作成
51
+ ### 1.プロジェクトディレクトリの作成
52
52
  **準備**
53
- 用意していない場合はディレクトリを作成し、仮想環境も準備てください
53
+
54
+ 用意していない場合はディレクトリを作成し、仮想環境も準備してください
54
55
  ```
55
- mkdir sample
56
- cd sample
56
+ mkdir banana_project
57
+ cd banana_project
57
58
 
58
59
  python -m venv venv
59
60
  source venv/bin/activate
60
61
  ```
61
- ### 2.npipでインストール、サーバーのビルド
62
+ ### 2. pipでインストール、サーバーのビルド
62
63
  **インストール**
64
+
63
65
  nexomをインストールします。
64
- ※まだベータ版のため、最新のバージョンを確認してください。
65
66
  ```
66
- pip install nexom==0.1.4
67
+ pip install
67
68
  ```
68
- **テンプレートサーバーのビルド**
69
- サーバーを置きたいディレクトリ上で、以下のコマンドを実行してください(sampleは自由)
69
+ **プロジェクトのビルド**
70
+
71
+ プロジェクトディレクトリ上で、以下のコマンドを実行してください(名前は自由)
72
+ もしNginxもしくはApacheを使用する場合 --gateway オプションにどちらか入力してください
73
+
74
+ ```
75
+ $ python -m nexom start-project
76
+ ```
77
+
78
+ 以下の構成でプロジェクトが生成されます。
79
+
70
80
  ```
71
- python -m nexom build-server sample
81
+ banana_project/
82
+ ├─ app/
83
+ │ ├─ pages/
84
+ │ │ ├─ __init__.py
85
+ │ │ ├─ _templates.py
86
+ │ │ └─ * pages *
87
+ │ ├─ static/
88
+ │ │ └─ * static items *
89
+ │ ├─ templates/
90
+ │ │ └─ * html files *
91
+ │ ├─ __init__.py
92
+ │ ├─ config.py
93
+ │ ├─ gunicorn.conf.py
94
+ │ ├─ router.py
95
+ │ └─ wsgi.py
96
+ ├─ auth/
97
+ │ ├─ __init__.py
98
+ │ ├─ config.py
99
+ │ ├─ gunicorn.conf.py
100
+ │ └─ wsgi.py
101
+ └─ data/
102
+ ├─ log/
103
+ │ └─ * app logs *
104
+ ├─ db/
105
+ │ └─ * app db *
106
+ └─ gateway/
107
+ ├─ app.nginx.conf
108
+ └─ app.apache.conf
72
109
  ```
73
110
 
74
111
  ### 3.起動
75
112
  以下のコマンドを起動します。
76
113
  ```
77
- gunicorn wsgi:app
114
+ $ python -m nexom run
78
115
  ```
79
116
  ブラウザからアクセスできるようになります。
80
117
  デフォルトのポートは8080です。
81
- [httpls://localhost:8080](httpls://localhost:8080)
118
+
119
+ [https://localhost:8080](https://localhost:8080)
120
+
82
121
  ポートなどの設定は `config.py` から変更してください。
83
122
 
84
123
  ## Nginx等使用して外部公開する
85
- `config.py` で指定したポートにプロキシしてください。
124
+ gatewayディレクトリにある設定を読み込んでください
86
125
  ```
87
- server {
88
- listen 443 ssl;
89
- server_name nexom.ceez7.com;
90
-
91
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
-
93
- location / {
94
- proxy_pass http://localhost:8080;
95
- }
126
+ http {
127
+ include /home/ubuntu/banana_project/gateway/*.conf;
96
128
  }
97
129
  ```
98
130
 
99
131
  ## Systemdに登録して自動起動する
100
132
  **Ubuntuの場合**
101
- 1. `/etc/systemd/system` に、 `your_server_name.service` を作成します。
102
- 2. `your_server_name.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
133
+ 1. `/etc/systemd/system` に、 `banana_sample.service` を作成します。
134
+ 2. `banana_sample.service` に以下を書き込みます。(これは一例です。環境に合わせて設定してください。)
103
135
 
104
- サーバーのディレクトリが `/home/ubuntu/nexom` にある場合
136
+ サーバーのディレクトリが `/home/ubuntu/banana_project` にある場合
105
137
  ```
106
138
  [Unit]
107
139
  Description=Nexom Web Freamework
@@ -110,9 +142,11 @@ After=network.target
110
142
  [Service]
111
143
  User=www-data
112
144
  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
145
+ WorkingDirectory=/home/ubuntu/banana_project
146
+ Environment="PYTHONPATH=/home/ubuntu/banana_project"
147
+ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn sample.wsgi:app --config sample/gunicorn.conf.py
148
+ Restart=always
149
+ RestartSec=3
116
150
  [Install]
117
151
  WantedBy=multi-user.target
118
152
  ```
@@ -120,23 +154,12 @@ WantedBy=multi-user.target
120
154
  以下のコマンドを実行します
121
155
  ```
122
156
  sudo systemd daemon-reload
123
- sudo systemd enable your_server_name
124
- sudo systemd start your_server_name
157
+ sudo systemd enable banana_sample
158
+ sudo systemd start banana_sample
125
159
  ```
126
160
 
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 ファイルを一枚にまとめられます。
161
+ ### テンプレートユニットを活用して複数のアプリを効率的に管理
162
+ テンプレートユニットを活用し .service ファイルを一枚にまとめられます。
140
163
 
141
164
  `/etc/systemd/system/banana-project@.service`
142
165
  ```
@@ -147,9 +170,11 @@ After=network.target
147
170
  [Service]
148
171
  User=www-data
149
172
  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
173
+ WorkingDirectory=/home/ubuntu/banana_project
174
+ Environment="PYTHONPATH=/home/ubuntu/banana_project"
175
+ ExecStart=/home/ubuntu/banana_project/venv/bin/gunicorn %iwsgi:app --config %i/gunicorn.conf.py
176
+ Restart=always
177
+ RestartSec=3
153
178
  [Install]
154
179
  WantedBy=multi-user.target
155
180
  ```
@@ -165,4 +190,4 @@ sudo systemd start banana-project@banana2
165
190
  sudo systemd start banana-project@banana3
166
191
  ```
167
192
 
168
- 2026 1/24
193
+ 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.1.dist-info/licenses/LICENSE,sha256=YbcHyxYLJ5jePeMS_NXpR9yiZjP5skhn32LvcKeknJw,1066
52
+ nexom-1.0.1.dist-info/METADATA,sha256=dacejsf9ca47t6GK-dBUEKT1EaEjxuwXKwmaJ4pTUPQ,5856
53
+ nexom-1.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
54
+ nexom-1.0.1.dist-info/entry_points.txt,sha256=0r1egKZmF1MUo25AKPt-2d55sk5Q_EIBOQwD3JC8RgI,46
55
+ nexom-1.0.1.dist-info/top_level.txt,sha256=mTyUruscL3rqXvYJRo8KGwDM6PWXRzgf4CamLr8LSX4,6
56
+ nexom-1.0.1.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