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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyWSGIRef
3
- Version: 1.0.2
4
- Summary: some tools for working with GitHub
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
- pycols.about()
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
- pycols.about()
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.2"
3
+ version = "1.1.0"
4
4
  authors = [
5
5
  {name="Leander Kafemann", email="leander@kafemann.berlin" },
6
6
  ]
7
- description = "some tools for working with GitHub"
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,7 @@
1
+ """
2
+ Set up and run the PyWSGIRef server with a simple HTML response.
3
+ """
4
+ from PyWSGIRef import main
5
+
6
+ if __name__ == "__main__":
7
+ main()
@@ -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.2
4
- Summary: some tools for working with GitHub
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
- pycols.about()
142
+ from PyWSGIRef import about
143
+
144
+ about()
117
145
  ```
118
146
  ### More coming soon
@@ -6,6 +6,7 @@ src/PyWSGIRef/__main__.py
6
6
  src/PyWSGIRef/defaults.py
7
7
  src/PyWSGIRef/exceptions.py
8
8
  src/PyWSGIRef/pyhtml.py
9
+ src/PyWSGIRef/templateDict.py
9
10
  src/PyWSGIRef.egg-info/PKG-INFO
10
11
  src/PyWSGIRef.egg-info/SOURCES.txt
11
12
  src/PyWSGIRef.egg-info/dependency_links.txt
@@ -1,2 +1,3 @@
1
1
  requests
2
2
  typing
3
+ legacy-cgi
@@ -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()
@@ -1,14 +0,0 @@
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>"""
File without changes
File without changes