@@ -211,14 +211,15 @@ def protocol_handlers(cls, protocol_version=None):
211211
212212 # Carry out Bolt subclass imports locally to avoid circular dependency issues.
213213 from neo4j .io ._bolt3 import Bolt3
214- from neo4j .io ._bolt4 import Bolt4x0 , Bolt4x1 , Bolt4x2 , Bolt4x3
214+ from neo4j .io ._bolt4 import Bolt4x0 , Bolt4x1 , Bolt4x2 , Bolt4x3 , Bolt4x4
215215
216216 handlers = {
217217 Bolt3 .PROTOCOL_VERSION : Bolt3 ,
218218 Bolt4x0 .PROTOCOL_VERSION : Bolt4x0 ,
219219 Bolt4x1 .PROTOCOL_VERSION : Bolt4x1 ,
220220 Bolt4x2 .PROTOCOL_VERSION : Bolt4x2 ,
221221 Bolt4x3 .PROTOCOL_VERSION : Bolt4x3 ,
222+ Bolt4x4 .PROTOCOL_VERSION : Bolt4x4 ,
222223 }
223224
224225 if protocol_version is None :
@@ -238,25 +239,24 @@ def version_list(cls, versions, limit=4):
238239 preference. The number of protocol versions (or ranges)
239240 returned is limited to four.
240241 """
241- ranges_supported = versions [0 ] >= Version (4 , 3 )
242- without_changes = {Version (4 , 2 )}
243- if versions and ranges_supported :
244- start , end = 0 , 0
245- first_major = versions [start ][0 ]
246- minors = []
247- for version in versions :
248- if version [0 ] == first_major :
249- minors .append (version [1 ])
250- else :
251- break
252- new_versions = [
253- Version (first_major , minors ),
254- * (v for v in versions [1 :] if v not in without_changes )
255- ]
256- else :
257- new_versions = [v for v in versions if v not in without_changes ]
258- new_versions = [* new_versions [:(limit - 1 )], versions [- 1 ]]
259- return new_versions
242+ # In fact, 4.3 is the fist version to support ranges. However, the range
243+ # support got backported to 4.2. But even if the server is too old to
244+ # have the backport, negotiating BOLT 4.1 is no problem as it's
245+ # equivalent to 4.2
246+ first_with_range_support = Version (4 , 2 )
247+ result = []
248+ for version in versions :
249+ if (result
250+ and version >= first_with_range_support
251+ and result [- 1 ][0 ] == version [0 ]
252+ and result [- 1 ][1 ][1 ] == version [1 ] + 1 ):
253+ # can use range to encompass this version
254+ result [- 1 ][1 ][1 ] = version [1 ]
255+ continue
256+ result .append (Version (version [0 ], [version [1 ], version [1 ]]))
257+ if len (result ) == 4 :
258+ break
259+ return result
260260
261261 @classmethod
262262 def get_handshake (cls ):
@@ -310,33 +310,38 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
310310 keep_alive = pool_config .keep_alive ,
311311 )
312312
313+ # Carry out Bolt subclass imports locally to avoid circular dependency
314+ # issues.
313315 if pool_config .protocol_version == (3 , 0 ):
314- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
315316 from neo4j .io ._bolt3 import Bolt3
316- connection = Bolt3 ( address , s , pool_config . max_connection_lifetime , auth = auth , user_agent = pool_config . user_agent , routing_context = routing_context )
317+ bolt_cls = Bolt3
317318 elif pool_config .protocol_version == (4 , 0 ):
318- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
319319 from neo4j .io ._bolt4 import Bolt4x0
320- connection = Bolt4x0 ( address , s , pool_config . max_connection_lifetime , auth = auth , user_agent = pool_config . user_agent , routing_context = routing_context )
320+ bolt_cls = Bolt4x0
321321 elif pool_config .protocol_version == (4 , 1 ):
322- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
323322 from neo4j .io ._bolt4 import Bolt4x1
324- connection = Bolt4x1 ( address , s , pool_config . max_connection_lifetime , auth = auth , user_agent = pool_config . user_agent , routing_context = routing_context )
323+ bolt_cls = Bolt4x1
325324 elif pool_config .protocol_version == (4 , 2 ):
326- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
327325 from neo4j .io ._bolt4 import Bolt4x2
328- connection = Bolt4x2 ( address , s , pool_config . max_connection_lifetime , auth = auth , user_agent = pool_config . user_agent , routing_context = routing_context )
326+ bolt_cls = Bolt4x2
329327 elif pool_config .protocol_version == (4 , 3 ):
330- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
331328 from neo4j .io ._bolt4 import Bolt4x3
332- connection = Bolt4x3 (address , s , pool_config .max_connection_lifetime , auth = auth , user_agent = pool_config .user_agent , routing_context = routing_context )
329+ bolt_cls = Bolt4x3
330+ elif pool_config .protocol_version == (4 , 4 ):
331+ from neo4j .io ._bolt4 import Bolt4x4
332+ bolt_cls = Bolt4x4
333333 else :
334334 log .debug ("[#%04X] S: <CLOSE>" , s .getpeername ()[1 ])
335335 _close_socket (s )
336336
337337 supported_versions = Bolt .protocol_handlers ().keys ()
338338 raise BoltHandshakeError ("The Neo4J server does not support communication with this driver. This driver have support for Bolt Protocols {}" .format (supported_versions ), address = address , request_data = handshake , response_data = data )
339339
340+ connection = bolt_cls (
341+ address , s , pool_config .max_connection_lifetime , auth = auth ,
342+ user_agent = pool_config .user_agent , routing_context = routing_context
343+ )
344+
340345 try :
341346 connection .hello ()
342347 except Exception :
0 commit comments