ghps 0.5__tar.gz → 0.7__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.
- {ghps-0.5 → ghps-0.7}/CHANGELOG.md +15 -1
- {ghps-0.5 → ghps-0.7}/PKG-INFO +34 -9
- {ghps-0.5 → ghps-0.7}/README.md +16 -5
- {ghps-0.5 → ghps-0.7}/SECURITY.md +2 -2
- {ghps-0.5 → ghps-0.7}/ghps/cli.py +8 -0
- ghps-0.7/ghps/params.py +92 -0
- {ghps-0.5 → ghps-0.7}/ghps/server.py +39 -3
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/PKG-INFO +34 -9
- {ghps-0.5 → ghps-0.7}/setup.py +3 -3
- {ghps-0.5 → ghps-0.7}/tests/test_cli.py +21 -0
- {ghps-0.5 → ghps-0.7}/tests/test_error.py +14 -0
- {ghps-0.5 → ghps-0.7}/tests/test_server.py +132 -0
- ghps-0.5/ghps/params.py +0 -25
- {ghps-0.5 → ghps-0.7}/AUTHORS.md +0 -0
- {ghps-0.5 → ghps-0.7}/LICENSE +0 -0
- {ghps-0.5 → ghps-0.7}/MANIFEST.in +0 -0
- {ghps-0.5 → ghps-0.7}/ghps/__init__.py +0 -0
- {ghps-0.5 → ghps-0.7}/ghps/__main__.py +0 -0
- {ghps-0.5 → ghps-0.7}/ghps/errors.py +0 -0
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/SOURCES.txt +0 -0
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/dependency_links.txt +0 -0
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/entry_points.txt +0 -0
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/requires.txt +0 -0
- {ghps-0.5 → ghps-0.7}/ghps.egg-info/top_level.txt +0 -0
- {ghps-0.5 → ghps-0.7}/requirements-dev.txt +0 -0
- {ghps-0.5 → ghps-0.7}/requirements-latest.txt +0 -0
- {ghps-0.5 → ghps-0.7}/setup.cfg +0 -0
|
@@ -5,6 +5,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
|
+
## [0.7] - 2026-09-22
|
|
9
|
+
### Added
|
|
10
|
+
- `host` parameter
|
|
11
|
+
- `--host` CLI argument
|
|
12
|
+
### Changed
|
|
13
|
+
- Test system modified
|
|
14
|
+
- `README.md` updated
|
|
15
|
+
## [0.6] - 2026-08-31
|
|
16
|
+
### Added
|
|
17
|
+
- Custom default error page
|
|
18
|
+
### Changed
|
|
19
|
+
- Server header modified
|
|
8
20
|
## [0.5] - 2026-08-02
|
|
9
21
|
### Added
|
|
10
22
|
- `directory_listing` parameter
|
|
@@ -47,7 +59,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
47
59
|
- Command line interface
|
|
48
60
|
- Test system
|
|
49
61
|
|
|
50
|
-
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.
|
|
62
|
+
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.7...dev
|
|
63
|
+
[0.7]: https://github.com/sepandhaghighi/ghps/compare/v0.6...v0.7
|
|
64
|
+
[0.6]: https://github.com/sepandhaghighi/ghps/compare/v0.5...v0.6
|
|
51
65
|
[0.5]: https://github.com/sepandhaghighi/ghps/compare/v0.4...v0.5
|
|
52
66
|
[0.4]: https://github.com/sepandhaghighi/ghps/compare/v0.3...v0.4
|
|
53
67
|
[0.3]: https://github.com/sepandhaghighi/ghps/compare/v0.2...v0.3
|
{ghps-0.5 → ghps-0.7}/PKG-INFO
RENAMED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghps
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: Ghps: A Minimal GitHub Pages Simulator for Local Development
|
|
5
5
|
Home-page: https://github.com/sepandhaghighi/ghps
|
|
6
|
-
Download-URL: https://github.com/sepandhaghighi/ghps/tarball/v0.
|
|
6
|
+
Download-URL: https://github.com/sepandhaghighi/ghps/tarball/v0.7
|
|
7
7
|
Author: Sepand Haghighi
|
|
8
8
|
Author-email: me@sepand.tech
|
|
9
9
|
License: MIT
|
|
10
10
|
Project-URL: Source, https://github.com/sepandhaghighi/ghps
|
|
11
11
|
Keywords: github gh-pages static-server static-hosting development server local http simulator testing cli python
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -101,13 +101,13 @@ Dynamic: summary
|
|
|
101
101
|
## Installation
|
|
102
102
|
|
|
103
103
|
### Source Code
|
|
104
|
-
- Download [Version 0.
|
|
104
|
+
- Download [Version 0.7](https://github.com/sepandhaghighi/ghps/archive/v0.7.zip) or [Latest Source](https://github.com/sepandhaghighi/ghps/archive/dev.zip)
|
|
105
105
|
- `pip install .`
|
|
106
106
|
|
|
107
107
|
### PyPI
|
|
108
108
|
|
|
109
109
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
110
|
-
- `pip install ghps==0.
|
|
110
|
+
- `pip install ghps==0.7`
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
## Usage
|
|
@@ -117,13 +117,14 @@ Ghps can be used both as a CLI tool and as a Python library.
|
|
|
117
117
|
### CLI
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
ghps --port=8080 --no-cache --no-threaded
|
|
120
|
+
ghps --host=127.0.0.1 --port=8080 --no-cache --no-threaded
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
#### Options
|
|
124
124
|
|
|
125
125
|
| Option | Description | Default |
|
|
126
126
|
|--------|-------------|----------|
|
|
127
|
+
| `--host` | Host address to bind to | `localhost` |
|
|
127
128
|
| `-p, --port` | Port to serve on | `8000` |
|
|
128
129
|
| `-d, --directory` | Directory to serve | Current directory (`.`) |
|
|
129
130
|
| `-b, --base-path` | Base path for project pages (e.g. `/repo-name`) | `""` |
|
|
@@ -133,7 +134,11 @@ ghps --port=8080 --no-cache --no-threaded
|
|
|
133
134
|
| `--auto-open` | Automatically open the server URL | Disable |
|
|
134
135
|
| `--directory-listing` | Enable directory listing | Disable |
|
|
135
136
|
|
|
136
|
-
|
|
137
|
+
> [!NOTE]
|
|
138
|
+
> You can set `--port=0` to let the OS automatically select an available port.
|
|
139
|
+
|
|
140
|
+
> [!NOTE]
|
|
141
|
+
> You can use `--host=0.0.0.0` to bind Ghps to all available network interfaces, or specify a particular address such as `127.0.0.1`.
|
|
137
142
|
|
|
138
143
|
|
|
139
144
|
### Library
|
|
@@ -143,6 +148,7 @@ from ghps import GHPageServer
|
|
|
143
148
|
|
|
144
149
|
server = GHPageServer(
|
|
145
150
|
directory="dist",
|
|
151
|
+
host="localhost",
|
|
146
152
|
port=5000,
|
|
147
153
|
base_path="/repo-name",
|
|
148
154
|
strict=True,
|
|
@@ -159,6 +165,7 @@ server.start()
|
|
|
159
165
|
| Parameter | Type | Description | Default |
|
|
160
166
|
|------------|------|-------------|----------|
|
|
161
167
|
| `directory` | `str` | Directory to serve | `"."` |
|
|
168
|
+
| `host` | `str` | Host address to bind the server to | `"localhost"` |
|
|
162
169
|
| `port` | `int` | Port number | `8000` |
|
|
163
170
|
| `base_path` | `str` | Base path for project page simulation | `""` |
|
|
164
171
|
| `strict` | `bool` | Enforce GitHub-like routing behavior | `True` |
|
|
@@ -167,7 +174,11 @@ server.start()
|
|
|
167
174
|
| `auto_open` | `bool` | Automatically open the server URL | `False` |
|
|
168
175
|
| `directory_listing` | `bool` | Enable directory listing | `False` |
|
|
169
176
|
|
|
170
|
-
|
|
177
|
+
> [!NOTE]
|
|
178
|
+
> You can set `port=0` to let the OS automatically select an available port.
|
|
179
|
+
|
|
180
|
+
> [!NOTE]
|
|
181
|
+
> The `host` parameter controls the network interface used for server binding. The default is `"localhost"`.
|
|
171
182
|
|
|
172
183
|
## Issues & Bug Reports
|
|
173
184
|
|
|
@@ -218,6 +229,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
218
229
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
219
230
|
|
|
220
231
|
## [Unreleased]
|
|
232
|
+
## [0.7] - 2026-09-22
|
|
233
|
+
### Added
|
|
234
|
+
- `host` parameter
|
|
235
|
+
- `--host` CLI argument
|
|
236
|
+
### Changed
|
|
237
|
+
- Test system modified
|
|
238
|
+
- `README.md` updated
|
|
239
|
+
## [0.6] - 2026-08-31
|
|
240
|
+
### Added
|
|
241
|
+
- Custom default error page
|
|
242
|
+
### Changed
|
|
243
|
+
- Server header modified
|
|
221
244
|
## [0.5] - 2026-08-02
|
|
222
245
|
### Added
|
|
223
246
|
- `directory_listing` parameter
|
|
@@ -260,7 +283,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
260
283
|
- Command line interface
|
|
261
284
|
- Test system
|
|
262
285
|
|
|
263
|
-
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.
|
|
286
|
+
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.7...dev
|
|
287
|
+
[0.7]: https://github.com/sepandhaghighi/ghps/compare/v0.6...v0.7
|
|
288
|
+
[0.6]: https://github.com/sepandhaghighi/ghps/compare/v0.5...v0.6
|
|
264
289
|
[0.5]: https://github.com/sepandhaghighi/ghps/compare/v0.4...v0.5
|
|
265
290
|
[0.4]: https://github.com/sepandhaghighi/ghps/compare/v0.3...v0.4
|
|
266
291
|
[0.3]: https://github.com/sepandhaghighi/ghps/compare/v0.2...v0.3
|
{ghps-0.5 → ghps-0.7}/README.md
RENAMED
|
@@ -50,13 +50,13 @@
|
|
|
50
50
|
## Installation
|
|
51
51
|
|
|
52
52
|
### Source Code
|
|
53
|
-
- Download [Version 0.
|
|
53
|
+
- Download [Version 0.7](https://github.com/sepandhaghighi/ghps/archive/v0.7.zip) or [Latest Source](https://github.com/sepandhaghighi/ghps/archive/dev.zip)
|
|
54
54
|
- `pip install .`
|
|
55
55
|
|
|
56
56
|
### PyPI
|
|
57
57
|
|
|
58
58
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
59
|
-
- `pip install ghps==0.
|
|
59
|
+
- `pip install ghps==0.7`
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
## Usage
|
|
@@ -66,13 +66,14 @@ Ghps can be used both as a CLI tool and as a Python library.
|
|
|
66
66
|
### CLI
|
|
67
67
|
|
|
68
68
|
```bash
|
|
69
|
-
ghps --port=8080 --no-cache --no-threaded
|
|
69
|
+
ghps --host=127.0.0.1 --port=8080 --no-cache --no-threaded
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
#### Options
|
|
73
73
|
|
|
74
74
|
| Option | Description | Default |
|
|
75
75
|
|--------|-------------|----------|
|
|
76
|
+
| `--host` | Host address to bind to | `localhost` |
|
|
76
77
|
| `-p, --port` | Port to serve on | `8000` |
|
|
77
78
|
| `-d, --directory` | Directory to serve | Current directory (`.`) |
|
|
78
79
|
| `-b, --base-path` | Base path for project pages (e.g. `/repo-name`) | `""` |
|
|
@@ -82,7 +83,11 @@ ghps --port=8080 --no-cache --no-threaded
|
|
|
82
83
|
| `--auto-open` | Automatically open the server URL | Disable |
|
|
83
84
|
| `--directory-listing` | Enable directory listing | Disable |
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
> [!NOTE]
|
|
87
|
+
> You can set `--port=0` to let the OS automatically select an available port.
|
|
88
|
+
|
|
89
|
+
> [!NOTE]
|
|
90
|
+
> You can use `--host=0.0.0.0` to bind Ghps to all available network interfaces, or specify a particular address such as `127.0.0.1`.
|
|
86
91
|
|
|
87
92
|
|
|
88
93
|
### Library
|
|
@@ -92,6 +97,7 @@ from ghps import GHPageServer
|
|
|
92
97
|
|
|
93
98
|
server = GHPageServer(
|
|
94
99
|
directory="dist",
|
|
100
|
+
host="localhost",
|
|
95
101
|
port=5000,
|
|
96
102
|
base_path="/repo-name",
|
|
97
103
|
strict=True,
|
|
@@ -108,6 +114,7 @@ server.start()
|
|
|
108
114
|
| Parameter | Type | Description | Default |
|
|
109
115
|
|------------|------|-------------|----------|
|
|
110
116
|
| `directory` | `str` | Directory to serve | `"."` |
|
|
117
|
+
| `host` | `str` | Host address to bind the server to | `"localhost"` |
|
|
111
118
|
| `port` | `int` | Port number | `8000` |
|
|
112
119
|
| `base_path` | `str` | Base path for project page simulation | `""` |
|
|
113
120
|
| `strict` | `bool` | Enforce GitHub-like routing behavior | `True` |
|
|
@@ -116,7 +123,11 @@ server.start()
|
|
|
116
123
|
| `auto_open` | `bool` | Automatically open the server URL | `False` |
|
|
117
124
|
| `directory_listing` | `bool` | Enable directory listing | `False` |
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
> [!NOTE]
|
|
127
|
+
> You can set `port=0` to let the OS automatically select an available port.
|
|
128
|
+
|
|
129
|
+
> [!NOTE]
|
|
130
|
+
> The `host` parameter controls the network interface used for server binding. The default is `"localhost"`.
|
|
120
131
|
|
|
121
132
|
## Issues & Bug Reports
|
|
122
133
|
|
|
@@ -32,6 +32,13 @@ def _parse_args() -> argparse.Namespace:
|
|
|
32
32
|
help="Version"
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
parser.add_argument(
|
|
36
|
+
"--host",
|
|
37
|
+
type=str,
|
|
38
|
+
default="localhost",
|
|
39
|
+
help="Host address to bind to (default: localhost)"
|
|
40
|
+
)
|
|
41
|
+
|
|
35
42
|
parser.add_argument(
|
|
36
43
|
"-p", "--port",
|
|
37
44
|
type=int,
|
|
@@ -94,6 +101,7 @@ def main() -> None:
|
|
|
94
101
|
else:
|
|
95
102
|
server = GHPageServer(
|
|
96
103
|
directory=args.directory,
|
|
104
|
+
host=args.host,
|
|
97
105
|
port=args.port,
|
|
98
106
|
base_path=args.base_path,
|
|
99
107
|
strict=not args.no_strict,
|
ghps-0.7/ghps/params.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""ghps params."""
|
|
3
|
+
|
|
4
|
+
GHPS_VERSION = "0.7"
|
|
5
|
+
GHPS_REPO = "https://github.com/sepandhaghighi/ghps"
|
|
6
|
+
|
|
7
|
+
INVALID_DIRECTORY_TYPE_ERROR = "`directory` must be str or pathlib.Path."
|
|
8
|
+
DIRECTORY_NOT_FOUND_ERROR = "`directory` does not exist."
|
|
9
|
+
DIRECTORY_NOT_DIR_ERROR = "`directory` must be a valid directory."
|
|
10
|
+
|
|
11
|
+
INVALID_HOST_TYPE_ERROR = "`host` must be str."
|
|
12
|
+
INVALID_PORT_TYPE_ERROR = "`port` must be int."
|
|
13
|
+
INVALID_PORT_RANGE_ERROR = "`port` must be between 0 and 65535."
|
|
14
|
+
|
|
15
|
+
INVALID_BASE_PATH_TYPE_ERROR = "`base_path` must be str."
|
|
16
|
+
INVALID_BASE_PATH_FORMAT_ERROR = "`base_path` must start with '/' or be empty."
|
|
17
|
+
|
|
18
|
+
INVALID_STRICT_TYPE_ERROR = "`strict` must be bool."
|
|
19
|
+
INVALID_NO_CACHE_TYPE_ERROR = "`no_cache` must be bool."
|
|
20
|
+
INVALID_THREADED_TYPE_ERROR = "`threaded` must be bool."
|
|
21
|
+
INVALID_AUTO_OPEN_TYPE_ERROR = "`auto_open` must be bool."
|
|
22
|
+
INVALID_DIRECTORY_LISTING_TYPE_ERROR = "`directory_listing` must be bool."
|
|
23
|
+
|
|
24
|
+
PORT_IN_USE_ERROR = "`port` is already in use. Try another port or use `0` for automatic allocation."
|
|
25
|
+
PORT_ACCESS_DENIED_ERROR = "`port` access denied. Try a different port or check permissions."
|
|
26
|
+
PORT_ADDRESS_NOT_AVAILABLE_ERROR = "`port` address is not available. Check network configuration."
|
|
27
|
+
PORT_BIND_GENERIC_ERROR = "Failed to start server on port `{port}`: {error}"
|
|
28
|
+
|
|
29
|
+
DEFAULT_ERROR_PAGE = """<!DOCTYPE html>
|
|
30
|
+
<html lang="en">
|
|
31
|
+
<head>
|
|
32
|
+
<meta charset="utf-8">
|
|
33
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
34
|
+
<title>{code} - {message}</title>
|
|
35
|
+
<style>
|
|
36
|
+
body {{
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: 40px 20px;
|
|
39
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont,
|
|
40
|
+
"Segoe UI", sans-serif;
|
|
41
|
+
background: #f6f8fa;
|
|
42
|
+
color: #24292f;
|
|
43
|
+
}}
|
|
44
|
+
|
|
45
|
+
main {{
|
|
46
|
+
max-width: 720px;
|
|
47
|
+
margin: 80px auto;
|
|
48
|
+
padding: 40px;
|
|
49
|
+
background: #ffffff;
|
|
50
|
+
border: 1px solid #d0d7de;
|
|
51
|
+
border-radius: 8px;
|
|
52
|
+
}}
|
|
53
|
+
|
|
54
|
+
h1 {{
|
|
55
|
+
margin: 0 0 12px;
|
|
56
|
+
font-size: 32px;
|
|
57
|
+
}}
|
|
58
|
+
|
|
59
|
+
p {{
|
|
60
|
+
margin: 8px 0;
|
|
61
|
+
color: #57606a;
|
|
62
|
+
}}
|
|
63
|
+
|
|
64
|
+
.status {{
|
|
65
|
+
font-size: 18px;
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
color: #24292f;
|
|
68
|
+
}}
|
|
69
|
+
|
|
70
|
+
footer {{
|
|
71
|
+
margin-top: 32px;
|
|
72
|
+
padding-top: 16px;
|
|
73
|
+
border-top: 1px solid #d0d7de;
|
|
74
|
+
font-size: 13px;
|
|
75
|
+
color: #57606a;
|
|
76
|
+
}}
|
|
77
|
+
</style>
|
|
78
|
+
</head>
|
|
79
|
+
<body>
|
|
80
|
+
<main>
|
|
81
|
+
<h1>{code}</h1>
|
|
82
|
+
<p class="status">{message}</p>
|
|
83
|
+
<p>{explain}</p>
|
|
84
|
+
<p>The requested resource could not be served by Ghps.</p>
|
|
85
|
+
|
|
86
|
+
<footer>
|
|
87
|
+
<a href="{repo}">Ghps/{version} — A Minimal GitHub Pages Simulator for Local Development</a>
|
|
88
|
+
</footer>
|
|
89
|
+
</main>
|
|
90
|
+
</body>
|
|
91
|
+
</html>
|
|
92
|
+
"""
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"""ghps server."""
|
|
3
3
|
|
|
4
4
|
import http.server
|
|
5
|
+
from http import HTTPStatus
|
|
5
6
|
import socketserver
|
|
6
7
|
import webbrowser
|
|
7
8
|
import errno
|
|
@@ -10,9 +11,13 @@ from typing import Optional, Any
|
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from urllib.parse import unquote
|
|
12
13
|
from .params import (
|
|
14
|
+
GHPS_VERSION,
|
|
15
|
+
GHPS_REPO,
|
|
16
|
+
DEFAULT_ERROR_PAGE,
|
|
13
17
|
INVALID_DIRECTORY_TYPE_ERROR,
|
|
14
18
|
DIRECTORY_NOT_FOUND_ERROR,
|
|
15
19
|
DIRECTORY_NOT_DIR_ERROR,
|
|
20
|
+
INVALID_HOST_TYPE_ERROR,
|
|
16
21
|
INVALID_PORT_TYPE_ERROR,
|
|
17
22
|
INVALID_PORT_RANGE_ERROR,
|
|
18
23
|
INVALID_BASE_PATH_TYPE_ERROR,
|
|
@@ -34,6 +39,7 @@ from .errors import GHPSValidationError, GHPSRuntimeError
|
|
|
34
39
|
|
|
35
40
|
def _validate_inputs(
|
|
36
41
|
directory: Any,
|
|
42
|
+
host: Any,
|
|
37
43
|
port: Any,
|
|
38
44
|
base_path: Any,
|
|
39
45
|
strict: Any,
|
|
@@ -46,6 +52,7 @@ def _validate_inputs(
|
|
|
46
52
|
Validate GHPageServer inputs.
|
|
47
53
|
|
|
48
54
|
:param directory: Root directory to serve files from.
|
|
55
|
+
:param host: Host address to bind the server to.
|
|
49
56
|
:param port: Port number to bind the server to.
|
|
50
57
|
:param base_path: URL base path prefix for serving content.
|
|
51
58
|
:param strict: If False, enables automatic ".html" resolution.
|
|
@@ -64,6 +71,9 @@ def _validate_inputs(
|
|
|
64
71
|
if not directory.is_dir():
|
|
65
72
|
raise GHPSValidationError(DIRECTORY_NOT_DIR_ERROR)
|
|
66
73
|
|
|
74
|
+
if not isinstance(host, str):
|
|
75
|
+
raise GHPSValidationError(INVALID_HOST_TYPE_ERROR)
|
|
76
|
+
|
|
67
77
|
if not isinstance(port, int) or isinstance(port, bool):
|
|
68
78
|
raise GHPSValidationError(INVALID_PORT_TYPE_ERROR)
|
|
69
79
|
|
|
@@ -119,6 +129,9 @@ def _handle_bind_error(port: int, e: OSError) -> None:
|
|
|
119
129
|
class _GHRequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
120
130
|
"""Custom HTTP request handler for serving static files with optional base path stripping, strict routing, custom 404 page support, and cache control headers."""
|
|
121
131
|
|
|
132
|
+
server_version = f"Ghps/{GHPS_VERSION}"
|
|
133
|
+
sys_version = ""
|
|
134
|
+
|
|
122
135
|
def __init__(
|
|
123
136
|
self,
|
|
124
137
|
*args: list,
|
|
@@ -196,7 +209,26 @@ class _GHRequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
|
196
209
|
with open(not_found, "rb") as f:
|
|
197
210
|
self.wfile.write(f.read())
|
|
198
211
|
return
|
|
199
|
-
|
|
212
|
+
if message is None:
|
|
213
|
+
message = HTTPStatus(code).phrase
|
|
214
|
+
if explain is None:
|
|
215
|
+
explain = HTTPStatus(code).description
|
|
216
|
+
|
|
217
|
+
html = DEFAULT_ERROR_PAGE.format(
|
|
218
|
+
code=code,
|
|
219
|
+
message=message,
|
|
220
|
+
explain=explain,
|
|
221
|
+
version=GHPS_VERSION,
|
|
222
|
+
repo=GHPS_REPO,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
encoded = html.encode("utf-8")
|
|
226
|
+
|
|
227
|
+
self.send_response(code)
|
|
228
|
+
self.send_header("Content-Type", "text/html; charset=utf-8")
|
|
229
|
+
self.send_header("Content-Length", str(len(encoded)))
|
|
230
|
+
self.end_headers()
|
|
231
|
+
self.wfile.write(encoded)
|
|
200
232
|
|
|
201
233
|
def end_headers(self) -> None:
|
|
202
234
|
"""
|
|
@@ -223,6 +255,7 @@ class GHPageServer:
|
|
|
223
255
|
def __init__(
|
|
224
256
|
self,
|
|
225
257
|
directory: str = ".",
|
|
258
|
+
host: str = "localhost",
|
|
226
259
|
port: int = 8000,
|
|
227
260
|
base_path: str = "",
|
|
228
261
|
strict: bool = True,
|
|
@@ -235,6 +268,7 @@ class GHPageServer:
|
|
|
235
268
|
Initialize the server.
|
|
236
269
|
|
|
237
270
|
:param directory: Root directory to serve files from.
|
|
271
|
+
:param host: Host address to bind the server to.
|
|
238
272
|
:param port: Port number to bind the server to.
|
|
239
273
|
:param base_path: URL base path prefix for serving content.
|
|
240
274
|
:param strict: If False, enables automatic ".html" resolution.
|
|
@@ -245,6 +279,7 @@ class GHPageServer:
|
|
|
245
279
|
"""
|
|
246
280
|
_validate_inputs(
|
|
247
281
|
directory=directory,
|
|
282
|
+
host=host,
|
|
248
283
|
port=port,
|
|
249
284
|
base_path=base_path,
|
|
250
285
|
strict=strict,
|
|
@@ -254,6 +289,7 @@ class GHPageServer:
|
|
|
254
289
|
directory_listing=directory_listing
|
|
255
290
|
)
|
|
256
291
|
self._directory = str(Path(directory).resolve())
|
|
292
|
+
self._host = host
|
|
257
293
|
self._port = port
|
|
258
294
|
self._url = None
|
|
259
295
|
self._base_path = base_path
|
|
@@ -289,11 +325,11 @@ class GHPageServer:
|
|
|
289
325
|
server_cls = _ThreadedTCPServer if self._threaded else socketserver.TCPServer
|
|
290
326
|
|
|
291
327
|
try:
|
|
292
|
-
self._httpd = server_cls((
|
|
328
|
+
self._httpd = server_cls((self._host, self._port), handler)
|
|
293
329
|
except OSError as e:
|
|
294
330
|
_handle_bind_error(self._port, e)
|
|
295
331
|
self._port = self._httpd.server_address[1]
|
|
296
|
-
self._url = f"http://
|
|
332
|
+
self._url = f"http://{self._host}:{self._port}{self._base_path}"
|
|
297
333
|
self._print_server_info()
|
|
298
334
|
|
|
299
335
|
if self._auto_open:
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ghps
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7
|
|
4
4
|
Summary: Ghps: A Minimal GitHub Pages Simulator for Local Development
|
|
5
5
|
Home-page: https://github.com/sepandhaghighi/ghps
|
|
6
|
-
Download-URL: https://github.com/sepandhaghighi/ghps/tarball/v0.
|
|
6
|
+
Download-URL: https://github.com/sepandhaghighi/ghps/tarball/v0.7
|
|
7
7
|
Author: Sepand Haghighi
|
|
8
8
|
Author-email: me@sepand.tech
|
|
9
9
|
License: MIT
|
|
10
10
|
Project-URL: Source, https://github.com/sepandhaghighi/ghps
|
|
11
11
|
Keywords: github gh-pages static-server static-hosting development server local http simulator testing cli python
|
|
12
|
-
Classifier: Development Status ::
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
14
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
15
|
Classifier: Operating System :: OS Independent
|
|
@@ -101,13 +101,13 @@ Dynamic: summary
|
|
|
101
101
|
## Installation
|
|
102
102
|
|
|
103
103
|
### Source Code
|
|
104
|
-
- Download [Version 0.
|
|
104
|
+
- Download [Version 0.7](https://github.com/sepandhaghighi/ghps/archive/v0.7.zip) or [Latest Source](https://github.com/sepandhaghighi/ghps/archive/dev.zip)
|
|
105
105
|
- `pip install .`
|
|
106
106
|
|
|
107
107
|
### PyPI
|
|
108
108
|
|
|
109
109
|
- Check [Python Packaging User Guide](https://packaging.python.org/installing/)
|
|
110
|
-
- `pip install ghps==0.
|
|
110
|
+
- `pip install ghps==0.7`
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
## Usage
|
|
@@ -117,13 +117,14 @@ Ghps can be used both as a CLI tool and as a Python library.
|
|
|
117
117
|
### CLI
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
|
-
ghps --port=8080 --no-cache --no-threaded
|
|
120
|
+
ghps --host=127.0.0.1 --port=8080 --no-cache --no-threaded
|
|
121
121
|
```
|
|
122
122
|
|
|
123
123
|
#### Options
|
|
124
124
|
|
|
125
125
|
| Option | Description | Default |
|
|
126
126
|
|--------|-------------|----------|
|
|
127
|
+
| `--host` | Host address to bind to | `localhost` |
|
|
127
128
|
| `-p, --port` | Port to serve on | `8000` |
|
|
128
129
|
| `-d, --directory` | Directory to serve | Current directory (`.`) |
|
|
129
130
|
| `-b, --base-path` | Base path for project pages (e.g. `/repo-name`) | `""` |
|
|
@@ -133,7 +134,11 @@ ghps --port=8080 --no-cache --no-threaded
|
|
|
133
134
|
| `--auto-open` | Automatically open the server URL | Disable |
|
|
134
135
|
| `--directory-listing` | Enable directory listing | Disable |
|
|
135
136
|
|
|
136
|
-
|
|
137
|
+
> [!NOTE]
|
|
138
|
+
> You can set `--port=0` to let the OS automatically select an available port.
|
|
139
|
+
|
|
140
|
+
> [!NOTE]
|
|
141
|
+
> You can use `--host=0.0.0.0` to bind Ghps to all available network interfaces, or specify a particular address such as `127.0.0.1`.
|
|
137
142
|
|
|
138
143
|
|
|
139
144
|
### Library
|
|
@@ -143,6 +148,7 @@ from ghps import GHPageServer
|
|
|
143
148
|
|
|
144
149
|
server = GHPageServer(
|
|
145
150
|
directory="dist",
|
|
151
|
+
host="localhost",
|
|
146
152
|
port=5000,
|
|
147
153
|
base_path="/repo-name",
|
|
148
154
|
strict=True,
|
|
@@ -159,6 +165,7 @@ server.start()
|
|
|
159
165
|
| Parameter | Type | Description | Default |
|
|
160
166
|
|------------|------|-------------|----------|
|
|
161
167
|
| `directory` | `str` | Directory to serve | `"."` |
|
|
168
|
+
| `host` | `str` | Host address to bind the server to | `"localhost"` |
|
|
162
169
|
| `port` | `int` | Port number | `8000` |
|
|
163
170
|
| `base_path` | `str` | Base path for project page simulation | `""` |
|
|
164
171
|
| `strict` | `bool` | Enforce GitHub-like routing behavior | `True` |
|
|
@@ -167,7 +174,11 @@ server.start()
|
|
|
167
174
|
| `auto_open` | `bool` | Automatically open the server URL | `False` |
|
|
168
175
|
| `directory_listing` | `bool` | Enable directory listing | `False` |
|
|
169
176
|
|
|
170
|
-
|
|
177
|
+
> [!NOTE]
|
|
178
|
+
> You can set `port=0` to let the OS automatically select an available port.
|
|
179
|
+
|
|
180
|
+
> [!NOTE]
|
|
181
|
+
> The `host` parameter controls the network interface used for server binding. The default is `"localhost"`.
|
|
171
182
|
|
|
172
183
|
## Issues & Bug Reports
|
|
173
184
|
|
|
@@ -218,6 +229,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
|
|
218
229
|
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
|
219
230
|
|
|
220
231
|
## [Unreleased]
|
|
232
|
+
## [0.7] - 2026-09-22
|
|
233
|
+
### Added
|
|
234
|
+
- `host` parameter
|
|
235
|
+
- `--host` CLI argument
|
|
236
|
+
### Changed
|
|
237
|
+
- Test system modified
|
|
238
|
+
- `README.md` updated
|
|
239
|
+
## [0.6] - 2026-08-31
|
|
240
|
+
### Added
|
|
241
|
+
- Custom default error page
|
|
242
|
+
### Changed
|
|
243
|
+
- Server header modified
|
|
221
244
|
## [0.5] - 2026-08-02
|
|
222
245
|
### Added
|
|
223
246
|
- `directory_listing` parameter
|
|
@@ -260,7 +283,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
260
283
|
- Command line interface
|
|
261
284
|
- Test system
|
|
262
285
|
|
|
263
|
-
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.
|
|
286
|
+
[Unreleased]: https://github.com/sepandhaghighi/ghps/compare/v0.7...dev
|
|
287
|
+
[0.7]: https://github.com/sepandhaghighi/ghps/compare/v0.6...v0.7
|
|
288
|
+
[0.6]: https://github.com/sepandhaghighi/ghps/compare/v0.5...v0.6
|
|
264
289
|
[0.5]: https://github.com/sepandhaghighi/ghps/compare/v0.4...v0.5
|
|
265
290
|
[0.4]: https://github.com/sepandhaghighi/ghps/compare/v0.3...v0.4
|
|
266
291
|
[0.3]: https://github.com/sepandhaghighi/ghps/compare/v0.2...v0.3
|
{ghps-0.5 → ghps-0.7}/setup.py
RENAMED
|
@@ -22,7 +22,7 @@ def read_description() -> str:
|
|
|
22
22
|
setup(
|
|
23
23
|
name='ghps',
|
|
24
24
|
packages=['ghps'],
|
|
25
|
-
version='0.
|
|
25
|
+
version='0.7',
|
|
26
26
|
description='Ghps: A Minimal GitHub Pages Simulator for Local Development',
|
|
27
27
|
long_description=read_description(),
|
|
28
28
|
long_description_content_type='text/markdown',
|
|
@@ -30,7 +30,7 @@ setup(
|
|
|
30
30
|
author='Sepand Haghighi',
|
|
31
31
|
author_email='me@sepand.tech',
|
|
32
32
|
url='https://github.com/sepandhaghighi/ghps',
|
|
33
|
-
download_url='https://github.com/sepandhaghighi/ghps/tarball/v0.
|
|
33
|
+
download_url='https://github.com/sepandhaghighi/ghps/tarball/v0.7',
|
|
34
34
|
keywords='github gh-pages static-server static-hosting development server local http simulator testing cli python',
|
|
35
35
|
project_urls={
|
|
36
36
|
'Source': 'https://github.com/sepandhaghighi/ghps'
|
|
@@ -38,7 +38,7 @@ setup(
|
|
|
38
38
|
install_requires=['art>=5.3'],
|
|
39
39
|
python_requires='>=3.7',
|
|
40
40
|
classifiers=[
|
|
41
|
-
'Development Status ::
|
|
41
|
+
'Development Status :: 4 - Beta',
|
|
42
42
|
'Natural Language :: English',
|
|
43
43
|
'License :: OSI Approved :: MIT License',
|
|
44
44
|
'Operating System :: OS Independent',
|
|
@@ -36,6 +36,7 @@ def test_cli_default_arguments(monkeypatch):
|
|
|
36
36
|
|
|
37
37
|
run_cli(monkeypatch, [])
|
|
38
38
|
|
|
39
|
+
assert captured["host"] == "localhost"
|
|
39
40
|
assert captured["port"] == 8000
|
|
40
41
|
assert captured["strict"] is True
|
|
41
42
|
assert captured["no_cache"] is False
|
|
@@ -64,6 +65,26 @@ def test_cli_custom_port_and_directory(monkeypatch, tmp_path):
|
|
|
64
65
|
assert captured["directory"] == str(tmp_path.resolve())
|
|
65
66
|
|
|
66
67
|
|
|
68
|
+
def test_cli_host(monkeypatch):
|
|
69
|
+
captured = {}
|
|
70
|
+
|
|
71
|
+
def fake_init(self, **kwargs):
|
|
72
|
+
captured.update(kwargs)
|
|
73
|
+
|
|
74
|
+
monkeypatch.setattr(ghps.cli, "GHPageServer", type(
|
|
75
|
+
"MockServer",
|
|
76
|
+
(),
|
|
77
|
+
{
|
|
78
|
+
"__init__": fake_init,
|
|
79
|
+
"start": lambda self: None,
|
|
80
|
+
},
|
|
81
|
+
))
|
|
82
|
+
|
|
83
|
+
run_cli(monkeypatch, ["--host", "127.0.0.1"])
|
|
84
|
+
|
|
85
|
+
assert captured["host"] == "127.0.0.1"
|
|
86
|
+
|
|
87
|
+
|
|
67
88
|
def test_cli_base_path(monkeypatch):
|
|
68
89
|
captured = {}
|
|
69
90
|
|
|
@@ -47,6 +47,20 @@ def test_directory_not_directory(tmp_path):
|
|
|
47
47
|
)
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
def test_invalid_host_type(tmp_path):
|
|
51
|
+
with pytest.raises(GHPSValidationError, match="`host` must be str."):
|
|
52
|
+
GHPageServer(
|
|
53
|
+
directory=tmp_path,
|
|
54
|
+
port=8000,
|
|
55
|
+
host=123,
|
|
56
|
+
base_path="",
|
|
57
|
+
strict=True,
|
|
58
|
+
no_cache=False,
|
|
59
|
+
threaded=True,
|
|
60
|
+
directory_listing=False,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
50
64
|
def test_invalid_port_type1(tmp_path):
|
|
51
65
|
with pytest.raises(GHPSValidationError, match="`port` must be int."):
|
|
52
66
|
GHPageServer(
|
|
@@ -6,6 +6,8 @@ from pathlib import Path
|
|
|
6
6
|
import requests
|
|
7
7
|
from unittest.mock import patch, MagicMock
|
|
8
8
|
from ghps import GHPageServer
|
|
9
|
+
from ghps.server import _GHRequestHandler
|
|
10
|
+
from http import HTTPStatus
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def run_server(server):
|
|
@@ -36,6 +38,25 @@ def test_404_without_custom_page():
|
|
|
36
38
|
|
|
37
39
|
response = requests.get("http://localhost:9002/missing", timeout=5)
|
|
38
40
|
assert response.status_code == 404
|
|
41
|
+
assert "404" in response.text
|
|
42
|
+
assert "The requested resource could not be served by Ghps." in response.text
|
|
43
|
+
assert "Ghps/" in response.text
|
|
44
|
+
|
|
45
|
+
server.stop()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_default_error_page_content():
|
|
49
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
50
|
+
server = GHPageServer(directory=tmpdir, port=9010)
|
|
51
|
+
run_server(server)
|
|
52
|
+
|
|
53
|
+
response = requests.get("http://localhost:9010/missing", timeout=5)
|
|
54
|
+
|
|
55
|
+
assert response.status_code == 404
|
|
56
|
+
assert response.headers["Content-Type"].startswith("text/html")
|
|
57
|
+
assert "404" in response.text
|
|
58
|
+
assert "The requested resource could not be served by Ghps." in response.text
|
|
59
|
+
assert "A Minimal GitHub Pages Simulator for Local Development" in response.text
|
|
39
60
|
|
|
40
61
|
server.stop()
|
|
41
62
|
|
|
@@ -54,6 +75,78 @@ def test_custom_404_page():
|
|
|
54
75
|
server.stop()
|
|
55
76
|
|
|
56
77
|
|
|
78
|
+
def test_send_error_uses_default_message(tmp_path):
|
|
79
|
+
handler = _GHRequestHandler.__new__(_GHRequestHandler)
|
|
80
|
+
|
|
81
|
+
handler.directory = str(tmp_path)
|
|
82
|
+
handler.wfile = MagicMock()
|
|
83
|
+
handler._no_cache = False
|
|
84
|
+
|
|
85
|
+
handler.send_response = MagicMock()
|
|
86
|
+
handler.send_header = MagicMock()
|
|
87
|
+
handler.end_headers = MagicMock()
|
|
88
|
+
|
|
89
|
+
_GHRequestHandler.send_error(
|
|
90
|
+
handler,
|
|
91
|
+
404,
|
|
92
|
+
message=None,
|
|
93
|
+
explain="custom explanation",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
html = handler.wfile.write.call_args[0][0].decode("utf-8")
|
|
97
|
+
|
|
98
|
+
assert HTTPStatus(404).phrase in html
|
|
99
|
+
assert "custom explanation" in html
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_send_error_uses_default_explain(tmp_path):
|
|
103
|
+
handler = _GHRequestHandler.__new__(_GHRequestHandler)
|
|
104
|
+
|
|
105
|
+
handler.directory = str(tmp_path)
|
|
106
|
+
handler.wfile = MagicMock()
|
|
107
|
+
handler._no_cache = False
|
|
108
|
+
|
|
109
|
+
handler.send_response = MagicMock()
|
|
110
|
+
handler.send_header = MagicMock()
|
|
111
|
+
handler.end_headers = MagicMock()
|
|
112
|
+
|
|
113
|
+
_GHRequestHandler.send_error(
|
|
114
|
+
handler,
|
|
115
|
+
404,
|
|
116
|
+
message="Custom message",
|
|
117
|
+
explain=None,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
html = handler.wfile.write.call_args[0][0].decode("utf-8")
|
|
121
|
+
|
|
122
|
+
assert "Custom message" in html
|
|
123
|
+
assert HTTPStatus(404).description in html
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_send_error_uses_default_message_and_explain(tmp_path):
|
|
127
|
+
handler = _GHRequestHandler.__new__(_GHRequestHandler)
|
|
128
|
+
|
|
129
|
+
handler.directory = str(tmp_path)
|
|
130
|
+
handler.wfile = MagicMock()
|
|
131
|
+
handler._no_cache = False
|
|
132
|
+
|
|
133
|
+
handler.send_response = MagicMock()
|
|
134
|
+
handler.send_header = MagicMock()
|
|
135
|
+
handler.end_headers = MagicMock()
|
|
136
|
+
|
|
137
|
+
_GHRequestHandler.send_error(
|
|
138
|
+
handler,
|
|
139
|
+
404,
|
|
140
|
+
message=None,
|
|
141
|
+
explain=None,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
html = handler.wfile.write.call_args[0][0].decode("utf-8")
|
|
145
|
+
|
|
146
|
+
assert HTTPStatus(404).phrase in html
|
|
147
|
+
assert HTTPStatus(404).description in html
|
|
148
|
+
|
|
149
|
+
|
|
57
150
|
def test_non_strict_html_fallback():
|
|
58
151
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
59
152
|
Path(tmpdir, "about.html").write_text("About Page")
|
|
@@ -166,6 +259,25 @@ def test_auto_open_disabled(mock_server_cls, mock_web_open, tmp_path):
|
|
|
166
259
|
mock_web_open.assert_not_called()
|
|
167
260
|
|
|
168
261
|
|
|
262
|
+
@patch("ghps.server.webbrowser.open")
|
|
263
|
+
@patch("ghps.server._ThreadedTCPServer")
|
|
264
|
+
def test_auto_open_custom_host(mock_server_cls, mock_web_open, tmp_path):
|
|
265
|
+
mock_server = mock_server_cls.return_value
|
|
266
|
+
mock_server.server_address = ("127.0.0.1", 8000)
|
|
267
|
+
mock_server.serve_forever.side_effect = KeyboardInterrupt
|
|
268
|
+
|
|
269
|
+
server = GHPageServer(
|
|
270
|
+
directory=tmp_path,
|
|
271
|
+
port=8000,
|
|
272
|
+
host="127.0.0.1",
|
|
273
|
+
auto_open=True,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
server.start()
|
|
277
|
+
|
|
278
|
+
mock_web_open.assert_called_once_with("http://127.0.0.1:8000")
|
|
279
|
+
|
|
280
|
+
|
|
169
281
|
@patch("ghps.server._ThreadedTCPServer")
|
|
170
282
|
def test_random_port_resolution(mock_server_cls, tmp_path):
|
|
171
283
|
mock_server = mock_server_cls.return_value
|
|
@@ -179,6 +291,26 @@ def test_random_port_resolution(mock_server_cls, tmp_path):
|
|
|
179
291
|
assert server._port == 54321
|
|
180
292
|
|
|
181
293
|
|
|
294
|
+
@patch("ghps.server._ThreadedTCPServer")
|
|
295
|
+
def test_custom_host_binding(mock_server_cls, tmp_path):
|
|
296
|
+
mock_server = mock_server_cls.return_value
|
|
297
|
+
mock_server.server_address = ("127.0.0.1", 8000)
|
|
298
|
+
mock_server.serve_forever.side_effect = KeyboardInterrupt
|
|
299
|
+
|
|
300
|
+
server = GHPageServer(
|
|
301
|
+
directory=tmp_path,
|
|
302
|
+
port=8000,
|
|
303
|
+
host="127.0.0.1",
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
server.start()
|
|
307
|
+
|
|
308
|
+
mock_server_cls.assert_called_once()
|
|
309
|
+
address = mock_server_cls.call_args[0][0]
|
|
310
|
+
|
|
311
|
+
assert address == ("127.0.0.1", 8000)
|
|
312
|
+
|
|
313
|
+
|
|
182
314
|
def test_directory_listing_enabled():
|
|
183
315
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
184
316
|
Path(tmpdir, "file.txt").write_text("Hello")
|
ghps-0.5/ghps/params.py
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""ghps params."""
|
|
3
|
-
|
|
4
|
-
GHPS_VERSION = "0.5"
|
|
5
|
-
|
|
6
|
-
INVALID_DIRECTORY_TYPE_ERROR = "`directory` must be str or pathlib.Path."
|
|
7
|
-
DIRECTORY_NOT_FOUND_ERROR = "`directory` does not exist."
|
|
8
|
-
DIRECTORY_NOT_DIR_ERROR = "`directory` must be a valid directory."
|
|
9
|
-
|
|
10
|
-
INVALID_PORT_TYPE_ERROR = "`port` must be int."
|
|
11
|
-
INVALID_PORT_RANGE_ERROR = "`port` must be between 0 and 65535."
|
|
12
|
-
|
|
13
|
-
INVALID_BASE_PATH_TYPE_ERROR = "`base_path` must be str."
|
|
14
|
-
INVALID_BASE_PATH_FORMAT_ERROR = "`base_path` must start with '/' or be empty."
|
|
15
|
-
|
|
16
|
-
INVALID_STRICT_TYPE_ERROR = "`strict` must be bool."
|
|
17
|
-
INVALID_NO_CACHE_TYPE_ERROR = "`no_cache` must be bool."
|
|
18
|
-
INVALID_THREADED_TYPE_ERROR = "`threaded` must be bool."
|
|
19
|
-
INVALID_AUTO_OPEN_TYPE_ERROR = "`auto_open` must be bool."
|
|
20
|
-
INVALID_DIRECTORY_LISTING_TYPE_ERROR = "`directory_listing` must be bool."
|
|
21
|
-
|
|
22
|
-
PORT_IN_USE_ERROR = "`port` is already in use. Try another port or use `0` for automatic allocation."
|
|
23
|
-
PORT_ACCESS_DENIED_ERROR = "`port` access denied. Try a different port or check permissions."
|
|
24
|
-
PORT_ADDRESS_NOT_AVAILABLE_ERROR = "`port` address is not available. Check network configuration."
|
|
25
|
-
PORT_BIND_GENERIC_ERROR = "Failed to start server on port `{port}`: {error}"
|
{ghps-0.5 → ghps-0.7}/AUTHORS.md
RENAMED
|
File without changes
|
{ghps-0.5 → ghps-0.7}/LICENSE
RENAMED
|
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
|
{ghps-0.5 → ghps-0.7}/setup.cfg
RENAMED
|
File without changes
|