Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove --fiximports helper #39274

Merged
merged 10 commits into from
Mar 22, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions src/.relint.yml
Original file line number Diff line number Diff line change
@@ -42,10 +42,7 @@

- name: 'namespace_pkg_all_import: import from .all of a namespace package'
hint: |
Sage library code should not import from sage.PAC.KAGE.all when sage.PAC.KAGE is an implicit
namespace package. Type import_statements("SOME_IDENTIFIER") to find a more specific import,
or use 'sage --fiximports' to fix automatically in the source file.
# Keep in sync with SAGE_ROOT/src/sage/misc/replace_dot_all.py
Sage library code should not import from sage.PAC.KAGE.all.
pattern: 'from\s+sage(|[.](arith|categories|combinat|crypto|databases|data_structures|dynamics|ext|game_theory|games|geometry|graphs|groups|interfaces|manifolds|matrix|matroids|misc|modules|monoids|numerical|probability|quadratic_forms|quivers|rings|sat|schemes|sets|stats|symbolic|tensor)[a-z0-9_.]*|[.]libs)[.]all\s+import'
# imports from .all are allowed in all.py; also allow in some modules that need sage.all
filePattern: '(.*/|)(?!(all|benchmark|dev_tools|parsing|sage_eval|explain_pickle|.*_test))[^/.]*[.](py|pyx|pxi)$'
9 changes: 0 additions & 9 deletions src/bin/sage
Original file line number Diff line number Diff line change
@@ -488,10 +488,6 @@ usage_advanced() {
echo " --fixdoctests file.py"
echo " -- Run doctests and replace output of failing doctests"
echo " with actual output."
echo " --fiximports <files|dirs>"
echo " -- Replace imports from sage.PAC.KAGE.all by specific"
echo " imports when sage.PAC.KAGE is an implicit namespace"
echo " package"
echo " --fixdistributions <files|dirs>"
echo " -- Check or update '# sage_setup: distribution'"
echo " directives in source files"
@@ -955,11 +951,6 @@ if [ "$1" = '-startuptime' -o "$1" = '--startuptime' ]; then
exec sage-startuptime.py "$@"
fi

if [ "$1" = '-fiximports' -o "$1" = '--fiximports' ]; then
shift
exec sage-python -m sage.misc.replace_dot_all "$@"
fi

if [ "$1" = '-fixdistributions' -o "$1" = '--fixdistributions' ]; then
shift
exec sage-python -m sage.misc.package_dir "$@"
2 changes: 0 additions & 2 deletions src/doc/en/developer/packaging_sage_library.rst
Original file line number Diff line number Diff line change
@@ -300,8 +300,6 @@ distribution -- which then must be declared as a run-time dependency.
:mod:`sage.rings.all`.

To audit the Sage library for such imports, use ``sage --tox -e relint``.
In most cases, the imports can be fixed automatically using the
tool ``sage --fiximports``.

- Replace module-level imports by method-level imports. Note that
this comes with a small runtime overhead, which can become
2 changes: 1 addition & 1 deletion src/sage/features/all.py
Original file line number Diff line number Diff line change
@@ -117,7 +117,7 @@ def name_feature(name, toplevel=None):
except AttributeError:
return None

from sage.misc.dev_tools import find_object_modules
from sage.misc.sageinspect import find_object_modules

for module, names in find_object_modules(obj).items():
if name in names and (feature := module_feature(module)):
1 change: 0 additions & 1 deletion src/sage/misc/all.py
Original file line number Diff line number Diff line change
@@ -125,7 +125,6 @@
lazy_import('sage.misc.inline_fortran', 'fortran')

lazy_import('sage.misc.banner', 'banner', deprecation=34259)
lazy_import('sage.misc.dev_tools', 'runsnake', deprecation=34259)
lazy_import('sage.misc.edit_module', 'set_edit_template', deprecation=34259)
lazy_import('sage.misc.profiler', 'Profiler', deprecation=34259)
lazy_import('sage.misc.trace', 'trace', deprecation=34259)
84 changes: 7 additions & 77 deletions src/sage/misc/dev_tools.py
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@
import os
import re
import sys

from collections import defaultdict

from sage.misc.sageinspect import find_object_modules


def runsnake(command):
"""
@@ -33,6 +34,7 @@

sage: from sage.misc.dev_tools import runsnake
sage: runsnake("list(SymmetricGroup(3))") # optional - runsnake
...

``command`` is first preparsed (see :func:`preparse`)::

@@ -65,6 +67,10 @@
from sage.misc.temporary_file import tmp_filename
from sage.misc.misc import get_main_globals
from sage.repl.preparse import preparse
from sage.misc.superseded import deprecation

Check warning on line 70 in src/sage/misc/dev_tools.py

Codecov / codecov/patch

src/sage/misc/dev_tools.py#L70

Added line #L70 was not covered by tests

deprecation(39274, "just use the runsnake program directly")

Check warning on line 72 in src/sage/misc/dev_tools.py

Codecov / codecov/patch

src/sage/misc/dev_tools.py#L72

Added line #L72 was not covered by tests

tmpfile = tmp_filename()
cProfile.runctx(preparse(command.lstrip().rstrip()), get_main_globals(),
locals(), filename=tmpfile)
@@ -281,82 +287,6 @@
return obj


def find_object_modules(obj):
r"""
Return a dictionary whose keys are the names of the modules where ``obj``
appear and the value at a given module name is the list of names that
``obj`` have in that module.

It is very unlikely that the output dictionary has several keys except when
``obj`` is an instance of a class.

EXAMPLES::

sage: from sage.misc.dev_tools import find_object_modules
sage: find_object_modules(RR) # needs sage.rings.real_mpfr
{'sage.rings.real_mpfr': ['RR']}
sage: find_object_modules(ZZ)
{'sage.rings.integer_ring': ['Z', 'ZZ']}

.. NOTE::

It might be a good idea to move this function in
:mod:`sage.misc.sageinspect`.
"""
from sage.misc import sageinspect

# see if the object is defined in its own module
# might be wrong for class instances as the instantiation might appear
# outside of the module !!
module_name = None
if sageinspect.isclassinstance(obj):
module_name = obj.__class__.__module__
elif hasattr(obj, '__module__') and obj.__module__:
module_name = obj.__module__

if module_name:
if module_name not in sys.modules:
raise ValueError("this should never happen")
d = sys.modules[module_name].__dict__
matching = sorted(key for key in d if d[key] is obj)
if matching:
return {module_name: matching}

# otherwise, we parse all (already loaded) modules and hope to find
# something
module_to_obj = {}
for module_name, module in sys.modules.items():
if module_name != '__main__' and hasattr(module, '__dict__'):
d = module.__dict__
names = [key for key in d if d[key] is obj]
if names:
module_to_obj[module_name] = names

# if the object is an instance, we try to guess where it is defined
if sageinspect.isclassinstance(obj):
dec_pattern = re.compile(r"^(\w[\w0-9\_]*)\s*=", re.MULTILINE)
module_to_obj2 = {}
for module_name, obj_names in module_to_obj.items():
module_to_obj2[module_name] = []
try:
src = sageinspect.sage_getsource(sys.modules[module_name])
except TypeError:
pass
else:
m = dec_pattern.search(src)
while m:
if m.group(1) in obj_names:
module_to_obj2[module_name].append(m.group(1))
m = dec_pattern.search(src, m.end())
if not module_to_obj2[module_name]:
del module_to_obj2[module_name]

if module_to_obj2:
return module_to_obj2

return module_to_obj


def import_statements(*objects, **kwds):
r"""
Print import statements for the given objects.
1 change: 0 additions & 1 deletion src/sage/misc/meson.build
Original file line number Diff line number Diff line change
@@ -62,7 +62,6 @@ py.install_sources(
'random_testing.py',
'randstate.pxd',
'remote_file.py',
'replace_dot_all.py',
'repr.py',
'rest_index_of_methods.py',
'sage_eval.py',
Loading
Loading