Skip to content
This repository has been archived by the owner on Sep 13, 2023. It is now read-only.

Add -c help WIP #363

Merged
merged 41 commits into from
Sep 8, 2022
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
46226d9
Add -c help to declare WIP
mike0sv Jul 25, 2022
30c8fcb
extrapolate for other commands
mike0sv Aug 9, 2022
869c4ea
some field docs and little improvements
mike0sv Aug 10, 2022
9dd465d
cli utils
mike0sv Aug 16, 2022
e929c5e
add simple_parsing
mike0sv Aug 16, 2022
ad6ff49
Merge branch 'main' into feature/cli-conf-help
mike0sv Aug 16, 2022
36de86e
fix tests
mike0sv Aug 16, 2022
b9bb837
fix tests
mike0sv Aug 16, 2022
5f6ba80
lazy help
mike0sv Aug 17, 2022
ae6be81
ooopsie
mike0sv Aug 17, 2022
61faf1d
class and fields docstrings
mike0sv Aug 17, 2022
93e96d8
reparsing cli params for nested complex objects
mike0sv Aug 17, 2022
751169f
fix for py37
mike0sv Aug 17, 2022
aa68263
support lists in build_model
mike0sv Aug 18, 2022
ffc012a
support lists in cli
mike0sv Aug 18, 2022
346f0f5
nested options WIP
mike0sv Aug 20, 2022
470902b
very nested options WIP
mike0sv Aug 21, 2022
9d6cbc1
all but flat nested WIP
mike0sv Aug 21, 2022
4ef61e6
lil refactoring
mike0sv Aug 21, 2022
b9a9fe2
flat nested stuff DONE
mike0sv Aug 21, 2022
27aa37d
Update mlem/contrib/heroku/build.py
mike0sv Aug 21, 2022
8f2800e
Update mlem/cli/declare.py
mike0sv Aug 21, 2022
cb9ad77
get rid of --conf, add mlem abc to declare
mike0sv Aug 21, 2022
460b889
fix tests
mike0sv Aug 21, 2022
18f30f9
fix lazyness
mike0sv Aug 21, 2022
7025fbd
fix serialization
mike0sv Aug 22, 2022
51f4865
fix tests
mike0sv Aug 22, 2022
e36fcaf
fix tests
mike0sv Aug 22, 2022
fa79e69
Update bitbucketfs.py
aguschin Aug 29, 2022
9348694
Apply suggestions from code review
aguschin Aug 29, 2022
72ed848
Merge branch 'main' into feature/cli-conf-help
mike0sv Aug 29, 2022
51926f2
fix comments and disable failfast for gh actions
mike0sv Aug 30, 2022
f7920c7
backport docs from mlem.ai
mike0sv Sep 3, 2022
0fd0bcf
sort import choices
mike0sv Sep 5, 2022
ee30197
merge
mike0sv Sep 5, 2022
ae26778
make run_cmd optional instead of bool
mike0sv Sep 5, 2022
5be78bf
docs for torch import
mike0sv Sep 5, 2022
645c0b6
allow --load for groups
mike0sv Sep 6, 2022
661c8c6
fix windows bugs
mike0sv Sep 6, 2022
f25630b
suddenly fix dockerhub requests
mike0sv Sep 7, 2022
cc8dc50
suddenly fix dockerhub requests
mike0sv Sep 7, 2022
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
2 changes: 1 addition & 1 deletion .github/workflows/check-test-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
# no HDF5 support installed for tables
- os: windows-latest
python: "3.9"
fail-fast: true
fail-fast: false
steps:
- uses: actions/checkout@v3
with:
Expand Down
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ ignore-comments=yes
ignore-docstrings=yes

# Ignore imports when computing similarities.
ignore-imports=no
ignore-imports=yes

# Ignore function signatures when computing similarities.
ignore-signatures=no
Expand Down
114 changes: 76 additions & 38 deletions mlem/cli/apply.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from json import dumps
from typing import List, Optional

from typer import Argument, Option
from typer import Argument, Option, Typer

from mlem.api import import_object
from mlem.cli.main import (
config_arg,
app,
mlem_command,
option_conf,
mlem_group,
option_data_project,
option_data_rev,
option_external,
Expand All @@ -20,6 +20,12 @@
option_rev,
option_target_project,
)
from mlem.cli.utils import (
abc_fields_parameters,
config_arg,
for_each_impl,
lazy_class_docstring,
)
from mlem.core.data_type import DataAnalyzer
from mlem.core.errors import UnsupportedDataBatchLoading
from mlem.core.import_objects import ImportHook
Expand All @@ -32,7 +38,7 @@

@mlem_command("apply", section="runtime")
def apply(
model: str = Argument(..., help="Path to model object"),
model: str = Argument(..., metavar="model", help="Path to model object"),
data_path: str = Argument(..., metavar="data", help="Path to data object"),
project: Optional[str] = option_project,
rev: Optional[str] = option_rev,
Expand Down Expand Up @@ -65,7 +71,8 @@ def apply(
external: bool = option_external,
json: bool = option_json,
):
"""Apply a model to data. Resulting data will be saved as MLEM object to `output` if it is provided, otherwise will be printed
"""Apply a model to data. The result will be saved as a MLEM object to `output` if
provided. Otherwise, it will be printed to `stdout`.

Examples:
Apply local mlem model to local mlem data
Expand Down Expand Up @@ -120,45 +127,76 @@ def apply(
)


@mlem_command("apply-remote", section="runtime")
def apply_remote(
subtype: str = Argument(
"",
help=f"Type of client. Choices: {list_implementations(Client)}",
show_default=False,
),
data: str = Argument(..., help="Path to data object"),
project: Optional[str] = option_project,
rev: Optional[str] = option_rev,
output: Optional[str] = Option(
None, "-o", "--output", help="Where to store the outputs."
),
target_project: Optional[str] = option_target_project,
method: str = option_method,
index: bool = option_index,
json: bool = option_json,
load: Optional[str] = option_load("client"),
conf: List[str] = option_conf("client"),
file_conf: List[str] = option_file_conf("client"),
):
"""Apply a model (deployed somewhere remotely) to data. Resulting data will be saved as MLEM object to `output` if it is provided, otherwise will be printed
apply_remote = Typer(
name="apply-remote",
help="""Apply a deployed-model (possibly remotely) to data. The results will be saved as
a MLEM object to `output` if provided. Otherwise, it will be printed to
`stdout`.

Examples:
Apply hosted mlem model to local mlem data
$ mlem apply-remote http mydata -c host="0.0.0.0" -c port=8080 --output myprediction
"""
client = config_arg(Client, load, subtype, conf, file_conf)

with set_echo(None if json else ...):
result = run_apply_remote(
client, data, project, rev, index, method, output, target_project
""",
cls=mlem_group("runtime"),
subcommand_metavar="client",
)
app.add_typer(apply_remote)


@for_each_impl(Client)
def create_apply_remote(type_name):
@mlem_command(
type_name,
section="clients",
parent=apply_remote,
dynamic_metavar="__kwargs__",
dynamic_options_generator=abc_fields_parameters(type_name, Client),
hidden=type_name.startswith("_"),
lazy_help=lazy_class_docstring(Client.abs_name, type_name),
)
def apply_remote_func(
data: str = Argument(..., help="Path to data object"),
project: Optional[str] = option_project,
rev: Optional[str] = option_rev,
output: Optional[str] = Option(
None, "-o", "--output", help="Where to store the outputs."
),
target_project: Optional[str] = option_target_project,
method: str = option_method,
index: bool = option_index,
json: bool = option_json,
load: Optional[str] = option_load("client"),
file_conf: List[str] = option_file_conf("client"),
**__kwargs__,
):
client = config_arg(
Client,
load,
type_name,
conf=None,
file_conf=file_conf,
**__kwargs__,
)
if output is None and json:
print(
dumps(
DataAnalyzer.analyze(result).get_serializer().serialize(result)

with set_echo(None if json else ...):
result = run_apply_remote(
client,
data,
project,
rev,
index,
method,
output,
target_project,
)
if output is None and json:
print(
dumps(
DataAnalyzer.analyze(result)
.get_serializer()
.serialize(result)
)
)
)


def run_apply_remote(
Expand Down
99 changes: 63 additions & 36 deletions mlem/cli/build.py
Original file line number Diff line number Diff line change
@@ -1,49 +1,76 @@
from typing import List, Optional

from typer import Argument
from typer import Argument, Typer

from mlem.cli.main import (
config_arg,
app,
mlem_command,
option_conf,
mlem_group,
option_file_conf,
option_load,
option_project,
option_rev,
)
from mlem.cli.utils import (
abc_fields_parameters,
config_arg,
for_each_impl,
lazy_class_docstring,
)
from mlem.core.metadata import load_meta
from mlem.core.objects import MlemBuilder, MlemModel
from mlem.utils.entrypoints import list_implementations


@mlem_command("build", section="runtime", aliases=["export"])
def build(
model: str = Argument(..., help="Path to model"),
subtype: str = Argument(
"",
help=f"Type of build. Choices: {list_implementations(MlemBuilder)}",
show_default=False,
),
project: Optional[str] = option_project,
rev: Optional[str] = option_rev,
load: Optional[str] = option_load("builder"),
conf: List[str] = option_conf("builder"),
file_conf: List[str] = option_file_conf("builder"),
):
"""
Build/export model

Examples:
Build docker image from model
$ mlem build mymodel docker -c server.type=fastapi -c image.name=myimage

Create build docker_dir declaration and build it
$ mlem declare builder docker_dir -c server=fastapi -c target=build build_dock
$ mlem build mymodel --load build_dock
"""
from mlem.api.commands import build

build(
config_arg(MlemBuilder, load, subtype, conf, file_conf),
load_meta(model, project, rev, force_type=MlemModel),

build = Typer(
name="build",
help="""
Build models to create re-usable, ship-able entities such as a Docker image or
Python package.
jorgeorpinel marked this conversation as resolved.
Show resolved Hide resolved

Examples:
Build docker image from model
$ mlem build mymodel docker -c server.type=fastapi -c image.name=myimage

Create build docker_dir declaration and build it
$ mlem declare builder docker_dir -c server=fastapi -c target=build build_dock
$ mlem build mymodel --load build_dock
Comment on lines +31 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Examples are outdated now.

As per https://github.com/iterative/mlem/issues/335, we need to remove Examples from docstrings at all. Since this PR will be merged in a separate branch and is not supposed to be released to users and you have other stuff to do, it's no rush and I can do it after my vacation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, let's do this separately

""",
cls=mlem_group("runtime", aliases=["export"]),
subcommand_metavar="builder",
)
app.add_typer(build)


@for_each_impl(MlemBuilder)
def create_build_command(type_name):
@mlem_command(
type_name,
section="builders",
parent=build,
dynamic_metavar="__kwargs__",
dynamic_options_generator=abc_fields_parameters(
type_name, MlemBuilder
),
hidden=type_name.startswith("_"),
lazy_help=lazy_class_docstring(MlemBuilder.abs_name, type_name),
)
def build_type(
model: str = Argument(..., help="Path to model"),
project: Optional[str] = option_project,
rev: Optional[str] = option_rev,
load: Optional[str] = option_load("builder"),
file_conf: List[str] = option_file_conf("builder"),
**__kwargs__
):
from mlem.api.commands import build

build(
config_arg(
MlemBuilder,
load,
type_name,
conf=None,
file_conf=file_conf,
**__kwargs__
),
load_meta(model, project, rev, force_type=MlemModel),
)
13 changes: 7 additions & 6 deletions mlem/cli/clone.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@ def clone(
external: Optional[bool] = option_external,
index: Optional[bool] = option_index,
):
"""Download MLEM object from `uri` and save it to `target`
"""Copy a MLEM Object from `uri` and
saves a copy of it to `target` path.

Examples:
Copy remote model to local directory
$ mlem clone models/logreg --project https://github.com/iterative/example-mlem --rev main mymodel
Examples:
Copy remote model to local directory
$ mlem clone models/logreg --project https://github.com/iterative/example-mlem --rev main mymodel

Copy remote model to remote MLEM project
$ mlem clone models/logreg --project https://github.com/iterative/example-mlem --rev main mymodel --tp s3://mybucket/mymodel
Copy remote model to remote MLEM project
$ mlem clone models/logreg --project https://github.com/iterative/example-mlem --rev main mymodel --tp s3://mybucket/mymodel
"""
from mlem.api.commands import clone

Expand Down
7 changes: 4 additions & 3 deletions mlem/cli/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from mlem.cli.main import app, mlem_command, mlem_group, option_project
from mlem.config import CONFIG_FILE_NAME, get_config_cls
from mlem.constants import MLEM_DIR
from mlem.core.base import get_recursively, set_recursively, smart_split
from mlem.core.base import SmartSplitDict, get_recursively, smart_split
from mlem.core.errors import MlemError
from mlem.core.meta_io import get_fs, get_uri
from mlem.ui import EMOJI_OK, echo
Expand Down Expand Up @@ -45,8 +45,9 @@ def config_set(
with fs.open(posixpath.join(project, MLEM_DIR, CONFIG_FILE_NAME)) as f:
new_conf = safe_load(f) or {}

new_conf[section] = new_conf.get(section, {})
set_recursively(new_conf[section], smart_split(name, "."), value)
conf = SmartSplitDict(new_conf.get(section, {}))
conf[name] = value
new_conf[section] = conf.build()
if validate:
config_cls = get_config_cls(section)
config_cls(**new_conf[section])
Expand Down
Loading