webdev 2.0.0__tar.gz → 2.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.
- {webdev-2.0.0 → webdev-2.1.0}/.gitignore +1 -0
- {webdev-2.0.0 → webdev-2.1.0}/PKG-INFO +91 -50
- {webdev-2.0.0 → webdev-2.1.0}/README.rst +90 -49
- webdev-2.1.0/tests/test_mime.py +47 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_static.py +27 -2
- webdev-2.1.0/tests/testfiles/app.config +2 -0
- webdev-2.1.0/tests/testfiles/config.yaml +2 -0
- webdev-2.1.0/tests/testfiles/config.yml +2 -0
- webdev-2.1.0/tests/testfiles/data.json +4 -0
- webdev-2.1.0/tests/testfiles/email.j2 +1 -0
- webdev-2.1.0/tests/testfiles/newsletter.jinja2 +1 -0
- webdev-2.1.0/tests/testfiles/page.tpl +1 -0
- webdev-2.1.0/tests/testfiles/sample.toml +2 -0
- webdev-2.1.0/tests/testfiles/sample.txt +1 -0
- webdev-2.1.0/tests/testfiles/setup.ini +2 -0
- webdev-2.1.0/tests/testfiles/site.template +1 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/__init__.py +1 -1
- {webdev-2.0.0 → webdev-2.1.0}/webdev/static.py +7 -0
- {webdev-2.0.0 → webdev-2.1.0}/LICENSE +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/pyproject.toml +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/conftest.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_config.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_index.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_livereload.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_net.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/tests/test_server.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/__main__.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/cli.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/config.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/index.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/livereload.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/net.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/run.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/server.py +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/templates/dark/base.html.jinja2 +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/templates/dark/index.html.jinja2 +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/templates/dark/partials/sort.js.jinja2 +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/templates/dark/partials/styles.css.jinja2 +0 -0
- {webdev-2.0.0 → webdev-2.1.0}/webdev/tls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: webdev
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: Small, fast development web server with a modern dark directory index
|
|
5
5
|
Project-URL: Homepage, https://github.com/kuralabs/webdev
|
|
6
6
|
Project-URL: Repository, https://github.com/kuralabs/webdev
|
|
@@ -32,49 +32,77 @@ Description-Content-Type: text/x-rst
|
|
|
32
32
|
Development Web Server
|
|
33
33
|
======================
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
``webdev`` is a small, fast development web server. It serves any local
|
|
39
|
-
directory over HTTP (or HTTPS) with developer-friendly conveniences, and ships
|
|
40
|
-
a modern, dark-themed directory index.
|
|
35
|
+
``webdev`` is a **small, fast local development web server**. Point it at a
|
|
36
|
+
folder and it serves it over HTTP (or HTTPS) with developer-friendly
|
|
37
|
+
conveniences and a modern, dark-themed directory index.
|
|
41
38
|
|
|
42
39
|
It is built on `Starlette <https://www.starlette.io/>`_ and
|
|
43
|
-
`Uvicorn <https://www.uvicorn.org/>`_ (an ASGI stack)
|
|
40
|
+
`Uvicorn <https://www.uvicorn.org/>`_ (an async ASGI stack) and requires
|
|
41
|
+
**Python 3.10+**.
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
Quick start
|
|
44
|
+
===========
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
directory under ``webdev/templates/<theme>/``.
|
|
62
|
-
- **Live reload** — connected browsers refresh automatically on file changes
|
|
63
|
-
(via a WebSocket; a tiny auto-reconnecting snippet is injected into HTML).
|
|
64
|
-
- **No-cache headers** for always-fresh development content.
|
|
65
|
-
- **SPA fallback** — optionally serve ``index.html`` for unknown routes.
|
|
66
|
-
- **Gzip**, **CORS**, optional **HTTPS** (self-signed if no cert/key is given),
|
|
67
|
-
and a startup **QR code / LAN URL** for quick mobile testing.
|
|
68
|
-
- **Config file** — every option can be set via ``webdev.toml`` (or a
|
|
69
|
-
``[tool.webdev]`` table). Precedence: CLI flag > config file > default.
|
|
46
|
+
::
|
|
47
|
+
|
|
48
|
+
# Install (see more options below)
|
|
49
|
+
uv tool install webdev
|
|
50
|
+
|
|
51
|
+
# Serve the current directory on http://localhost:8080
|
|
52
|
+
webdev
|
|
53
|
+
|
|
54
|
+
# Serve a specific folder
|
|
55
|
+
webdev ./public
|
|
56
|
+
|
|
57
|
+
# See every option
|
|
58
|
+
webdev --help
|
|
70
59
|
|
|
71
60
|
Installation
|
|
72
61
|
============
|
|
73
62
|
|
|
74
|
-
::
|
|
63
|
+
With `uv <https://docs.astral.sh/uv/>`_ (recommended)::
|
|
64
|
+
|
|
65
|
+
uv tool install webdev
|
|
66
|
+
|
|
67
|
+
With `pipx <https://pipx.pypa.io/>`_::
|
|
68
|
+
|
|
69
|
+
pipx install webdev
|
|
70
|
+
|
|
71
|
+
Or with plain ``pip`` into an environment of your choice::
|
|
75
72
|
|
|
76
73
|
pip install webdev
|
|
77
74
|
|
|
75
|
+
Features
|
|
76
|
+
========
|
|
77
|
+
|
|
78
|
+
- 🗂️ **Serve any directory** — passed as the first positional argument; defaults
|
|
79
|
+
to the current directory.
|
|
80
|
+
- 🩹 **Graceful when the folder disappears** — responds with ``404`` instead of
|
|
81
|
+
crashing if the served directory is removed, and **recovers automatically**
|
|
82
|
+
the moment it is recreated. Paths are resolved against the live filesystem on
|
|
83
|
+
every request — ideal for build systems that clean and rebuild output.
|
|
84
|
+
- 🔀 **Automatic port selection** — if the base port is busy, the next free port
|
|
85
|
+
in a range is used. Can be forced to a single exact port.
|
|
86
|
+
- 🔮 **Serve a not-yet-existing folder** — ``--future`` assumes the folder will
|
|
87
|
+
be created later.
|
|
88
|
+
- 🎨 **Modern dark directory index** — breadcrumbs, file-type icons,
|
|
89
|
+
human-readable sizes, modified dates and client-side sortable columns.
|
|
90
|
+
**Themable**: drop a new directory under ``webdev/templates/<theme>/``.
|
|
91
|
+
- 🔁 **Live reload** — connected browsers refresh automatically on file changes
|
|
92
|
+
(via a WebSocket; a tiny auto-reconnecting snippet is injected into HTML).
|
|
93
|
+
- 📱 **Instant mobile testing** — a **QR code and LAN URL** are printed at
|
|
94
|
+
startup so you can open the site on your phone.
|
|
95
|
+
- 🌈 **Colorized, level-aware logs** for readable output.
|
|
96
|
+
- ⚡ **No-cache headers** for always-fresh development content.
|
|
97
|
+
- 👀 **Previews text inline** — plain-text, config and template files (``.txt``,
|
|
98
|
+
``.json``, ``.yaml``, ``.ini``, ``.toml``, ``.j2``/``.jinja2``, ``.template``,
|
|
99
|
+
``.config`` and more) open in the browser instead of being downloaded.
|
|
100
|
+
- 🧭 **SPA fallback** — optionally serve ``index.html`` for unknown routes.
|
|
101
|
+
- 📦 **Gzip**, **CORS** and optional **HTTPS** (self-signed if no cert/key is
|
|
102
|
+
given).
|
|
103
|
+
- ⚙️ **Config file** — every option can be set via ``webdev.toml`` (or a
|
|
104
|
+
``[tool.webdev]`` table). Precedence: CLI flag > config file > default.
|
|
105
|
+
|
|
78
106
|
Usage
|
|
79
107
|
=====
|
|
80
108
|
|
|
@@ -100,6 +128,9 @@ Examples::
|
|
|
100
128
|
# Single-page app: fall back to index.html for client-side routes
|
|
101
129
|
webdev --spa ./dist
|
|
102
130
|
|
|
131
|
+
# Serve a build output folder that does not exist yet
|
|
132
|
+
webdev --future ./dist
|
|
133
|
+
|
|
103
134
|
Options and config keys
|
|
104
135
|
-----------------------
|
|
105
136
|
|
|
@@ -125,30 +156,19 @@ Colorized logs ``--color/--no-color`` ``color`` enabled
|
|
|
125
156
|
HTTPS/TLS ``--https/--no-https`` ``https`` disabled
|
|
126
157
|
TLS cert / key ``--cert`` / ``--key`` ``cert`` / ``key`` self-signed
|
|
127
158
|
Index theme ``--theme`` ``theme`` dark
|
|
159
|
+
Verbosity ``-v`` (repeatable) ``verbose`` 0
|
|
128
160
|
===================== ======================== ================== ==========
|
|
129
161
|
|
|
130
|
-
|
|
162
|
+
Commit a ``webdev.toml`` next to your project to share settings with your team.
|
|
163
|
+
Any option works as a flat key, or under a ``[tool.webdev]`` table (handy inside
|
|
164
|
+
a ``pyproject.toml``)::
|
|
131
165
|
|
|
166
|
+
# webdev.toml
|
|
132
167
|
port = 3000
|
|
133
168
|
force_port = true
|
|
134
169
|
spa = true
|
|
135
170
|
cors = true
|
|
136
171
|
|
|
137
|
-
Design notes
|
|
138
|
-
============
|
|
139
|
-
|
|
140
|
-
- **Framework:** Starlette + Uvicorn was chosen over a full framework such as
|
|
141
|
-
Sanic because this is a static file server: Starlette provides exactly the
|
|
142
|
-
primitives needed (routing, static serving, WebSockets, middleware) with a
|
|
143
|
-
small surface, and Uvicorn handles fast binding, HTTP keep-alive, HTTPS and
|
|
144
|
-
graceful shutdown.
|
|
145
|
-
- **The legacy reload hack is gone.** The old server patched ``send_head`` to
|
|
146
|
-
``chdir`` back into the served folder; modern ``http.server`` captures the
|
|
147
|
-
working directory in the handler constructor, so that hook stopped running and
|
|
148
|
-
a removed folder crashed the request. ``webdev`` now resolves every request
|
|
149
|
-
against the live filesystem, so missing folders yield a real ``404`` and
|
|
150
|
-
recover automatically.
|
|
151
|
-
|
|
152
172
|
Development
|
|
153
173
|
===========
|
|
154
174
|
|
|
@@ -165,12 +185,32 @@ only tool you need preinstalled::
|
|
|
165
185
|
# Build and verify the distribution
|
|
166
186
|
tox -e build
|
|
167
187
|
|
|
188
|
+
# Build, install in a throwaway venv and run (pass args after --)
|
|
189
|
+
tox -e run -- -p 3000 ./public
|
|
190
|
+
|
|
168
191
|
Each environment declares its own tooling dependencies in ``tox.ini`` so it
|
|
169
192
|
installs only what it needs.
|
|
170
193
|
|
|
171
194
|
Changelog
|
|
172
195
|
=========
|
|
173
196
|
|
|
197
|
+
2.1.0
|
|
198
|
+
-----
|
|
199
|
+
|
|
200
|
+
**New**
|
|
201
|
+
|
|
202
|
+
- Plain-text, config and template files (such as ``.yaml``, ``.tpl``, ``.j2``,
|
|
203
|
+
``.jinja2``, ``.template`` and ``.config``) now open inline in the browser
|
|
204
|
+
instead of being downloaded (issue #8). Thanks to zaro0508 for the report.
|
|
205
|
+
|
|
206
|
+
2.0.1
|
|
207
|
+
-----
|
|
208
|
+
|
|
209
|
+
**Changed**
|
|
210
|
+
|
|
211
|
+
- Modernized and expanded the README (uv-first installation, refreshed feature
|
|
212
|
+
overview and usage).
|
|
213
|
+
|
|
174
214
|
2.0.0
|
|
175
215
|
-----
|
|
176
216
|
|
|
@@ -224,7 +264,8 @@ License
|
|
|
224
264
|
|
|
225
265
|
::
|
|
226
266
|
|
|
227
|
-
Copyright (C)
|
|
267
|
+
Copyright (C) 2026 KuraLabs S.R.L <info@kuralabs.io>
|
|
268
|
+
Copyright (C) 2015-2016 Carlos Jenkins <carlos@jenkins.co.cr>
|
|
228
269
|
|
|
229
270
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
230
271
|
you may not use this file except in compliance with the License.
|
|
@@ -2,49 +2,77 @@
|
|
|
2
2
|
Development Web Server
|
|
3
3
|
======================
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
``webdev`` is a small, fast development web server. It serves any local
|
|
9
|
-
directory over HTTP (or HTTPS) with developer-friendly conveniences, and ships
|
|
10
|
-
a modern, dark-themed directory index.
|
|
5
|
+
``webdev`` is a **small, fast local development web server**. Point it at a
|
|
6
|
+
folder and it serves it over HTTP (or HTTPS) with developer-friendly
|
|
7
|
+
conveniences and a modern, dark-themed directory index.
|
|
11
8
|
|
|
12
9
|
It is built on `Starlette <https://www.starlette.io/>`_ and
|
|
13
|
-
`Uvicorn <https://www.uvicorn.org/>`_ (an ASGI stack)
|
|
10
|
+
`Uvicorn <https://www.uvicorn.org/>`_ (an async ASGI stack) and requires
|
|
11
|
+
**Python 3.10+**.
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
Quick start
|
|
14
|
+
===========
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
directory under ``webdev/templates/<theme>/``.
|
|
32
|
-
- **Live reload** — connected browsers refresh automatically on file changes
|
|
33
|
-
(via a WebSocket; a tiny auto-reconnecting snippet is injected into HTML).
|
|
34
|
-
- **No-cache headers** for always-fresh development content.
|
|
35
|
-
- **SPA fallback** — optionally serve ``index.html`` for unknown routes.
|
|
36
|
-
- **Gzip**, **CORS**, optional **HTTPS** (self-signed if no cert/key is given),
|
|
37
|
-
and a startup **QR code / LAN URL** for quick mobile testing.
|
|
38
|
-
- **Config file** — every option can be set via ``webdev.toml`` (or a
|
|
39
|
-
``[tool.webdev]`` table). Precedence: CLI flag > config file > default.
|
|
16
|
+
::
|
|
17
|
+
|
|
18
|
+
# Install (see more options below)
|
|
19
|
+
uv tool install webdev
|
|
20
|
+
|
|
21
|
+
# Serve the current directory on http://localhost:8080
|
|
22
|
+
webdev
|
|
23
|
+
|
|
24
|
+
# Serve a specific folder
|
|
25
|
+
webdev ./public
|
|
26
|
+
|
|
27
|
+
# See every option
|
|
28
|
+
webdev --help
|
|
40
29
|
|
|
41
30
|
Installation
|
|
42
31
|
============
|
|
43
32
|
|
|
44
|
-
::
|
|
33
|
+
With `uv <https://docs.astral.sh/uv/>`_ (recommended)::
|
|
34
|
+
|
|
35
|
+
uv tool install webdev
|
|
36
|
+
|
|
37
|
+
With `pipx <https://pipx.pypa.io/>`_::
|
|
38
|
+
|
|
39
|
+
pipx install webdev
|
|
40
|
+
|
|
41
|
+
Or with plain ``pip`` into an environment of your choice::
|
|
45
42
|
|
|
46
43
|
pip install webdev
|
|
47
44
|
|
|
45
|
+
Features
|
|
46
|
+
========
|
|
47
|
+
|
|
48
|
+
- 🗂️ **Serve any directory** — passed as the first positional argument; defaults
|
|
49
|
+
to the current directory.
|
|
50
|
+
- 🩹 **Graceful when the folder disappears** — responds with ``404`` instead of
|
|
51
|
+
crashing if the served directory is removed, and **recovers automatically**
|
|
52
|
+
the moment it is recreated. Paths are resolved against the live filesystem on
|
|
53
|
+
every request — ideal for build systems that clean and rebuild output.
|
|
54
|
+
- 🔀 **Automatic port selection** — if the base port is busy, the next free port
|
|
55
|
+
in a range is used. Can be forced to a single exact port.
|
|
56
|
+
- 🔮 **Serve a not-yet-existing folder** — ``--future`` assumes the folder will
|
|
57
|
+
be created later.
|
|
58
|
+
- 🎨 **Modern dark directory index** — breadcrumbs, file-type icons,
|
|
59
|
+
human-readable sizes, modified dates and client-side sortable columns.
|
|
60
|
+
**Themable**: drop a new directory under ``webdev/templates/<theme>/``.
|
|
61
|
+
- 🔁 **Live reload** — connected browsers refresh automatically on file changes
|
|
62
|
+
(via a WebSocket; a tiny auto-reconnecting snippet is injected into HTML).
|
|
63
|
+
- 📱 **Instant mobile testing** — a **QR code and LAN URL** are printed at
|
|
64
|
+
startup so you can open the site on your phone.
|
|
65
|
+
- 🌈 **Colorized, level-aware logs** for readable output.
|
|
66
|
+
- ⚡ **No-cache headers** for always-fresh development content.
|
|
67
|
+
- 👀 **Previews text inline** — plain-text, config and template files (``.txt``,
|
|
68
|
+
``.json``, ``.yaml``, ``.ini``, ``.toml``, ``.j2``/``.jinja2``, ``.template``,
|
|
69
|
+
``.config`` and more) open in the browser instead of being downloaded.
|
|
70
|
+
- 🧭 **SPA fallback** — optionally serve ``index.html`` for unknown routes.
|
|
71
|
+
- 📦 **Gzip**, **CORS** and optional **HTTPS** (self-signed if no cert/key is
|
|
72
|
+
given).
|
|
73
|
+
- ⚙️ **Config file** — every option can be set via ``webdev.toml`` (or a
|
|
74
|
+
``[tool.webdev]`` table). Precedence: CLI flag > config file > default.
|
|
75
|
+
|
|
48
76
|
Usage
|
|
49
77
|
=====
|
|
50
78
|
|
|
@@ -70,6 +98,9 @@ Examples::
|
|
|
70
98
|
# Single-page app: fall back to index.html for client-side routes
|
|
71
99
|
webdev --spa ./dist
|
|
72
100
|
|
|
101
|
+
# Serve a build output folder that does not exist yet
|
|
102
|
+
webdev --future ./dist
|
|
103
|
+
|
|
73
104
|
Options and config keys
|
|
74
105
|
-----------------------
|
|
75
106
|
|
|
@@ -95,30 +126,19 @@ Colorized logs ``--color/--no-color`` ``color`` enabled
|
|
|
95
126
|
HTTPS/TLS ``--https/--no-https`` ``https`` disabled
|
|
96
127
|
TLS cert / key ``--cert`` / ``--key`` ``cert`` / ``key`` self-signed
|
|
97
128
|
Index theme ``--theme`` ``theme`` dark
|
|
129
|
+
Verbosity ``-v`` (repeatable) ``verbose`` 0
|
|
98
130
|
===================== ======================== ================== ==========
|
|
99
131
|
|
|
100
|
-
|
|
132
|
+
Commit a ``webdev.toml`` next to your project to share settings with your team.
|
|
133
|
+
Any option works as a flat key, or under a ``[tool.webdev]`` table (handy inside
|
|
134
|
+
a ``pyproject.toml``)::
|
|
101
135
|
|
|
136
|
+
# webdev.toml
|
|
102
137
|
port = 3000
|
|
103
138
|
force_port = true
|
|
104
139
|
spa = true
|
|
105
140
|
cors = true
|
|
106
141
|
|
|
107
|
-
Design notes
|
|
108
|
-
============
|
|
109
|
-
|
|
110
|
-
- **Framework:** Starlette + Uvicorn was chosen over a full framework such as
|
|
111
|
-
Sanic because this is a static file server: Starlette provides exactly the
|
|
112
|
-
primitives needed (routing, static serving, WebSockets, middleware) with a
|
|
113
|
-
small surface, and Uvicorn handles fast binding, HTTP keep-alive, HTTPS and
|
|
114
|
-
graceful shutdown.
|
|
115
|
-
- **The legacy reload hack is gone.** The old server patched ``send_head`` to
|
|
116
|
-
``chdir`` back into the served folder; modern ``http.server`` captures the
|
|
117
|
-
working directory in the handler constructor, so that hook stopped running and
|
|
118
|
-
a removed folder crashed the request. ``webdev`` now resolves every request
|
|
119
|
-
against the live filesystem, so missing folders yield a real ``404`` and
|
|
120
|
-
recover automatically.
|
|
121
|
-
|
|
122
142
|
Development
|
|
123
143
|
===========
|
|
124
144
|
|
|
@@ -135,12 +155,32 @@ only tool you need preinstalled::
|
|
|
135
155
|
# Build and verify the distribution
|
|
136
156
|
tox -e build
|
|
137
157
|
|
|
158
|
+
# Build, install in a throwaway venv and run (pass args after --)
|
|
159
|
+
tox -e run -- -p 3000 ./public
|
|
160
|
+
|
|
138
161
|
Each environment declares its own tooling dependencies in ``tox.ini`` so it
|
|
139
162
|
installs only what it needs.
|
|
140
163
|
|
|
141
164
|
Changelog
|
|
142
165
|
=========
|
|
143
166
|
|
|
167
|
+
2.1.0
|
|
168
|
+
-----
|
|
169
|
+
|
|
170
|
+
**New**
|
|
171
|
+
|
|
172
|
+
- Plain-text, config and template files (such as ``.yaml``, ``.tpl``, ``.j2``,
|
|
173
|
+
``.jinja2``, ``.template`` and ``.config``) now open inline in the browser
|
|
174
|
+
instead of being downloaded (issue #8). Thanks to zaro0508 for the report.
|
|
175
|
+
|
|
176
|
+
2.0.1
|
|
177
|
+
-----
|
|
178
|
+
|
|
179
|
+
**Changed**
|
|
180
|
+
|
|
181
|
+
- Modernized and expanded the README (uv-first installation, refreshed feature
|
|
182
|
+
overview and usage).
|
|
183
|
+
|
|
144
184
|
2.0.0
|
|
145
185
|
-----
|
|
146
186
|
|
|
@@ -194,7 +234,8 @@ License
|
|
|
194
234
|
|
|
195
235
|
::
|
|
196
236
|
|
|
197
|
-
Copyright (C)
|
|
237
|
+
Copyright (C) 2026 KuraLabs S.R.L <info@kuralabs.io>
|
|
238
|
+
Copyright (C) 2015-2016 Carlos Jenkins <carlos@jenkins.co.cr>
|
|
198
239
|
|
|
199
240
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
200
241
|
you may not use this file except in compliance with the License.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Serve the committed ``testfiles`` fixtures and assert plain-text, config and
|
|
3
|
+
template files load inline in the browser instead of being downloaded.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from starlette.testclient import TestClient
|
|
12
|
+
|
|
13
|
+
from webdev.config import Settings
|
|
14
|
+
from webdev.server import create_app
|
|
15
|
+
from webdev.static import guess_media_type
|
|
16
|
+
|
|
17
|
+
TESTFILES = Path(__file__).parent / 'testfiles'
|
|
18
|
+
|
|
19
|
+
#: Every committed fixture, discovered dynamically.
|
|
20
|
+
FIXTURES = sorted(p for p in TESTFILES.iterdir() if p.is_file())
|
|
21
|
+
|
|
22
|
+
#: Content types browsers render inline rather than offering to download.
|
|
23
|
+
INLINE_TYPES = {'text/plain', 'application/json'}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.fixture
|
|
27
|
+
def testfiles_client() -> TestClient:
|
|
28
|
+
settings = Settings(
|
|
29
|
+
path=str(TESTFILES),
|
|
30
|
+
reload=False,
|
|
31
|
+
qr=False,
|
|
32
|
+
gzip=False,
|
|
33
|
+
).normalized()
|
|
34
|
+
return TestClient(create_app(settings))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.parametrize('fixture', FIXTURES, ids=lambda p: p.name)
|
|
38
|
+
def test_file_served_inline(testfiles_client: TestClient, fixture: Path) -> None:
|
|
39
|
+
with testfiles_client as c:
|
|
40
|
+
resp = c.get('/{}'.format(fixture.name))
|
|
41
|
+
assert resp.status_code == 200
|
|
42
|
+
|
|
43
|
+
content_type = resp.headers['content-type'].split(';')[0]
|
|
44
|
+
assert content_type == guess_media_type(fixture)
|
|
45
|
+
assert content_type in INLINE_TYPES
|
|
46
|
+
# The browser must render the file, never download it.
|
|
47
|
+
assert 'attachment' not in resp.headers.get('content-disposition', '')
|
|
@@ -46,10 +46,35 @@ def test_find_index_file(served_dir: Path) -> None:
|
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def test_guess_media_type_registered_extensions(tmp_path: Path) -> None:
|
|
49
|
-
|
|
49
|
+
extensions = (
|
|
50
|
+
'conf.toml',
|
|
51
|
+
'setup.ini',
|
|
52
|
+
'app.cfg',
|
|
53
|
+
'notes.log',
|
|
54
|
+
'config.yaml',
|
|
55
|
+
'config.yml',
|
|
56
|
+
'site.template',
|
|
57
|
+
'page.tmpl',
|
|
58
|
+
'legacy.tpl',
|
|
59
|
+
'email.j2',
|
|
60
|
+
'base.jinja',
|
|
61
|
+
'newsletter.jinja2',
|
|
62
|
+
'app.config',
|
|
63
|
+
)
|
|
64
|
+
for name in extensions:
|
|
50
65
|
f = tmp_path / name
|
|
51
66
|
f.write_text('key = 1')
|
|
52
|
-
assert guess_media_type(f) == 'text/plain'
|
|
67
|
+
assert guess_media_type(f) == 'text/plain', name
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_guess_media_type_txt_and_json(tmp_path: Path) -> None:
|
|
71
|
+
txt = tmp_path / 'notes.txt'
|
|
72
|
+
txt.write_text('hello')
|
|
73
|
+
assert guess_media_type(txt) == 'text/plain'
|
|
74
|
+
|
|
75
|
+
data = tmp_path / 'data.json'
|
|
76
|
+
data.write_text('{"ok": true}')
|
|
77
|
+
assert guess_media_type(data) == 'application/json'
|
|
53
78
|
|
|
54
79
|
|
|
55
80
|
def test_guess_media_type_known_binary(tmp_path: Path) -> None:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Hello {{ name }}, this is a Jinja2 template.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p>Hello {{ name }}</p>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Hello {{ name }}, this is a .tpl template.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Just a plain text note.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Hello {{ name }}, this is a .template file.
|
|
@@ -50,6 +50,13 @@ EXTRA_MIME_TYPES = {
|
|
|
50
50
|
'.svelte': 'text/plain',
|
|
51
51
|
'.yml': 'text/plain',
|
|
52
52
|
'.yaml': 'text/plain',
|
|
53
|
+
'.template': 'text/plain',
|
|
54
|
+
'.tmpl': 'text/plain',
|
|
55
|
+
'.tpl': 'text/plain',
|
|
56
|
+
'.j2': 'text/plain',
|
|
57
|
+
'.jinja': 'text/plain',
|
|
58
|
+
'.jinja2': 'text/plain',
|
|
59
|
+
'.config': 'text/plain',
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
#: Number of bytes inspected when sniffing whether an unknown file is text.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|