Skip to content

Commit

Permalink
Merge 31833d5 into 6b177b3
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieldemarmiesse committed Aug 2, 2019
2 parents 6b177b3 + 31833d5 commit a17b84e
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 71 deletions.
80 changes: 15 additions & 65 deletions sacred/commandline_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,63 +7,14 @@
Some further options that add observers to the run are defined alongside those.
"""

import warnings

from sacred.commands import print_config
from sacred.settings import SETTINGS
from sacred.utils import (convert_camel_case_to_snake_case, get_inheritors,
module_exists)


# from six.with_metaclass
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
class Metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(Metaclass, 'temporary_class', (), {})


def parse_mod_deps(depends_on):
if not isinstance(depends_on, (list, tuple)):
depends_on = [depends_on]
module_names = []
package_names = []
for d in depends_on:
mod, _, pkg = d.partition('#')
module_names.append(mod)
package_names.append(pkg or mod)
return module_names, package_names


class CheckDependencies(type):
"""Modifies the CommandLineOption if a specified dependency is not met."""
def __init__(cls, what, bases=None, dict_=None): # noqa
if '__depends_on__' in dict_:
mod_names, package_names = parse_mod_deps(dict_['__depends_on__'])
mods_exist = [module_exists(m) for m in mod_names]

if not all(mods_exist):
missing_pkgs = [p for p, x in zip(package_names, mods_exist)
if not x]
if len(missing_pkgs) > 1:
error_msg = '{} depends on missing [{}] packages.'.format(
cls.__name__, ", ".join(missing_pkgs))
else:
error_msg = '{} depends on missing "{}" package.'.format(
cls.__name__, missing_pkgs[0])

def _apply(cls, args, run):
raise ImportError(error_msg)
cls.__doc__ = '( ' + error_msg + ')'
cls.apply = classmethod(_apply)
cls._enabled = False

type.__init__(cls, what, bases, dict_)


class CommandLineOption(with_metaclass(CheckDependencies, object)):
from sacred.utils import convert_camel_case_to_snake_case, get_inheritors


class CommandLineOption:
"""
Base class for all command-line options.
Expand All @@ -77,14 +28,9 @@ class CommandLineOption(with_metaclass(CheckDependencies, object)):
value of the argument (if applicable) and the current run. You can modify
the run object in any way.
If the command line option depends on one or more installed packages, this
should be specified as the `__depends_on__` attribute.
It can be either a string with the name of the module, or a list/tuple of
such names.
If the module name (import name) differs from the name of the package, the
latter can be specified using a '#' to improve the description and error
message.
For example `__depends_on__ = 'git#GitPython'`.
If the command line option depends on one or more installed packages, those
should be imported in the `apply` method to get a proper ImportError
if the packages are not available.
"""

_enabled = True
Expand Down Expand Up @@ -282,10 +228,14 @@ def apply(cls, args, run):
class EnforceCleanOption(CommandLineOption):
"""Fail if any version control repository is dirty."""

__depends_on__ = 'git#GitPython'

@classmethod
def apply(cls, args, run):
try:
import git
except ImportError:
warnings.warn('GitPython must be installed to use the '
'--enforce-clean option.')
raise
repos = run.experiment_info['repositories']
if not repos:
raise RuntimeError('No version control detected. '
Expand Down
2 changes: 0 additions & 2 deletions sacred/observers/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,8 +352,6 @@ def __eq__(self, other):
class MongoDbOption(CommandLineOption):
"""Add a MongoDB Observer to the experiment."""

__depends_on__ = 'pymongo'

arg = 'DB'
arg_description = "Database specification. Can be " \
"[host:port:]db_name[.collection[:id]][!priority]"
Expand Down
1 change: 0 additions & 1 deletion sacred/observers/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ def __eq__(self, other):

class SqlOption(CommandLineOption):
"""Add a SQL Observer to the experiment."""
__depends_on__ = 'sqlalchemy'

arg = 'DB_URL'
arg_description = \
Expand Down
3 changes: 0 additions & 3 deletions sacred/observers/tinydb_hashfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,6 @@ def __eq__(self, other):
class TinyDbOption(CommandLineOption):
"""Add a TinyDB Observer to the experiment."""

__depends_on__ = ['tinydb', 'hashfs',
'tinydb_serialization#tinydb-serialization']

arg = 'BASEDIR'

@classmethod
Expand Down

0 comments on commit a17b84e

Please sign in to comment.