Skip to content

Commit

Permalink
Remove mentions / workaround for unsupported Python versions
Browse files Browse the repository at this point in the history
There are some stale mentions in docs / comments about
Python versions that are no longer supported. There
are also some workarounds to make driver work with those
versions. This commit removes all mentions and workarounds
that I was able to find.
  • Loading branch information
Lorak-mmk authored and fruch committed Jul 31, 2024
1 parent 2d1c787 commit 2467864
Show file tree
Hide file tree
Showing 5 changed files with 10 additions and 243 deletions.
1 change: 0 additions & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ To protect the community, all contributors are required to `sign the DataStax Co

Design and Implementation Guidelines
------------------------------------
- We support Python 2.7+, so any changes must work in any of these runtimes (we use ``six``, ``futures``, and some internal backports for compatability)
- We have integrations (notably Cassandra cqlsh) that require pure Python and minimal external dependencies. We try to avoid new external dependencies. Where compiled extensions are concerned, there should always be a pure Python fallback implementation.
- This project follows `semantic versioning <http://semver.org/>`_, so breaking API changes will only be introduced in major versions.
- Legacy ``cqlengine`` has varying degrees of overreaching client-side validation. Going forward, we will avoid client validation where server feedback is adequate and not overly expensive.
Expand Down
3 changes: 0 additions & 3 deletions cassandra/encoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@


def cql_quote(term):
# The ordering of this method is important for the result of this method to
# be a native str type (for both Python 2 and 3)

if isinstance(term, str):
return "'%s'" % str(term).replace("'", "''")
else:
Expand Down
246 changes: 9 additions & 237 deletions cassandra/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@
# limitations under the License.

from __future__ import with_statement
from _weakref import ref
import calendar
from collections import OrderedDict
from collections.abc import Mapping
import datetime
from functools import total_ordering
import logging
from itertools import chain
import keyword
import logging
import pickle
import random
import re
import uuid
import socket
import sys
import time
import uuid

_HAS_GEOMET = True
try:
Expand Down Expand Up @@ -213,147 +218,6 @@ def _resolve_contact_points_to_string_map(contact_points):
)


try:
from collections import OrderedDict
except ImportError:
# OrderedDict from Python 2.7+

# Copyright (c) 2009 Raymond Hettinger
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
from UserDict import DictMixin

class OrderedDict(dict, DictMixin): # noqa
""" A dictionary which maintains the insertion order of keys. """

def __init__(self, *args, **kwds):
""" A dictionary which maintains the insertion order of keys. """

if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__end
except AttributeError:
self.clear()
self.update(*args, **kwds)

def clear(self):
self.__end = end = []
end += [None, end, end] # sentinel node for doubly linked list
self.__map = {} # key --> [key, prev, next]
dict.clear(self)

def __setitem__(self, key, value):
if key not in self:
end = self.__end
curr = end[1]
curr[2] = end[1] = self.__map[key] = [key, curr, end]
dict.__setitem__(self, key, value)

def __delitem__(self, key):
dict.__delitem__(self, key)
key, prev, next = self.__map.pop(key)
prev[2] = next
next[1] = prev

def __iter__(self):
end = self.__end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]

def __reversed__(self):
end = self.__end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]

def popitem(self, last=True):
if not self:
raise KeyError('dictionary is empty')
if last:
key = next(reversed(self))
else:
key = next(iter(self))
value = self.pop(key)
return key, value

def __reduce__(self):
items = [[k, self[k]] for k in self]
tmp = self.__map, self.__end
del self.__map, self.__end
inst_dict = vars(self).copy()
self.__map, self.__end = tmp
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)

def keys(self):
return list(self)

setdefault = DictMixin.setdefault
update = DictMixin.update
pop = DictMixin.pop
values = DictMixin.values
items = DictMixin.items
iterkeys = DictMixin.iterkeys
itervalues = DictMixin.itervalues
iteritems = DictMixin.iteritems

def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())

def copy(self):
return self.__class__(self)

@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
for key in iterable:
d[key] = value
return d

def __eq__(self, other):
if isinstance(other, OrderedDict):
if len(self) != len(other):
return False
for p, q in zip(self.items(), other.items()):
if p != q:
return False
return True
return dict.__eq__(self, other)

def __ne__(self, other):
return not self == other


# WeakSet from Python 2.7+ (https://code.google.com/p/weakrefset)

from _weakref import ref


class _IterationGuard(object):
# This context manager registers itself in the current iterators of the
# weak container, such as to delay all removals until the context manager
Expand Down Expand Up @@ -916,10 +780,6 @@ def _serialize_key(self, key):
return self.cass_key_type.serialize(key, self.protocol_version)


import datetime
import time


@total_ordering
class Time(object):
'''
Expand Down Expand Up @@ -1145,97 +1005,9 @@ def __str__(self):
# If we overflow datetime.[MIN|MAX]
return str(self.days_from_epoch)

import socket
if hasattr(socket, 'inet_pton'):
inet_pton = socket.inet_pton
inet_ntop = socket.inet_ntop
else:
"""
Windows doesn't have socket.inet_pton and socket.inet_ntop until Python 3.4
This is an alternative impl using ctypes, based on this win_inet_pton project:
https://github.com/hickeroar/win_inet_pton
"""
import ctypes

class sockaddr(ctypes.Structure):
"""
Shared struct for ipv4 and ipv6.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx
``__pad1`` always covers the port.

When being used for ``sockaddr_in6``, ``ipv4_addr`` actually covers ``sin6_flowinfo``, resulting
in proper alignment for ``ipv6_addr``.
"""
_fields_ = [("sa_family", ctypes.c_short),
("__pad1", ctypes.c_ushort),
("ipv4_addr", ctypes.c_byte * 4),
("ipv6_addr", ctypes.c_byte * 16),
("__pad2", ctypes.c_ulong)]

if hasattr(ctypes, 'windll'):
WSAStringToAddressA = ctypes.windll.ws2_32.WSAStringToAddressA
WSAAddressToStringA = ctypes.windll.ws2_32.WSAAddressToStringA
else:
def not_windows(*args):
raise OSError("IPv6 addresses cannot be handled on Windows. "
"Missing ctypes.windll")
WSAStringToAddressA = not_windows
WSAAddressToStringA = not_windows

def inet_pton(address_family, ip_string):
if address_family == socket.AF_INET:
return socket.inet_aton(ip_string)

addr = sockaddr()
addr.sa_family = address_family
addr_size = ctypes.c_int(ctypes.sizeof(addr))

if WSAStringToAddressA(
ip_string,
address_family,
None,
ctypes.byref(addr),
ctypes.byref(addr_size)
) != 0:
raise socket.error(ctypes.FormatError())

if address_family == socket.AF_INET6:
return ctypes.string_at(addr.ipv6_addr, 16)

raise socket.error('unknown address family')

def inet_ntop(address_family, packed_ip):
if address_family == socket.AF_INET:
return socket.inet_ntoa(packed_ip)

addr = sockaddr()
addr.sa_family = address_family
addr_size = ctypes.c_int(ctypes.sizeof(addr))
ip_string = ctypes.create_string_buffer(128)
ip_string_size = ctypes.c_int(ctypes.sizeof(ip_string))

if address_family == socket.AF_INET6:
if len(packed_ip) != ctypes.sizeof(addr.ipv6_addr):
raise socket.error('packed IP wrong length for inet_ntoa')
ctypes.memmove(addr.ipv6_addr, packed_ip, 16)
else:
raise socket.error('unknown address family')

if WSAAddressToStringA(
ctypes.byref(addr),
addr_size,
None,
ip_string,
ctypes.byref(ip_string_size)
) != 0:
raise socket.error(ctypes.FormatError())

return ip_string[:ip_string_size.value - 1]


import keyword
inet_pton = socket.inet_pton
inet_ntop = socket.inet_ntop


# similar to collections.namedtuple, reproduced here because Python 2.6 did not have the rename logic
Expand Down
2 changes: 1 addition & 1 deletion docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Installation

Supported Platforms
-------------------
Python 2.7, 3.5, 3.6, 3.7 and 3.8 are supported. Both CPython (the standard Python
Python versions 3.6-3.11 are supported. Both CPython (the standard Python
implementation) and `PyPy <http://pypy.org>`_ are supported and tested.

Linux, OSX, and Windows are supported.
Expand Down
1 change: 0 additions & 1 deletion tests/integration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,6 @@ def _id_and_mark(f):
incorrect_test = lambda reason='This test seems to be incorrect and should be fixed', *args, **kwargs: pytest.mark.xfail(reason=reason, *args, **kwargs)

pypy = unittest.skipUnless(platform.python_implementation() == "PyPy", "Test is skipped unless it's on PyPy")
notpy3 = unittest.skipIf(sys.version_info >= (3, 0), "Test not applicable for Python 3.x runtime")
requiresmallclockgranularity = unittest.skipIf("Windows" in platform.system() or "asyncore" in EVENT_LOOP_MANAGER,
"This test is not suitible for environments with large clock granularity")
requiressimulacron = unittest.skipIf(SIMULACRON_JAR is None or CASSANDRA_VERSION < Version("2.1"), "Simulacron jar hasn't been specified or C* version is 2.0")
Expand Down

0 comments on commit 2467864

Please sign in to comment.