Skip to content

Commit

Permalink
Trac #29869: Move attrcall and friends from sage.misc.misc to new mod…
Browse files Browse the repository at this point in the history
…ule sage.misc.call

This will help with #29865

URL: https://trac.sagemath.org/29869
Reported by: mkoeppe
Ticket author(s): Matthias Koeppe
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Jul 4, 2020
2 parents 4be8eb3 + 6024ffd commit 0c5a199
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 182 deletions.
1 change: 1 addition & 0 deletions src/doc/en/reference/misc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Special Base Classes, Decorators, etc.
sage/misc/method_decorator
sage/misc/object_multiplexer
sage/misc/fast_methods
sage/misc/call

Lists and Iteration, etc.
~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/category_with_axiom.py
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class
from sage.misc.cachefunc import cached_method, cached_function
from sage.misc.lazy_attribute import lazy_class_attribute
from sage.misc.lazy_import import LazyImport
from sage.misc.misc import call_method
from sage.misc.call import call_method
from sage.categories.category import Category
from sage.categories.category_singleton import Category_singleton
from sage.categories.category_types import Category_over_base_ring
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/coxeter_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from sage.misc.cachefunc import cached_method, cached_in_parent_method
from sage.misc.lazy_import import LazyImport
from sage.misc.constant_function import ConstantFunction
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
from sage.categories.category_singleton import Category_singleton
from sage.categories.enumerated_sets import EnumeratedSets
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/finite_posets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1889,7 +1889,7 @@ def order_ideals_lattice(self, as_ideals=True, facade=None):
if facade is None:
facade = self._is_facade
if as_ideals:
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
from sage.sets.set import Set
ideals = [Set(self.order_ideal(antichain))
for antichain in self.antichains()]
Expand Down
2 changes: 1 addition & 1 deletion src/sage/categories/finite_semigroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# *****************************************************************************

from sage.misc.cachefunc import cached_method
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
from sage.categories.category_with_axiom import CategoryWithAxiom


Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/root_system/root_lattice_realizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from __future__ import print_function, absolute_import

from sage.misc.abstract_method import abstract_method, AbstractMethod
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
from sage.misc.cachefunc import cached_method, cached_in_parent_method
from sage.misc.lazy_attribute import lazy_attribute
from sage.misc.lazy_import import LazyImport
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/root_system/type_dual.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# ****************************************************************************
from __future__ import print_function, absolute_import

from sage.misc.misc import attrcall
from sage.misc.call import attrcall
from sage.misc.cachefunc import cached_method
from sage.misc.lazy_attribute import lazy_attribute
from sage.combinat.root_system import cartan_type
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/sf/sfa.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ def corresponding_basis_over(self, R):
put on a more robust and systematic footing.
"""
from sage.combinat.sf.sf import SymmetricFunctions
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
try:
return attrcall(self._basis)(SymmetricFunctions(R))
except AttributeError: # or except (AttributeError, ValueError):
Expand Down
2 changes: 1 addition & 1 deletion src/sage/geometry/hyperbolic_space/hyperbolic_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from sage.rings.infinity import infinity
from sage.functions.other import real, imag, sqrt
from sage.misc.lazy_import import lazy_import
lazy_import('sage.misc.misc', 'attrcall')
lazy_import('sage.misc.call', 'attrcall')

class HyperbolicModelCoercion(Morphism):
"""
Expand Down
2 changes: 1 addition & 1 deletion src/sage/matrix/matrix_symbolic_dense.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ cdef class Matrix_symbolic_dense(Matrix_generic_dense):
[ x^2 + 2 -2*x + 3]
[ -4*x + 6 x^2 - 6*x + 11]
"""
from sage.misc.misc import attrcall
from sage.misc.call import attrcall
return self.apply_map(attrcall('expand'))

def variables(self):
Expand Down
4 changes: 3 additions & 1 deletion src/sage/misc/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
exists, forall, is_iterator,
random_sublist, walltime,
repr_lincomb,
pad_zeros, attrcall,
pad_zeros,
SAGE_DB, SAGE_TMP,
newton_method_sizes, compose,
nest)

from .call import attrcall

from .banner import version, banner

from .temporary_file import tmp_dir, tmp_filename
Expand Down
182 changes: 182 additions & 0 deletions src/sage/misc/call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
"""
Attribute and method calling
"""

# ****************************************************************************
# Copyright (C) 2008 Mike Hansen
# Copyright (C) 2010, 2013 Nicolas M. Thiery
# Copyright (C) 2018 Frédéric Chapoton
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
# https://www.gnu.org/licenses/
# ****************************************************************************

#############################################
# Operators
#############################################
class AttrCallObject(object):
def __init__(self, name, args, kwds):
"""
TESTS::
sage: f = attrcall('core', 3); f
*.core(3)
sage: TestSuite(f).run()
"""
self.name = name
self.args = args
self.kwds = kwds

def __call__(self, x, *args):
"""
Gets the ``self.name`` method from ``x``, calls it with
``self.args`` and ``args`` as positional parameters and
``self.kwds`` as keyword parameters, and returns the result.
EXAMPLES::
sage: core = attrcall('core', 3)
sage: core(Partition([4,2]))
[4, 2]
sage: series = attrcall('series', x)
sage: series(sin(x), 4)
1*x + (-1/6)*x^3 + Order(x^4)
"""
return getattr(x, self.name)(*(self.args + args), **self.kwds)

def __repr__(self):
"""
Return a string representation of this object.
The star in the output represents the object passed into ``self``.
EXAMPLES::
sage: attrcall('core', 3)
*.core(3)
sage: attrcall('hooks', flatten=True)
*.hooks(flatten=True)
sage: attrcall('hooks', 3, flatten=True)
*.hooks(3, flatten=True)
"""
s = "*.%s(%s" % (self.name, ", ".join(map(repr, self.args)))
if self.kwds:
if self.args:
s += ", "
s += ", ".join("%s=%s" % keyvalue for keyvalue in self.kwds.items())
s += ")"
return s

def __eq__(self, other):
"""
Equality testing
EXAMPLES::
sage: attrcall('core', 3, flatten = True) == attrcall('core', 3, flatten = True)
True
sage: attrcall('core', 2) == attrcall('core', 3)
False
sage: attrcall('core', 2) == 1
False
"""
return self.__class__ == other.__class__ and self.__dict__ == other.__dict__

def __ne__(self, other):
"""
Equality testing
EXAMPLES::
sage: attrcall('core', 3, flatten = True) != attrcall('core', 3, flatten = True)
False
sage: attrcall('core', 2) != attrcall('core', 3)
True
sage: attrcall('core', 2) != 1
True
"""
return not self == other

def __hash__(self):
"""
Hash value
This method tries to ensure that, when two ``attrcall``
objects are equal, they have the same hash value.
.. warning:: dicts are not hashable, so we instead hash their
items; however the order of those items might differ. The
proper fix would be to use a frozen dict for ``kwds``, when
frozen dicts will be available in Python.
EXAMPLES::
sage: x = attrcall('core', 3, flatten = True, blah = 1)
sage: hash(x) # random # indirect doctest
210434060
sage: type(hash(x))
<type 'int'>
sage: y = attrcall('core', 3, blah = 1, flatten = True)
sage: hash(y) == hash(x)
True
sage: y = attrcall('core', 3, flatten = True, blah = 2)
sage: hash(y) != hash(x)
True
sage: hash(attrcall('core', 2)) != hash(attrcall('core', 3))
True
sage: hash(attrcall('core', 2)) != hash(1)
True
Note: a missing ``__hash__`` method here used to break the
unique representation of parents taking ``attrcall`` objects
as input; see :trac:`8911`.
"""
return hash((self.args, tuple(sorted(self.kwds.items()))))


def attrcall(name, *args, **kwds):
"""
Returns a callable which takes in an object, gets the method named
name from that object, and calls it with the specified arguments
and keywords.
INPUT:
- ``name`` - a string of the name of the method you
want to call
- ``args, kwds`` - arguments and keywords to be passed
to the method
EXAMPLES::
sage: f = attrcall('core', 3); f
*.core(3)
sage: [f(p) for p in Partitions(5)]
[[2], [1, 1], [1, 1], [3, 1, 1], [2], [2], [1, 1]]
"""
return AttrCallObject(name, args, kwds)


def call_method(obj, name, *args, **kwds):
"""
Call the method ``name`` on ``obj``.
This has to exist somewhere in Python!!!
.. SEEALSO:: :func:`operator.methodcaller` :func:`attrcal`
EXAMPLES::
sage: from sage.misc.call import call_method
sage: call_method(1, "__add__", 2)
3
"""
return getattr(obj, name)(*args, **kwds)

from sage.misc.persist import register_unpickle_override
register_unpickle_override("sage.misc.misc", "call_method", call_method)
Loading

0 comments on commit 0c5a199

Please sign in to comment.