PyWSGIRef 1.1.16__tar.gz → 1.1.18__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.
Files changed (25) hide show
  1. {pywsgiref-1.1.16/src/PyWSGIRef.egg-info → pywsgiref-1.1.18}/PKG-INFO +1 -1
  2. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/pyproject.toml +1 -1
  3. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/__init__.py +16 -4
  4. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/exceptions.py +16 -0
  5. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/loadContent.py +5 -4
  6. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/pyhtml.py +1 -1
  7. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/stats.py +6 -3
  8. {pywsgiref-1.1.16 → pywsgiref-1.1.18/src/PyWSGIRef.egg-info}/PKG-INFO +1 -1
  9. pywsgiref-1.1.18/tests/testMainServer.py +3 -0
  10. pywsgiref-1.1.16/tests/testMainServer.py +0 -3
  11. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/LICENSE +0 -0
  12. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/README.md +0 -0
  13. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/setup.cfg +0 -0
  14. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/__main__.py +0 -0
  15. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/beta.py +0 -0
  16. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/commons.py +0 -0
  17. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/defaults.py +0 -0
  18. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/finished.py +0 -0
  19. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/patterns.py +0 -0
  20. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/simpleServer.py +0 -0
  21. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef/templateDict.py +0 -0
  22. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef.egg-info/SOURCES.txt +0 -0
  23. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef.egg-info/dependency_links.txt +0 -0
  24. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef.egg-info/requires.txt +0 -0
  25. {pywsgiref-1.1.16 → pywsgiref-1.1.18}/src/PyWSGIRef.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyWSGIRef
3
- Version: 1.1.16
3
+ Version: 1.1.18
4
4
  Summary: easy server-setup
5
5
  Author-email: Leander Kafemann <leander.kafemann+python@icloud.com>
6
6
  Project-URL: Homepage, https://github.com/LeanderKafemann/PyWSGIRef
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "PyWSGIRef"
3
- version = "1.1.16"
3
+ version = "1.1.18"
4
4
  authors = [
5
5
  {name="Leander Kafemann", email="leander.kafemann+python@icloud.com" },
6
6
  ]
@@ -18,7 +18,7 @@ def about():
18
18
  """
19
19
  Returns information about your release and other projects by Leander Kafemann
20
20
  """
21
- return {"Version": (1, 1, 16), "Author": "Leander Kafemann", "date": "05.09.2025",\
21
+ return {"Version": (1, 1, 18), "Author": "Leander Kafemann", "date": "08.11.2025",\
22
22
  "recommend": ("pyimager"), "feedbackTo": "leander.kafemann+python@icloud.com"}
23
23
 
24
24
  SCHABLONEN = TemplateDict()
@@ -34,7 +34,8 @@ def addSchablone(name: str, content: str):
34
34
  SCHABLONEN[name] = PyHTML(content)
35
35
 
36
36
  def makeApplicationObject(contentGeneratingFunction: Callable, advanced: bool = False, setAdvancedHeaders: bool = False,\
37
- getIP: bool = False, vercelPythonHosting: bool = False, getStats: bool = False) -> Callable:
37
+ getIP: bool = False, vercelPythonHosting: bool = False, getStats: bool = False,
38
+ advancedStats: bool = False, customEncoding: bool = False) -> Callable:
38
39
  """
39
40
  Returns a WSGI application object based on your contentGeneratingFunction.
40
41
  The contentGeneratingFunction should take a single argument (the path) and return the content as a string.
@@ -43,6 +44,8 @@ def makeApplicationObject(contentGeneratingFunction: Callable, advanced: bool =
43
44
  If getIP is True, the contentGeneratingFunction will receive the IP address of the client as an additional argument.
44
45
  If vercelPythonHosting is True, your application object will be optimized for Vercel's unusual WSGI methods.
45
46
  If getStats is True, stats are saved in the STATS object (BETA).
47
+ If advancedStats is True, more detailed stats are collected (BETA).
48
+ If customEncoding is True, the contentGeneratingFunction has to encode the content itself.
46
49
  Locks BETA mode.
47
50
  """
48
51
  if not callable(contentGeneratingFunction):
@@ -57,10 +60,12 @@ def makeApplicationObject(contentGeneratingFunction: Callable, advanced: bool =
57
60
  raise BetaNotEnabledError()
58
61
  STATS.count.increase()
59
62
  perfTime = STATS.startPerfTime("applicationCallNr"+str(STATS.count.count))
63
+ storage = FieldStorage(fp=environ.get("wsgi.input"), environ=environ, keep_blank_values=True)
64
+ if storage.getvalue("realAccessDeviceMonitorAgent", "") not in ["PyWSGIRef/1.1", ""]:
65
+ raise OutdatedPyWSGIRefVersionError("Access with outdated PyWSGIRef version detected. Please update to the latest version.")
60
66
  type_ = "text/html"
61
67
  status = "200 OK"
62
68
  if advanced:
63
- storage = FieldStorage(fp=environ.get("wsgi.input"), environ=environ, keep_blank_values=True)
64
69
  if setAdvancedHeaders:
65
70
  if getIP:
66
71
  content, type_, status = contentGeneratingFunction(environ["PATH_INFO"], storage, environ["HTTP_X_REAL_IP"])
@@ -79,13 +84,20 @@ def makeApplicationObject(contentGeneratingFunction: Callable, advanced: bool =
79
84
  else:
80
85
  content = contentGeneratingFunction(environ["PATH_INFO"])
81
86
  headers = [("Content-Type", type_),
82
- ("Content-Length", str(len(content))),
87
+ ("Content-Length", str(len(content if not customEncoding else content[0]))),
83
88
  ('Access-Control-Allow-Origin', '*')]
84
89
  start_response(status, headers)
85
90
  if getStats:
86
91
  STATS.stopPerfTime(perfTime)
92
+ perfTime.data["ip"] = environ.get("HTTP_X_REAL_IP", "unknown")
93
+ perfTime.data["path"] = environ.get("PATH_INFO", "unknown")
87
94
  if not vercelPythonHosting:
95
+ if customEncoding:
96
+ return content
88
97
  return [content.encode("utf-8")]
98
+ else:
99
+ if customEncoding:
100
+ raise VercelIncompabilityError("customEncoding cannot be used with vercelPythonHosting.")
89
101
  return simpleApplication
90
102
 
91
103
  def setUpServer(application: Callable, port: int = 8000) -> WSGIServer:
@@ -84,5 +84,21 @@ class BetaNotEnabledError(Exception):
84
84
  Raised when trying to use a BETA feature when BETA mode is not enabled.
85
85
  """
86
86
  def __init__(self, message="BETA mode is not enabled."):
87
+ self.message = message
88
+ super().__init__(self.message)
89
+
90
+ class VercelIncompabilityError(Exception):
91
+ """
92
+ Raised when trying to use Vercel hosting without enabling Vercel compatibility.
93
+ """
94
+ def __init__(self, message="Vercel compatibility is not enabled."):
95
+ self.message = message
96
+ super().__init__(self.message)
97
+
98
+ class OutdatedPyWSGIRefVersionError(Exception):
99
+ """
100
+ Raised when the PyWSGIRef version is outdated and does not support a requested feature.
101
+ """
102
+ def __init__(self, message="The PyWSGIRef version is outdated and does not support this feature."):
87
103
  self.message = message
88
104
  super().__init__(self.message)
@@ -6,18 +6,19 @@ import requests
6
6
  from .exceptions import *
7
7
  from .finished import finished
8
8
 
9
- def loadFromWeb(url: str) -> str:
9
+ def loadFromWeb(url: str, overrideException: bool = False) -> str:
10
10
  """
11
11
  Loads content from the given URL with the given data.
12
+ Overrides ServerAlreadyGeneratedError if overrideException is True.
12
13
  """
13
- if finished.value:
14
+ if finished.value and not overrideException:
14
15
  raise ServerAlreadyGeneratedError()
15
16
  if not url.endswith(".pyhtml"):
16
17
  raise InvalidFiletypeError()
17
18
 
18
19
  # trick GitHub Pages guardian
19
- headers = {"User-Agent": "Mozilla/5.0", "realAccessDeviceMonitorAgent": "PyWSGIRef/1.1"}
20
- rq = requests.get(url, headers=headers)
20
+ headers = {"User-Agent": "Mozilla/5.0"}
21
+ rq = requests.get(url, headers=headers, data={"realAccessDeviceMonitorAgent": "PyWSGIRef/1.1"})
21
22
  if rq.status_code != 200:
22
23
  raise AccessToTemplateForbidden()
23
24
  rq_content = rq.content
@@ -20,7 +20,7 @@ class PyHTML:
20
20
  if self.html.startswith(EVAL_PYHTML):
21
21
  self.html = START_REPLACE + self.html[len(EVAL_PYHTML):]
22
22
  if self.html.endswith(EVAL_PYHTML):
23
- self.html = self.html[:-len(EVAL_PYHTML)-1] + END_REPLACE
23
+ self.html = self.html[:-len(EVAL_PYHTML)] + END_REPLACE
24
24
 
25
25
  def _replace_modern_styling(self):
26
26
  """
@@ -1,9 +1,10 @@
1
1
  import datetime
2
2
 
3
3
  class PerformanceTime:
4
- def __init__(self, title: str):
4
+ def __init__(self, title: str, data: dict = {}):
5
5
  self.start = datetime.datetime.now()
6
6
  self.title = title
7
+ self.data = data
7
8
  def stop(self):
8
9
  self.end = datetime.datetime.now()
9
10
 
@@ -29,10 +30,11 @@ class Stats:
29
30
  perfTime.stop()
30
31
  self.performanceTimes.append(perfTime)
31
32
 
32
- def export_stats(self, filename: str = None) -> str:
33
+ def export_stats(self, filename: str = None, html: bool = True) -> str:
33
34
  """
34
35
  Exports all current stats as a formatted string.
35
36
  If filename is given, it will also save the stats to that file.
37
+ If html is true, the output will be formatted as HTML.
36
38
  """
37
39
  lines = []
38
40
  lines.append("PyWSGIRef Statistic-Export")
@@ -54,7 +56,8 @@ class Stats:
54
56
  lines.append(f" {i}. {title}: started at {start} (not stopped until now)")
55
57
  else:
56
58
  lines.append(f" {i}. {title}: (no time data)")
57
- result = "\n".join(lines)
59
+ lines[-1] = lines[-1] + " data: " + ", ".join(f"{k}={v}" for k, v in perf.data.items())
60
+ result = "\n".join(lines) if not html else "<br>".join(lines)
58
61
  if filename:
59
62
  if not filename.endswith(".pywsgirefstats"):
60
63
  filename += ".pywsgirefstats"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyWSGIRef
3
- Version: 1.1.16
3
+ Version: 1.1.18
4
4
  Summary: easy server-setup
5
5
  Author-email: Leander Kafemann <leander.kafemann+python@icloud.com>
6
6
  Project-URL: Homepage, https://github.com/LeanderKafemann/PyWSGIRef
@@ -0,0 +1,3 @@
1
+ from PyWSGIRef.simpleServer import *
2
+
3
+ main()
@@ -1,3 +0,0 @@
1
- from PyWSGIRef import *
2
-
3
- main()
File without changes
File without changes
File without changes