Skip to content

Commit 19a0ced

Browse files
authored
Merge pull request #65 from tcalmant/issue64
Fixes for #64
2 parents 987cbff + ffa04ac commit 19a0ced

File tree

10 files changed

+85
-113
lines changed

10 files changed

+85
-113
lines changed

.github/workflows/build-20.04.yml

Lines changed: 0 additions & 47 deletions
This file was deleted.

.github/workflows/build-24.04.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ name: CI Build
66
on:
77
push:
88
branches: [ "master" ]
9-
tags: '**'
9+
tags:
10+
- '**'
1011
pull_request:
1112
branches: [ "master" ]
1213

@@ -17,7 +18,7 @@ jobs:
1718
strategy:
1819
fail-fast: false
1920
matrix:
20-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14-dev"]
21+
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
2122

2223
steps:
2324
- uses: actions/[email protected]

.readthedocs.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ formats:
88
- htmlzip
99

1010
build:
11-
os: ubuntu-22.04
11+
os: ubuntu-24.04
1212
tools:
13-
python: "3.11"
13+
python: "3.12"
1414

1515
sphinx:
1616
configuration: docs/conf.py

jsonrpclib/SimpleJSONRPCServer.py

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
# variant of this package.
4646
SimpleXMLRPCDispatcher = xmlrpcserver.SimpleXMLRPCDispatcher
4747
SimpleXMLRPCRequestHandler = xmlrpcserver.SimpleXMLRPCRequestHandler
48-
CGIXMLRPCRequestHandler = xmlrpcserver.CGIXMLRPCRequestHandler
4948
resolve_dotted_attribute = xmlrpcserver.resolve_dotted_attribute # type: ignore # noqa: E501 # pylint: disable=invalid-name,line-too-long
5049
import socketserver
5150
except (ImportError, AttributeError):
@@ -55,7 +54,6 @@
5554

5655
SimpleXMLRPCDispatcher = xmlrpcserver.SimpleXMLRPCDispatcher # type: ignore # noqa: E501 # pylint: disable=invalid-name,line-too-long
5756
SimpleXMLRPCRequestHandler = xmlrpcserver.SimpleXMLRPCRequestHandler # type: ignore # noqa: E501 # pylint: disable=invalid-name,line-too-long
58-
CGIXMLRPCRequestHandler = xmlrpcserver.CGIXMLRPCRequestHandler # type: ignore # noqa: E501 # pylint: disable=invalid-name,line-too-long
5957
resolve_dotted_attribute = xmlrpcserver.resolve_dotted_attribute # type: ignore # noqa: E501 # pylint: disable=invalid-name,line-too-long
6058
import SocketServer as socketserver # type: ignore
6159

@@ -688,41 +686,43 @@ def server_close(self):
688686

689687
# ------------------------------------------------------------------------------
690688

689+
if sys.version_info < (3, 15):
690+
CGIXMLRPCRequestHandler = xmlrpcserver.CGIXMLRPCRequestHandler
691691

692-
class CGIJSONRPCRequestHandler(
693-
SimpleJSONRPCDispatcher, CGIXMLRPCRequestHandler
694-
):
695-
"""
696-
JSON-RPC CGI handler (and dispatcher)
697-
"""
698-
699-
def __init__(self, encoding="UTF-8", config=jsonrpclib.config.DEFAULT):
692+
class CGIJSONRPCRequestHandler(
693+
SimpleJSONRPCDispatcher, CGIXMLRPCRequestHandler
694+
):
700695
"""
701-
Sets up the dispatcher
702-
703-
:param encoding: Dispatcher encoding
704-
:param config: A JSONRPClib Config instance
696+
JSON-RPC CGI handler (and dispatcher)
705697
"""
706-
SimpleJSONRPCDispatcher.__init__(self, encoding, config)
707-
CGIXMLRPCRequestHandler.__init__(self, encoding=encoding)
708698

709-
def handle_jsonrpc(self, request_text):
710-
"""
711-
Handle a JSON-RPC request
712-
"""
713-
try:
714-
writer = sys.stdout.buffer
715-
except AttributeError:
716-
writer = sys.stdout
717-
718-
response = self._marshaled_dispatch(request_text)
719-
response = response.encode(self.encoding)
720-
print("Content-Type:", self.json_config.content_type)
721-
print("Content-Length:", len(response))
722-
print()
723-
sys.stdout.flush()
724-
writer.write(response)
725-
writer.flush()
726-
727-
# XML-RPC alias
728-
handle_xmlrpc = handle_jsonrpc
699+
def __init__(self, encoding="UTF-8", config=jsonrpclib.config.DEFAULT):
700+
"""
701+
Sets up the dispatcher
702+
703+
:param encoding: Dispatcher encoding
704+
:param config: A JSONRPClib Config instance
705+
"""
706+
SimpleJSONRPCDispatcher.__init__(self, encoding, config)
707+
CGIXMLRPCRequestHandler.__init__(self, encoding=encoding)
708+
709+
def handle_jsonrpc(self, request_text):
710+
"""
711+
Handle a JSON-RPC request
712+
"""
713+
try:
714+
writer = sys.stdout.buffer
715+
except AttributeError:
716+
writer = sys.stdout
717+
718+
response = self._marshaled_dispatch(request_text)
719+
response = response.encode(self.encoding)
720+
print("Content-Type:", self.json_config.content_type)
721+
print("Content-Length:", len(response))
722+
print()
723+
sys.stdout.flush()
724+
writer.write(response)
725+
writer.flush()
726+
727+
# XML-RPC alias
728+
handle_xmlrpc = handle_jsonrpc

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ classifiers = [
3333
"Programming Language :: Python :: 3.11",
3434
"Programming Language :: Python :: 3.12",
3535
"Programming Language :: Python :: 3.13",
36+
"Programming Language :: Python :: 3.14",
3637
]
3738
license = "Apache-2.0"
3839
license-files = ["LICENSE"]

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,6 @@
7575
"Programming Language :: Python :: 3.11",
7676
"Programming Language :: Python :: 3.12",
7777
"Programming Language :: Python :: 3.13",
78+
"Programming Language :: Python :: 3.14",
7879
],
7980
)

tests/cgi-bin/cgi_server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22
"""
3-
Sample CGI server
3+
Sample CGI server. Won't work with Python 3.15 and later
44
"""
55

66
import os

tests/test_cgi.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@
1111
# Standard library
1212
import os
1313
import random
14+
import socket
1415
import threading
16+
import sys
1517
import unittest
1618

19+
20+
if sys.version_info >= (3, 15):
21+
raise unittest.SkipTest("CGI support has been removed in Python 3.15")
22+
1723
try:
1824
from http.server import HTTPServer, CGIHTTPRequestHandler
1925
except ImportError:
@@ -25,6 +31,8 @@
2531

2632
# ------------------------------------------------------------------------------
2733

34+
HOST = socket.gethostbyname("localhost")
35+
2836

2937
class CGIHandlerTests(unittest.TestCase):
3038
"""
@@ -40,7 +48,7 @@ def test_server(self):
4048
try:
4149
# Setup server
4250
os.chdir(os.path.dirname(__file__))
43-
server = HTTPServer(("localhost", 0), CGIHTTPRequestHandler)
51+
server = HTTPServer((HOST, 0), CGIHTTPRequestHandler)
4452

4553
# Serve in a thread
4654
thread = threading.Thread(target=server.serve_forever)
@@ -52,7 +60,7 @@ def test_server(self):
5260

5361
# Make the client
5462
client = ServerProxy(
55-
"http://localhost:{0}/cgi-bin/cgi_server.py".format(port)
63+
"http://{0}:{1}/cgi-bin/cgi_server.py".format(HOST, port)
5664
)
5765

5866
# Check call

tests/test_headers.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# Standard library
1010
import contextlib
1111
import re
12+
import socket
1213
import sys
1314
import unittest
1415
import jsonrpclib
@@ -29,6 +30,8 @@
2930

3031
# ------------------------------------------------------------------------------
3132

33+
HOST = socket.gethostbyname("localhost")
34+
3235

3336
class HeadersTests(unittest.TestCase):
3437
"""
@@ -85,18 +88,20 @@ def captured_headers(self, check_duplicates=True):
8588

8689
# Extract headers
8790
raw_headers = request_line.splitlines()[1:-1]
88-
raw_headers = map(lambda h: re.split(r":\s?", h, 1), raw_headers)
91+
raw_headers = map(
92+
lambda h: re.split(r":\s?", h, maxsplit=1), raw_headers
93+
)
8994
for header, value in raw_headers:
9095
header = header.lower()
9196
if check_duplicates and header in headers:
9297
raise KeyError("Header defined twice: {0}".format(header))
9398
headers[header] = value
9499

95100
def test_should_extract_headers(self):
96-
""" Check client headers capture """
101+
"""Check client headers capture"""
97102
# given
98103
client = jsonrpclib.ServerProxy(
99-
"http://localhost:{0}".format(self.port), verbose=1
104+
"http://{0}:{1}".format(HOST, self.port), verbose=1
100105
)
101106

102107
# when
@@ -110,10 +115,10 @@ def test_should_extract_headers(self):
110115
self.assertEqual(headers["content-type"], "application/json-rpc")
111116

112117
def test_should_add_additional_headers(self):
113-
""" Check sending of custom headers """
118+
"""Check sending of custom headers"""
114119
# given
115120
client = jsonrpclib.ServerProxy(
116-
"http://localhost:{0}".format(self.port),
121+
"http://{0}:{1}".format(HOST, self.port),
117122
verbose=1,
118123
headers={"X-My-Header": "Test"},
119124
)
@@ -128,10 +133,10 @@ def test_should_add_additional_headers(self):
128133
self.assertEqual(headers["x-my-header"], "Test")
129134

130135
def test_should_add_additional_headers_to_notifications(self):
131-
""" Check custom headers on notifications """
136+
"""Check custom headers on notifications"""
132137
# given
133138
client = jsonrpclib.ServerProxy(
134-
"http://localhost:{0}".format(self.port),
139+
"http://{0}:{1}".format(HOST, self.port),
135140
verbose=1,
136141
headers={"X-My-Header": "Test"},
137142
)
@@ -145,10 +150,10 @@ def test_should_add_additional_headers_to_notifications(self):
145150
self.assertEqual(headers["x-my-header"], "Test")
146151

147152
def test_should_override_headers(self):
148-
""" Custom headers must override default ones """
153+
"""Custom headers must override default ones"""
149154
# given
150155
client = jsonrpclib.ServerProxy(
151-
"http://localhost:{0}".format(self.port),
156+
"http://{0}:{1}".format(HOST, self.port),
152157
verbose=1,
153158
headers={"User-Agent": "jsonrpclib test", "Host": "example.com"},
154159
)
@@ -163,10 +168,10 @@ def test_should_override_headers(self):
163168
self.assertEqual(headers["host"], "example.com")
164169

165170
def test_should_not_override_content_length(self):
166-
""" Custom headers can't override Content-Length """
171+
"""Custom headers can't override Content-Length"""
167172
# given
168173
client = jsonrpclib.ServerProxy(
169-
"http://localhost:{0}".format(self.port),
174+
"http://{0}:{1}".format(HOST, self.port),
170175
verbose=1,
171176
headers={"Content-Length": "invalid value"},
172177
)
@@ -181,10 +186,10 @@ def test_should_not_override_content_length(self):
181186
self.assertNotEqual(headers["content-length"], "invalid value")
182187

183188
def test_should_convert_header_values_to_basestring(self):
184-
""" Custom headers values should be converted to str """
189+
"""Custom headers values should be converted to str"""
185190
# given
186191
client = jsonrpclib.ServerProxy(
187-
"http://localhost:{0}".format(self.port),
192+
"http://{0}:{1}".format(HOST, self.port),
188193
verbose=1,
189194
headers={"X-Test": 123},
190195
)
@@ -199,10 +204,10 @@ def test_should_convert_header_values_to_basestring(self):
199204
self.assertEqual(headers["x-test"], "123")
200205

201206
def test_should_add_custom_headers_to_methods(self):
202-
""" Check method-based custom headers """
207+
"""Check method-based custom headers"""
203208
# given
204209
client = jsonrpclib.ServerProxy(
205-
"http://localhost:{0}".format(self.port), verbose=1
210+
"http://{0}:{1}".format(HOST, self.port), verbose=1
206211
)
207212

208213
# when
@@ -217,10 +222,10 @@ def test_should_add_custom_headers_to_methods(self):
217222
self.assertEqual(headers["x-method"], "Method")
218223

219224
def test_should_override_global_headers(self):
220-
""" Method-based custom headers override context ones """
225+
"""Method-based custom headers override context ones"""
221226
# given
222227
client = jsonrpclib.ServerProxy(
223-
"http://localhost:{0}".format(self.port),
228+
"http://{0}:{1}".format(HOST, self.port),
224229
verbose=1,
225230
headers={"X-Test": "Global"},
226231
)
@@ -236,10 +241,10 @@ def test_should_override_global_headers(self):
236241
self.assertEqual(headers["x-test"], "Method")
237242

238243
def test_should_restore_global_headers(self):
239-
""" Check custom headers context clean up """
244+
"""Check custom headers context clean up"""
240245
# given
241246
client = jsonrpclib.ServerProxy(
242-
"http://localhost:{0}".format(self.port),
247+
"http://{0}:{1}".format(HOST, self.port),
243248
verbose=1,
244249
headers={"X-Test": "Global"},
245250
)
@@ -262,10 +267,10 @@ def test_should_restore_global_headers(self):
262267
self.assertEqual(headers["x-test"], "Global")
263268

264269
def test_should_allow_to_nest_additional_header_blocks(self):
265-
""" Check nested additional headers """
270+
"""Check nested additional headers"""
266271
# given
267272
client = jsonrpclib.ServerProxy(
268-
"http://localhost:{0}".format(self.port), verbose=1
273+
"http://{0}:{1}".format(HOST, self.port), verbose=1
269274
)
270275

271276
# when

0 commit comments

Comments
 (0)