Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 1 addition & 74 deletions .pylint-rc
Original file line number Diff line number Diff line change
Expand Up @@ -54,86 +54,13 @@ confidence=
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
invalid-unicode-literal,
raw-checker-failed,
disable=raw-checker-failed,
bad-inline-option,
locally-disabled,
locally-enabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
deprecated-operator-function,
deprecated-urllib-function,
xreadlines-attribute,
deprecated-sys-function,
exception-escape,
comprehension-escape,
# Removed in latest pylint and fights with flake8 etc.
bad-continuation,
# Added for pynuodb
Expand Down
5 changes: 2 additions & 3 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ Requirements

Developers should use virtualenv to maintain multiple side-by-side
environments to test with. Specifically, all contributions must be
tested with both 2.7.6 and 3.4.3 to ensure the library is syntax
compatible between the two versions.
tested with Python >= 3.9 to ensure the library remains compatible.

Dependencies
~~~~~~~~~~~~

Here was my basic setup on Mac OS X:

| virtualenv --python=/usr/bin/python2.7 ~/.venv/pynuodb
| virtualenv --python=/usr/bin/python3 ~/.venv/pynuodb
| source ~/.venv/pynuodb/bin/activate
| pip install mock
| pip install nose
Expand Down
6 changes: 2 additions & 4 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ with limited support and testing from NuoDB.
Requirements
------------

* Python >= 2.7
* Python >= 3.9

- Recommended Python version >= 3.8

- Tested with CPython_ 2.7 and 3.6
- Tested with CPython_ 3.9

* NuoDB_ >= 6.0.2

Expand Down
78 changes: 15 additions & 63 deletions pynuodb/crypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import hashlib
import random
import binascii
import sys

try:
from typing import Optional # pylint: disable=unused-import
Expand All @@ -57,77 +56,35 @@
arc4Imported = False
AESImported = False

isP2 = sys.version[0] == '2'


def get_ciphers():
# type: () -> str
"""Return the list of ciphers supported by this client."""
return ("AES-256-CTR,AES-128-CTR," if AESImported else '') + "RC4"


# We use a bytearray for our sending buffer because we need to construct it.
# If we were using only Python3, then our received data could be stored in a
# bytes object which might be slightly more efficient. But in Python2 a bytes
# object is the same as a string so it can't be portable: if use bytes we need
# different code to extract it on P2 vs. P3.
#
# Instead, we'll use a bytearray for the received data as well as the sending
# data for as long as we need to support Python 2.

if isP2:
def bytesToArray(data):
# type: (bytes) -> bytearray
"""Convert bytes to a bytearray.

On Python 2 bytes is a string so we have to ord each character.
"""
return bytearray([ord(c) for c in data]) # type: ignore

def arrayToStr(data):
# type: (bytearray) -> str
"""Convert a bytearray to a str.

On Python 2 we can just use the str() constructor. If we use decode
we get back a unicode string not a string..
"""
return str(data)
def bytesToArray(data):
# type: (bytes) -> bytearray
"""Convert bytes to a bytearray."""
return bytearray(data)

def hexstrToBytes(hexstr):
# type: (Optional[str]) -> Optional[bytes]
"""Convert a hex string to bytes."""
return binascii.unhexlify(hexstr) if hexstr is not None else None
else:
def bytesToArray(data):
# type: (bytes) -> bytearray
"""Convert bytes to a bytearray.

On Python 3 bytes is a binary string so we can just convert it.
"""
return bytearray(data)
def arrayToStr(data):
# type: (bytearray) -> str
"""Convert a bytearray to a str: assume UTF-8 always."""
return data.decode('utf-8')

def arrayToStr(data):
# type: (bytearray) -> str
"""Convert a bytearray to a str.

On Python 3 we must decode: assume UTF-8 always.
"""
return data.decode('utf-8')

def hexstrToBytes(hexstr):
# type: (Optional[str]) -> Optional[bytes]
"""Convert a hex string to bytes."""
return bytes.fromhex(hexstr) if hexstr is not None else None # pylint: disable=no-member
def hexstrToBytes(hexstr):
# type: (Optional[str]) -> Optional[bytes]
"""Convert a hex string to bytes."""
return bytes.fromhex(hexstr) if hexstr is not None else None


def toHex(bigInt):
# type: (int) -> str
"""Convert an integer into a hex string."""
if isP2:
hexStr = (hex(bigInt)[2:])[:-1]
else:
# Python 3 will no longer insert an L for type formatting
hexStr = hex(bigInt)[2:]
hexStr = hex(bigInt)[2:]
# Some platforms assume hex strings are even length: add padding if needed
if len(hexStr) % 2 == 1:
hexStr = '0' + hexStr
Expand Down Expand Up @@ -435,13 +392,8 @@ def transform(self, data):
# type: (bytes) -> bytes
"""Perform a byte by byte RC4 transform on the stream.

Python 2:
automatically handles encoding bytes into an extended ASCII
encoding [0,255] w/ 1 byte per character

Python 3:
bytes objects must be converted into extended ASCII, latin-1 uses
the desired range of [0,255]
bytes objects must be converted into extended ASCII, latin-1 uses
the desired range of [0,255].

For utf-8 strings (characters consisting of more than 1 byte) the
values are broken into 1 byte sections and shifted. The RC4 stream
Expand Down
61 changes: 21 additions & 40 deletions pynuodb/datatype.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
'TimestampToTicks', 'Binary', 'Vector', 'STRING', 'BINARY', 'NUMBER',
'DATETIME', 'ROWID', 'VECTOR_DOUBLE', 'TypeObjectFromNuodb']

import sys
import decimal
from datetime import datetime as Timestamp, date as Date, time as Time
from datetime import timedelta as TimeDelta
from datetime import timezone
from datetime import tzinfo # pylint: disable=unused-import

from pynuodb import protocol
Expand All @@ -47,41 +47,23 @@
from .exception import DataError
from .calendar import ymd2day, day2ymd

# zoneinfo.ZoneInfo is preferred but not introduced until python3.9
if sys.version_info >= (3, 9):
# used for python>=3.9 with support for zoneinfo.ZoneInfo
from datetime import timezone # pylint: disable=no-name-in-module,ungrouped-imports
UTC = timezone.utc

def utc_TimeStamp(year, month, day, hour=0, minute=0, second=0, microsecond=0):
# type: (int, int, int, int, int, int, int) -> Timestamp
"""Return a Timestamp UTC timezone."""
return Timestamp(year=year, month=month, day=day,
hour=hour, minute=minute, second=second,
microsecond=microsecond, tzinfo=UTC)

def timezone_aware(tstamp, tz_info):
# type: (Timestamp, tzinfo) -> Timestamp
"""Return a Timestamp that uses the provided timezone."""
return tstamp.replace(tzinfo=tz_info)

else:
# used for python<3.9 without support for zoneinfo.ZoneInfo
from pytz import utc as UTC

def utc_TimeStamp(year, month, day, hour=0, minute=0, second=0, microsecond=0):
# type: (int, int, int, int, int, int, int) -> Timestamp
"""Return a Timestamp UTC timezone."""
dt = Timestamp(year=year, month=month, day=day,
hour=hour, minute=minute, second=second, microsecond=microsecond)
return UTC.localize(dt, is_dst=None)

def timezone_aware(tstamp, tz_info):
# type: (Timestamp, tzinfo) -> Timestamp
"""Return a Timestamp that uses the provided timezone."""
return tz_info.localize(tstamp, is_dst=None) # type: ignore[attr-defined]

isP2 = sys.version[0] == '2'
UTC = timezone.utc


def utc_TimeStamp(year, month, day, hour=0, minute=0, second=0, microsecond=0):
# type: (int, int, int, int, int, int, int) -> Timestamp
"""Return a Timestamp UTC timezone."""
return Timestamp(year=year, month=month, day=day,
hour=hour, minute=minute, second=second,
microsecond=microsecond, tzinfo=UTC)


def timezone_aware(tstamp, tz_info):
# type: (Timestamp, tzinfo) -> Timestamp
"""Return a Timestamp that uses the provided timezone."""
return tstamp.replace(tzinfo=tz_info)


TICKSDAY = 86400
LOCALZONE = tzlocal.get_localzone()

Expand All @@ -104,8 +86,7 @@ def __new__(cls, data):
# I can't figure out how to get mypy to be OK with this.
if isinstance(data, bytearray):
return bytes.__new__(cls, data) # type: ignore
# In Python2 there's no distinction between str and bytes :(
if isinstance(data, str) and not isP2:
if isinstance(data, str):
return bytes.__new__(cls, data.encode('latin-1')) # type: ignore
return bytes.__new__(cls, data) # type: ignore

Expand All @@ -114,9 +95,9 @@ def __str__(self):
# This is pretty terrible but it's what the old version did.
# What does it really mean to run str(Binary)? That should probably
# be illegal, but I'm sure lots of code does "%s" % (Binary(x)) or
# the equivalent. In Python 3 we have to remove the 'b' prefix too.
# the equivalent. We have to remove the 'b' prefix too.
# I'll leave this for consideration at some future time.
return repr(self)[1:-1] if isP2 else repr(self)[2:-1]
return repr(self)[2:-1]

@property
def string(self):
Expand Down
15 changes: 2 additions & 13 deletions pynuodb/encodedsession.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
import uuid
import struct
import decimal
import sys
import threading
import datetime # pylint: disable=unused-import
from zoneinfo import ZoneInfo # pylint: disable=import-error

try:
from typing import Any, Collection, Dict, List # pylint: disable=unused-import
Expand All @@ -37,15 +37,6 @@
from . import result_set
from .datatype import LOCALZONE_NAME

# ZoneInfo is preferred but not introduced until 3.9
if sys.version_info >= (3, 9):
# preferred python >= 3.9
from zoneinfo import ZoneInfo # pylint: disable=import-error
else:
# fallback to pytz if python < 3.9
from pytz import timezone as ZoneInfo

isP2 = sys.version[0] == '2'
REMOVE_FORMAT = 0


Expand Down Expand Up @@ -98,8 +89,6 @@ class EncodedSession(session.Session): # pylint: disable=too-many-public-method
closed = False

__output = None # type: bytearray
# If we did not need to be compatible with Python 2 this should be bytes
# But in Python 2, bytes is just another name for str, so use bytearray
__input = None # type: bytearray
__inpos = 0 # type: int
__encryption = True
Expand Down Expand Up @@ -645,7 +634,7 @@ def putString(self, value):

:type value: str
"""
data = bytes(value) if isP2 else value.encode('utf-8') # type: ignore
data = value.encode('utf-8')
length = len(data)
if length < 40:
self.__output.append(protocol.UTF8LEN0 + length)
Expand Down
Loading