Skip to content

Commit

Permalink
Let AstroidManager.clear_cache reload brain plugins (#1528)
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobtylerwalls authored May 4, 2022
1 parent dd37ad3 commit f125fa7
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 12 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Release date: TBA

Closes #1512

* Allowed ``AstroidManager.clear_cache`` to reload necessary brain plugins.

* Rename ``ModuleSpec`` -> ``module_type`` constructor parameter to match attribute
name and improve typing. Use ``type`` instead.

Expand Down
5 changes: 1 addition & 4 deletions astroid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import functools
import tokenize
from importlib import import_module
from pathlib import Path

# isort: off
# We have an isort: off on '__version__' because the packaging need to access
Expand All @@ -49,7 +48,7 @@
from astroid.bases import BaseInstance, BoundMethod, Instance, UnboundMethod
from astroid.brain.helpers import register_module_extender
from astroid.builder import extract_node, parse
from astroid.const import PY310_PLUS, Context, Del, Load, Store
from astroid.const import BRAIN_MODULES_DIRECTORY, PY310_PLUS, Context, Del, Load, Store
from astroid.exceptions import (
AstroidBuildingError,
AstroidBuildingException,
Expand Down Expand Up @@ -193,8 +192,6 @@
tokenize._compile = functools.lru_cache()(tokenize._compile) # type: ignore[attr-defined]

# load brain plugins
ASTROID_INSTALL_DIRECTORY = Path(__file__).parent
BRAIN_MODULES_DIRECTORY = ASTROID_INSTALL_DIRECTORY / "brain"
for module in BRAIN_MODULES_DIRECTORY.iterdir():
if module.suffix == ".py":
import_module(f"astroid.brain.{module.stem}")
5 changes: 5 additions & 0 deletions astroid/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import enum
import sys
from pathlib import Path

PY36 = sys.version_info[:2] == (3, 6)
PY38 = sys.version_info[:2] == (3, 8)
Expand All @@ -30,3 +31,7 @@ class Context(enum.Enum):
Load = Context.Load
Store = Context.Store
Del = Context.Del


ASTROID_INSTALL_DIRECTORY = Path(__file__).parent
BRAIN_MODULES_DIRECTORY = ASTROID_INSTALL_DIRECTORY / "brain"
15 changes: 13 additions & 2 deletions astroid/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
import os
import types
import zipimport
from importlib.util import find_spec, module_from_spec
from typing import TYPE_CHECKING, ClassVar, List, Optional

from astroid.const import BRAIN_MODULES_DIRECTORY
from astroid.exceptions import AstroidBuildingError, AstroidImportError
from astroid.interpreter._import import spec
from astroid.modutils import (
Expand Down Expand Up @@ -360,7 +362,16 @@ def bootstrap(self):

raw_building._astroid_bootstrapping()

def clear_cache(self):
"""Clear the underlying cache. Also bootstraps the builtins module."""
def clear_cache(self) -> None:
"""Clear the underlying cache, bootstrap the builtins module and
re-register transforms."""
self.astroid_cache.clear()
AstroidManager.brain["_transform"] = TransformVisitor()
self.bootstrap()

# Reload brain plugins. During initialisation this is done in astroid.__init__.py
for module in BRAIN_MODULES_DIRECTORY.iterdir():
if module.suffix == ".py":
module_spec = find_spec(f"astroid.brain.{module.stem}")
module_object = module_from_spec(module_spec)
module_spec.loader.exec_module(module_object)
13 changes: 7 additions & 6 deletions tests/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def tearDown(self) -> None:


class AstroidCacheSetupMixin:
"""Mixin for handling the astroid cache problems.
"""Mixin for handling test isolation issues with the astroid cache.
When clearing the astroid cache, some tests fails due to
When clearing the astroid cache, some tests fail due to
cache inconsistencies, where some objects had a different
builtins object referenced.
This saves the builtins module and makes sure to add it
back to the astroid_cache after the tests finishes.
This saves the builtins module and TransformVisitor and
replaces them after the tests finish.
The builtins module is special, since some of the
transforms for a couple of its objects (str, bytes etc)
are executed only once, so astroid_bootstrapping will be
Expand All @@ -52,8 +52,9 @@ class AstroidCacheSetupMixin:
@classmethod
def setup_class(cls):
cls._builtins = AstroidManager().astroid_cache.get("builtins")
cls._transforms = AstroidManager.brain["_transform"]

@classmethod
def teardown_class(cls):
if cls._builtins:
AstroidManager().astroid_cache["builtins"] = cls._builtins
AstroidManager().astroid_cache["builtins"] = cls._builtins
AstroidManager.brain["_transform"] = cls._transforms
9 changes: 9 additions & 0 deletions tests/unittest_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from astroid import manager, test_utils
from astroid.const import IS_JYTHON
from astroid.exceptions import AstroidBuildingError, AstroidImportError
from astroid.nodes import Const

from . import resources

Expand Down Expand Up @@ -315,5 +316,13 @@ def test_borg(self) -> None:
self.assertIs(built, second_built)


class ClearCacheTest(unittest.TestCase, resources.AstroidCacheSetupMixin):
def test_brain_plugins_reloaded_after_clearing_cache(self) -> None:
astroid.MANAGER.clear_cache()
format_call = astroid.extract_node("''.format()")
inferred = next(format_call.infer())
self.assertIsInstance(inferred, Const)


if __name__ == "__main__":
unittest.main()

0 comments on commit f125fa7

Please sign in to comment.