Skip to content

Commit 3b62cdc

Browse files
merge
2 parents a0d1fba + d1d5840 commit 3b62cdc

File tree

3 files changed

+46
-26
lines changed

3 files changed

+46
-26
lines changed

cardinal_pythonlib/sqlalchemy/merge_db.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,12 @@ def wipe_primary_key(inst: object) -> None:
986986
# new PK will be created when session is flushed
987987

988988
if tdc.is_parent:
989-
objmap[oldobj] = newobj # for its children's benefit
989+
try:
990+
objmap[oldobj] = newobj # for its children's benefit
991+
except KeyError:
992+
raise KeyError(
993+
f"Missing attribute {oldobj=} in {objmap=}"
994+
)
990995

991996
if flush_per_record:
992997
flush()

cardinal_pythonlib/sqlalchemy/orm_inspect.py

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
2727
"""
2828

29+
import logging
2930
from typing import (
3031
Dict,
3132
Generator,
@@ -37,7 +38,6 @@
3738
Union,
3839
)
3940

40-
# noinspection PyProtectedMember
4141
from sqlalchemy import inspect
4242
from sqlalchemy.orm.base import class_mapper
4343
from sqlalchemy.orm.mapper import Mapper
@@ -51,13 +51,12 @@
5151
from cardinal_pythonlib.classes import gen_all_subclasses
5252
from cardinal_pythonlib.enumlike import OrderedNamespace
5353
from cardinal_pythonlib.dicts import reversedict
54-
from cardinal_pythonlib.logs import get_brace_style_log_with_null_handler
5554

5655
if TYPE_CHECKING:
5756
from sqlalchemy.orm.state import InstanceState
5857
from sqlalchemy.sql.schema import Table
5958

60-
log = get_brace_style_log_with_null_handler(__name__)
59+
log = logging.getLogger(__name__)
6160

6261

6362
# =============================================================================
@@ -253,7 +252,7 @@ def walk_orm_tree(
253252
continue
254253
seen.add(obj)
255254
if debug:
256-
log.debug("walk: yielding {!r}", obj)
255+
log.debug(f"walk: yielding {obj!r}")
257256
yield obj
258257
insp = inspect(obj) # type: InstanceState
259258
for (
@@ -272,10 +271,10 @@ def walk_orm_tree(
272271
continue
273272
# Process relationship
274273
if debug:
275-
log.debug("walk: following relationship {}", relationship)
274+
log.debug(f"walk: following relationship {relationship}")
276275
related = getattr(obj, attrname)
277276
if debug and related:
278-
log.debug("walk: queueing {!r}", related)
277+
log.debug(f"walk: queueing {related!r}")
279278
if relationship.uselist:
280279
stack.extend(related)
281280
elif related is not None:
@@ -331,20 +330,20 @@ def copy_sqla_object(
331330
prohibited |= fk_keys
332331
prohibited |= set(omit_attrs)
333332
if debug:
334-
log.debug("copy_sqla_object: skipping: {}", prohibited)
333+
log.debug(f"copy_sqla_object: skipping: {prohibited}")
335334
for k in [
336335
p.key for p in mapper.iterate_properties if p.key not in prohibited
337336
]:
338337
try:
339338
value = getattr(obj, k)
340339
if debug:
341340
log.debug(
342-
"copy_sqla_object: processing attribute {} = {}", k, value
341+
f"copy_sqla_object: processing attribute {k} = {value}"
343342
)
344343
setattr(newobj, k, value)
345344
except AttributeError:
346345
if debug:
347-
log.debug("copy_sqla_object: failed attribute {}", k)
346+
log.debug(f"copy_sqla_object: failed attribute {k}")
348347
pass
349348
return newobj
350349

@@ -428,8 +427,8 @@ def rewrite_relationships(
428427
if related_table_name in skip_table_names:
429428
if debug:
430429
log.debug(
431-
"Skipping relationship for related table {!r}",
432-
related_table_name,
430+
f"Skipping relationship for related table "
431+
f"{related_table_name!r}"
433432
)
434433
continue
435434
# The relationship is an abstract object (so getting the
@@ -439,17 +438,25 @@ def rewrite_relationships(
439438
# rel_key = rel.key # type: str
440439
# ... but also available from the mapper as attrname, above
441440
related_old = getattr(oldobj, attrname)
442-
if rel_prop.uselist:
443-
related_new = [objmap[r] for r in related_old]
444-
elif related_old is not None:
445-
related_new = objmap[related_old]
446-
else:
447-
related_new = None
441+
try:
442+
if rel_prop.uselist:
443+
related_new = [objmap[r] for r in related_old]
444+
elif related_old is not None:
445+
related_new = objmap[related_old]
446+
else:
447+
related_new = None
448+
except KeyError as e:
449+
# Often long messages; caps makes it slightly easier to read.
450+
log.critical(
451+
f"WHILE PROCESSING {oldobj = !r}, AN ATTRIBUTE FROM "
452+
f"{related_old = !r}, ACCESSED AS oldobj.{attrname}, "
453+
f"IS MISSING FROM {objmap = !r}. ERROR WAS: KeyError: {e}"
454+
)
455+
raise
448456
if debug:
449457
log.debug(
450-
"rewrite_relationships: relationship {} -> {}",
451-
attrname,
452-
related_new,
458+
f"rewrite_relationships: relationship "
459+
f"{attrname} -> {related_new}"
453460
)
454461
setattr(newobj, attrname, related_new)
455462

@@ -508,7 +515,7 @@ def deepcopy_sqla_objects(
508515
for startobj in startobjs:
509516
for oldobj in walk_orm_tree(startobj, seen=seen, debug=debug_walk):
510517
if debug:
511-
log.debug("deepcopy_sqla_objects: copying {}", oldobj)
518+
log.debug(f"deepcopy_sqla_objects: copying {oldobj}")
512519
newobj = copy_sqla_object(oldobj, omit_pk=True, omit_fk=True)
513520
# Don't insert the new object into the session here; it may trigger
514521
# an autoflush as the relationships are queried, and the new
@@ -525,7 +532,7 @@ def deepcopy_sqla_objects(
525532
log.debug("deepcopy_sqla_objects: pass 2: set relationships")
526533
for oldobj, newobj in objmap.items():
527534
if debug:
528-
log.debug("deepcopy_sqla_objects: newobj: {}", newobj)
535+
log.debug(f"deepcopy_sqla_objects: newobj: {newobj}")
529536
rewrite_relationships(oldobj, newobj, objmap, debug=debug_rewrite_rel)
530537

531538
# Now we can do session insert.

cardinal_pythonlib/sqlalchemy/schema.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@
6868
Boolean,
6969
Date,
7070
DateTime,
71-
Double,
7271
Enum,
7372
Float,
7473
Integer,
@@ -95,6 +94,16 @@
9594

9695
log = get_brace_style_log_with_null_handler(__name__)
9796

97+
try:
98+
from sqlalchemy.sql.sqltypes import Double
99+
except ImportError:
100+
# This code present to allow testing with older SQLAlchemy 1.4.
101+
log.warning(
102+
"Can't import sqlalchemy.sql.sqltypes.Double "
103+
"(are you using SQLAlchemy prior to 2.0?)"
104+
)
105+
Double = None
106+
98107

99108
# =============================================================================
100109
# Constants
@@ -123,7 +132,7 @@
123132
"BOOLEAN": Boolean,
124133
"DATE": Date,
125134
"TIMESTAMP_NTZ": DateTime,
126-
"DOUBLE": Double,
135+
"DOUBLE": Double if Double is not None else Float,
127136
"FLOAT": Float,
128137
"INT": Integer,
129138
"DECIMAL": Numeric,
@@ -1183,7 +1192,6 @@ def is_sqlatype_binary(coltype: Union[TypeEngine, VisitableType]) -> bool:
11831192
# Several binary types inherit internally from _Binary, making that the
11841193
# easiest to check. We obtain BinaryBaseClass (= _Binary) as above.
11851194
coltype = coltype_as_typeengine(coltype)
1186-
# noinspection PyProtectedMember
11871195
return isinstance(coltype, BinaryBaseClass)
11881196

11891197

0 commit comments

Comments
 (0)