Skip to content

Commit

Permalink
mimic dependencies of lsst.log in lsst.utils
Browse files Browse the repository at this point in the history
lsst.log depends on a couple functions in lsst.utils, and
lsst.utils depends on numpy, but not for functions used by
lsst.log. To reduce the run container size we remove numpy
and "mimic" the functions in lsst.utils, by copying them into
a duplicate module tree and installing into the qserv run image.
  • Loading branch information
n8pease committed Feb 2, 2022
1 parent 737d042 commit 88dfb14
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 4 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ enable_testing()
include(GNUInstallDirs)
set(CMAKE_INSTALL_PREFIX ${PROJECT_BINARY_DIR}/install)

# utils is Python-only, so just install with pip instead of embedded cmake
install(CODE "execute_process(COMMAND pip3 install ${CMAKE_CURRENT_SOURCE_DIR}/extern/utils -t ${CMAKE_INSTALL_PREFIX}/python --no-deps --no-compile)")

add_subdirectory(extern/log)
add_subdirectory(extern/partition)
add_subdirectory(extern/qserv_web)
Expand Down
1 change: 0 additions & 1 deletion admin/tools/docker/base/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ RUN pip3 install \
deprecated \
jinja2 \
mysql-connector-python \
numpy \
pyyaml \
requests \
sqlalchemy
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ add_subdirectory(css)
add_subdirectory(czar)
add_subdirectory(global)
add_subdirectory(memman)
add_subdirectory(mimic)
add_subdirectory(mysql)
add_subdirectory(parser)
add_subdirectory(proto)
Expand Down
1 change: 1 addition & 0 deletions src/mimic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
install(DIRECTORY python/lsst/utils DESTINATION ${CMAKE_INSTALL_PREFIX}/python/lsst/)
9 changes: 9 additions & 0 deletions src/mimic/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
The mimic module has small amounts of python code copied from modules that we do
not want to import all of, because of unused indirect dependencies, or
installation time or size.

For example, lsst.log depends on a couple functions in lsst.utils, and
lsst.utils depends on numpy, but lsst.log does not indirectly depend on numpy;
i.e. lsst.log does not use functions in lsst.utils that depend on numpy. Since
the amount of code used by lsst.log in lsst.utils is small, we copy the code
here.
101 changes: 101 additions & 0 deletions src/mimic/python/lsst/utils/wrappers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# This file is part of qserv.
#
# Developed for the LSST Data Management System.
# This product includes software developed by the LSST Project
# (https://www.lsst.org).
# See the COPYRIGHT file at the top-level directory of this distribution
# for details of code ownership.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

"""This module mimics the lsst.utils.wrappers.py module.
This provides only the dependencies for modules we use (`lsst.log`) and reduces
upstream dependencies, i.e. `lsst.utls` depends on numpy, but we don't need
numpy for the `lsst.utils` functions used by `lsst.log`
"""


import sys


def continueClass(cls):
"""Re-open the decorated class, adding any new definitions into the
original.
For example:
.. code-block:: python
class Foo:
pass
@continueClass
class Foo:
def run(self):
return None
is equivalent to:
.. code-block:: python
class Foo:
def run(self):
return None
.. warning::
Python's built-in `super` function does not behave properly in classes
decorated with `continueClass`. Base class methods must be invoked
directly using their explicit types instead.
"""
orig = getattr(sys.modules[cls.__module__], cls.__name__)
for name in dir(cls):
# Common descriptors like classmethod and staticmethod can only be
# accessed without invoking their magic if we use __dict__; if we use
# getattr on those we'll get e.g. a bound method instance on the dummy
# class rather than a classmethod instance we can put on the target
# class.
attr = cls.__dict__.get(name, None) or getattr(cls, name)
if isAttributeSafeToTransfer(name, attr):
setattr(orig, name, attr)
return orig


INTRINSIC_SPECIAL_ATTRIBUTES = frozenset((
"__qualname__",
"__module__",
"__metaclass__",
"__dict__",
"__weakref__",
"__class__",
"__subclasshook__",
"__name__",
"__doc__",
))


def isAttributeSafeToTransfer(name, value):
"""Return True if an attribute is safe to monkeypatch-transfer to another
class.
This rejects special methods that are defined automatically for all
classes, leaving only those explicitly defined in a class decorated by
`continueClass` or registered with an instance of `TemplateMeta`.
"""
if name.startswith("__") and (value is getattr(object, name, None)
or name in INTRINSIC_SPECIAL_ATTRIBUTES):
return False
return True

0 comments on commit 88dfb14

Please sign in to comment.