Skip to content

Commit

Permalink
Move more code out of mathics.builtin.__init__
Browse files Browse the repository at this point in the history
Moved to mathics.eval.builtin. Possibly not the best place, but it is
better and is a start.
  • Loading branch information
rocky committed Jul 1, 2023
1 parent cab50bb commit 162f729
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 179 deletions.
171 changes: 6 additions & 165 deletions mathics/builtin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
Mathics Builtin Functions and Variables.
Mathics Builtin Functions and Variables.
Mathics has over a thousand Built-in functions and variables, all of
which are defined here.
Expand All @@ -10,10 +10,6 @@
``mathics.format`` for rendering details, or ``mathics.compile`` for
compilation details.
What remains here is then mostly the top-level definition of a Mathics
Builtin, and attributes that have not been segregated elsewhere such
as has been done for one of the other modules listed above.
A Mathics Builtin is implemented one of a particular kind of Python
class. Within these classes class variables give properties of the
builtin class such as the Builtin's Attributes, its Information text,
Expand All @@ -22,24 +18,13 @@

import glob
import importlib
import inspect
import os.path as osp
import pkgutil
import re
from typing import List, Optional

from mathics.builtin.base import (
Builtin,
Operator,
PatternObject,
SympyObject,
mathics_to_python,
)
from mathics.core.pattern import pattern_objects
from mathics.core.symbols import Symbol
from mathics.eval.makeboxes import builtins_precedence
from mathics.builtin.base import Builtin
from mathics.eval.builtin import add_builtins, import_builtins, name_is_builtin_symbol
from mathics.settings import ENABLE_FILES_MODULE
from mathics.version import __version__ # noqa used in loading to check consistency.

# Get a list of files in this directory. We'll exclude from the start
# files with leading characters we don't want like __init__ with its leading underscore.
Expand All @@ -48,154 +33,14 @@
for f in glob.glob(osp.join(osp.dirname(__file__), "[a-z]*.py"))
]


def add_builtins(new_builtins):
from mathics.core.convert.sympy import mathics_to_sympy, sympy_to_mathics

for var_name, builtin in new_builtins:
name = builtin.get_name()
if hasattr(builtin, "python_equivalent"):
# print("XXX0", builtin.python_equivalent)
mathics_to_python[name] = builtin.python_equivalent

if isinstance(builtin, SympyObject):
mathics_to_sympy[name] = builtin
for sympy_name in builtin.get_sympy_names():
# print("XXX1", sympy_name)
sympy_to_mathics[sympy_name] = builtin
if isinstance(builtin, Operator):
builtins_precedence[Symbol(name)] = builtin.precedence
if isinstance(builtin, PatternObject):
pattern_objects[name] = builtin.__class__
_builtins.update(dict(new_builtins))


def builtins_dict():
return {
builtin.get_name(): builtin
for modname, builtins in builtins_by_module.items()
for builtin in builtins
}


def contribute(definitions):
# let MakeBoxes contribute first
_builtins["System`MakeBoxes"].contribute(definitions)
for name, item in _builtins.items():
if name != "System`MakeBoxes":
item.contribute(definitions)

from mathics.core.definitions import Definition
from mathics.core.expression import ensure_context
from mathics.core.parser import all_operator_names

# All builtins are loaded. Create dummy builtin definitions for
# any remaining operators that don't have them. This allows
# operators like \[Cup] to behave correctly.
for operator in all_operator_names:
if not definitions.have_definition(ensure_context(operator)):
op = ensure_context(operator)
definitions.builtin[op] = Definition(name=op)


def import_builtins(module_names: List[str], submodule_name=None) -> None:
"""
Imports the list of Mathics Built-in modules so that inside
Mathics we have these Builtin Functions, like Plus[], List[] are defined.
"""

def import_module(module_name: str, import_name: str):
try:
module = importlib.import_module(import_name)
except Exception as e:
print(e)
print(f" Not able to load {module_name}. Check your installation.")
print(f" mathics.builtin loads from {__file__[:-11]}")
return None

if module:
modules.append(module)

if submodule_name:
import_module(submodule_name, f"mathics.builtin.{submodule_name}")

for module_name in module_names:
import_name = (
f"mathics.builtin.{submodule_name}.{module_name}"
if submodule_name
else f"mathics.builtin.{module_name}"
)
import_module(module_name, import_name)


def name_is_builtin_symbol(module, name: str) -> Optional[type]:
"""
Checks if ``name`` should be added to definitions, and return
its associated Builtin class.
Return ``None`` if the name should not get added to definitions.
"""
if name.startswith("_"):
return None

module_object = getattr(module, name)

# Look only at Class objects.
if not inspect.isclass(module_object):
return None

# Skip those builtins defined in or imported from another module.

# rocky: I think this is a code smell. It doesn't feel like
# we should have to do this if things are organized and modularized
# builtins and use less custom code.
# mmatera reports that we need this because of the interaction of
# * the custom Mathics3 loading/importing mechanism,
# * the builtin module hierarchy, e.g. mathics.builtin.arithmetic
# nested under mathics.builtin, and
# * our custom doc/doctest and possibly custom checking system

# Mathics3 modules modules, however, right now import all builtin modules from
# __init__
# Note Mathics3 modules do not support buitin hierarchies, e.g.
# pymathics.graph.parametric is allowed but not pymathics.graph.parametric.xxx.
# This too has to do with the custom doc/doctest that is currently used.

if inspect.getmodule(
module_object
) is not module and not module.__name__.startswith("pymathics."):
return None

# Skip objects in module mathics.builtin.base.
if module_object.__module__ == "mathics.builtin.base":
return None

# Skip those builtins that are not submodules of mathics.builtin.
if not (
module_object.__module__.startswith("mathics.builtin.")
or module_object.__module__.startswith("pymathics.")
):
return None

# If it is not a subclass of Builtin, skip it.
if not issubclass(module_object, Builtin):
return None

# Skip Builtin classes that were explicitly marked for skipping.
if module_object in getattr(module, "DOES_NOT_ADD_BUILTIN_DEFINITION", []):
return None
return module_object


# FIXME: redo using importlib since that is probably less fragile.
exclude_files = {"codetables", "base"}
module_names = [
f for f in __py_files__ if re.match(r"^[a-z\d]+$", f) if f not in exclude_files
]

modules = []
import_builtins(module_names)
import_builtins(modules, module_names)

_builtins_list = []
builtins_by_module = {}
Expand Down Expand Up @@ -237,11 +82,10 @@ def name_is_builtin_symbol(module, name: str) -> Optional[type]:

builtin_module = importlib.import_module(import_name)
submodule_names = [
modname
for importer, modname, ispkg in pkgutil.iter_modules(builtin_module.__path__)
modname for _, modname, _ in pkgutil.iter_modules(builtin_module.__path__)
]
# print("XXX3", submodule_names)
import_builtins(submodule_names, subdir)
import_builtins(modules, submodule_names, subdir)

for module in modules:
builtins_by_module[module.__name__] = []
Expand All @@ -262,9 +106,6 @@ def name_is_builtin_symbol(module, name: str) -> Optional[type]:

new_builtins = _builtins_list

# FIXME: some magic is going on here..
_builtins = {}

add_builtins(new_builtins)

display_operators_set = set()
Expand Down
5 changes: 3 additions & 2 deletions mathics/builtin/box/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
At the other end, the top level, we have a Notebook which is just a \
collection of Expressions usually contained in boxes.
"""
# Docs are not yet ready for prime time. Maybe after release 6.0.0.
no_doc = True

from mathics.builtin.base import Builtin
from mathics.builtin.box.expression import BoxExpression
Expand All @@ -32,6 +30,9 @@
)
from mathics.eval.makeboxes import eval_makeboxes

# Docs are not yet ready for prime time. Maybe after release 6.0.0.
no_doc = True


def to_boxes(x, evaluation: Evaluation, options={}) -> BoxElementMixin:
"""
Expand Down
4 changes: 2 additions & 2 deletions mathics/builtin/lowlevelprofile.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
Low-level Profiling
Low-level (Python) profile from inside the Mathics interpreter
Low-level (Python) profile from inside the Mathics3 interpreter
"""

Expand All @@ -12,7 +12,7 @@
import sys
from io import StringIO

from mathics.builtin import Builtin
from mathics.builtin.base import Builtin
from mathics.core.attributes import A_HOLD_ALL_COMPLETE, A_PROTECTED
from mathics.core.convert.python import from_python
from mathics.core.evaluation import Evaluation
Expand Down
5 changes: 3 additions & 2 deletions mathics/core/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from mathics.core.expression import Expression
from mathics.core.symbols import Atom, Symbol, strip_context
from mathics.core.systemsymbols import SymbolGet
from mathics.eval.builtin import definition_contribute

type_compiled_pattern = type(re.compile("a.a"))

Expand Down Expand Up @@ -137,7 +138,7 @@ def __init__(
self.timing_trace_evaluation = False

if add_builtin:
from mathics.builtin import contribute, modules
from mathics.builtin import modules
from mathics.settings import ROOT_DIR

loaded = False
Expand All @@ -149,7 +150,7 @@ def __init__(
self.builtin = pickle.load(builtin_file)
loaded = True
if not loaded:
contribute(self)
definition_contribute(self)
for module in extension_modules:
try:
load_pymathics_module(self, module)
Expand Down
10 changes: 6 additions & 4 deletions mathics/docpipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
Does 2 things which can either be done independently or
as a pipeline:
1. Extracts tests and runs them from static mdoc files and docstrings from Mathics built-in functions
1. Extracts tests and runs them from static mdoc files and docstrings from Mathics
built-in functions
2. Creates/updates internal documentation data
"""

Expand All @@ -21,19 +22,20 @@
import mathics
import mathics.settings
from mathics import settings, version_string
from mathics.builtin import builtins_dict
from mathics.builtin import builtins_by_module
from mathics.core.definitions import Definitions
from mathics.core.evaluation import Evaluation, Output
from mathics.core.parser import MathicsSingleLineFeeder
from mathics.doc.common_doc import MathicsMainDocumentation
from mathics.eval.builtin import builtins_dict
from mathics.eval.pymathics import PyMathicsLoadException, eval_LoadModule
from mathics.timing import show_lru_cache_statistics

builtins = builtins_dict()
builtins = builtins_dict(builtins_by_module)


class TestOutput(Output):
def max_stored_size(self, settings):
def max_stored_size(self, _):
return None


Expand Down
Loading

0 comments on commit 162f729

Please sign in to comment.