python-tds
Advanced tools
| import struct | ||
| class Version: | ||
| _struct = struct.Struct('>LH') | ||
| size = _struct.size | ||
| def __init__(self): | ||
| self._version = None | ||
| self._subbuild = None | ||
| def set_version(self, value: int) -> None: self._version = value | ||
| def set_subbuild(self, value: int) -> None: self._subbuild = value | ||
| def get_version(self) -> int: return self._version | ||
| def get_subbuild(self) -> int: return self._subbuild | ||
| @classmethod | ||
| def unpack(cls, data): | ||
| res = cls() | ||
| version, subbuild = cls._struct.unpack(data) | ||
| res.set_version(version) | ||
| res.set_subbuild(subbuild) | ||
| return res | ||
| @classmethod | ||
| def read(cls, src): | ||
| cls.unpack(src.read(cls._struct.size)) | ||
| class Prelogin: | ||
| _offset_len = struct.Struct(">HH") | ||
| _tag_offset_len = struct.Struct(">BHH") | ||
| _fencryption_struct = struct.Struct('@B') | ||
| _thread_id_struct = struct.Struct('>L') | ||
| _mars_struct = struct.Struct('@B') | ||
| def __init__(self, version=None, fencryption=None, instance=None, thread_id=None, mars=None): | ||
| self._version = version | ||
| self._fencryption = fencryption | ||
| self._instance = instance | ||
| self._thread_id = thread_id | ||
| self._mars = mars | ||
| def _unpack_version(self, buf): self._version = Version.unpack(buf) | ||
| def _unpack_fencryption(self, buf): self._fencryption = self._fencryption_struct.unpack(buf)[0] | ||
| def _unpack_instance(self, buf): self._instance = buf.decode('ascii') | ||
| def _unpack_thread_id(self, buf): self._thread_id = self._thread_id_struct.unpack(buf)[0] | ||
| def _unpack_mars(self, buf): self._mars = self._mars_struct.unpack(buf)[0] | ||
| _unpackers = { | ||
| 0: _unpack_version, | ||
| 1: _unpack_fencryption, | ||
| 2: _unpack_instance, | ||
| 3: _unpack_thread_id, | ||
| 4: _unpack_mars, | ||
| } | ||
| @classmethod | ||
| def unpack(cls, buf): | ||
| res = cls() | ||
| pos: int = 0 | ||
| while True: | ||
| tag = buf[pos] | ||
| pos += 1 | ||
| if tag == 255: | ||
| break | ||
| else: | ||
| offset, size = cls._offset_len.unpack_from(buf, pos) | ||
| pos += cls._offset_len.size | ||
| cls._unpackers[tag](res, buf[offset:offset + size]) | ||
| return res | ||
| def _hdr_size(self) -> int: | ||
| hdr_sz: int = 0 | ||
| if self._version is not None: | ||
| hdr_sz += self._tag_offset_len.size | ||
| if self._fencryption is not None: | ||
| hdr_sz += self._tag_offset_len.size | ||
| if self._instance is not None: | ||
| hdr_sz += self._tag_offset_len.size | ||
| if self._thread_id is not None: | ||
| hdr_sz += self._tag_offset_len.size | ||
| if self._mars is not None: | ||
| hdr_sz += self._tag_offset_len.size | ||
| hdr_sz += 1 # space for terminator | ||
| return hdr_sz | ||
| def _size(self) -> (int, int): | ||
| hdr_sz: int = 0 | ||
| data_sz: int = 0 | ||
| if self._version is not None: | ||
| hdr_sz += self._offset_len.size | ||
| data_sz += Version.size | ||
| if self._fencryption is not None: | ||
| hdr_sz += self._offset_len.size | ||
| data_sz += self._fencryption_struct.size | ||
| if self._instance is not None: | ||
| hdr_sz += self._offset_len.size | ||
| data_sz += len(self._instance.encode("ascii")) | ||
| if self._thread_id is not None: | ||
| hdr_sz += self._offset_len.size | ||
| data_sz += self._thread_id_struct.size | ||
| if self._mars is not None: | ||
| hdr_sz += self._offset_len.size | ||
| data_sz += self._mars_struct.size | ||
| hdr_sz += 1 # space for terminator | ||
| return (hdr_sz, data_sz) | ||
| def pack_into(self, buf): | ||
| hdr_pos = 0 | ||
| hdr_sz = self._hdr_size() | ||
| data_pos = hdr_sz | ||
| if self._version is not None: | ||
| data_buf = self._version.pack() | ||
| self._tag_offset_len.pack_into(buf, 0, hdr_pos, data_pos, len(data_buf)); hdr_pos += self._tag_offset_len.size | ||
| buf[data_pos:len(data_buf)] = data_buf[:]; data_pos += len(data_buf) | ||
| if self._fencryption is not None: | ||
| data_buf = self._fencryption_struct.pack(self._fencryption) | ||
| self._tag_offset_len.pack_into(buf, 1, hdr_pos, data_pos, len(data_buf)); hdr_pos += self._tag_offset_len.size | ||
| buf[data_pos:len(data_buf)] = data_buf[:]; data_pos += len(data_buf) | ||
| if self._instance is not None: | ||
| data_buf = self._instance.encode("ascii") | ||
| self._tag_offset_len.pack_into(buf, 2, hdr_pos, data_pos, len(data_buf)); hdr_pos += self._tag_offset_len.size | ||
| buf[data_pos:len(data_buf)] = data_buf[:]; data_pos += len(data_buf) | ||
| if self._thread_id is not None: | ||
| data_buf = self._thread_id_struct.pack(self._thread_id) | ||
| self._tag_offset_len.pack_into(buf, 3, hdr_pos, data_pos, len(data_buf)); hdr_pos += self._tag_offset_len.size | ||
| buf[data_pos:len(data_buf)] = data_buf[:]; data_pos += len(data_buf) | ||
| if self._mars is not None: | ||
| data_buf = self._mars_struct.pack(self._mars) | ||
| self._tag_offset_len.pack_into(buf, 4, hdr_pos, data_pos, len(data_buf)); hdr_pos += self._tag_offset_len.size | ||
| buf[data_pos:len(data_buf)] = data_buf[:]; data_pos += len(data_buf) | ||
| buf[hdr_pos] = 255; hdr_pos += 1 | ||
| return data_pos |
+0
-0
| include requirements.txt test_requirements.txt RELEASE-VERSION version.py |
+1
-1
| Metadata-Version: 1.1 | ||
| Name: python-tds | ||
| Version: 1.10.0 | ||
| Version: 1.11.0 | ||
| Summary: Python DBAPI driver for MSSQL using pure Python TDS (Tabular Data Stream) protocol implementation | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/denisenkom/pytds |
+7
-0
@@ -30,2 +30,3 @@ pytds | ||
| * TLS connection encryption | ||
| * Kerberos support on non-Windows platforms (requires kerberos package) | ||
@@ -53,2 +54,8 @@ Installation | ||
| To use Kerberos on non-Windows platforms (experimental) install kerberos package: | ||
| .. code-block:: bash | ||
| $ pip install kerberos | ||
| Documentation | ||
@@ -55,0 +62,0 @@ ------------- |
+0
-0
| six>=1.4.1 |
+0
-0
@@ -0,0 +0,0 @@ [egg_info] |
+0
-0
@@ -0,0 +0,0 @@ import os |
+27
-12
@@ -277,3 +277,3 @@ """DB-SIG compliant module for communicating with MS SQL servers""" | ||
| def _connect(self, host, port, instance, timeout): | ||
| def _connect(self, host, port, instance, timeout, sock=None): | ||
| login = self._login | ||
@@ -289,4 +289,5 @@ | ||
| timeout=timeout) | ||
| logger.info('Opening socket to %s:%d', host, port) | ||
| sock = socket.create_connection((host, port), timeout) | ||
| if not sock: | ||
| logger.info('Opening socket to %s:%d', host, port) | ||
| sock = socket.create_connection((host, port), timeout) | ||
| except Exception as e: | ||
@@ -334,3 +335,3 @@ raise LoginError("Cannot connect to server '{0}': {1}".format(host, e), e) | ||
| def _try_open(self, timeout): | ||
| def _try_open(self, timeout, sock=None): | ||
| if self._pooling: | ||
@@ -356,5 +357,5 @@ res = _connection_pool.take(self._key) | ||
| host, port, instance = login.servers[0] | ||
| self._connect(host=host, port=port, instance=instance, timeout=timeout) | ||
| self._connect(host=host, port=port, instance=instance, timeout=timeout, sock=sock) | ||
| def _open(self): | ||
| def _open(self, sock=None): | ||
| import time | ||
@@ -375,3 +376,3 @@ self._conn = None | ||
| try: | ||
| self._try_open(timeout=retry_time) | ||
| self._try_open(timeout=retry_time, sock=sock) | ||
| return | ||
@@ -1154,5 +1155,6 @@ except OperationalError as e: | ||
| row_strategy=None, failover_partner=None, server=None, | ||
| cafile=None, validate_host=True, enc_login_only=False, | ||
| disable_connect_retry=False, | ||
| cafile=None, sock=None, validate_host=True, | ||
| enc_login_only=False, disable_connect_retry=False, | ||
| pooling=False, | ||
| use_sso=False, | ||
| ): | ||
@@ -1213,4 +1215,8 @@ """ | ||
| :type enc_login_only: bool | ||
| :keyword use_sso: Enables SSO login, e.g. Kerberos using SSPI on Windows and kerberos package on other platforms. | ||
| Cannot be used together with auth parameter. | ||
| :returns: An instance of :class:`Connection` | ||
| """ | ||
| if use_sso and auth: | ||
| raise ValueError('use_sso cannot be used with auth parameter defined') | ||
| login = _TdsLogin() | ||
@@ -1266,3 +1272,2 @@ login.client_host_name = socket.gethostname()[:128] | ||
| login.blocksize = blocksize | ||
| login.auth = auth | ||
| login.readonly = readonly | ||
@@ -1295,2 +1300,12 @@ login.load_balancer = load_balancer | ||
| if use_sso: | ||
| spn = "MSSQLSvc@{}:{}".format(parsed_servers[0][0], parsed_servers[0][1]) | ||
| from . import login as pytds_login | ||
| try: | ||
| login.auth = pytds_login.SspiAuth(spn=spn) | ||
| except ImportError: | ||
| login.auth = pytds_login.KerberosAuth(spn) | ||
| else: | ||
| login.auth = auth | ||
| login.servers = _get_servers_deque(tuple(parsed_servers), database) | ||
@@ -1337,5 +1352,5 @@ | ||
| if disable_connect_retry: | ||
| conn._try_open(timeout=login.connect_timeout) | ||
| conn._try_open(timeout=login.connect_timeout, sock=sock) | ||
| else: | ||
| conn._open() | ||
| conn._open(sock=sock) | ||
| return conn | ||
@@ -1342,0 +1357,0 @@ |
@@ -0,0 +0,0 @@ import codecs |
@@ -0,0 +0,0 @@ #: Transaction can read uncommitted data |
@@ -0,0 +0,0 @@ # Copyright 2010 Michael Murr |
+39
-0
@@ -148,1 +148,40 @@ # vim: set fileencoding=utf8 : | ||
| pass | ||
| class KerberosAuth(object): | ||
| def __init__(self, server_principal): | ||
| try: | ||
| import kerberos | ||
| except ImportError: | ||
| import winkerberos as kerberos | ||
| self._kerberos = kerberos | ||
| res, context = kerberos.authGSSClientInit(server_principal) | ||
| if res < 0: | ||
| raise RuntimeError('authGSSClientInit failed with code {}'.format(res)) | ||
| logger.info('Initialized GSS context') | ||
| self._context = context | ||
| def create_packet(self): | ||
| import base64 | ||
| res = self._kerberos.authGSSClientStep(self._context, '') | ||
| if res < 0: | ||
| raise RuntimeError('authGSSClientStep failed with code {}'.format(res)) | ||
| data = self._kerberos.authGSSClientResponse(self._context) | ||
| logger.info('created first client GSS packet %s', data) | ||
| return base64.b64decode(data) | ||
| def handle_next(self, packet): | ||
| import base64 | ||
| res = self._kerberos.authGSSClientStep(self._context, base64.b64encode(packet).decode('ascii')) | ||
| if res < 0: | ||
| raise RuntimeError('authGSSClientStep failed with code {}'.format(res)) | ||
| if res == self._kerberos.AUTH_GSS_COMPLETE: | ||
| logger.info('GSS authentication completed') | ||
| return b'' | ||
| else: | ||
| data = self._kerberos.authGSSClientResponse(self._context) | ||
| logger.info('created client GSS packet %s', data) | ||
| return base64.b64decode(data) | ||
| def close(self): | ||
| pass |
+0
-0
@@ -0,0 +0,0 @@ # This file implements Session Multiplex Protocol used by MARS connections |
@@ -0,0 +0,0 @@ import six |
@@ -0,0 +0,0 @@ import socket |
+10
-5
@@ -147,7 +147,12 @@ import logging | ||
| logger.debug('got WantReadError, getting data from the write end of the TLS connection buffer') | ||
| req = conn.bio_read(BUFSIZE) | ||
| logger.debug('sending %d bytes of the handshake data to the server', len(req)) | ||
| w.begin_packet(tds_base.PacketType.PRELOGIN) | ||
| w.write(req) | ||
| w.flush() | ||
| try: | ||
| req = conn.bio_read(BUFSIZE) | ||
| except OpenSSL.SSL.WantReadError: | ||
| # PyOpenSSL - https://github.com/pyca/pyopenssl/issues/887 | ||
| logger.debug('got WantReadError again, waiting for response...') | ||
| else: | ||
| logger.debug('sending %d bytes of the handshake data to the server', len(req)) | ||
| w.begin_packet(tds_base.PacketType.PRELOGIN) | ||
| w.write(req) | ||
| w.flush() | ||
| logger.debug('receiving response from the server') | ||
@@ -154,0 +159,0 @@ resp = r.read_whole_packet() |
+0
-0
@@ -0,0 +0,0 @@ import time as _time |
| Metadata-Version: 1.1 | ||
| Name: python-tds | ||
| Version: 1.10.0 | ||
| Version: 1.11.0 | ||
| Summary: Python DBAPI driver for MSSQL using pure Python TDS (Tabular Data Stream) protocol implementation | ||
@@ -5,0 +5,0 @@ Home-page: https://github.com/denisenkom/pytds |
@@ -9,2 +9,3 @@ MANIFEST.in | ||
| src/pytds/__init__.py | ||
| src/pytds/_generated.py | ||
| src/pytds/collate.py | ||
@@ -11,0 +12,0 @@ src/pytds/extensions.py |
@@ -7,2 +7,6 @@ pytest>=3.3.2 | ||
| ntlm-auth | ||
| namedlist | ||
| namedlist | ||
| # cryptography 3.4.5 fails build, requires rust compiler | ||
| # see example failure: https://ci.appveyor.com/project/denisenkom/pytds/builds/37803561/job/lln9d25ye5vnljbr | ||
| # requiring older cryptography library to avoid this error | ||
| cryptography < 3.3 |
+0
-0
@@ -0,0 +0,0 @@ # -*- coding: utf-8 -*- |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Alert delta unavailable
Currently unable to show alert delta for PyPI packages.
307634
5.74%28
3.7%7424
2.37%