@@ -298,11 +298,31 @@ cdef class flint_mpoly_context(flint_elem):
298298
299299 _ctx_cache = None
300300
301- def __init__ (self , names: Iterable[str]):
301+ def __init__ (self , *_ , **_2 ):
302+ raise RuntimeError (
303+ f" {self.__class__.__name__} should not be constructed directly. "
304+ f" Use '{self.__class__.__name__}.get' instead."
305+ )
306+
307+ @classmethod
308+ def _new_ (_ , flint_mpoly_context self , names: Iterable[str]):
309+ """
310+ Constructor for all mpoly context types. This method is not intended for
311+ user-face use. See ``get`` instead.
312+
313+ Construction via ``__init__`` is disabled to prevent the accidental creation of
314+ new mpoly contexts. By ensuring each context is unique they can be compared via
315+ pointer comparisons.
316+
317+ Each concrete subclass should maintain their own context cache in
318+ ``_ctx_cache``, and the ``get`` method should insert newly created contexts into
319+ the cache.
320+ """
302321 self .py_names = tuple (name.encode(" ascii" ) if not isinstance (name, bytes) else name for name in names)
303322 self .c_names = < const char ** > libc.stdlib.malloc(len (names) * sizeof(const char * ))
304323 for i in range (len (names)):
305324 self .c_names[i] = self .py_names[i]
325+ return self
306326
307327 def __dealloc__ (self ):
308328 libc.stdlib.free(self .c_names)
@@ -342,15 +362,17 @@ cdef class flint_mpoly_context(flint_elem):
342362 return i
343363
344364 @staticmethod
345- def create_variable_names (names: Iterable[str | tuple[str , int]]) -> tuple[str]:
365+ def create_variable_names (names: str | Iterable[str | tuple[str , int]]) -> tuple[str]:
346366 """
347- Create a tuple of variable names based off either ``Iterable[str]``,
367+ Create a tuple of variable names based off either ``str``, `` Iterable[str]``,
348368 ``tuple[str , int]``, or ``Iterable[tuple[str , int]]``.
349369
350- >>> flint_mpoly_context.create_variable_names([( 'x', 3), 'y'] )
351- ('x0', 'x1', 'x2', 'y' )
370+ >>> flint_mpoly_context.create_variable_names('x')
371+ ('x', )
352372 >>> flint_mpoly_context.create_variable_names(('x', 3))
353373 ('x0', 'x1', 'x2')
374+ >>> flint_mpoly_context.create_variable_names([('x', 3), 'y'])
375+ ('x0', 'x1', 'x2', 'y')
354376 """
355377 res: list[str] = []
356378
@@ -372,7 +394,7 @@ cdef class flint_mpoly_context(flint_elem):
372394 @classmethod
373395 def create_context_key (
374396 cls ,
375- names: Iterable[str | tuple[str , int]],
397+ names: str | Iterable[str | tuple[str , int]],
376398 ordering: Ordering | str = Ordering.lex
377399 ):
378400 """
@@ -391,7 +413,7 @@ cdef class flint_mpoly_context(flint_elem):
391413
392414 ctx = cls ._ctx_cache.get(key)
393415 if ctx is None :
394- ctx = cls ._ctx_cache.setdefault(key, cls (* key))
416+ ctx = cls ._ctx_cache.setdefault(key, cls ._new_ (* key))
395417 return ctx
396418
397419 @classmethod
@@ -432,10 +454,13 @@ cdef class flint_mpoly_context(flint_elem):
432454 return self .from_dict({tuple (exp_vec): coeff})
433455
434456cdef class flint_mod_mpoly_context(flint_mpoly_context):
435- def __init__ (self , names , prime_modulus ):
436- super ().__init__(names)
457+ @classmethod
458+ def _new_ (_ , flint_mod_mpoly_context self , names , prime_modulus ):
459+ super ()._new_(self , names)
437460 self .__prime_modulus = < bint> prime_modulus
438461
462+ return self
463+
439464 @classmethod
440465 def create_context_key (
441466 cls ,
0 commit comments