Skip to content

Dev/support entry point #333

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Feb 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
fee728e
started adding a fix for the entry point
mirkobronzi Nov 7, 2019
e8a0de1
Merge branch 'develop' into dev/support_entry_point
mirkobronzi Nov 8, 2019
380d7b0
Merge remote-tracking branch 'upstream/develop' into dev/support_entr…
mirkobronzi Feb 13, 2020
3b214c8
removed check on entry points
mirkobronzi Feb 13, 2020
578ba70
make flake8 more happy
mirkobronzi Feb 13, 2020
bcc740e
correctly setting user_script
mirkobronzi Feb 13, 2020
94b8bb6
removed redundant check
mirkobronzi Feb 13, 2020
c96a3df
added test for entry point
mirkobronzi Feb 14, 2020
9e12b61
removed entry point test
mirkobronzi Feb 14, 2020
5a9c879
removed check that is not true anymore (after supporting entry points)
mirkobronzi Feb 14, 2020
f2dee40
adding more check for the provided script
mirkobronzi Feb 17, 2020
11c6ec7
make flake8 happy
mirkobronzi Feb 17, 2020
4770045
fixing flake8
mirkobronzi Feb 17, 2020
fe0e588
returning python as script
mirkobronzi Feb 17, 2020
0aaac4c
using shutils instead of distutils
mirkobronzi Feb 18, 2020
b059d83
fixed logic in if
mirkobronzi Feb 18, 2020
3811c86
Merge branch 'develop' into dev/support_entry_point
bouthilx Feb 18, 2020
a05a792
Move user script inference to OrionCmdlineParser
bouthilx Feb 23, 2020
8330b5b
Adapt to new user script inference
bouthilx Feb 23, 2020
2ca4e3c
Merge pull request #5 from bouthilx/dev/support_entry_point
mirkobronzi Feb 24, 2020
c6b4373
Add missing fix for func algo tests
bouthilx Feb 24, 2020
cb7277f
Merge pull request #6 from bouthilx/dev/support_entry_point
mirkobronzi Feb 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/orion/core/io/orion_cmdline_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

from collections import defaultdict, OrderedDict
import copy
import errno
import os
import re
import shutil

from orion.core.io.cmdline_parser import CmdlineParser
from orion.core.io.convert import infer_converter_from_file_type
Expand Down Expand Up @@ -51,6 +54,8 @@ class OrionCmdlineParser():
An OrderedDict obtained by parsing the config file, if one was found.
priors : OrderedDict
An OrderedDict obtained from merging `cmd_priors` and `file_priors`.
user_script : str
File path of the script executed (inferred from parsed commandline)
config_prefix : str
Prefix for the configuration file used by the parser to identify it.
file_config_path : str
Expand All @@ -67,7 +72,7 @@ class OrionCmdlineParser():

"""

def __init__(self, config_prefix='config'):
def __init__(self, config_prefix='config', allow_non_existing_user_script=False):
"""Create an `OrionCmdlineParser`."""
self.parser = CmdlineParser()
self.cmd_priors = OrderedDict()
Expand All @@ -78,6 +83,9 @@ def __init__(self, config_prefix='config'):
self.file_config_path = None
self.converter = None

self.allow_non_existing_user_script = allow_non_existing_user_script
self.user_script = None

# Extraction methods for the file parsing part.
self._extraction_method = {dict: self._extract_dict,
defaultdict: self._extract_defaultdict,
Expand Down Expand Up @@ -126,6 +134,7 @@ def parse(self, commandline):
If a prior inside the commandline and the config file have the same name.

"""
self.infer_user_script(commandline)
replaced = self._replace_priors(commandline)
configuration = self.parser.parse(replaced)
self._build_priors(configuration)
Expand All @@ -135,6 +144,24 @@ def parse(self, commandline):
raise ValueError("Conflict: definition of same prior in commandline and config: "
"{}".format(duplicated_priors))

def infer_user_script(self, user_args):
"""Infer the script name and perform some checks"""
if not user_args:
return

# TODO: Parse commandline for any options to python and pick the script filepath properly
if user_args[0] == 'python':
user_script = user_args[1]
else:
user_script = user_args[0]

if (not os.path.exists(user_script) and not shutil.which(user_script) and
not self.allow_non_existing_user_script):
raise OSError(errno.ENOENT, "The path specified for the script does not exist",
user_script)

self.user_script = user_script

@property
def priors(self):
"""Return an OrderedDict obtained from merging `cmd_priors` and `file_priors`."""
Expand Down
25 changes: 10 additions & 15 deletions src/orion/core/io/resolve_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
.. note:: `Optimization` entries are required, `Dynamic` entry is optional.

"""
import errno
import getpass
import hashlib
import logging
Expand All @@ -44,6 +43,7 @@
import orion
import orion.core
from orion.core import config
from orion.core.io.orion_cmdline_parser import OrionCmdlineParser


def is_exe(path):
Expand Down Expand Up @@ -171,28 +171,23 @@ def fetch_metadata(user=None, user_args=None):
if len(user_args) == 1 and user_args[0] == '':
user_args = []

user_script = user_args[0] if user_args else None
cmdline_parser = OrionCmdlineParser(config.user_script_config)
cmdline_parser.parse(user_args)

if user_script:
abs_user_script = os.path.abspath(user_script)
if is_exe(abs_user_script):
user_script = abs_user_script

if user_script and not os.path.exists(user_script):
raise OSError(errno.ENOENT, "The path specified for the script does not exist", user_script)

if user_script:
metadata['user_script'] = user_script
metadata['VCS'] = infer_versioning_metadata(metadata['user_script'])
if cmdline_parser.user_script:
# TODO: Remove this, it is all in cmdline_parser now
metadata['user_script'] = cmdline_parser.user_script
metadata['VCS'] = infer_versioning_metadata(cmdline_parser.user_script)

if user_args:
metadata['user_args'] = user_args[1:]
# TODO: Remove this, it is all in cmdline_parser now
metadata['user_args'] = user_args

return metadata


def merge_configs(*configs):
"""Merge configuration dictionnaries following the given hierarchy
"""Merge configuration dictionaries following the given hierarchy

Suppose function is called as merge_configs(A, B, C). Then any pair (key, value) in C would
overwrite any previous value from A or B. Same apply for B over A.
Expand Down
19 changes: 0 additions & 19 deletions src/orion/core/io/space_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
from scipy.stats import distributions as sp_dists

from orion.algo.space import (Categorical, Fidelity, Integer, Real, Space)
from orion.core import config as orion_config
from orion.core.io.orion_cmdline_parser import OrionCmdlineParser
from orion.core.utils.flatten import flatten


Expand Down Expand Up @@ -258,23 +256,6 @@ def __init__(self):
self.converter = None
self.parser = None

def build_from(self, config):
"""Build a `Space` object from a configuration.

Initialize a new parser for this commandline and parse the given config then
build a `Space` object from that configuration.

Returns
-------
`orion.algo.space.Space`
The problem's search space definition.

"""
self.parser = OrionCmdlineParser(orion_config.user_script_config)
self.parser.parse(config)

return self.build(self.parser.priors)

def build(self, configuration):
"""Create a definition of the problem's search space.

Expand Down
11 changes: 10 additions & 1 deletion src/orion/core/utils/backward.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,21 @@
from orion.core.io.orion_cmdline_parser import OrionCmdlineParser


def update_user_args(metadata):
"""Make sure user script is not removed from metadata"""
if "user_script" in metadata and metadata["user_script"] not in metadata["user_args"]:
metadata["user_args"] = [metadata["user_script"]] + metadata["user_args"]


def populate_priors(metadata):
"""Compute parser state and priors based on user_args and populate metadata."""
if 'user_args' not in metadata:
return

parser = OrionCmdlineParser(orion.core.config.user_script_config)
update_user_args(metadata)

parser = OrionCmdlineParser(orion.core.config.user_script_config,
allow_non_existing_user_script=True)
parser.parse(metadata["user_args"])
metadata["parser"] = parser.get_state_dict()
metadata["priors"] = dict(parser.priors)
Expand Down
5 changes: 2 additions & 3 deletions src/orion/core/worker/consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ def __init__(self, experiment):
else:
self.working_dir = os.path.join(tempfile.gettempdir(), 'orion')

self.script_path = experiment.metadata['user_script']

self.pacemaker = None

def consume(self, trial):
Expand Down Expand Up @@ -186,9 +184,10 @@ def _consume(self, trial, workdirname):

return results_file

# pylint: disable = no-self-use
def execute_process(self, cmd_args, environ):
"""Facilitate launching a black-box trial."""
command = [self.script_path] + cmd_args
command = cmd_args

signal.signal(signal.SIGTERM, _handler)
process = subprocess.Popen(command, env=environ)
Expand Down
8 changes: 3 additions & 5 deletions tests/functional/algos/test_algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ def test_simple(monkeypatch, config_file):
assert 'datetime' in exp['metadata']
assert 'orion_version' in exp['metadata']
assert 'user_script' in exp['metadata']
assert os.path.isabs(exp['metadata']['user_script'])
assert exp['metadata']['user_args'] == ['-x~uniform(-50, 50)']
assert exp['metadata']['user_args'] == ['./black_box.py', '-x~uniform(-50, 50)']

trials = storage.fetch_trials(uid=exp_id)
assert len(trials) <= config['max_trials']
Expand Down Expand Up @@ -97,9 +96,8 @@ def test_with_fidelity(database, monkeypatch, config_file):
assert 'datetime' in exp['metadata']
assert 'orion_version' in exp['metadata']
assert 'user_script' in exp['metadata']
assert os.path.isabs(exp['metadata']['user_script'])
assert exp['metadata']['user_args'] == ['-x~uniform(-50, 50, precision=None)',
"--fidelity~fidelity(1,10,4)"]
assert exp['metadata']['user_args'] == ['./black_box.py', '-x~uniform(-50, 50, precision=None)',
'--fidelity~fidelity(1,10,4)']

trials = storage.fetch_trials(uid=exp_id)
assert len(trials) <= config['max_trials']
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/branching/black_box_new.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def execute():
# 1. Receive inputs as you want
parser = argparse.ArgumentParser()
parser.add_argument('-x', type=float, required=True)
parser.add_argument('--a-new', type=str, required=True)
parser.add_argument('--a-new', type=str)
inputs = parser.parse_args()

# 2. Perform computations
Expand Down
32 changes: 22 additions & 10 deletions tests/functional/branching/test_branching.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def init_full_x_full_y(init_full_x):
name = "full_x"
branch = "full_x_full_y"
orion.core.cli.main(
("init_only -n {branch} --branch-from {name} ./black_box_with_y.py "
("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box_with_y.py "
"-x~uniform(-10,10) "
"-y~+uniform(-10,10,default_value=1)").format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=1 -y=1".format(branch=branch).split(" "))
Expand Down Expand Up @@ -73,7 +74,8 @@ def init_full_x_rename_y_z(init_full_x_full_y):
"""Rename y from full x full y to z"""
name = "full_x_full_y"
branch = "full_x_rename_y_z"
orion.core.cli.main(("init_only -n {branch} --branch-from {name} ./black_box_with_z.py "
orion.core.cli.main(("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box_with_z.py "
"-x~uniform(-10,10) -y~>z -z~uniform(-10,10,default_value=1)"
).format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=4 -z=4".format(branch=branch).split(" "))
Expand All @@ -87,7 +89,8 @@ def init_full_x_rename_half_y_half_z(init_full_x_half_y):
"""Rename y from full x half y to z"""
name = "full_x_half_y"
branch = "full_x_rename_half_y_half_z"
orion.core.cli.main(("init_only -n {branch} --branch-from {name} ./black_box_with_z.py "
orion.core.cli.main(("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box_with_z.py "
"-x~uniform(-10,10) -y~>z -z~uniform(0,10,default_value=1)"
).format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=5 -z=5".format(branch=branch).split(" "))
Expand All @@ -100,7 +103,8 @@ def init_full_x_rename_half_y_full_z(init_full_x_half_y):
name = "full_x_half_y"
branch = "full_x_rename_half_y_full_z"
orion.core.cli.main(
("init_only -n {branch} --branch-from {name} ./black_box_with_z.py "
("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box_with_z.py "
"-x~uniform(-10,10) -y~>z "
"-z~+uniform(-10,10,default_value=1)").format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=6 -z=6".format(branch=branch).split(" "))
Expand All @@ -115,7 +119,8 @@ def init_full_x_remove_y(init_full_x_full_y):
name = "full_x_full_y"
branch = "full_x_remove_y"
orion.core.cli.main(
("init_only -n {branch} --branch-from {name} ./black_box.py "
("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box.py "
"-x~uniform(-10,10) -y~-").format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=7".format(branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=-7".format(branch=branch).split(" "))
Expand All @@ -127,7 +132,8 @@ def init_full_x_remove_z(init_full_x_rename_y_z):
name = "full_x_rename_y_z"
branch = "full_x_remove_z"
orion.core.cli.main(
("init_only -n {branch} --branch-from {name} ./black_box.py "
("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box.py "
"-x~uniform(-10,10) -z~-").format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=8".format(branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=-8".format(branch=branch).split(" "))
Expand All @@ -139,7 +145,8 @@ def init_full_x_remove_z_default_4(init_full_x_rename_y_z):
name = "full_x_rename_y_z"
branch = "full_x_remove_z_default_4"
orion.core.cli.main(
("init_only -n {branch} --branch-from {name} ./black_box.py "
("init_only -n {branch} --branch-from {name} --cli-change-type noeffect "
"./black_box.py "
"-x~uniform(-10,10) -z~-4").format(name=name, branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=9".format(branch=branch).split(" "))
orion.core.cli.main("insert -n {branch} script -x=-9".format(branch=branch).split(" "))
Expand Down Expand Up @@ -173,10 +180,15 @@ def init_full_x_new_cli(init_full_x):
@pytest.fixture
def init_full_x_ignore_cli(init_full_x):
"""Use the --non-monitored-arguments argument"""
name = "full_x"
name = "full_x_with_new_opt"
orion.core.cli.main(("init_only -n {name} --config orion_config.yaml ./black_box_new.py "
"-x~uniform(-10,10)").format(name=name).split(" "))
orion.core.cli.main("insert -n {name} script -x=0".format(name=name).split(" "))

orion.core.cli.main(
("init_only -n {name} --non-monitored-arguments a-new --cli-change-type noeffect "
"./black_box_new.py -x~uniform(-10,10) --a-new argument").format(name=name).split(" "))
("init_only -n {name} --non-monitored-arguments a-new "
"--config orion_config.yaml ./black_box_new.py "
"-x~uniform(-10,10) --a-new argument").format(name=name).split(" "))
orion.core.cli.main("insert -n {name} script -x=1.2".format(name=name).split(" "))
orion.core.cli.main("insert -n {name} script -x=-1.2".format(name=name).split(" "))

Expand Down
Loading