From 9e2927501010093f8313ce35d5bfb45758f91436 Mon Sep 17 00:00:00 2001 From: Gonzalo Casas Date: Wed, 4 Nov 2020 01:36:35 +0100 Subject: [PATCH 1/3] closes #649: remove usage of ABCMeta to prevent performance issues on IronPython --- src/compas/base.py | 31 +++++++++++--------- src/compas/datastructures/_mutablemapping.py | 4 ++- src/compas/robots/base_artist/_artist.py | 7 +---- src/compas_ghpython/artists/_artist.py | 9 ++---- src/compas_rhino/artists/_artist.py | 8 ++--- src/compas_rhino/forms/base.py | 10 ++----- src/compas_rhino/geometry/_geometry.py | 8 ++--- src/compas_rhino/objects/_object.py | 20 ++++--------- 8 files changed, 35 insertions(+), 62 deletions(-) diff --git a/src/compas/base.py b/src/compas/base.py index 4718c41a774b..b776ad81dee5 100644 --- a/src/compas/base.py +++ b/src/compas/base.py @@ -1,21 +1,28 @@ +""" +If you ever feel tempted to use ABCMeta in your code: don't, just DON'T. +Assigning __metaclass__ = ABCMeta to a class causes a severe memory leak/performance +degradation on IronPython 2.7. + +See these issues for more details: + - https://github.com/compas-dev/compas/issues/562 + - https://github.com/compas-dev/compas/issues/649 +""" from __future__ import print_function from __future__ import absolute_import from __future__ import division -import abc import json from uuid import uuid4 from compas.utilities import DataEncoder from compas.utilities import DataDecoder -from compas.utilities import abstractclassmethod - -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) __all__ = [ 'Base', ] +import abc +ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) class Base(ABC): @@ -73,24 +80,22 @@ def dtype(self): """ return "{}/{}".format(".".join(self.__class__.__module__.split(".")[:2]), self.__class__.__name__) - @abc.abstractproperty + @property def data(self): """dict : The representation of the object as native Python data. The structure uf the data is described by the data schema. """ - pass + raise NotImplementedError @data.setter def data(self, data): pass - @abstractclassmethod def from_data(cls, data): """Construct an object of this type from the provided data.""" - pass + raise NotImplementedError - @abc.abstractmethod def to_data(self): """Convert an object to its native data representation. @@ -99,9 +104,8 @@ def to_data(self): dict The data representation of the object as described by the schema. """ - pass + raise NotImplementedError - @abstractclassmethod def from_json(cls, filepath): """Construct an object from serialised data contained in a JSON file. @@ -110,9 +114,8 @@ def from_json(cls, filepath): filepath: str The path to the file for serialisation. """ - pass + raise NotImplementedError - @abc.abstractmethod def to_json(self, filepath): """Serialize the data representation of an object to a JSON file. @@ -121,7 +124,7 @@ def to_json(self, filepath): filepath: str The path to the file containing the data. """ - pass + raise NotImplementedError def __getstate__(self): """Return the object data for state state serialisation with older pickle protocols.""" diff --git a/src/compas/datastructures/_mutablemapping.py b/src/compas/datastructures/_mutablemapping.py index 6715f3f875f2..504955c0e82f 100644 --- a/src/compas/datastructures/_mutablemapping.py +++ b/src/compas/datastructures/_mutablemapping.py @@ -5,7 +5,9 @@ * The Mapping class does not have a __metaclass__ = ABCMeta set because this causes performance issues on IronPython 2.7.x -See this issue for more details: https://github.com/compas-dev/compas/issues/562 +See these issues for more details: + - https://github.com/compas-dev/compas/issues/562 + - https://github.com/compas-dev/compas/issues/649 """ from __future__ import absolute_import from __future__ import division diff --git a/src/compas/robots/base_artist/_artist.py b/src/compas/robots/base_artist/_artist.py index 4df7c96cfe60..5211d7458341 100644 --- a/src/compas/robots/base_artist/_artist.py +++ b/src/compas/robots/base_artist/_artist.py @@ -2,7 +2,6 @@ from __future__ import division from __future__ import print_function -import abc import itertools from compas.geometry import Frame @@ -10,16 +9,13 @@ from compas.geometry import Transformation from compas.robots import Geometry -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - __all__ = [ 'BaseRobotModelArtist' ] -class AbstractRobotModelArtist(ABC): - @abc.abstractmethod +class AbstractRobotModelArtist(object): def transform(self, geometry, transformation): """Transforms a CAD-specific geometry using a **COMPAS** transformation. @@ -32,7 +28,6 @@ def transform(self, geometry, transformation): """ raise NotImplementedError - @abc.abstractmethod def draw_geometry(self, geometry, name=None, color=None): """Draw a **COMPAS** geometry in the respective CAD environment. diff --git a/src/compas_ghpython/artists/_artist.py b/src/compas_ghpython/artists/_artist.py index 189a042b153c..57a640a7a121 100644 --- a/src/compas_ghpython/artists/_artist.py +++ b/src/compas_ghpython/artists/_artist.py @@ -2,24 +2,19 @@ from __future__ import absolute_import from __future__ import division -import abc - -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - __all__ = ["BaseArtist"] -class BaseArtist(ABC): +class BaseArtist(object): """Abstract base class for all GH artists. """ def __init__(self): pass - @abc.abstractmethod def draw(self): - pass + raise NotImplementedError @staticmethod def draw_collection(collection): diff --git a/src/compas_rhino/artists/_artist.py b/src/compas_rhino/artists/_artist.py index 975e5025b2f4..1ee5006fb2c0 100644 --- a/src/compas_rhino/artists/_artist.py +++ b/src/compas_rhino/artists/_artist.py @@ -2,11 +2,8 @@ from __future__ import absolute_import from __future__ import division -import abc import compas_rhino -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - __all__ = ["BaseArtist"] @@ -14,7 +11,7 @@ _ITEM_ARTIST = {} -class BaseArtist(ABC): +class BaseArtist(object): """Base class for all Rhino artists. Attributes @@ -51,9 +48,8 @@ def build(item, **kwargs): artist = artist_type(item, **kwargs) return artist - @abc.abstractmethod def draw(self): - pass + raise NotImplementedError def redraw(self): compas_rhino.rs.EnableRedraw(True) diff --git a/src/compas_rhino/forms/base.py b/src/compas_rhino/forms/base.py index 3f383cf75943..f4b54f6d5119 100644 --- a/src/compas_rhino/forms/base.py +++ b/src/compas_rhino/forms/base.py @@ -2,8 +2,6 @@ from __future__ import absolute_import from __future__ import division -import abc - import System from System.Windows.Forms import DialogResult from System.Windows.Forms import FormBorderStyle @@ -11,13 +9,10 @@ import Rhino -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - - __all__ = ['BaseForm'] -class BaseForm(System.Windows.Forms.Form, ABC): +class BaseForm(System.Windows.Forms.Form): """Base class for Windows forms.""" def __init__(self, title='Form', width=None, height=None): @@ -33,9 +28,8 @@ def __init__(self, title='Form', width=None, height=None): self.ResumeLayout() self.FormClosed += self.on_form_closed - @abc.abstractmethod def init(self): - pass + raise NotImplementedError def show(self): """Show the form as a modal dialog. diff --git a/src/compas_rhino/geometry/_geometry.py b/src/compas_rhino/geometry/_geometry.py index bc6c923c114d..658f4627509b 100644 --- a/src/compas_rhino/geometry/_geometry.py +++ b/src/compas_rhino/geometry/_geometry.py @@ -2,19 +2,16 @@ from __future__ import absolute_import from __future__ import division -import abc import Rhino import compas_rhino from compas.utilities import abstractclassmethod -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - __all__ = ['BaseRhinoGeometry'] -class BaseRhinoGeometry(ABC): +class BaseRhinoGeometry(object): """Base class for Rhino geometry objects. Attributes @@ -107,9 +104,8 @@ def from_geometry(cls, geometry): def from_selection(cls): pass - @abc.abstractmethod def to_compas(self, cls=None): - pass + raise NotImplementedError def transform(self, T): """Transform the Rhino object. diff --git a/src/compas_rhino/objects/_object.py b/src/compas_rhino/objects/_object.py index 00267af6b56b..26f61d476383 100644 --- a/src/compas_rhino/objects/_object.py +++ b/src/compas_rhino/objects/_object.py @@ -2,12 +2,9 @@ from __future__ import division from __future__ import print_function -import abc from uuid import uuid4 from compas_rhino.artists import BaseArtist -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) - __all__ = ['BaseObject'] @@ -15,7 +12,7 @@ _ITEM_OBJECT = {} -class BaseObject(ABC): +class BaseObject(object): """Abstract base class for COMPAS Rhino objects. Parameters @@ -133,38 +130,33 @@ def build(item, **kwargs): object_type = _ITEM_OBJECT[type(item)] return object_type(item, **kwargs) - @abc.abstractmethod def clear(self): """Clear all previously created Rhino objects.""" - pass + raise NotImplementedError def clear_layer(self): """Clear the layer of the object.""" self.artist.clear_layer() - @abc.abstractmethod def draw(self): """Draw the object representing the item.""" - pass + raise NotImplementedError def redraw(self): """Redraw the Rhino scene/view.""" self.artist.redraw() - @abc.abstractmethod def select(self): """Select the object representing the item.""" - pass + raise NotImplementedError - @abc.abstractmethod def modify(self): """Modify the item represented by the object.""" - pass + raise NotImplementedError - @abc.abstractmethod def move(self): """Move the item represented by the object.""" - pass + raise NotImplementedError # ============================================================================ From 64c45a1779cde278920611f4dbf5b745b68adacf Mon Sep 17 00:00:00 2001 From: Gonzalo Casas Date: Wed, 4 Nov 2020 01:40:15 +0100 Subject: [PATCH 2/3] Add changelog item --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa876b1887a..153b72875444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * Fixed bug in `__getstate__`, `__setstate__` of `compas.base.Base`. +* Removed `ABCMeta` from the list of base clases of several objects in compas. ### Removed From c475f1524ce73ad11e66a08f1a79605410d24907 Mon Sep 17 00:00:00 2001 From: Tom Van Mele Date: Wed, 4 Nov 2020 08:20:41 +0100 Subject: [PATCH 3/3] remove ABC from base --- src/compas/base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compas/base.py b/src/compas/base.py index b776ad81dee5..7137b57f8627 100644 --- a/src/compas/base.py +++ b/src/compas/base.py @@ -21,11 +21,13 @@ __all__ = [ 'Base', ] -import abc -ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) -class Base(ABC): +# import abc +# ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) + + +class Base(object): """Abstract base class for all COMPAS objects. Attributes