Skip to content

Commit

Permalink
Bump driver version to 4.4, drop Python 3.5 support (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
robsdedude authored Jul 12, 2021
1 parent 76b399d commit ed1dd97
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 74 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Neo4j Driver Change Log

## Version 4.4

- Python 3.5 support has been dropped.


## Version 4.3

Expand Down Expand Up @@ -35,4 +39,4 @@
+ Python 3.2 support has been dropped.
+ Python 3.1 support has been dropped.
+ Python 3.0 support has been dropped.
+ Python 2.7 support has been dropped.
+ Python 2.7 support has been dropped.
3 changes: 1 addition & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ These drivers will also be compatible with the previous Neo4j release, although
+ Python 3.8 supported.
+ Python 3.7 supported.
+ Python 3.6 supported.
+ Python 3.5 supported.

Python 2.7 support has been dropped as of the Neo4j 4.0 release.

Expand Down Expand Up @@ -120,4 +119,4 @@ Other Information
.. _`Neo4j Cypher Refcard`: https://neo4j.com/docs/cypher-refcard/current/
.. _`Example Project`: https://github.com/neo4j-examples/movies-python-bolt
.. _`Driver Wiki`: https://github.com/neo4j/neo4j-python-driver/wiki
.. _`Neo4j 4.0 Migration Guide`: https://neo4j.com/docs/migration-guide/4.0/
.. _`Neo4j 4.0 Migration Guide`: https://neo4j.com/docs/migration-guide/4.0/
6 changes: 3 additions & 3 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Neo4j Driver Testing

To run driver tests, [Tox](https://tox.readthedocs.io) is required as well as at least one version of Python.
The versions of Python supported by this driver are CPython 2.7, 3.4, 3.5 and 3.6.
The versions of Python supported by this driver are CPython 3.6, 3.7, 3.8, and 3.9.


## Unit Tests & Stub Tests
Expand Down Expand Up @@ -40,7 +40,7 @@ a report can be viewed after the run with `coverage report --show-missing`.

## Testing with Testkit

Tests **require** the latest [Testkit 4.3](https://github.com/neo4j-drivers/testkit/tree/4.3), Python3 and Docker.
Tests **require** the latest [Testkit 4.4](https://github.com/neo4j-drivers/testkit/tree/4.4), Python3 and Docker.

Testkit is needed to be cloned and configured to run against the Python Driver. Use the following steps to configure Testkit.

Expand Down Expand Up @@ -69,4 +69,4 @@ To run test against against some Neo4j version:
python3 main.py
```

More details about how to use Teskit could be found on [its repository](https://github.com/neo4j-drivers/testkit/tree/4.3)
More details about how to use Teskit could be found on [its repository](https://github.com/neo4j-drivers/testkit/tree/4.4)
3 changes: 1 addition & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ The Official Neo4j Driver for Python.

Neo4j versions supported:

* Neo4j 4.4
* Neo4j 4.3
* Neo4j 4.2
* Neo4j 3.5

Python versions supported:
Expand All @@ -16,7 +16,6 @@ Python versions supported:
* Python 3.8
* Python 3.7
* Python 3.6
* Python 3.5

.. note::

Expand Down
32 changes: 8 additions & 24 deletions neo4j/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,30 +232,14 @@ def get_ssl_context(self):
# TLS 1.1 - Released in 2006, published as RFC 4346. (Disabled)
# TLS 1.2 - Released in 2008, published as RFC 5246.

try:
# python 3.6+
# https://docs.python.org/3.6/library/ssl.html#ssl.PROTOCOL_TLS_CLIENT
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

# For recommended security options see
# https://docs.python.org/3.6/library/ssl.html#protocol-versions
ssl_context.options |= ssl.OP_NO_TLSv1 # Python 3.2
ssl_context.options |= ssl.OP_NO_TLSv1_1 # Python 3.4

except AttributeError:
# python 3.5
# https://docs.python.org/3.5/library/ssl.html#ssl.PROTOCOL_TLS
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)

# For recommended security options see
# https://docs.python.org/3.5/library/ssl.html#protocol-versions
ssl_context.options |= ssl.OP_NO_SSLv2 # Python 3.2
ssl_context.options |= ssl.OP_NO_SSLv3 # Python 3.2
ssl_context.options |= ssl.OP_NO_TLSv1 # Python 3.2
ssl_context.options |= ssl.OP_NO_TLSv1_1 # Python 3.4

ssl_context.verify_mode = ssl.CERT_REQUIRED # https://docs.python.org/3.5/library/ssl.html#ssl.SSLContext.verify_mode
ssl_context.check_hostname = True # https://docs.python.org/3.5/library/ssl.html#ssl.SSLContext.check_hostname
# https://docs.python.org/3.6/library/ssl.html#ssl.PROTOCOL_TLS_CLIENT
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

# For recommended security options see
# https://docs.python.org/3.6/library/ssl.html#protocol-versions
ssl_context.options |= ssl.OP_NO_TLSv1 # Python 3.2
ssl_context.options |= ssl.OP_NO_TLSv1_1 # Python 3.4


if self.trust == TRUST_ALL_CERTIFICATES:
ssl_context.check_hostname = False
Expand Down
65 changes: 35 additions & 30 deletions neo4j/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,15 @@ def protocol_handlers(cls, protocol_version=None):

# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt3 import Bolt3
from neo4j.io._bolt4 import Bolt4x0, Bolt4x1, Bolt4x2, Bolt4x3
from neo4j.io._bolt4 import Bolt4x0, Bolt4x1, Bolt4x2, Bolt4x3, Bolt4x4

handlers = {
Bolt3.PROTOCOL_VERSION: Bolt3,
Bolt4x0.PROTOCOL_VERSION: Bolt4x0,
Bolt4x1.PROTOCOL_VERSION: Bolt4x1,
Bolt4x2.PROTOCOL_VERSION: Bolt4x2,
Bolt4x3.PROTOCOL_VERSION: Bolt4x3,
Bolt4x4.PROTOCOL_VERSION: Bolt4x4,
}

if protocol_version is None:
Expand All @@ -238,25 +239,24 @@ def version_list(cls, versions, limit=4):
preference. The number of protocol versions (or ranges)
returned is limited to four.
"""
ranges_supported = versions[0] >= Version(4, 3)
without_changes = {Version(4, 2)}
if versions and ranges_supported:
start, end = 0, 0
first_major = versions[start][0]
minors = []
for version in versions:
if version[0] == first_major:
minors.append(version[1])
else:
break
new_versions = [
Version(first_major, minors),
*(v for v in versions[1:] if v not in without_changes)
]
else:
new_versions = [v for v in versions if v not in without_changes]
new_versions = [*new_versions[:(limit - 1)], versions[-1]]
return new_versions
# In fact, 4.3 is the fist version to support ranges. However, the range
# support got backported to 4.2. But even if the server is too old to
# have the backport, negotiating BOLT 4.1 is no problem as it's
# equivalent to 4.2
first_with_range_support = Version(4, 2)
result = []
for version in versions:
if (result
and version >= first_with_range_support
and result[-1][0] == version[0]
and result[-1][1][1] == version[1] + 1):
# can use range to encompass this version
result[-1][1][1] = version[1]
continue
result.append(Version(version[0], [version[1], version[1]]))
if len(result) == 4:
break
return result

@classmethod
def get_handshake(cls):
Expand Down Expand Up @@ -310,33 +310,38 @@ def open(cls, address, *, auth=None, timeout=None, routing_context=None, **pool_
keep_alive=pool_config.keep_alive,
)

# Carry out Bolt subclass imports locally to avoid circular dependency
# issues.
if pool_config.protocol_version == (3, 0):
# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt3 import Bolt3
connection = Bolt3(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
bolt_cls = Bolt3
elif pool_config.protocol_version == (4, 0):
# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt4 import Bolt4x0
connection = Bolt4x0(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
bolt_cls = Bolt4x0
elif pool_config.protocol_version == (4, 1):
# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt4 import Bolt4x1
connection = Bolt4x1(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
bolt_cls = Bolt4x1
elif pool_config.protocol_version == (4, 2):
# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt4 import Bolt4x2
connection = Bolt4x2(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
bolt_cls = Bolt4x2
elif pool_config.protocol_version == (4, 3):
# Carry out Bolt subclass imports locally to avoid circular dependency issues.
from neo4j.io._bolt4 import Bolt4x3
connection = Bolt4x3(address, s, pool_config.max_connection_lifetime, auth=auth, user_agent=pool_config.user_agent, routing_context=routing_context)
bolt_cls = Bolt4x3
elif pool_config.protocol_version == (4, 4):
from neo4j.io._bolt4 import Bolt4x4
bolt_cls = Bolt4x4
else:
log.debug("[#%04X] S: <CLOSE>", s.getpeername()[1])
_close_socket(s)

supported_versions = Bolt.protocol_handlers().keys()
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)

connection = bolt_cls(
address, s, pool_config.max_connection_lifetime, auth=auth,
user_agent=pool_config.user_agent, routing_context=routing_context
)

try:
connection.hello()
except Exception:
Expand Down
2 changes: 1 addition & 1 deletion neo4j/io/_bolt3.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
class Bolt3(Bolt):
""" Protocol handler for Bolt 3.
This is supported by Neo4j versions 3.5, 4.0, 4.1 and 4.2.
This is supported by Neo4j versions 3.5, 4.0, 4.1, 4.2, 4.3, and 4.4.
"""

PROTOCOL_VERSION = Version(3, 0)
Expand Down
15 changes: 12 additions & 3 deletions neo4j/io/_bolt4.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def defunct(self):
class Bolt4x1(Bolt4x0):
""" Protocol handler for Bolt 4.1.
This is supported by Neo4j versions 4.1 and 4.2.
This is supported by Neo4j versions 4.1 - 4.4.
"""

PROTOCOL_VERSION = Version(4, 1)
Expand All @@ -338,7 +338,7 @@ def get_base_headers(self):
class Bolt4x2(Bolt4x1):
""" Protocol handler for Bolt 4.2.
This is supported by Neo4j version 4.2.
This is supported by Neo4j version 4.2 - 4.4.
"""

PROTOCOL_VERSION = Version(4, 2)
Expand All @@ -347,7 +347,7 @@ class Bolt4x2(Bolt4x1):
class Bolt4x3(Bolt4x2):
""" Protocol handler for Bolt 4.3.
This is supported by Neo4j version 4.3.
This is supported by Neo4j version 4.3 - 4.4.
"""

PROTOCOL_VERSION = Version(4, 3)
Expand Down Expand Up @@ -376,3 +376,12 @@ def fail(md):
self.send_all()
self.fetch_all()
return [metadata.get("rt")]


class Bolt4x4(Bolt4x3):
""" Protocol handler for Bolt 4.4.
This is supported by Neo4j version 4.4.
"""

PROTOCOL_VERSION = Version(4, 4)
2 changes: 1 addition & 1 deletion neo4j/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

# Can be automatically overridden in builds
package = "neo4j"
version = "4.3.dev0"
version = "4.4.dev0"


def get_user_agent():
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"Operating System :: OS Independent",
"Topic :: Database",
"Topic :: Software Development",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
Expand Down
4 changes: 2 additions & 2 deletions testkit/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ ENV PYENV_ROOT /.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH

# Set minimum supported Python version
RUN pyenv install 3.5.9
RUN pyenv install 3.6.13
RUN pyenv rehash
RUN pyenv global 3.5.9
RUN pyenv global 3.6.13

# Install Latest pip for each environment
# https://pip.pypa.io/en/stable/news/
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/io/test_class_bolt.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
def test_class_method_protocol_handlers():
# python -m pytest tests/unit/io/test_class_bolt.py -s -v -k test_class_method_protocol_handlers
protocol_handlers = Bolt.protocol_handlers()
assert len(protocol_handlers) == 5
assert len(protocol_handlers) == 6


@pytest.mark.parametrize(
Expand All @@ -53,7 +53,7 @@ def test_class_method_protocol_handlers_with_invalid_protocol_version():
def test_class_method_get_handshake():
# python -m pytest tests/unit/io/test_class_bolt.py -s -v -k test_class_method_get_handshake
handshake = Bolt.get_handshake()
assert handshake == b"\x00\x03\x03\x04\x00\x00\x01\x04\x00\x00\x00\x04\x00\x00\x00\x03"
assert handshake == b"\x00\x02\x04\x04\x00\x00\x01\x04\x00\x00\x00\x04\x00\x00\x00\x03"


def test_magic_preamble():
Expand Down
2 changes: 1 addition & 1 deletion tox-unit.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tox]
envlist =
py35
py36

[testenv]
deps =
Expand Down
1 change: 0 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[tox]
envlist =
py35
py36
py37
py38
Expand Down

0 comments on commit ed1dd97

Please sign in to comment.