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

Move mathics.core.builtin initialization code into system_initialize() #648

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions examples/symbolic_logic/gries_schneider/test_gs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
from mathics.core.definitions import Definitions
from mathics.core.evaluation import Evaluation
from mathics.core.parser import MathicsSingleLineFeeder, parse
from mathics.core.system_init import initialize_system

initialize_system()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This routine is called each time Definitions(add_builtins=True) is called. And what it essentially does is to initialize (a part of) the mathics.builtins module, so if you do not call it, Definitions(add_builtins=True) can not do what it is expected. So, should not be better either
a) call it in mathics.buitlin.__init__ module.
b) import it (locally) and call it in mathics.core.definitions.Definitions.__init__, if the add_builtins==True?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to resolve. I don't like a) because we want to remove stuff from mathics.builtin.__init__ - that is the whole point of this.

We want a function, initialize_system() that is explicitly called that will load will initialize all predefined Builtins.

Once that is done, we are in a position to write a routine to dump out all of this to say a pickle file and then we have the possibility to replace that code with code that reads in the dumped information instead.

Equally important, this is conceptually simpler, and coding-wise we don't have critical stuff or magic code inside the an __init__ module.

definitions = Definitions(add_builtin=True)

for i in range(0, 4):
Expand Down
120 changes: 16 additions & 104 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 @@ -20,13 +20,10 @@
among other things.
"""

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

from mathics.builtin.base import (
Builtin,
Expand All @@ -36,15 +33,18 @@
mathics_to_python,
)
from mathics.core.pattern import pattern_objects
from mathics.core.system_init import get_builtin_pyfiles, 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.
__py_files__ = [
osp.basename(f[0:-3])
for f in glob.glob(osp.join(osp.dirname(__file__), "[a-z]*.py"))
]
__py_files__ = get_builtin_pyfiles()

mathics_to_sympy = {} # here we have: name -> sympy object
sympy_to_mathics = {}
builtins_list = []

builtins_precedence = {}

system_builtins = {}


def add_builtins(new_builtins):
Expand All @@ -63,35 +63,7 @@ def add_builtins(new_builtins):
builtins_precedence[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)
system_builtins.update(dict(new_builtins))


def import_builtins(module_names: List[str], submodule_name=None) -> None:
Expand Down Expand Up @@ -125,48 +97,6 @@ def import_module(module_name: str, import_name: str):
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

# FIXME: tests involving module_object.__module__ are fragile and
# Python implementation specific. Figure out how to do this
# via the inspect module which is not implementation specific.

# Skip those builtins defined in or imported from another module.
if module_object.__module__ != module.__name__:
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."):
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 = [
Expand All @@ -176,7 +106,6 @@ def name_is_builtin_symbol(module, name: str) -> Optional[type]:
modules = []
import_builtins(module_names)

_builtins_list = []
builtins_by_module = {}

disable_file_module_names = (
Expand Down Expand Up @@ -232,25 +161,8 @@ def name_is_builtin_symbol(module, name: str) -> Optional[type]:
# This set the default context for symbols in mathics.builtins
if not type(instance).context:
type(instance).context = "System`"
_builtins_list.append((instance.get_name(), instance))
builtins_by_module[module.__name__].append(instance)

mathics_to_sympy = {} # here we have: name -> sympy object
sympy_to_mathics = {}

builtins_precedence = {}

new_builtins = _builtins_list

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

add_builtins(new_builtins)
builtins_list.append((instance.get_name(), instance))
builtins_by_module[module.__name__].append(instance)

display_operators_set = set()
for modname, builtins in builtins_by_module.items():
for builtin in builtins:
# name = builtin.get_name()
operator = builtin.get_operator_display()
if operator is not None:
display_operators_set.add(operator)
add_builtins(builtins_list)
3 changes: 2 additions & 1 deletion mathics/core/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Symbol,
strip_context,
)
from mathics.core.system_init import contribute
from mathics.core.systemsymbols import SymbolGet

from mathics_scanner.tokeniser import full_names_pattern
Expand Down Expand Up @@ -130,7 +131,7 @@ def __init__(
self.timing_trace_evaluation = False

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

loaded = False
Expand Down
3 changes: 1 addition & 2 deletions mathics/core/pymathics.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@


from mathics.core.evaluation import Evaluation
from mathics.core.system_init import builtins_by_module, name_is_builtin_symbol

# This dict probably does not belong here.
pymathics = {}
Expand All @@ -22,7 +23,6 @@ def __init__(self, module):
# Why do we need this?
def eval_clear_pymathics_modules():
global pymathics
from mathics.builtin import builtins_by_module

for key in list(builtins_by_module.keys()):
if not key.startswith("mathics."):
Expand Down Expand Up @@ -61,7 +61,6 @@ def load_pymathics_module(definitions, module):
"""
from mathics.builtin import (
builtins_by_module,
name_is_builtin_symbol,
Builtin,
)

Expand Down
Loading