Skip to content

Commit 8201e51

Browse files
committed
Support Python 3.13 and 3.14
1 parent 3fdb8cb commit 8201e51

File tree

15 files changed

+72
-34
lines changed

15 files changed

+72
-34
lines changed

.github/workflows/release-docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ jobs:
1212

1313
steps:
1414
- uses: actions/checkout@v5
15-
- name: Set up Python 3.12
15+
- name: Set up Python 3.13
1616
uses: actions/setup-python@v6
1717
with:
18-
python-version: "3.12"
18+
python-version: "3.13"
1919
- name: Install dependencies
2020
run: |
2121
python -m pip install --upgrade pip

.github/workflows/test-package.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
strategy:
1111
max-parallel: 6
1212
matrix:
13-
python-version: ['3.10', '3.11', '3.12', 'pypy-3.10', 'pypy-3.11']
13+
python-version: ['3.10', '3.11', '3.12', '3.13', 'pypy-3.10', 'pypy-3.11']
1414

1515
steps:
1616
- uses: actions/checkout@v5
@@ -23,11 +23,11 @@ jobs:
2323
python -m pip install --upgrade pip
2424
pip install .[tests]
2525
- name: Lint with flake8
26-
if: matrix.python-version == '3.12'
26+
if: matrix.python-version == '3.13'
2727
run: |
2828
flake8 webware --count --exit-zero --statistics
2929
- name: Lint with pylint
30-
if: matrix.python-version == '3.12'
30+
if: matrix.python-version == '3.13'
3131
run: |
3232
pylint webware
3333
- name: Run all unit tests

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"editor.rulers": [
3+
79, 88
4+
]
5+
}

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ classifiers = [
2828
"Programming Language :: Python :: 3.10",
2929
"Programming Language :: Python :: 3.11",
3030
"Programming Language :: Python :: 3.12",
31+
"Programming Language :: Python :: 3.13",
32+
"Programming Language :: Python :: 3.14",
3133
"Programming Language :: Python :: Implementation :: CPython",
3234
"Programming Language :: Python :: Implementation :: PyPy",
3335
"Operating System :: OS Independent",

tox.ini

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
[tox]
2-
envlist = py3{10,11,12}, pypy3{10,11}, flake8, pylint, docs, manifest
2+
envlist = py3{10,11,12,13,14rc2}, pypy3{10,11}, flake8, pylint, docs, manifest
33

44
[testenv:flake8]
5-
basepython = python3.12
5+
basepython = python3.13
66
deps = flake8>=7,<8
77
commands =
88
flake8 webware
99

1010
[testenv:pylint]
11-
basepython = python3.12
11+
basepython = python3.13
1212
deps = pylint>=3,<4
1313
commands =
1414
pylint webware
1515

1616
[testenv:docs]
17-
basepython = python3.12
17+
basepython = python3.13
1818
extras =
1919
docs
2020
commands =
2121
sphinx-build -b html -nEW docs docs/_build/html
2222

2323
[testenv:manifest]
24-
basepython = python3.12
24+
basepython = python3.13
2525
deps = check-manifest>=0.50
2626
commands =
2727
check-manifest -v

webware/Admin/AppControl.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ def writeContent(self):
2424
wr('<tr><td></td><td>')
2525
for n in sorted(sys.modules):
2626
m = sys.modules[n]
27-
if (not n.endswith('__init__') and not hasattr(m, '__path__')
27+
if (not n.endswith('__init__')
28+
and not hasattr(m, '__path__')
2829
and not hasattr(m, '__orig_file__')):
2930
# show only the easily reloadable modules
30-
wr(f'<input type="checkbox" name="reloads" value="{n}">'
31-
f' {n}<br>')
31+
wr(f'<input type="checkbox" name="reloads"'
32+
f' value="{n}"> {n}<br>')
3233
wr('</td></tr>\n</table>\n</form>')
3334

3435
case "Clear cache":

webware/Application.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"""
1515

1616
import atexit
17+
import importlib
1718
import os
1819
import signal
1920
import sys
@@ -295,12 +296,12 @@ def initSessions(self):
295296
moduleName = setting('SessionModule')
296297
className = moduleName.rpartition('.')[2]
297298
try:
298-
exec(f'from {moduleName} import {className}')
299-
cls = locals()[className]
299+
module = importlib.import_module(moduleName)
300+
cls = getattr(module, className)
300301
if not isinstance(cls, type):
301302
raise ImportError
302303
self._sessionClass = cls
303-
except ImportError:
304+
except (ImportError, AttributeError):
304305
print(f"ERROR: Could not import Session class '{className}'"
305306
f" from module '{moduleName}'")
306307
self._sessionClass = None
@@ -310,8 +311,8 @@ def initSessions(self):
310311
moduleName = f'Session{moduleName}Store'
311312
className = moduleName.rpartition('.')[2]
312313
try:
313-
exec(f'from {moduleName} import {className}')
314-
cls = locals()[className]
314+
module = importlib.import_module(moduleName)
315+
cls = getattr(module, className)
315316
if not isinstance(cls, type):
316317
raise ImportError
317318
self._sessions = cls(self)

webware/MiscUtils/DBPool.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,20 @@ def __init__(self, dbapi, maxconnections, *args, **kwargs):
128128
for _count in range(maxconnections):
129129
self.addConnection(dbapi.connect(*args, **kwargs))
130130

131+
def close(self):
132+
"""Close all connections in the pool."""
133+
try:
134+
queue = self._queue
135+
except AttributeError:
136+
connections = self._connections
137+
while connections:
138+
con = connections.pop()
139+
con.close()
140+
else:
141+
while not queue.empty():
142+
con = queue.get_nowait()
143+
con.close()
144+
131145
# The following functions are used with DB-API 2 modules
132146
# that do not have connection level threadsafety, like PyGreSQL.
133147
# However, the module must be threadsafe at the module level.

webware/MiscUtils/NamedValueAccess.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ def valueForKey(obj, key, default=NoDefault):
7777
underKey = '_' + key
7878
if not (method := getattr(cls, underKey, None) if cls else None):
7979
if (attr := getattr(obj, key, NoDefault)) is NoDefault:
80-
if (attr := getattr(obj, underKey, NoDefault)) is NoDefault and cls is not None:
80+
if ((attr := getattr(obj, underKey, NoDefault))
81+
is NoDefault and cls is not None):
8182
if getitem := getattr(cls, '__getitem__', None):
8283
try:
8384
getitem(obj, key)

webware/MiscUtils/Tests/TestDBPool.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@
66

77
class TestDBPool(unittest.TestCase):
88

9+
def setUp(self):
10+
self.pool = DBPool(sqlite3, 10, database=':memory:')
11+
12+
def tearDown(self):
13+
self.pool.close()
14+
915
def testDbPool(self):
10-
pool = DBPool(sqlite3, 10, database=':memory:')
16+
query = "select 1 union select 2 union select 3 order by 1"
17+
result = [(1,), (2,), (3,)]
1118
for _count in range(15):
12-
con = pool.connection()
19+
con = self.pool.connection()
1320
cursor = con.cursor()
14-
cursor.execute("select 1 union select 2 union select 3 order by 1")
21+
cursor.execute(query)
1522
rows = cursor.fetchall()
16-
self.assertEqual(rows, [(1,), (2,), (3,)])
23+
self.assertEqual(rows, result)
1724
con.close()

0 commit comments

Comments
 (0)