PyWSGIRef 1.0.2__tar.gz → 1.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.
- {pywsgiref-1.0.2/src/PyWSGIRef.egg-info → pywsgiref-1.1.0}/PKG-INFO +32 -4
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/README.md +29 -2
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/pyproject.toml +3 -2
- pywsgiref-1.1.0/src/PyWSGIRef/__init__.py +128 -0
- pywsgiref-1.1.0/src/PyWSGIRef/__main__.py +7 -0
- pywsgiref-1.1.0/src/PyWSGIRef/defaults.py +28 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef/exceptions.py +8 -0
- pywsgiref-1.1.0/src/PyWSGIRef/templateDict.py +51 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0/src/PyWSGIRef.egg-info}/PKG-INFO +32 -4
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef.egg-info/SOURCES.txt +1 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef.egg-info/requires.txt +1 -0
- pywsgiref-1.0.2/src/PyWSGIRef/__init__.py +0 -82
- pywsgiref-1.0.2/src/PyWSGIRef/__main__.py +0 -55
- pywsgiref-1.0.2/src/PyWSGIRef/defaults.py +0 -14
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/LICENSE +0 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/setup.cfg +0 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef/pyhtml.py +0 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef.egg-info/dependency_links.txt +0 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/src/PyWSGIRef.egg-info/top_level.txt +0 -0
- {pywsgiref-1.0.2 → pywsgiref-1.1.0}/tests/testMainServer.py +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyWSGIRef
|
|
3
|
-
Version: 1.0
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: easy server-setup
|
|
5
5
|
Author-email: Leander Kafemann <leander@kafemann.berlin>
|
|
6
6
|
Project-URL: Homepage, https://github.com/LeanderKafemann/PyWSGIRef
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -12,6 +12,7 @@ Description-Content-Type: text/markdown
|
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
Requires-Dist: requests
|
|
14
14
|
Requires-Dist: typing
|
|
15
|
+
Requires-Dist: legacy-cgi
|
|
15
16
|
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# PyWSGIRef
|
|
@@ -59,6 +60,29 @@ server.serve_forever()
|
|
|
59
60
|
The <code>makeWSGIApp</code> function requires a callable that takes a single argument (the path) and returns a string response.<br/>
|
|
60
61
|
The <code>makeWSGIServer</code> function creates a WSGI server that listens on the specified port (default is 8000)<br/>
|
|
61
62
|
and calls the application object with the environ.<br/>
|
|
63
|
+
You may also specify advanced options in <code>makeWSGIApp</code>:<br/>
|
|
64
|
+
- you can set the <code>advanced</code> parameter to <code>True</code>, so that your application method also gets an FieldStorage type object<br/>
|
|
65
|
+
- you can set the <code>setAdvancedHeaders</code> parameter to <code>True</code>, so that the application method is also able to set status codes and types in the response headers,<br/>
|
|
66
|
+
which is only possible if the <code>advanced</code> parameter is set to <code>True</code><br/>
|
|
67
|
+
Example:
|
|
68
|
+
```python
|
|
69
|
+
from PyWSGIRef import *
|
|
70
|
+
|
|
71
|
+
# Create a WSGI application object with advanced options
|
|
72
|
+
def advanced_app(path: str, form: FieldStorage) -> str, str, str:
|
|
73
|
+
# You can access form data here
|
|
74
|
+
name = str(form.getvalue('name'))
|
|
75
|
+
|
|
76
|
+
if path == "/hello":
|
|
77
|
+
return f"Hello, {name}, you visited {path}!", "text/html", "200 OK"
|
|
78
|
+
else:
|
|
79
|
+
return "Page not found", "text/html", "404 Not Found"
|
|
80
|
+
application = makeWSGIApp(advanced_app, advanced=True, setAdvancedHeaders=True)
|
|
81
|
+
|
|
82
|
+
# Create a WSGI server
|
|
83
|
+
server = makeWSGIServer(application, port=8000)
|
|
84
|
+
server.serve_forever()
|
|
85
|
+
```
|
|
62
86
|
You can also use your own application object instead of the one created by <code>makeWSGIApp</code>.
|
|
63
87
|
### Loading PyHTML
|
|
64
88
|
PyWSGIRef also provides a simple way to load PyHTML files:
|
|
@@ -102,7 +126,7 @@ addSchablone("error", ERROR)
|
|
|
102
126
|
### __main__ script
|
|
103
127
|
You may produce a simple WSGI server by using either:<br/>
|
|
104
128
|
```python
|
|
105
|
-
from PyWSGIRef import
|
|
129
|
+
from PyWSGIRef import main
|
|
106
130
|
|
|
107
131
|
main()
|
|
108
132
|
```
|
|
@@ -110,9 +134,13 @@ or (from a commandline)
|
|
|
110
134
|
```bash
|
|
111
135
|
py -m PyWSGIRef
|
|
112
136
|
```
|
|
137
|
+
### Decoding PyHTML
|
|
138
|
+
coming soon...
|
|
113
139
|
### Others
|
|
114
140
|
Use the following to get information about your release and the author of the module:
|
|
115
141
|
```python
|
|
116
|
-
|
|
142
|
+
from PyWSGIRef import about
|
|
143
|
+
|
|
144
|
+
about()
|
|
117
145
|
```
|
|
118
146
|
### More coming soon
|
|
@@ -43,6 +43,29 @@ server.serve_forever()
|
|
|
43
43
|
The <code>makeWSGIApp</code> function requires a callable that takes a single argument (the path) and returns a string response.<br/>
|
|
44
44
|
The <code>makeWSGIServer</code> function creates a WSGI server that listens on the specified port (default is 8000)<br/>
|
|
45
45
|
and calls the application object with the environ.<br/>
|
|
46
|
+
You may also specify advanced options in <code>makeWSGIApp</code>:<br/>
|
|
47
|
+
- you can set the <code>advanced</code> parameter to <code>True</code>, so that your application method also gets an FieldStorage type object<br/>
|
|
48
|
+
- you can set the <code>setAdvancedHeaders</code> parameter to <code>True</code>, so that the application method is also able to set status codes and types in the response headers,<br/>
|
|
49
|
+
which is only possible if the <code>advanced</code> parameter is set to <code>True</code><br/>
|
|
50
|
+
Example:
|
|
51
|
+
```python
|
|
52
|
+
from PyWSGIRef import *
|
|
53
|
+
|
|
54
|
+
# Create a WSGI application object with advanced options
|
|
55
|
+
def advanced_app(path: str, form: FieldStorage) -> str, str, str:
|
|
56
|
+
# You can access form data here
|
|
57
|
+
name = str(form.getvalue('name'))
|
|
58
|
+
|
|
59
|
+
if path == "/hello":
|
|
60
|
+
return f"Hello, {name}, you visited {path}!", "text/html", "200 OK"
|
|
61
|
+
else:
|
|
62
|
+
return "Page not found", "text/html", "404 Not Found"
|
|
63
|
+
application = makeWSGIApp(advanced_app, advanced=True, setAdvancedHeaders=True)
|
|
64
|
+
|
|
65
|
+
# Create a WSGI server
|
|
66
|
+
server = makeWSGIServer(application, port=8000)
|
|
67
|
+
server.serve_forever()
|
|
68
|
+
```
|
|
46
69
|
You can also use your own application object instead of the one created by <code>makeWSGIApp</code>.
|
|
47
70
|
### Loading PyHTML
|
|
48
71
|
PyWSGIRef also provides a simple way to load PyHTML files:
|
|
@@ -86,7 +109,7 @@ addSchablone("error", ERROR)
|
|
|
86
109
|
### __main__ script
|
|
87
110
|
You may produce a simple WSGI server by using either:<br/>
|
|
88
111
|
```python
|
|
89
|
-
from PyWSGIRef import
|
|
112
|
+
from PyWSGIRef import main
|
|
90
113
|
|
|
91
114
|
main()
|
|
92
115
|
```
|
|
@@ -94,9 +117,13 @@ or (from a commandline)
|
|
|
94
117
|
```bash
|
|
95
118
|
py -m PyWSGIRef
|
|
96
119
|
```
|
|
120
|
+
### Decoding PyHTML
|
|
121
|
+
coming soon...
|
|
97
122
|
### Others
|
|
98
123
|
Use the following to get information about your release and the author of the module:
|
|
99
124
|
```python
|
|
100
|
-
|
|
125
|
+
from PyWSGIRef import about
|
|
126
|
+
|
|
127
|
+
about()
|
|
101
128
|
```
|
|
102
129
|
### More coming soon
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "PyWSGIRef"
|
|
3
|
-
version = "1.0
|
|
3
|
+
version = "1.1.0"
|
|
4
4
|
authors = [
|
|
5
5
|
{name="Leander Kafemann", email="leander@kafemann.berlin" },
|
|
6
6
|
]
|
|
7
|
-
description = "
|
|
7
|
+
description = "easy server-setup"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
requires-python = ">=3.11"
|
|
10
10
|
classifiers = [
|
|
@@ -15,6 +15,7 @@ classifiers = [
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"requests",
|
|
17
17
|
"typing",
|
|
18
|
+
"legacy-cgi",
|
|
18
19
|
]
|
|
19
20
|
|
|
20
21
|
[project.urls]
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PYWSGIREF
|
|
3
|
+
"""
|
|
4
|
+
from typing import Callable
|
|
5
|
+
import requests
|
|
6
|
+
from wsgiref.simple_server import make_server, WSGIServer
|
|
7
|
+
from cgi import FieldStorage
|
|
8
|
+
|
|
9
|
+
from .exceptions import *
|
|
10
|
+
from .pyhtml import PyHTML
|
|
11
|
+
from .defaults import *
|
|
12
|
+
from .templateDict import TemplateDict, OneWayBoolean
|
|
13
|
+
|
|
14
|
+
def about():
|
|
15
|
+
"""
|
|
16
|
+
Returns information about your release and other projects by LK
|
|
17
|
+
"""
|
|
18
|
+
return {"Version":(1, 1, 0), "Author":"Leander Kafemann", "date":"08.06.2025",\
|
|
19
|
+
"recommend":("Büro by LK", "pyimager by LK"), "feedbackTo": "leander@kafemann.berlin"}
|
|
20
|
+
|
|
21
|
+
SCHABLONEN = TemplateDict()
|
|
22
|
+
finished = OneWayBoolean()
|
|
23
|
+
|
|
24
|
+
def loadFromWeb(url: str, data: dict = {}) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Loads content from the given URL with the given data.
|
|
27
|
+
"""
|
|
28
|
+
if finished.value:
|
|
29
|
+
raise ServerAlreadyGeneratedError()
|
|
30
|
+
if not url.endswith(".pyhtml"):
|
|
31
|
+
raise InvalidFiletypeError()
|
|
32
|
+
rq = requests.post(url, data).content
|
|
33
|
+
return rq.decode()
|
|
34
|
+
|
|
35
|
+
def loadFromFile(filename: str) -> str:
|
|
36
|
+
"""
|
|
37
|
+
Loads a file from the given filename.
|
|
38
|
+
"""
|
|
39
|
+
if finished.value:
|
|
40
|
+
raise ServerAlreadyGeneratedError()
|
|
41
|
+
if not filename.endswith(".pyhtml"):
|
|
42
|
+
raise InvalidFiletypeError()
|
|
43
|
+
with open(filename, "r", encoding="utf-8") as f:
|
|
44
|
+
content = f.read()
|
|
45
|
+
return content
|
|
46
|
+
|
|
47
|
+
def addSchablone(name: str, content: str):
|
|
48
|
+
"""
|
|
49
|
+
Adds a template to the SCHABLONEN dictionary.
|
|
50
|
+
"""
|
|
51
|
+
global SCHABLONEN
|
|
52
|
+
if finished.value:
|
|
53
|
+
raise ServerAlreadyGeneratedError()
|
|
54
|
+
SCHABLONEN[name] = PyHTML(content)
|
|
55
|
+
|
|
56
|
+
def makeApplicationObject(contentGeneratingFunction: Callable, advanced: bool = False, setAdvancedHeaders: bool = False) -> Callable:
|
|
57
|
+
"""
|
|
58
|
+
Returns a WSGI application object based on your contentGeneratingFunction.
|
|
59
|
+
The contentGeneratingFunction should take a single argument (the path) and return the content as a string.
|
|
60
|
+
If advanced is True, the contentGeneratingFunction will receive a FieldStorage object as the second argument.
|
|
61
|
+
If setAdvancedHeaders is True, it will allow you to set advanced headers for the response.
|
|
62
|
+
"""
|
|
63
|
+
if not callable(contentGeneratingFunction):
|
|
64
|
+
raise InvalidCallableError()
|
|
65
|
+
def simpleApplication(environ, start_response) -> list:
|
|
66
|
+
"""
|
|
67
|
+
A simple WSGI application object that serves as a template.
|
|
68
|
+
"""
|
|
69
|
+
type_ = "text/html"
|
|
70
|
+
status = "200 OK"
|
|
71
|
+
if advanced:
|
|
72
|
+
storage = FieldStorage(fp=environ.get("wsgi.input"), environ=environ, keep_blank_values=True)
|
|
73
|
+
if setAdvancedHeaders:
|
|
74
|
+
content, type_, status = contentGeneratingFunction(environ["PATH_INFO"], storage)
|
|
75
|
+
else:
|
|
76
|
+
content = contentGeneratingFunction(environ["PATH_INFO"], storage)
|
|
77
|
+
else:
|
|
78
|
+
if setAdvancedHeaders:
|
|
79
|
+
raise AdvancedHeadersWithoutAdvancedModeError()
|
|
80
|
+
content = contentGeneratingFunction(environ["PATH_INFO"])
|
|
81
|
+
headers = [("Content-Type", type_),
|
|
82
|
+
("Content-Length", str(len(content))),
|
|
83
|
+
('Access-Control-Allow-Origin', '*')]
|
|
84
|
+
start_response(status, headers)
|
|
85
|
+
return [content.encode("utf-8")]
|
|
86
|
+
return simpleApplication
|
|
87
|
+
|
|
88
|
+
def setUpServer(application: Callable, port: int = 8000) -> WSGIServer:
|
|
89
|
+
"""
|
|
90
|
+
Creates a WSGI server.
|
|
91
|
+
No additional Schablonen can be loaded from the web.
|
|
92
|
+
"""
|
|
93
|
+
finished.set_true()
|
|
94
|
+
server = make_server('', 8000, application)
|
|
95
|
+
return server
|
|
96
|
+
|
|
97
|
+
def main():
|
|
98
|
+
"""
|
|
99
|
+
Main function to set up and run the PyWSGIRef server.
|
|
100
|
+
"""
|
|
101
|
+
# add Schablone 'Hallo Welt' as main
|
|
102
|
+
addSchablone("main", MAIN_HTML)
|
|
103
|
+
|
|
104
|
+
# set up application object
|
|
105
|
+
def contentGenerator(path: str) -> str:
|
|
106
|
+
"""
|
|
107
|
+
Serves as the main WSGI application.
|
|
108
|
+
"""
|
|
109
|
+
match path:
|
|
110
|
+
case "/":
|
|
111
|
+
content = SCHABLONEN["main"].decoded().format(about()["Version"])
|
|
112
|
+
case "/hello":
|
|
113
|
+
content = HELLO_WORLD
|
|
114
|
+
case _:
|
|
115
|
+
content = ERROR
|
|
116
|
+
return content
|
|
117
|
+
|
|
118
|
+
# make the application object
|
|
119
|
+
application = makeApplicationObject(contentGenerator)
|
|
120
|
+
|
|
121
|
+
# set up server
|
|
122
|
+
server = setUpServer(application)
|
|
123
|
+
|
|
124
|
+
# Note: This code is intended to be run as a script, not as a module.
|
|
125
|
+
print("Successfully started WSGI server on port 8000.")
|
|
126
|
+
|
|
127
|
+
# start serving
|
|
128
|
+
server.serve_forever()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
HELLO_WORLD = """<!DOCTYPE html>
|
|
2
|
+
<html lang"de">
|
|
3
|
+
<body>
|
|
4
|
+
<h1>Hallo Welt!</h1>
|
|
5
|
+
</body>
|
|
6
|
+
<html>"""
|
|
7
|
+
|
|
8
|
+
ERROR = """<!DOCTYPE html>
|
|
9
|
+
<html lang"de">
|
|
10
|
+
<body>
|
|
11
|
+
<h1>Fehler!</h1>
|
|
12
|
+
<p>Es ist ein Fehler aufgetreten.</p>
|
|
13
|
+
</body>
|
|
14
|
+
</html>"""
|
|
15
|
+
|
|
16
|
+
MAIN_HTML = """<!DOCTYPE html>
|
|
17
|
+
<html lang="de">
|
|
18
|
+
<head>
|
|
19
|
+
<meta charset="UTF-8">
|
|
20
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
21
|
+
<title>PyWSGIRef Server</title>
|
|
22
|
+
</head>
|
|
23
|
+
<body>
|
|
24
|
+
<h1>Willkommen zum PyWSGIRef Server!</h1>
|
|
25
|
+
<p>Dies ist die Hauptseite des Servers.</p>
|
|
26
|
+
<p>Sie nutzen Version {} von PyWSGIRef.</p>
|
|
27
|
+
</body>
|
|
28
|
+
</html>"""
|
|
@@ -20,5 +20,13 @@ class InvalidCallableError(Exception):
|
|
|
20
20
|
Raised when a callable is expected but not provided.
|
|
21
21
|
"""
|
|
22
22
|
def __init__(self, message="Expected a callable object."):
|
|
23
|
+
self.message = message
|
|
24
|
+
super().__init__(self.message)
|
|
25
|
+
|
|
26
|
+
class AdvancedHeadersWithoutAdvancedModeError(Exception):
|
|
27
|
+
"""
|
|
28
|
+
Raised when advanced headers are set without advanced mode being enabled.
|
|
29
|
+
"""
|
|
30
|
+
def __init__(self, message="Advanced headers cannot be set without enabling advanced mode."):
|
|
23
31
|
self.message = message
|
|
24
32
|
super().__init__(self.message)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from .exceptions import ServerAlreadyGeneratedError
|
|
2
|
+
from .pyhtml import PyHTML
|
|
3
|
+
|
|
4
|
+
class TemplateDict:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
self.dictionary = {}
|
|
7
|
+
self.locked = OneWayBoolean()
|
|
8
|
+
|
|
9
|
+
def __getitem__(self, key: str) -> PyHTML:
|
|
10
|
+
return self.dictionary[key]
|
|
11
|
+
|
|
12
|
+
def __setitem__(self, key: str, value: PyHTML):
|
|
13
|
+
if not isinstance(value, PyHTML):
|
|
14
|
+
raise TypeError("Value must be an instance of PyHTML.")
|
|
15
|
+
if not isinstance(key, str):
|
|
16
|
+
raise TypeError("Key must be a string.")
|
|
17
|
+
if self.locked.value:
|
|
18
|
+
raise ServerAlreadyGeneratedError("Cannot modify TemplateDict after it has been locked.")
|
|
19
|
+
self.dictionary[key] = value
|
|
20
|
+
|
|
21
|
+
def __contains__(self, key: str):
|
|
22
|
+
return key in self.dictionary
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
return f"TemplateDict({self.dictionary})"
|
|
26
|
+
|
|
27
|
+
def keys(self) -> list:
|
|
28
|
+
return list(self.dictionary.keys())
|
|
29
|
+
|
|
30
|
+
def values(self) -> list:
|
|
31
|
+
return list(self.dictionary.values())
|
|
32
|
+
|
|
33
|
+
def items(self) -> list:
|
|
34
|
+
return list(self.dictionary.items())
|
|
35
|
+
|
|
36
|
+
class OneWayBoolean:
|
|
37
|
+
def __init__(self):
|
|
38
|
+
self.value = False
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def value(self) -> bool:
|
|
42
|
+
return self.value
|
|
43
|
+
|
|
44
|
+
def set_true(self):
|
|
45
|
+
"""
|
|
46
|
+
Setzt den Wert auf True, wenn er False ist.
|
|
47
|
+
"""
|
|
48
|
+
if not self.value:
|
|
49
|
+
self.value = True
|
|
50
|
+
else:
|
|
51
|
+
raise ValueError("Value is already True, cannot set again.")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyWSGIRef
|
|
3
|
-
Version: 1.0
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: easy server-setup
|
|
5
5
|
Author-email: Leander Kafemann <leander@kafemann.berlin>
|
|
6
6
|
Project-URL: Homepage, https://github.com/LeanderKafemann/PyWSGIRef
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -12,6 +12,7 @@ Description-Content-Type: text/markdown
|
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
Requires-Dist: requests
|
|
14
14
|
Requires-Dist: typing
|
|
15
|
+
Requires-Dist: legacy-cgi
|
|
15
16
|
Dynamic: license-file
|
|
16
17
|
|
|
17
18
|
# PyWSGIRef
|
|
@@ -59,6 +60,29 @@ server.serve_forever()
|
|
|
59
60
|
The <code>makeWSGIApp</code> function requires a callable that takes a single argument (the path) and returns a string response.<br/>
|
|
60
61
|
The <code>makeWSGIServer</code> function creates a WSGI server that listens on the specified port (default is 8000)<br/>
|
|
61
62
|
and calls the application object with the environ.<br/>
|
|
63
|
+
You may also specify advanced options in <code>makeWSGIApp</code>:<br/>
|
|
64
|
+
- you can set the <code>advanced</code> parameter to <code>True</code>, so that your application method also gets an FieldStorage type object<br/>
|
|
65
|
+
- you can set the <code>setAdvancedHeaders</code> parameter to <code>True</code>, so that the application method is also able to set status codes and types in the response headers,<br/>
|
|
66
|
+
which is only possible if the <code>advanced</code> parameter is set to <code>True</code><br/>
|
|
67
|
+
Example:
|
|
68
|
+
```python
|
|
69
|
+
from PyWSGIRef import *
|
|
70
|
+
|
|
71
|
+
# Create a WSGI application object with advanced options
|
|
72
|
+
def advanced_app(path: str, form: FieldStorage) -> str, str, str:
|
|
73
|
+
# You can access form data here
|
|
74
|
+
name = str(form.getvalue('name'))
|
|
75
|
+
|
|
76
|
+
if path == "/hello":
|
|
77
|
+
return f"Hello, {name}, you visited {path}!", "text/html", "200 OK"
|
|
78
|
+
else:
|
|
79
|
+
return "Page not found", "text/html", "404 Not Found"
|
|
80
|
+
application = makeWSGIApp(advanced_app, advanced=True, setAdvancedHeaders=True)
|
|
81
|
+
|
|
82
|
+
# Create a WSGI server
|
|
83
|
+
server = makeWSGIServer(application, port=8000)
|
|
84
|
+
server.serve_forever()
|
|
85
|
+
```
|
|
62
86
|
You can also use your own application object instead of the one created by <code>makeWSGIApp</code>.
|
|
63
87
|
### Loading PyHTML
|
|
64
88
|
PyWSGIRef also provides a simple way to load PyHTML files:
|
|
@@ -102,7 +126,7 @@ addSchablone("error", ERROR)
|
|
|
102
126
|
### __main__ script
|
|
103
127
|
You may produce a simple WSGI server by using either:<br/>
|
|
104
128
|
```python
|
|
105
|
-
from PyWSGIRef import
|
|
129
|
+
from PyWSGIRef import main
|
|
106
130
|
|
|
107
131
|
main()
|
|
108
132
|
```
|
|
@@ -110,9 +134,13 @@ or (from a commandline)
|
|
|
110
134
|
```bash
|
|
111
135
|
py -m PyWSGIRef
|
|
112
136
|
```
|
|
137
|
+
### Decoding PyHTML
|
|
138
|
+
coming soon...
|
|
113
139
|
### Others
|
|
114
140
|
Use the following to get information about your release and the author of the module:
|
|
115
141
|
```python
|
|
116
|
-
|
|
142
|
+
from PyWSGIRef import about
|
|
143
|
+
|
|
144
|
+
about()
|
|
117
145
|
```
|
|
118
146
|
### More coming soon
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
PYWSGIREF
|
|
3
|
-
"""
|
|
4
|
-
from typing import Callable
|
|
5
|
-
import requests
|
|
6
|
-
from wsgiref.simple_server import make_server, WSGIServer
|
|
7
|
-
|
|
8
|
-
from .exceptions import *
|
|
9
|
-
from .pyhtml import PyHTML
|
|
10
|
-
from .defaults import *
|
|
11
|
-
from .__main__ import main
|
|
12
|
-
|
|
13
|
-
def about():
|
|
14
|
-
"""
|
|
15
|
-
Returns information about your release and other projects by LK
|
|
16
|
-
"""
|
|
17
|
-
return {"Version":(1, 0, 2), "Author":"Leander Kafemann", "date":"07.06.2025",\
|
|
18
|
-
"recommend":("Büro by LK", "pyimager by LK"), "feedbackTo": "leander@kafemann.berlin"}
|
|
19
|
-
|
|
20
|
-
SCHABLONEN = {}
|
|
21
|
-
finished = False
|
|
22
|
-
|
|
23
|
-
def loadFromWeb(url: str, data: dict = {}) -> str:
|
|
24
|
-
"""
|
|
25
|
-
Loads content from the given URL with the given data.
|
|
26
|
-
"""
|
|
27
|
-
if finished:
|
|
28
|
-
raise ServerAlreadyGeneratedError()
|
|
29
|
-
if not url.endswith(".pyhtml"):
|
|
30
|
-
raise InvalidFiletypeError()
|
|
31
|
-
rq = requests.post(url, data).content
|
|
32
|
-
return rq.decode()
|
|
33
|
-
|
|
34
|
-
def loadFromFile(filename: str) -> str:
|
|
35
|
-
"""
|
|
36
|
-
Loads a file from the given filename.
|
|
37
|
-
"""
|
|
38
|
-
if finished:
|
|
39
|
-
raise ServerAlreadyGeneratedError()
|
|
40
|
-
if not filename.endswith(".pyhtml"):
|
|
41
|
-
raise InvalidFiletypeError()
|
|
42
|
-
with open(filename, "r", encoding="utf-8") as f:
|
|
43
|
-
content = f.read()
|
|
44
|
-
return content
|
|
45
|
-
|
|
46
|
-
def addSchablone(name: str, content: str):
|
|
47
|
-
"""
|
|
48
|
-
Adds a template to the SCHABLONEN dictionary.
|
|
49
|
-
"""
|
|
50
|
-
global SCHABLONEN
|
|
51
|
-
SCHABLONEN[name] = PyHTML(content)
|
|
52
|
-
|
|
53
|
-
def makeApplicationObject(contentGeneratingFunction: Callable) -> Callable:
|
|
54
|
-
"""
|
|
55
|
-
Returns a WSGI application object based on your contentGeneratingFunction.
|
|
56
|
-
The contentGeneratingFunction should take a single argument (the path) and return the content as a string.
|
|
57
|
-
"""
|
|
58
|
-
if not callable(contentGeneratingFunction):
|
|
59
|
-
raise InvalidCallableError()
|
|
60
|
-
def simpleApplication(environ, start_response) -> list:
|
|
61
|
-
"""
|
|
62
|
-
A simple WSGI application object that serves as a template.
|
|
63
|
-
"""
|
|
64
|
-
type_ = "text/html"
|
|
65
|
-
status = "200 OK"
|
|
66
|
-
content = contentGeneratingFunction(environ["PATH_INFO"])
|
|
67
|
-
headers = [("Content-Type", type_),
|
|
68
|
-
("Content-Length", str(len(content))),
|
|
69
|
-
('Access-Control-Allow-Origin', '*')]
|
|
70
|
-
start_response(status, headers)
|
|
71
|
-
return [content.encode("utf-8")]
|
|
72
|
-
return simpleApplication
|
|
73
|
-
|
|
74
|
-
def setUpServer(application: Callable) -> WSGIServer:
|
|
75
|
-
"""
|
|
76
|
-
Creates a WSGI server.
|
|
77
|
-
No additional Schablonen can be loaded from the web.
|
|
78
|
-
"""
|
|
79
|
-
global finished
|
|
80
|
-
finished = True
|
|
81
|
-
server = make_server('', 8000, application)
|
|
82
|
-
return server
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Set up and run the PyWSGIRef server with a simple HTML response.
|
|
3
|
-
"""
|
|
4
|
-
from PyWSGIRef import *
|
|
5
|
-
|
|
6
|
-
def main():
|
|
7
|
-
"""
|
|
8
|
-
Main function to set up and run the PyWSGIRef server.
|
|
9
|
-
"""
|
|
10
|
-
# define main html response
|
|
11
|
-
MAIN_HTML = """<!DOCTYPE html>
|
|
12
|
-
<html lang="de">
|
|
13
|
-
<head>
|
|
14
|
-
<meta charset="UTF-8">
|
|
15
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
16
|
-
<title>PyWSGIRef Server</title>
|
|
17
|
-
</head>
|
|
18
|
-
<body>
|
|
19
|
-
<h1>Willkommen zum PyWSGIRef Server!</h1>
|
|
20
|
-
<p>Dies ist die Hauptseite des Servers.</p>
|
|
21
|
-
<p>Sie nutzen Version {} von PyWSGIRef.</p>
|
|
22
|
-
</body>
|
|
23
|
-
</html>"""
|
|
24
|
-
|
|
25
|
-
# add Schablone 'Hallo Welt' as main
|
|
26
|
-
addSchablone("main", MAIN_HTML)
|
|
27
|
-
|
|
28
|
-
# set up application object
|
|
29
|
-
def contentGenerator(path: str) -> str:
|
|
30
|
-
"""
|
|
31
|
-
Serves as the main WSGI application.
|
|
32
|
-
"""
|
|
33
|
-
match path:
|
|
34
|
-
case "/":
|
|
35
|
-
content = SCHABLONEN["main"].decoded().format(about()["Version"])
|
|
36
|
-
case "/hello":
|
|
37
|
-
content = HELLO_WORLD
|
|
38
|
-
case _:
|
|
39
|
-
content = ERROR
|
|
40
|
-
return content
|
|
41
|
-
|
|
42
|
-
# make the application object
|
|
43
|
-
application = makeApplicationObject(contentGenerator)
|
|
44
|
-
|
|
45
|
-
# set up server
|
|
46
|
-
server = setUpServer(application)
|
|
47
|
-
|
|
48
|
-
# Note: This code is intended to be run as a script, not as a module.
|
|
49
|
-
print("Successfully started WSGI server on port 8000.")
|
|
50
|
-
|
|
51
|
-
# start serving
|
|
52
|
-
server.serve_forever()
|
|
53
|
-
|
|
54
|
-
if __name__ == "__main__":
|
|
55
|
-
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|