Source code for caikit.core.toolkit.compatibility
# Copyright The Caikit Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Standard
import importlib
import sys
# First Party
import alog
# Local
from ..exceptions import error_handler
log = alog.use_channel("COMPATIBILITY")
error = error_handler.get(log)
[docs]
def unsupported_platforms(platforms):
"""This decorator can be used to raise NotImplementedError if it's run on a given platform.
Otherwise it runs as normal. For guidance on different permissible values of platforms,
see: https://docs.python.org/3/library/sys.html#sys.platform
Args:
platforms (List | Tuple | str): Platforms on which this capability is
not implemented.
"""
error.type_check("<COR48137162E>", list, tuple, str, platforms=platforms)
if not isinstance(platforms, str):
error.type_check_all("<COR92928316E>", str, platforms=platforms)
def decorator(func):
def wrapper(*args, **kwargs):
if (
isinstance(platforms, str) and sys.platform == platforms
) or sys.platform in platforms:
error(
"<COR12233351E>",
NotImplementedError(
"Operation [{}] has not been implemented for platform [{}]".format(
func.__name__, sys.platform
)
),
)
return func(*args, **kwargs)
return wrapper
return decorator
[docs]
def is_importable_on_platform(module, package, exc_type, platforms, platform_hint):
"""Some modules have trouble on specific operating systems. This function takes
a module and package from which we want to import, and an exception type to look
out for on a given problem. If the exception is raised, we warn the platform hint.
NOTE: This function does set any properties on your package. You should use this
function to check if something is importable, then you should import it. This will
only run the package initialization one time, because this function will add your
module into the loaded packages if it's successful, but doing things this way prevents
your package from having a bunch of undesirable attributes and keeps it cleaner than other
approaches. It also ensures that the import stack trace doesn't look abnormally handled if we
raise on other platforms.
Args:
module (str): Module that we want to import.
package (str): Package from which we want to import the module.
exc_type (Exception): Exception that we want to warn a hint for if we
hit it on import for a given platform.
platforms (str): Platform on which we expect potential bad import from
for this module.
platform_hint (str): Hint to warn if we hit the exception type on the
provided platform.
"""
error.type_check(
"<COR48442162E>",
str,
module=module,
package=package,
platform_hint=platform_hint,
)
error.type_check("<COR62245359E>", list, tuple, str, platforms=platforms)
if not isinstance(platforms, str):
error.type_check_all("<COR86935489E>", str, platforms=platforms)
# If this is not a platform that needs special handling, just return True
if (
isinstance(platforms, str) and sys.platform != platforms
) or sys.platform not in platforms:
return True
# We are running on a platform that has potential issues for this module.
# If we succeed on import, return True. If we throw the known exception type,
# catch it and log the hint, then return False. This is non-fatal.
try:
log.debug(
"Determining if module {} is importable on platform {}".format(
module, platforms
)
)
importlib.import_module(module, package)
return True
except exc_type as e:
log.warning(
"Module [{}] from package [{}] failed to import on platform [{}]"
" with error [{}] and will not be available.\nHINT: {}".format(
module, package, platforms, str(e), platform_hint
)
)
return False