Skip to content

Commit 9a652b8

Browse files
Ensure that the value of __module__ for all clases is left untouched in
order to make inspect.getsource() behave as expected; use a metaclass instead to change the repr() of the class.
1 parent e2344c1 commit 9a652b8

24 files changed

+141
-118
lines changed

doc/src/release_notes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ Common Changes
9999
:ref:`DbObject <dbobjecttype>` which is not actually a collection.
100100
#) API documentation is now generated from the source code.
101101
#) The test suite now uses `pytest <https://docs.pytest.org/>`__.
102+
#) Internal change: the value of ``__module__`` for all classes is now left
103+
untouched to avoid issues with ``inspect.getsource()`` but the
104+
``__repr__()`` now consistently shows the module as ``oracledb``.
102105
#) Internal change: `typing_extensions <https://pypi.org/project/
103106
typing-extensions/>`__ is now a dependency.
104107

src/oracledb/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,6 +1211,7 @@ class JsonId(bytes):
12111211
fetch_info, # noqa
12121212
future, # noqa
12131213
lob, # noqa
1214+
pipeline, # noqa
12141215
pool, # noqa
12151216
pool_params, # noqa
12161217
sparse_vector, # noqa

src/oracledb/aq.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@
3434
from . import connection as connection_module
3535
from typing import Any, Union
3636
from . import errors
37+
from .base import BaseMetaClass
3738
from .dbobject import DbObject, DbObjectType
3839

3940

40-
class BaseQueue:
41+
class BaseQueue(metaclass=BaseMetaClass):
4142
@classmethod
4243
def _from_impl(cls, connection, impl):
4344
queue = cls.__new__(cls)
@@ -267,7 +268,7 @@ async def enqone(self, message: "MessageProperties") -> None:
267268
await self._impl.enq_one(message._impl)
268269

269270

270-
class DeqOptions:
271+
class DeqOptions(metaclass=BaseMetaClass):
271272
@classmethod
272273
def _from_impl(cls, impl):
273274
options = cls.__new__(cls)
@@ -420,7 +421,7 @@ def wait(self, value: int) -> None:
420421
self._impl.set_wait(value)
421422

422423

423-
class EnqOptions:
424+
class EnqOptions(metaclass=BaseMetaClass):
424425
@classmethod
425426
def _from_impl(cls, impl):
426427
options = cls.__new__(cls)
@@ -471,7 +472,7 @@ def visibility(self, value: int) -> None:
471472
self._impl.set_visibility(value)
472473

473474

474-
class MessageProperties:
475+
class MessageProperties(metaclass=BaseMetaClass):
475476
_recipients = []
476477

477478
@classmethod

src/oracledb/arrow_array.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@
3030
# -----------------------------------------------------------------------------
3131

3232
from .arrow_impl import ArrowArrayImpl
33+
from .base import BaseMetaClass
3334

3435
from . import errors
3536

3637

37-
class ArrowArray:
38+
class ArrowArray(metaclass=BaseMetaClass):
3839
_impl = None
3940

4041
def __init__(self):

src/oracledb/base.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# -----------------------------------------------------------------------------
2+
# Copyright (c) 2025, Oracle and/or its affiliates.
3+
#
4+
# This software is dual-licensed to you under the Universal Permissive License
5+
# (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
6+
# 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
7+
# either license.
8+
#
9+
# If you elect to accept the software under the Apache License, Version 2.0,
10+
# the following applies:
11+
#
12+
# Licensed under the Apache License, Version 2.0 (the "License");
13+
# you may not use this file except in compliance with the License.
14+
# You may obtain a copy of the License at
15+
#
16+
# https://www.apache.org/licenses/LICENSE-2.0
17+
#
18+
# Unless required by applicable law or agreed to in writing, software
19+
# distributed under the License is distributed on an "AS IS" BASIS,
20+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21+
# See the License for the specific language governing permissions and
22+
# limitations under the License.
23+
# -----------------------------------------------------------------------------
24+
25+
# -----------------------------------------------------------------------------
26+
# base.py
27+
#
28+
# Contains base classes and methods that have no internal dependencies.
29+
# -----------------------------------------------------------------------------
30+
31+
from . import __name__ as MODULE_NAME
32+
33+
34+
# metaclass used by all oracledb classes; currently this only ensures that when
35+
# the class is displayed it only shows the overall module name instead of any
36+
# subpackage names
37+
class BaseMetaClass(type):
38+
39+
def __new__(cls, name, bases, attrs):
40+
module_name = attrs["__module__"]
41+
qual_name = attrs["__qualname__"]
42+
if module_name.startswith(MODULE_NAME):
43+
module_name = MODULE_NAME
44+
attrs["_public_name"] = f"{module_name}.{qual_name}"
45+
return super().__new__(cls, name, bases, attrs)
46+
47+
def __repr__(cls):
48+
return f"<class '{cls._public_name}'>"

src/oracledb/base_impl.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ cdef class PoolParamsImpl(ConnectParamsImpl):
654654
public uint32_t min
655655
public uint32_t max
656656
public uint32_t increment
657-
public type connectiontype
657+
public object connectiontype
658658
public uint32_t getmode
659659
public bint homogeneous
660660
public uint32_t timeout

src/oracledb/connect_params.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,16 @@
3939

4040
import oracledb
4141

42+
from .base import BaseMetaClass
4243
from . import base_impl, utils
4344

4445

45-
class ConnectParams:
46+
class ConnectParams(metaclass=BaseMetaClass):
4647
"""
4748
Contains all parameters used for establishing a connection to the
4849
database.
4950
"""
5051

51-
__module__ = oracledb.__name__
5252
__slots__ = ["_impl"]
5353
_impl_class = base_impl.ConnectParamsImpl
5454

src/oracledb/connection.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@
4040

4141
import oracledb
4242

43-
from . import __name__ as MODULE_NAME
44-
4543
from . import base_impl, driver_mode, errors, thick_impl, thin_impl
4644
from . import pool as pool_module
4745
from .aq import AsyncQueue, Queue, MessageProperties
4846
from .arrow_impl import ArrowSchemaImpl
47+
from .base import BaseMetaClass
4948
from .base_impl import DB_TYPE_BLOB, DB_TYPE_CLOB, DB_TYPE_NCLOB, DbType
5049
from .connect_params import ConnectParams
5150
from .cursor import AsyncCursor, Cursor
@@ -63,16 +62,14 @@
6362
)
6463

6564

66-
class BaseConnection:
67-
__module__ = MODULE_NAME
65+
class BaseConnection(metaclass=BaseMetaClass):
6866
_impl = None
6967

7068
def __init__(self):
7169
self._version = None
7270

7371
def __repr__(self):
74-
typ = self.__class__
75-
cls_name = f"{typ.__module__}.{typ.__qualname__}"
72+
cls_name = self.__class__._public_name
7673
if self._impl is None:
7774
return f"<{cls_name} disconnected>"
7875
elif self.username is None:
@@ -841,7 +838,6 @@ def xid(
841838

842839

843840
class Connection(BaseConnection):
844-
__module__ = MODULE_NAME
845841

846842
def __init__(
847843
self,
@@ -2069,7 +2065,6 @@ def connect(
20692065

20702066

20712067
class AsyncConnection(BaseConnection):
2072-
__module__ = MODULE_NAME
20732068

20742069
def __init__(
20752070
self,

src/oracledb/cursor.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@
3131

3232
from typing import Any, Union, Callable, Optional
3333

34-
from . import __name__ as MODULE_NAME
3534
from . import connection as connection_module
3635
from . import errors
3736
from . import utils
38-
from .fetch_info import FetchInfo
39-
from .var import Var
37+
from .base import BaseMetaClass
4038
from .base_impl import DbType, DB_TYPE_OBJECT
4139
from .dbobject import DbObjectType
40+
from .fetch_info import FetchInfo
41+
from .var import Var
4242

4343

44-
class BaseCursor:
44+
class BaseCursor(metaclass=BaseMetaClass):
4545
_impl = None
4646

4747
def __init__(
@@ -73,8 +73,7 @@ def __exit__(self, exc_type, exc_value, exc_tb):
7373
self._impl = None
7474

7575
def __repr__(self):
76-
typ = self.__class__
77-
cls_name = f"{typ.__module__}.{typ.__qualname__}"
76+
cls_name = self.__class__._public_name
7877
return f"<{cls_name} on {self.connection!r}>"
7978

8079
def _call(
@@ -655,7 +654,6 @@ def warning(self) -> Union[errors._Error, None]:
655654

656655

657656
class Cursor(BaseCursor):
658-
__module__ = MODULE_NAME
659657

660658
def __iter__(self):
661659
"""
@@ -1040,7 +1038,6 @@ def scroll(self, value: int = 0, mode: str = "relative") -> None:
10401038

10411039

10421040
class AsyncCursor(BaseCursor):
1043-
__module__ = MODULE_NAME
10441041

10451042
async def __aenter__(self):
10461043
"""

src/oracledb/dataframe.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@
3131

3232
from .arrow_array import ArrowArray
3333
from .arrow_impl import DataFrameImpl
34+
from .base import BaseMetaClass
3435
from . import errors
3536

3637

37-
class DataFrame:
38+
class DataFrame(metaclass=BaseMetaClass):
3839
_impl = None
3940

4041
def __init__(self):

0 commit comments

Comments
 (0)