From 336628268c069a66d81742f08d5c57e31743fcb9 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 01:28:17 +0000 Subject: [PATCH 1/6] Resolve a few cyclic imports in cattegories/structure/misc --- src/sage/categories/__init__.py | 1 + src/sage/categories/all__sagemath_objects.py | 4 ---- src/sage/categories/category.py | 7 ++++++- src/sage/categories/category_singleton.pyx | 3 ++- src/sage/categories/map.pyx | 11 ++++++++++- src/sage/categories/morphism.pyx | 4 ++-- src/sage/misc/__init__.py | 1 + src/sage/misc/all__sagemath_objects.py | 2 -- src/sage/misc/c3_controlled.pyx | 3 ++- src/sage/misc/fast_methods.pyx | 3 ++- src/sage/sets/pythonclass.pyx | 3 ++- src/sage/structure/category_object.pyx | 3 ++- 12 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 src/sage/categories/__init__.py create mode 100644 src/sage/misc/__init__.py diff --git a/src/sage/categories/__init__.py b/src/sage/categories/__init__.py new file mode 100644 index 00000000000..3f293d43eac --- /dev/null +++ b/src/sage/categories/__init__.py @@ -0,0 +1 @@ +import sage.structure.element # resolve a cyclic import (categories.map > structure.element > ... > categories.map) diff --git a/src/sage/categories/all__sagemath_objects.py b/src/sage/categories/all__sagemath_objects.py index dee0881d787..c390b6d3291 100644 --- a/src/sage/categories/all__sagemath_objects.py +++ b/src/sage/categories/all__sagemath_objects.py @@ -2,10 +2,6 @@ from sage.misc.lazy_import import lazy_import -# Resolve a circular import so that "import sage.categories.all" can succeed -# in initializing the category system. -import sage.structure.category_object # imports sage.categories.category - # Small part of "from .basic import *": from .objects import Objects from .sets_cat import Sets, EmptySetError diff --git a/src/sage/categories/category.py b/src/sage/categories/category.py index 57ef7f4184b..1cd0d19392a 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -107,7 +107,6 @@ from sage.misc.cachefunc import cached_method, cached_function from sage.misc.c3_controlled import _cmp_key, _cmp_key_named, C3_sorted_merge from sage.misc.lazy_attribute import lazy_attribute -from sage.misc.unknown import Unknown from sage.misc.weak_dict import WeakValueDictionary from sage.structure.sage_object import SageObject @@ -1817,6 +1816,8 @@ def is_subcategory(self, c): sage: PoV3.is_subcategory(PoA3) False """ + from sage.misc.unknown import Unknown + if c is self: return True subcat_hook = c._subcategory_hook_(self) @@ -2896,6 +2897,8 @@ def _subcategory_hook_(self, C): sage: Bimodules(QQ,QQ)._subcategory_hook_(Rings()) False """ + from sage.misc.unknown import Unknown + if not issubclass(C.parent_class, self.parent_class): return False return Unknown @@ -3063,6 +3066,8 @@ def is_subcategory(self, C): sage: Category.join([Rings(),Modules(QQ)]).is_subcategory(Category.join([Rngs(),Bimodules(QQ,QQ)])) True """ + from sage.misc.unknown import Unknown + if C is self: return True hook = C._subcategory_hook_(self) diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index 543ce0375f7..2b63a5c7cf9 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -9,7 +9,6 @@ Singleton categories # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.constant_function import ConstantFunction from sage.misc.lazy_attribute import lazy_class_attribute from sage.categories.category import Category from sage.structure.category_object cimport CategoryObject @@ -314,6 +313,8 @@ class Category_singleton(Category): ... AssertionError: is not a direct subclass of """ + from sage.misc.constant_function import ConstantFunction + if isinstance(cls, DynamicMetaclass): # cls is something like Rings_with_category cls = cls.__base__ # TODO: find a better way to check that cls is an abstract class diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index 45c30ae6c31..9a33c13449b 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -26,7 +26,6 @@ import weakref from sage.ext.stdsage cimport HAS_DICTIONARY from sage.arith.power cimport generic_power from sage.sets.pythonclass cimport Set_PythonType -from sage.misc.constant_function import ConstantFunction from sage.structure.element cimport parent from cpython.object cimport PyObject_RichCompare @@ -120,6 +119,8 @@ cdef class Map(Element): From: Univariate Polynomial Ring in x over Rational Field To: Symmetric group of order 6! as a permutation group """ + from sage.misc.constant_function import ConstantFunction + if codomain is not None: if isinstance(parent, type): parent = Set_PythonType(parent) @@ -304,6 +305,8 @@ cdef class Map(Element): sage: phi Defunct map """ + from sage.misc.constant_function import ConstantFunction + if not isinstance(self.domain, ConstantFunction): return self.domain = weakref.ref(self.domain()) @@ -380,6 +383,8 @@ cdef class Map(Element): ... ValueError: This map is in an invalid state, the domain has been garbage collected """ + from sage.misc.constant_function import ConstantFunction + if isinstance(self.domain, ConstantFunction): return D = self.domain() @@ -418,6 +423,8 @@ cdef class Map(Element): sage: f._repr_type_str 'bla' """ + from sage.misc.constant_function import ConstantFunction + # todo: the following can break during unpickling of complex # objects with circular references! In that case, _slots might # contain incomplete objects. @@ -584,6 +591,8 @@ cdef class Map(Element): sage: phi Defunct map """ + from sage.misc.constant_function import ConstantFunction + D = self.domain() if D is None: return "Defunct map" diff --git a/src/sage/categories/morphism.pyx b/src/sage/categories/morphism.pyx index 571f90a7330..1d1ea29bad2 100644 --- a/src/sage/categories/morphism.pyx +++ b/src/sage/categories/morphism.pyx @@ -39,8 +39,6 @@ AUTHORS: from cpython.object cimport * -from sage.misc.constant_function import ConstantFunction - from sage.structure.element cimport Element, ModuleElement from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool from sage.structure.parent cimport Parent @@ -90,6 +88,8 @@ cdef class Morphism(Map): sage: phi Defunct morphism """ + from sage.misc.constant_function import ConstantFunction + D = self.domain() if D is None: return "Defunct morphism" diff --git a/src/sage/misc/__init__.py b/src/sage/misc/__init__.py new file mode 100644 index 00000000000..61c5460232b --- /dev/null +++ b/src/sage/misc/__init__.py @@ -0,0 +1 @@ +import sage.structure.element # to break a cyclic import (misc.constant_function > structure.element > ... > misc.constant_function) diff --git a/src/sage/misc/all__sagemath_objects.py b/src/sage/misc/all__sagemath_objects.py index 43a9c1c06d5..e6b2bd3d939 100644 --- a/src/sage/misc/all__sagemath_objects.py +++ b/src/sage/misc/all__sagemath_objects.py @@ -1,7 +1,5 @@ # Subset of sage.misc.all that is made available by the sage-objects distribution -import sage.structure.all # to break a cyclic import - from .lazy_attribute import lazy_attribute, lazy_class_attribute from .lazy_import import lazy_import diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index 442dda7264f..53396ba9e17 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -365,7 +365,6 @@ AUTHOR: from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute -from sage.structure.dynamic_class import dynamic_class ############################################################################## # Implementation of the total order between categories @@ -1349,6 +1348,8 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: x.cls.mro() [, , , , , , , , <... 'object'>] """ + from sage.structure.dynamic_class import dynamic_class + super_classes = tuple(self._from_value(base).cls for base in self._bases_controlled) if not super_classes: super_classes = (object,) diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index 370cefc46a0..90def838075 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -29,7 +29,6 @@ AUTHOR: #***************************************************************************** from sage.misc.classcall_metaclass import ClasscallMetaclass, typecall -from sage.misc.constant_function import ConstantFunction from cpython.object cimport Py_EQ, Py_NE @@ -296,6 +295,8 @@ class Singleton(WithEqualityById, metaclass=ClasscallMetaclass): sage: loads(dumps(c)) is copy(c) is C() # indirect doctest True """ + from sage.misc.constant_function import ConstantFunction + assert cls.mro()[1] == Singleton, "{} is not a direct subclass of {}".format(cls, Singleton) res = typecall(cls) cf = ConstantFunction(res) diff --git a/src/sage/sets/pythonclass.pyx b/src/sage/sets/pythonclass.pyx index bfa7f3bc617..40ffbd55a89 100644 --- a/src/sage/sets/pythonclass.pyx +++ b/src/sage/sets/pythonclass.pyx @@ -14,7 +14,6 @@ Set of all objects of a given Python class from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport rich_to_bool -from sage.categories.sets_cat import Sets cdef dict _type_set_cache = {} @@ -83,6 +82,8 @@ cdef class Set_PythonType_class(Set_generic): sage: Set_PythonType(float).category() Category of sets """ + from sage.categories.sets_cat import Sets + if not isinstance(typ, type): raise TypeError(f"must be initialized with a class, not {typ!r}") super().__init__(category=Sets()) diff --git a/src/sage/structure/category_object.pyx b/src/sage/structure/category_object.pyx index b6a7eaecb5b..0d1366f3b30 100644 --- a/src/sage/structure/category_object.pyx +++ b/src/sage/structure/category_object.pyx @@ -58,7 +58,6 @@ This example illustrates generators for a free module over `\ZZ`. from sage.cpython.getattr import dir_with_other_class from sage.cpython.getattr cimport getattr_from_other_class -from sage.categories.category import Category from sage.misc.cachefunc import cached_method from sage.structure.dynamic_class import DynamicMetaclass @@ -145,6 +144,8 @@ cdef class CategoryObject(SageObject): ... TypeError: CategoryObject of type CategoryObject requires a Category, list or tuple, not NoneType """ + from sage.categories.category import Category + if isinstance(category, Category): self._category = category elif isinstance(category, (list, tuple)): From 851a51026ffb421553c12c421d8019715c1f7d9f Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 11:17:25 +0000 Subject: [PATCH 2/6] Remove old workaround --- src/sage/structure/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sage/structure/__init__.py b/src/sage/structure/__init__.py index 8689eb1717f..e69de29bb2d 100644 --- a/src/sage/structure/__init__.py +++ b/src/sage/structure/__init__.py @@ -1,2 +0,0 @@ -# Resolve a cyclic import -import sage.structure.element From c5dcd9851e0d65d50e61c5607d6c39f1a95a8095 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 11:39:40 +0000 Subject: [PATCH 3/6] fix import --- src/sage/misc/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sage/misc/__init__.py b/src/sage/misc/__init__.py index 61c5460232b..cbea4b5b616 100644 --- a/src/sage/misc/__init__.py +++ b/src/sage/misc/__init__.py @@ -1 +1,5 @@ -import sage.structure.element # to break a cyclic import (misc.constant_function > structure.element > ... > misc.constant_function) +try: + import sage.structure.element # to break a cyclic import (misc.constant_function > structure.element > ... > misc.constant_function) +except ModuleNotFoundError: + # Ignore, the import above may fail while collecting metadata info (at which point sage.structure is not yet installed) + pass From 8f2b9be9eb2963a8735d62234f994630ae1bd01c Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Mon, 30 Oct 2023 17:57:11 +0000 Subject: [PATCH 4/6] Remove old import to break structure.factory > structure.test_factory --- src/sage/structure/factory.pyx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/sage/structure/factory.pyx b/src/sage/structure/factory.pyx index ddb55501d94..cb9133464c5 100644 --- a/src/sage/structure/factory.pyx +++ b/src/sage/structure/factory.pyx @@ -768,7 +768,3 @@ def lookup_global(name): else: import sage.all as all return getattr(all, name) - - -# Old imports required for unpickling old pickles -from sage.structure.test_factory import test_factory From 4eede1a8fc890618b19967918bb3d099998a0406 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Tue, 31 Oct 2023 05:56:21 +0000 Subject: [PATCH 5/6] Break import cycle rings.integer > rings.rational > rings.integer --- src/sage/rings/rational.pyx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index 0b398428006..e3f6c365750 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -72,9 +72,7 @@ from sage.structure.richcmp cimport rich_to_bool_sgn import sage.rings.rational_field cimport sage.rings.integer as integer -from .integer cimport Integer - -from .integer_ring import ZZ +from sage.rings.integer cimport Integer from sage.structure.coerce cimport is_numpy_type @@ -1749,7 +1747,7 @@ cdef class Rational(sage.structure.element.FieldElement): return (self > 0) ## Check that p is prime - from .integer_ring import ZZ + from sage.rings.integer_ring import ZZ p = ZZ(p) if check and not p.is_prime(): raise ValueError('p must be "infinity" or a positive prime number.') @@ -2059,6 +2057,7 @@ cdef class Rational(sage.structure.element.FieldElement): ... ValueError: cannot take even root of negative number """ + from sage.rings.integer_ring import ZZ # TODO -- this could be quicker, by using GMP directly. cdef integer.Integer num cdef integer.Integer den @@ -3165,6 +3164,7 @@ cdef class Rational(sage.structure.element.FieldElement): sage: (-1/2).log(3) # needs sage.symbolic (I*pi + log(1/2))/log(3) """ + from sage.rings.integer_ring import ZZ cdef int self_sgn if self.denom().is_one(): return ZZ(self.numer()).log(m, prec) @@ -4094,8 +4094,8 @@ cdef class Z_to_Q(Morphism): From: Integer Ring To: Rational Field """ - from . import integer_ring - from . import rational_field + from sage.rings import integer_ring + from sage.rings import rational_field import sage.categories.homset Morphism.__init__(self, sage.categories.homset.Hom(integer_ring.ZZ, rational_field.QQ)) From b6310d9eb30b11d8694344212563164a36749ec8 Mon Sep 17 00:00:00 2001 From: Tobias Diez Date: Thu, 16 Nov 2023 10:32:40 +0800 Subject: [PATCH 6/6] Fix codestyle --- src/sage/misc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/misc/__init__.py b/src/sage/misc/__init__.py index cbea4b5b616..f5961558d9f 100644 --- a/src/sage/misc/__init__.py +++ b/src/sage/misc/__init__.py @@ -1,4 +1,4 @@ -try: +try: import sage.structure.element # to break a cyclic import (misc.constant_function > structure.element > ... > misc.constant_function) except ModuleNotFoundError: # Ignore, the import above may fail while collecting metadata info (at which point sage.structure is not yet installed)