@@ -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,28 @@ 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+ first_with_range_support = Version (4 , 3 )
243+ without_changes = {
244+ # to: from
245+ Version (4 , 2 ): Version (4 , 1 ),
246+ }
247+ result = []
248+ for version in versions :
249+ if (version in without_changes
250+ and without_changes [version ] in versions ):
251+ # equivalent lower protocol can and will be negotiated
252+ continue
253+ if (result
254+ and version >= first_with_range_support
255+ and result [- 1 ][0 ] == version [0 ]
256+ and result [- 1 ][1 ][1 ] == version [1 ] + 1 ):
257+ # can use range to encompass this version
258+ result [- 1 ][1 ][1 ] = version [1 ]
259+ continue
260+ result .append (Version (version [0 ], [version [1 ], version [1 ]]))
261+ if len (result ) == 4 :
262+ break
263+ return result
260264
261265 @classmethod
262266 def get_handshake (cls ):
@@ -310,33 +314,38 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
310314 keep_alive = pool_config .keep_alive ,
311315 )
312316
317+ # Carry out Bolt subclass imports locally to avoid circular dependency
318+ # issues.
313319 if pool_config .protocol_version == (3 , 0 ):
314- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
315320 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 )
321+ bolt_cls = Bolt3
317322 elif pool_config .protocol_version == (4 , 0 ):
318- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
319323 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 )
324+ bolt_cls = Bolt4x0
321325 elif pool_config .protocol_version == (4 , 1 ):
322- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
323326 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 )
327+ bolt_cls = Bolt4x1
325328 elif pool_config .protocol_version == (4 , 2 ):
326- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
327329 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 )
330+ bolt_cls = Bolt4x2
329331 elif pool_config .protocol_version == (4 , 3 ):
330- # Carry out Bolt subclass imports locally to avoid circular dependency issues.
331332 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 )
333+ bolt_cls = Bolt4x3
334+ elif pool_config .protocol_version == (4 , 4 ):
335+ from neo4j .io ._bolt4 import Bolt4x4
336+ bolt_cls = Bolt4x4
333337 else :
334338 log .debug ("[#%04X] S: <CLOSE>" , s .getpeername ()[1 ])
335339 _close_socket (s )
336340
337341 supported_versions = Bolt .protocol_handlers ().keys ()
338342 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 )
339343
344+ connection = bolt_cls (
345+ address , s , pool_config .max_connection_lifetime , auth = auth ,
346+ user_agent = pool_config .user_agent , routing_context = routing_context
347+ )
348+
340349 try :
341350 connection .hello ()
342351 except Exception :
0 commit comments