[Django] #36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union

16 views
Skip to first unread message

Django

unread,
Oct 7, 2025, 12:33:54 PM10/7/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Type:
| Uncategorized
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Normal
Keywords: Oracle | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
When running Django v5.2.7 with oracledb 3.4.0, the following traceback is
generated. In the 3.4.0 release they changed the definition of
{{{Binary}}} from an alias to {{{bytes}}} to a function
(https://github.com/oracle/python-
oracledb/blob/a71468238ea98f38a331afe0a0664b2fa707a294/src/oracledb/constructors.py#L37-L41).
The issue does not occur with oracledb 3.3.0.

{{{
Traceback (most recent call last):
File "C:\Users\johnwa\AppData\Roaming\uv\python\cpython-3.13.7-windows-
x86_64-none\Lib\threading.py", line 1043, in _bootstrap_inner
self.run()
~~~~~~~~^^
File "C:\Users\johnwa\AppData\Roaming\uv\python\cpython-3.13.7-windows-
x86_64-none\Lib\threading.py", line 994, in run
self._target(*self._args, **self._kwargs)
~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\utils\autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
~~^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\core\management\commands\runserver.py", line 137, in
inner_run
self.check_migrations()
~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\core\management\base.py", line 587, in check_migrations
executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\migrations\executor.py", line 18, in __init__
self.loader = MigrationLoader(self.connection)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\migrations\loader.py", line 58, in __init__
self.build_graph()
~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\migrations\loader.py", line 235, in build_graph
self.applied_migrations = recorder.applied_migrations()
~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\migrations\recorder.py", line 89, in applied_migrations
if self.has_table():
~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\migrations\recorder.py", line 63, in has_table
with self.connection.cursor() as cursor:
~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py",
line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\base\base.py", line 320, in cursor
return self._cursor()
~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\base\base.py", line 296, in _cursor
self.ensure_connection()
~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py",
line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\base\base.py", line 279, in ensure_connection
self.connect()
~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-packages\django\utils\asyncio.py",
line 26, in inner
return func(*args, **kwargs)
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\base\base.py", line 258, in connect
self.init_connection_state()
~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\oracle\base.py", line 336, in
init_connection_state
cursor.execute(
~~~~~~~~~~~~~~^
"SELECT 1 FROM DUAL WHERE DUMMY %s"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
% self._standard_operators["contains"],
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
["X"],
^^^^^^
)
^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\oracle\base.py", line 630, in execute
query, params = self._fix_for_params(query, params,
unify_by_values=True)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\oracle\base.py", line 627, in _fix_for_params
return query, self._format_params(params)
~~~~~~~~~~~~~~~~~~~^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\oracle\base.py", line 555, in _format_params
return {k: OracleParam(v, self, True) for k, v in params.items()}
~~~~~~~~~~~^^^^^^^^^^^^^^^
File "C:\Projects\rsvp\.venv\Lib\site-
packages\django\db\backends\oracle\base.py", line 441, in __init__
elif isinstance(param, (Database.Binary, datetime.timedelta)):
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Oct 7, 2025, 10:02:00 PM10/7/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: (none)
Type: New feature | Status: new
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):

* cc: Mariusz Felisiak, Simon Charette (added)
* stage: Unreviewed => Accepted
* type: Uncategorized => New feature

Comment:

Thank you John Wagenleitner, do you have availability to work on the fix?
It seems that our `Database.Date` and `Database.Timestamp` may also be
affected?

Setting as "New Feature" since oracledb 3.4.0 was released October 2025.

For reference, [https://github.com/oracle/python-
oracledb/commit/869a887819cdac7fcd610f9d9d463ade49ea7de6 commit
869a887819cdac7fcd610f9d9d463ade49ea7de6] contains:
{{{#!diff
--- a/src/oracledb/constructors.py
+++ b/src/oracledb/constructors.py
@@ -29,22 +29,23 @@
#
-----------------------------------------------------------------------------

import datetime
+from typing import Any

from . import errors

-# synonyms for the types mandated by the database API
-Binary = bytes
-Date = datetime.date
-Timestamp = datetime.datetime

+def Binary(value: Any) -> bytes:
+ """
+ Constructs an object holding a binary (long) string value.
+ """
+ return bytes(value)

-def Time(hour: int, minute: int, second: int) -> None:
+
+def Date(year: int, month: int, day: int) -> datetime.date:
"""
- Constructor mandated by the database API for creating a time value.
Since
- Oracle doesn't support time only values, an exception is raised when
this
- method is called.
+ Constructs an object holding a date value.
"""
- errors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)
+ return datetime.date(year, month, day)


def DateFromTicks(ticks: float) -> datetime.date:
@@ -56,6 +57,15 @@ def DateFromTicks(ticks: float) -> datetime.date:
return datetime.date.fromtimestamp(ticks)


+def Time(hour: int, minute: int, second: int) -> None:
+ """
+ Constructor mandated by the database API for creating a time value.
Since
+ Oracle doesn't support time only values, an exception is raised when
this
+ method is called.
+ """
+ errors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)
+
+
def TimeFromTicks(ticks: float) -> None:
"""
Constructor mandated by the database API for creating a time value
given
@@ -66,6 +76,20 @@ def TimeFromTicks(ticks: float) -> None:
errors._raise_err(errors.ERR_TIME_NOT_SUPPORTED)


+def Timestamp(
+ year: int,
+ month: int,
+ day: int,
+ hour: int = 0,
+ minute: int = 0,
+ second: int = 0,
+) -> datetime.datetime:
+ """
+ Constructs an object holding a time stamp value.
+ """
+ return datetime.datetime(year, month, day, hour, minute, second)
+
+
def TimestampFromTicks(ticks: float) -> datetime.datetime:
"""
Constructor mandated by the database API for creating a timestamp
value
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:1>

Django

unread,
Oct 8, 2025, 2:39:36 AM10/8/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* owner: (none) => Mariusz Felisiak
* status: new => assigned

Comment:

I can work on that, I'd consider backport to Django 5.2 and 6.0. We were
always more flexible with fixing support for database drivers (see #31751
or #30331).
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:2>

Django

unread,
Oct 8, 2025, 8:25:28 AM10/8/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Accepted
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Natalia Bidart):

Replying to [comment:2 Mariusz Felisiak]:
> I can work on that, I'd consider backport to Django 5.2 and 6.0. We were
always more flexible with fixing support for database drivers (see #31751
or #30331).

Thank you Mariusz! Assuming the fix is not too invasive/big/risky, I agree
it's OK to backport up to 5.2.
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:3>

Django

unread,
Oct 8, 2025, 12:34:34 PM10/8/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Simon Charette):

* has_patch: 0 => 1

Comment:

Ended up [https://github.com/django/django/pull/19932 creating the MR]
after looking at the issue with Mariusz in Palafrugell 🏖️
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:4>

Django

unread,
Oct 10, 2025, 9:32:14 AM10/10/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:5>

Django

unread,
Oct 10, 2025, 5:08:30 PM10/10/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by GitHub <noreply@…>):

In [changeset:"99e033694c54b5d0e2cfd796ce598cc1e6c9af4a" 99e03369]:
{{{#!CommitTicketReference repository=""
revision="99e033694c54b5d0e2cfd796ce598cc1e6c9af4a"
[5.1.x] Refs #36646 -- Doc'd that oracledb < 3.3.0 is required.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:6>

Django

unread,
Oct 10, 2025, 5:11:33 PM10/10/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 1
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* needs_better_patch: 0 => 1
* stage: Ready for checkin => Accepted

--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:7>

Django

unread,
Oct 11, 2025, 10:55:03 AM10/11/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: assigned
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution:
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak):

* needs_better_patch: 1 => 0
* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:8>

Django

unread,
Oct 11, 2025, 1:03:02 PM10/11/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution: fixed
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Mariusz Felisiak <felisiak.mariusz@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"315dbe675df338ae66c8fa43274a76ecbed7ef67" 315dbe6]:
{{{#!CommitTicketReference repository=""
revision="315dbe675df338ae66c8fa43274a76ecbed7ef67"
Fixed #36646 -- Added compatibility for oracledb 3.4.0.

The Database.Binary, Date, and Timestamp attributes were changed from
aliases to bytes, datetime.date, and datetime.datetime to factory
functions in oracle/python-oracledb@869a887819cdac7fcd610f9d9d463ade49ea7
which made their usage inadequate for isinstance checks.

Thanks John Wagenleitner for the report and Natalia for the triage.

Co-authored-by: Mariusz Felisiak <felisiak...@gmail.com>
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:9>

Django

unread,
Oct 11, 2025, 1:03:27 PM10/11/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution: fixed
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):

In [changeset:"c4309f46270432c6d48dfc8b6bf2de20a01d0d6b" c4309f46]:
{{{#!CommitTicketReference repository=""
revision="c4309f46270432c6d48dfc8b6bf2de20a01d0d6b"
[6.0.x] Fixed #36646 -- Added compatibility for oracledb 3.4.0.

The Database.Binary, Date, and Timestamp attributes were changed from
aliases to bytes, datetime.date, and datetime.datetime to factory
functions in oracle/python-oracledb@869a887819cdac7fcd610f9d9d463ade49ea7
which made their usage inadequate for isinstance checks.

Thanks John Wagenleitner for the report and Natalia for the triage.

Co-authored-by: Mariusz Felisiak <felisiak...@gmail.com>

Backport of 315dbe675df338ae66c8fa43274a76ecbed7ef67 from main
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:10>

Django

unread,
Oct 11, 2025, 1:03:49 PM10/11/25
to django-...@googlegroups.com
#36646: oracledb 3.4.0 TypeError: isinstance() arg 2 must be a type, a tuple of
types, or a union
-------------------------------------+-------------------------------------
Reporter: John Wagenleitner | Owner: Mariusz
| Felisiak
Type: New feature | Status: closed
Component: Database layer | Version: 5.2
(models, ORM) |
Severity: Normal | Resolution: fixed
Keywords: Oracle | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Mariusz Felisiak <felisiak.mariusz@…>):

In [changeset:"88ef9ea6c5840ea9925a3975cb1126651dff8b3d" 88ef9ea]:
{{{#!CommitTicketReference repository=""
revision="88ef9ea6c5840ea9925a3975cb1126651dff8b3d"
[5.2.x] Fixed #36646 -- Added compatibility for oracledb 3.4.0.

The Database.Binary, Date, and Timestamp attributes were changed from
aliases to bytes, datetime.date, and datetime.datetime to factory
functions in oracle/python-oracledb@869a887819cdac7fcd610f9d9d463ade49ea7
which made their usage inadequate for isinstance checks.

Thanks John Wagenleitner for the report and Natalia for the triage.

Co-authored-by: Mariusz Felisiak <felisiak...@gmail.com>

Backport of 315dbe675df338ae66c8fa43274a76ecbed7ef67 from main
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/36646#comment:11>
Reply all
Reply to author
Forward
0 new messages