| 1032 | return cloned_traverse(obj, opts, visitors) |
| 1033 | |
| 1034 | def clone(elem: ExternallyTraversible, **kw: Any) -> ExternallyTraversible: |
| 1035 | if elem in stop_on: |
| 1036 | return elem |
| 1037 | else: |
| 1038 | if id(elem) not in cloned: |
| 1039 | if "replace" in kw: |
| 1040 | newelem = cast( |
| 1041 | Optional[ExternallyTraversible], kw["replace"](elem) |
| 1042 | ) |
| 1043 | if newelem is not None: |
| 1044 | cloned[id(elem)] = newelem |
| 1045 | return newelem |
| 1046 | |
| 1047 | # the _clone method for immutable normally returns "self". |
| 1048 | # however, the method is still allowed to return a |
| 1049 | # different object altogether; ColumnClause._clone() will |
| 1050 | # based on options clone the subquery to which it is associated |
| 1051 | # and return the new corresponding column. |
| 1052 | cloned[id(elem)] = newelem = elem._clone(clone=clone, **kw) |
| 1053 | newelem._copy_internals(clone=clone, **kw) |
| 1054 | |
| 1055 | # however, visit methods which are tasked with in-place |
| 1056 | # mutation of the object should not get access to the immutable |
| 1057 | # object. |
| 1058 | if not elem._is_immutable: |
| 1059 | meth = visitors.get(newelem.__visit_name__, None) |
| 1060 | if meth: |
| 1061 | meth(newelem) |
| 1062 | return cloned[id(elem)] |
| 1063 | |
| 1064 | if obj is not None: |
| 1065 | obj = clone( |