| 119 | Here we demonstrate the effect of the ``first_run`` argument:: |
| 120 | |
| 121 | sage: modify_for_nested_pickle(A, 'X', sys.modules['__main__']) |
| 122 | sage: A.B.__name__ # nothing changed |
| 123 | 'A.B' |
| 124 | sage: modify_for_nested_pickle(A, 'X', sys.modules['__main__'], first_run=False) |
| 125 | sage: A.B.__name__ |
| 126 | 'X.A.B' |
| 127 | |
| 128 | Note that the class is now found in the module under both its old and |
| 129 | its new name:: |
| 130 | |
| 131 | sage: getattr(module, 'A.B', 'Not found') |
| 132 | <class '__main__.X.A.B'> |
| 133 | sage: getattr(module, 'X.A.B', 'Not found') |
| 134 | <class '__main__.X.A.B'> |
| 135 | |
| 136 | |
| 137 | TESTS: |
| 138 | |
| 139 | The following is a real life example, that was enabled by the internal |
| 140 | use of the``first_run`` in :trac:`9107`:: |
| 141 | |
| 142 | sage: cython_code = [ |
| 143 | ....: "from sage.structure.unique_representation import UniqueRepresentation", |
| 144 | ....: "class A1(UniqueRepresentation):", |
| 145 | ....: " class B1(UniqueRepresentation):", |
| 146 | ....: " class C1: pass", |
| 147 | ....: " class B2:", |
| 148 | ....: " class C2: pass"] |
| 149 | sage: import os |
| 150 | sage: cython(os.linesep.join(cython_code)) |
| 151 | |
| 152 | Before :trac:`9107`, the name of ``A1.B1.C1`` would have been wrong:: |
| 153 | |
| 154 | sage: A1.B1.C1.__name__ |
| 155 | 'A1.B1.C1' |
| 156 | sage: A1.B2.C2.__name__ |
| 157 | 'A1.B2.C2' |
| 158 | sage: A_module = sys.modules[A1.__module__] |
| 159 | sage: getattr(A_module, 'A1.B1.C1', 'Not found').__name__ |
| 160 | 'A1.B1.C1' |
| 161 | sage: getattr(A_module, 'A1.B2.C2', 'Not found').__name__ |
| 162 | 'A1.B2.C2' |
| 163 | |
117 | | for (name, v) in cls.__dict__.iteritems(): |
118 | | if isinstance(v, (type, ClassType)): |
119 | | if v.__name__ == name and v.__module__ == mod_name and getattr(module, name, None) is not v: |
120 | | # OK, probably this is a nested class. |
121 | | dotted_name = name_prefix + '.' + name |
122 | | v.__name__ = dotted_name |
123 | | setattr(module, dotted_name, v) |
124 | | modify_for_nested_pickle(v, dotted_name, module) |
| 167 | cdef str cls_name = cls.__name__+'.' |
| 168 | cdef str v_name |
| 169 | if first_run: |
| 170 | for (name, v) in cls.__dict__.iteritems(): |
| 171 | if isinstance(v, NestedClassMetaclass): |
| 172 | v_name = v.__name__ |
| 173 | if v_name==name and v.__module__ == mod_name and getattr(module, v_name, None) is not v: |
| 174 | # OK, probably this is a nested class. |
| 175 | dotted_name = name_prefix + '.' + v_name |
| 176 | setattr(module, dotted_name, v) |
| 177 | modify_for_nested_pickle(v, name_prefix, module, False) |
| 178 | v.__name__ = dotted_name |
| 179 | elif isinstance(v, (type, ClassType)): |
| 180 | v_name = v.__name__ |
| 181 | if v_name==name and v.__module__ == mod_name and getattr(module, v_name, None) is not v: |
| 182 | # OK, probably this is a nested class. |
| 183 | dotted_name = name_prefix + '.' + v_name |
| 184 | setattr(module, dotted_name, v) |
| 185 | modify_for_nested_pickle(v, dotted_name, module) |
| 186 | v.__name__ = dotted_name |
| 187 | else: |
| 188 | for (name, v) in cls.__dict__.iteritems(): |
| 189 | if isinstance(v, (type, ClassType, NestedClassMetaclass)): |
| 190 | v_name = v.__name__ |
| 191 | if v_name==cls_name+name and v.__module__ == mod_name: |
| 192 | # OK, probably this is a nested class. |
| 193 | dotted_name = name_prefix + '.' + v_name |
| 194 | setattr(module, dotted_name, v) |
| 195 | modify_for_nested_pickle(v, name_prefix, module, False) |
| 196 | v.__name__ = dotted_name |
| 197 | |