Skip to content

Commit 2675d76

Browse files
committed
Update from upstream
Includes the following fixes: - better dealing with @pip_base and @conda_base decorators -- it is now more intuitive and the user does not need to remember if a named environment is a conda or pip one (it will always work) - resolves an issue with pip not honoring platform flags -- we now run pip resolution inside a conda environment with the right python version - improve the speed of using a named environment with no modification (ie: a "clean" named environment) - fix issues with running when none of the environments are cached - make the `metaflow environment` commands more consistent wrt `pathspec`.
1 parent 108f5b4 commit 2675d76

File tree

7 files changed

+660
-188
lines changed

7 files changed

+660
-188
lines changed

metaflow_extensions/netflix_ext/cmd/environment/environment_cmd.py

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,11 @@ def create(
297297
start = time.time()
298298
# We need to install ipykernel into the resolved environment
299299
obj.echo(" Resolving an environment compatible with Jupyter ...", nl=False)
300-
# We don't pin to avoid issues with python versions -- it will take the
301-
# best one it can.
302-
env = cast(Conda, obj.conda).add_to_resolved_env(
300+
301+
# We use envsresolver to properly deal with builder environments and what not
302+
ipy_env_id, ipy_sources, ipy_deps, _, _ = cast(
303+
Conda, obj.conda
304+
).info_for_add_to_resolved_env(
303305
env,
304306
using_steps=["ipykernel"],
305307
deps=[
@@ -309,12 +311,46 @@ def create(
309311
)
310312
],
311313
sources=[],
314+
extras=[],
312315
architecture=arch_id(),
313316
)
314-
# Cache this information for the next time around
315-
cast(Conda, obj.conda).cache_environments([env])
316-
cast(Conda, obj.conda).add_environments([env])
317-
cast(Conda, obj.conda).set_default_environment(env.env_id)
317+
resolver = EnvsResolver(obj.conda)
318+
resolver.add_environment(
319+
ipy_env_id, deps=ipy_deps, sources=ipy_sources, extras=[], base_env=env
320+
)
321+
resolver.resolve_environments(obj.echo)
322+
update_envs = [] # type: List[ResolvedEnvironment]
323+
if obj.datastore_type != "local":
324+
# We may need to update caches
325+
# Note that it is possible that something we needed to resolve, we don't need
326+
# to cache (if we resolved to something already cached).
327+
formats = set() # type: Set[str]
328+
for _, resolved_env, f, _ in resolver.need_caching_environments(
329+
include_builder_envs=True
330+
):
331+
update_envs.append(resolved_env)
332+
formats.update(f)
333+
334+
cast(Conda, obj.conda).cache_environments(
335+
update_envs, {"conda": list(formats)}
336+
)
337+
else:
338+
update_envs = [
339+
resolved_env
340+
for _, resolved_env, _ in resolver.new_environments(
341+
include_builder_envs=True
342+
)
343+
]
344+
cast(Conda, obj.conda).add_environments(update_envs)
345+
346+
# Update the default environment
347+
for env_id, resolved_env, _ in resolver.all_environments(
348+
include_builder_envs=True
349+
):
350+
obj.conda.set_default_environment(resolved_env.env_id)
351+
352+
cast(Conda, obj.conda).write_out_environments()
353+
318354
delta_time = int(time.time() - start)
319355
obj.echo(" done in %d second%s." % (delta_time, plural_marker(delta_time)))
320356

@@ -552,10 +588,10 @@ def resolve(
552588
not base_env or base_env.env_type == EnvType.PIP_ONLY
553589
):
554590
# Assume a pip environment for base deps
555-
pip_deps = get_pinned_conda_libs(base_env_python, obj.datastore_type)
591+
pip_deps = dict(get_pinned_conda_libs(base_env_python, obj.datastore_type))
556592
conda_deps = {}
557593
else:
558-
conda_deps = get_pinned_conda_libs(base_env_python, obj.datastore_type)
594+
conda_deps = dict(get_pinned_conda_libs(base_env_python, obj.datastore_type))
559595
pip_deps = {}
560596

561597
pip_deps.update(base_env_pip_deps)
@@ -618,6 +654,11 @@ def resolve(
618654
sources,
619655
extras,
620656
base_env,
657+
clean_base=(not new_extras)
658+
and (not new_sources)
659+
and (not new_np_conda_deps)
660+
and (not new_conda_deps)
661+
and (not new_pip_deps),
621662
local_only=local_only,
622663
force=force,
623664
force_co_resolve=len(archs) > 1,
@@ -632,7 +673,7 @@ def resolve(
632673
if alias and not dry_run:
633674
# We don't care about arch for aliasing so pick one
634675
obj.echo(
635-
"Not environments to resolve, aliasing only. Use --force to force "
676+
"No environments to resolve, aliasing only. Use --force to force "
636677
"re-resolution"
637678
)
638679
obj.conda.alias_environment(
@@ -681,21 +722,28 @@ def resolve(
681722
# Note that it is possible that something we needed to resolve, we don't need
682723
# to cache (if we resolved to something already cached).
683724
formats = set() # type: Set[str]
684-
for _, resolved_env, f, _ in resolver.need_caching_environments():
725+
for _, resolved_env, f, _ in resolver.need_caching_environments(
726+
include_builder_envs=True
727+
):
685728
update_envs.append(resolved_env)
686729
formats.update(f)
687730

688731
cast(Conda, obj.conda).cache_environments(update_envs, {"conda": list(formats)})
689732
else:
690733
update_envs = [
691-
resolved_env for _, resolved_env, _ in resolver.new_environments()
734+
resolved_env
735+
for _, resolved_env, _ in resolver.new_environments(
736+
include_builder_envs=True
737+
)
692738
]
693739

694740
cast(Conda, obj.conda).add_environments(update_envs)
695741

696742
# Update the default environment
697743
if set_default:
698-
for env_id, resolved_env, _ in resolver.all_environments():
744+
for env_id, resolved_env, _ in resolver.all_environments(
745+
include_builder_envs=True
746+
):
699747
obj.conda.set_default_environment(resolved_env.env_id)
700748

701749
# We are done -- write back out the environments
@@ -715,9 +763,16 @@ def resolve(
715763
default=arch_id(),
716764
help="Show environment for this architecture",
717765
)
766+
@click.option(
767+
"--pathspec",
768+
default=False,
769+
is_flag=True,
770+
show_default=True,
771+
help="The environments given are pathspecs",
772+
)
718773
@click.argument("envs", required=True, nargs=-1)
719774
@click.pass_obj
720-
def show(obj, local_only: bool, arch: str, envs: Tuple[str]):
775+
def show(obj, local_only: bool, arch: str, pathspec: bool, envs: Tuple[str]):
721776
# req-id -> full-id -> List of paths
722777
all_envs = {} # Dict[str, Dict[str, List[str]]]
723778
created_envs = cast(Conda, obj.conda).created_environments()
@@ -727,6 +782,8 @@ def show(obj, local_only: bool, arch: str, envs: Tuple[str]):
727782
]
728783

729784
for env_name in envs:
785+
if pathspec:
786+
env_name = "step:%s" % env_name
730787
resolved_env = cast(Conda, obj.conda).environment_from_alias(
731788
env_name, arch, local_only
732789
)
@@ -768,11 +825,19 @@ def show(obj, local_only: bool, arch: str, envs: Tuple[str]):
768825
default=False,
769826
help="Only resolve source env using local information",
770827
)
828+
@click.option(
829+
"--pathspec",
830+
default=False,
831+
is_flag=True,
832+
show_default=True,
833+
help="The source environment given is a pathspec",
834+
)
771835
@click.argument("source_env")
772836
@click.argument("alias")
773837
@click.pass_obj
774-
def alias(obj, local_only: bool, source_env: str, alias: str):
775-
838+
def alias(obj, local_only: bool, pathspec: bool, source_env: str, alias: str):
839+
if pathspec:
840+
source_env = "step:%s" % source_env
776841
env_id_for_alias = cast(Conda, obj.conda).env_id_from_alias(source_env, local_only)
777842
if env_id_for_alias is None:
778843
raise CommandException(
@@ -797,9 +862,18 @@ def alias(obj, local_only: bool, source_env: str, alias: str):
797862
show_default=True,
798863
help="Request this architecture -- defaults to current architecture if not specified",
799864
)
865+
@click.option(
866+
"--pathspec",
867+
default=False,
868+
is_flag=True,
869+
show_default=True,
870+
help="The environment name given is a pathspec",
871+
)
800872
@click.argument("source_env")
801873
@click.pass_obj
802-
def get(obj, default: bool, arch: Optional[str], source_env: str):
874+
def get(obj, default: bool, arch: Optional[str], pathspec: bool, source_env: str):
875+
if pathspec:
876+
source_env = "step:%s" % source_env
803877
env = cast(Conda, obj.conda).environment_from_alias(source_env, arch)
804878
if env is None:
805879
raise CommandException(

0 commit comments

Comments
 (0)