firebird-driver 2.0.2__tar.gz → 2.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: firebird-driver
3
- Version: 2.0.2
3
+ Version: 2.0.3
4
4
  Summary: Firebird driver for Python
5
5
  Project-URL: Home, https://github.com/FirebirdSQL/python3-driver
6
6
  Project-URL: Documentation, https://firebird-driver.rtfd.io
@@ -57,6 +57,7 @@ Description-Content-Type: text/markdown
57
57
  [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
58
58
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/firebird-driver)](https://pypi.org/project/firebird-driver)
59
59
  [![Libraries.io SourceRank](https://img.shields.io/librariesio/sourcerank/pypi/firebird-driver)](https://libraries.io/pypi/firebird-driver)
60
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FirebirdSQL/python3-driver)
60
61
 
61
62
  This package provides official Python Database API 2.0-compliant driver for the open
62
63
  source relational database Firebird®. In addition to the minimal feature set of
@@ -7,6 +7,7 @@
7
7
  [![Hatch project](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
8
8
  [![PyPI - Downloads](https://img.shields.io/pypi/dm/firebird-driver)](https://pypi.org/project/firebird-driver)
9
9
  [![Libraries.io SourceRank](https://img.shields.io/librariesio/sourcerank/pypi/firebird-driver)](https://libraries.io/pypi/firebird-driver)
10
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/FirebirdSQL/python3-driver)
10
11
 
11
12
  This package provides official Python Database API 2.0-compliant driver for the open
12
13
  source relational database Firebird®. In addition to the minimal feature set of
@@ -55,6 +55,15 @@ allow-direct-references = true
55
55
  dependencies = [
56
56
  ]
57
57
 
58
+ [tool.hatch.envs.gdocs]
59
+ dependencies = [
60
+ "great-docs",
61
+ ]
62
+
63
+ [tool.hatch.envs.gdocs.scripts]
64
+ build = "great-docs build"
65
+ preview = "great-docs preview"
66
+
58
67
  [tool.hatch.envs.hatch-test]
59
68
  extra-args = ["--host=localhost"]
60
69
  extra-dependencies = [
@@ -62,7 +71,7 @@ extra-dependencies = [
62
71
  ]
63
72
 
64
73
  [[tool.hatch.envs.hatch-test.matrix]]
65
- python = ["3.11", "3.12", "3.13"]
74
+ python = ["3.11", "3.12", "3.13", "3.14"]
66
75
 
67
76
  [tool.hatch.envs.doc]
68
77
  detached = false
@@ -133,4 +133,4 @@ from .types import (
133
133
  )
134
134
 
135
135
  #: Current driver version, SEMVER string.
136
- __VERSION__ = '2.0.2'
136
+ __VERSION__ = '2.0.3'
@@ -1799,7 +1799,8 @@ class Connection:
1799
1799
  warn("Connection disposed without prior close()", ResourceWarning)
1800
1800
  self._close()
1801
1801
  self._close_internals()
1802
- self._att.detach()
1802
+ with contextlib.suppress(DatabaseError):
1803
+ self._att.detach()
1803
1804
  def __enter__(self) -> Self:
1804
1805
  return self
1805
1806
  def __exit__(self, exc_type, exc_value, traceback) -> None:
@@ -2397,6 +2398,7 @@ def create_database(database: str | Path, *, user: str | None=None, password: st
2397
2398
  if isinstance(database, Path):
2398
2399
  database = str(database)
2399
2400
  db_config: DatabaseConfig = driver_config.get_database(database)
2401
+ dsn: str | None = None
2400
2402
  if db_config is None:
2401
2403
  db_config = driver_config.db_defaults
2402
2404
  srv_config = driver_config.server_defaults
@@ -3392,7 +3394,7 @@ class Cursor:
3392
3394
  elif dtype in (a.blr_short, a.blr_long, a.blr_int64):
3393
3395
  val = (0).from_bytes(buf[bufpos:bufpos + esize], 'little', signed=True)
3394
3396
  if subtype or scale:
3395
- val = decimal.Decimal(val) / _ten_to[abs(scale)]
3397
+ val = decimal.Decimal(val).scaleb(-abs(scale))
3396
3398
  elif dtype == a.blr_bool:
3397
3399
  val = (0).from_bytes(buf[bufpos:bufpos + esize], 'little') == 1
3398
3400
  elif dtype == a.blr_float:
@@ -3799,7 +3801,7 @@ class Cursor:
3799
3801
  value = (0).from_bytes(buffer[offset:offset + length], 'little', signed=True)
3800
3802
  # It's scalled integer?
3801
3803
  if desc.subtype or desc.scale:
3802
- value = decimal.Decimal(value) / _ten_to[abs(desc.scale)]
3804
+ value = decimal.Decimal(value).scaleb(-abs(desc.scale))
3803
3805
  elif datatype == SQLDataType.DATE:
3804
3806
  value = _util.decode_date(buffer[offset:offset+length])
3805
3807
  elif datatype == SQLDataType.TIME:
@@ -3964,7 +3966,13 @@ class Cursor:
3964
3966
  in_meta.release()
3965
3967
  def _clear(self) -> None:
3966
3968
  if self._result is not None:
3967
- self._result.close()
3969
+ if self._stmt is not None and self._stmt._istmt is not None:
3970
+ self._result.close()
3971
+ else:
3972
+ # Statement was already freed; the result set is invalidated
3973
+ # at the Firebird API level, so we must not call close() on it.
3974
+ # Also prevent __del__ from calling release() on the invalid interface.
3975
+ self._result._refcnt = 0
3968
3976
  self._result = None
3969
3977
  self._name = None
3970
3978
  self._last_fetch_status = None
@@ -4278,7 +4286,8 @@ class Cursor:
4278
4286
  elif meta.datatype == SQLDataType.INT64:
4279
4287
  vtype = int
4280
4288
  dispsize = 20
4281
- elif meta.datatype in (SQLDataType.FLOAT, SQLDataType.D_FLOAT, SQLDataType.DOUBLE):
4289
+ elif meta.datatype in (SQLDataType.FLOAT, SQLDataType.D_FLOAT, SQLDataType.DOUBLE,
4290
+ SQLDataType.DEC16, SQLDataType.DEC34):
4282
4291
  # Special case, dialect 1 DOUBLE/FLOAT
4283
4292
  # could be Fixed point
4284
4293
  if (self._stmt._dialect < 3) and meta.scale:
@@ -4291,13 +4300,13 @@ class Cursor:
4291
4300
  vtype = str if meta.subtype == 1 else bytes
4292
4301
  scale = meta.subtype
4293
4302
  dispsize = 0
4294
- elif meta.datatype == SQLDataType.TIMESTAMP:
4303
+ elif meta.datatype in (SQLDataType.TIMESTAMP, SQLDataType.TIMESTAMP_TZ, SQLDataType.TIMESTAMP_TZ_EX):
4295
4304
  vtype = datetime.datetime
4296
4305
  dispsize = 22
4297
4306
  elif meta.datatype == SQLDataType.DATE:
4298
4307
  vtype = datetime.date
4299
4308
  dispsize = 10
4300
- elif meta.datatype == SQLDataType.TIME:
4309
+ elif meta.datatype in (SQLDataType.TIME, SQLDataType.TIME_TZ, SQLDataType.TIME_TZ_EX):
4301
4310
  vtype = datetime.time
4302
4311
  dispsize = 11
4303
4312
  elif meta.datatype == SQLDataType.ARRAY:
@@ -5721,9 +5730,11 @@ class Server:
5721
5730
  data = self.response.read_sized_string(encoding=self.encoding, errors=self.encoding_errors)
5722
5731
  if self.response.get_tag() == SrvInfoCode.TIMEOUT:
5723
5732
  return TIMEOUT
5724
- if data:
5725
- return data + '\n'
5726
- return None
5733
+ # read_sized_string() returns lines ending with '\r ' (CR + space).
5734
+ # Strip the trailing space to get proper '\r' line endings.
5735
+ if data and data.endswith('\r '):
5736
+ data = data[:-1] # Remove space, keep '\r'
5737
+ return data if data else None
5727
5738
  def readline(self) -> str | None:
5728
5739
  """Get next line of textual output from last service query.
5729
5740
 
@@ -5850,11 +5861,11 @@ def connect_server(server: str, *, user: str | None=None, password: str | None=N
5850
5861
  srv_config = driver_config.get_server(server)
5851
5862
  if srv_config is None:
5852
5863
  srv_config = driver_config.server_defaults
5853
- host = server or None
5854
- port = None
5855
- else:
5856
- host = srv_config.host.value
5857
- port = srv_config.port.value
5864
+ #host = server or None
5865
+ #port = None
5866
+ #else:
5867
+ host = srv_config.host.value
5868
+ port = srv_config.port.value
5858
5869
  if host is None:
5859
5870
  host = 'service_mgr'
5860
5871
  if not host.endswith('service_mgr'):
File without changes