Skip to content
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

mypy static type checking for mlos_bench #306

Merged
merged 137 commits into from
Apr 19, 2023
Merged
Show file tree
Hide file tree
Changes from 129 commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
083e347
mypy type checking support for mlos_core (mlos_bench to follow later)
bpkroth Apr 11, 2023
88ef7bb
remove a comment
bpkroth Apr 11, 2023
228d977
more spelling changes
bpkroth Apr 11, 2023
6a8622b
more spelling issues
bpkroth Apr 11, 2023
6160ad5
ignore that line
bpkroth Apr 11, 2023
6a8c4b0
license headers
bpkroth Apr 11, 2023
5c29b3b
Merge branch 'main' into mypy-typing-mlos_core
bpkroth Apr 11, 2023
2e4c8b4
test fixups
bpkroth Apr 11, 2023
c00ab7f
make more test dynamic
bpkroth Apr 11, 2023
795ee8a
stub files to make mypy not complain about multiple conftest.py
bpkroth Apr 11, 2023
5d9ffac
enable mypy for mlos_bench
bpkroth Apr 11, 2023
03454f0
ignore missing matplotlib stubs
bpkroth Apr 11, 2023
5a68d29
ignore setup.py errors
bpkroth Apr 11, 2023
b1fa37e
Merge remote-tracking branch 'upstream/main' into mypy-typing-mlos_bench
bpkroth Apr 12, 2023
7eb1877
Merge remote-tracking branch 'upstream/main' into mypy-typing-mlos_bench
bpkroth Apr 12, 2023
5b93328
add some ignores
bpkroth Apr 12, 2023
b7a7647
type check fixups
bpkroth Apr 12, 2023
7f46392
more strict return values
bpkroth Apr 12, 2023
0179ca7
more type tweaks
bpkroth Apr 12, 2023
8032064
wip: more typing fixups
bpkroth Apr 12, 2023
8b8aadc
wip: typing
bpkroth Apr 12, 2023
6fcc9ff
force function definitions to have type decorations
bpkroth Apr 12, 2023
a0fa181
type annotations
bpkroth Apr 12, 2023
f6ee713
ignore errors on listening to port 81 from 127.0.0.1 so we can run tw…
bpkroth Apr 12, 2023
db83926
more type check fixups
bpkroth Apr 12, 2023
d281668
ignore missing matplotlib stubs
bpkroth Apr 11, 2023
15286a2
more typing
bpkroth Apr 12, 2023
25a5403
spelling
bpkroth Apr 13, 2023
c4261df
annotate test functions
bpkroth Apr 13, 2023
9a3242d
spelling
bpkroth Apr 13, 2023
bddb03c
types
bpkroth Apr 13, 2023
168f2b8
spelling
bpkroth Apr 13, 2023
6516337
more typing
bpkroth Apr 13, 2023
22643be
more typing fixups
bpkroth Apr 13, 2023
25427ed
more strict
bpkroth Apr 13, 2023
bbe5f6d
more typing fixups
bpkroth Apr 13, 2023
53f22cf
fixups
bpkroth Apr 13, 2023
bc52c20
more
bpkroth Apr 13, 2023
25464d8
Merge branch 'main' into mypy-typing_mlos-core_updates
bpkroth Apr 13, 2023
4e47016
spaces
bpkroth Apr 13, 2023
7cd7465
Merge branch 'main' into mypy-typing_mlos-core_updates
bpkroth Apr 13, 2023
b431286
merge conflict fixups
bpkroth Apr 13, 2023
912dfea
more merge conflicts
bpkroth Apr 13, 2023
37a1d27
fixup
bpkroth Apr 13, 2023
d6bf2ae
back that change out
bpkroth Apr 13, 2023
3876112
Merge branch 'mypy-typing_mlos-core_updates' into mypy-typing-mlos_bench
bpkroth Apr 13, 2023
8d432bb
type hinting
bpkroth Apr 13, 2023
ef26724
minor tweaks for unimplemented function
bpkroth Apr 13, 2023
faf42e5
comments
bpkroth Apr 13, 2023
5f85bef
typing
bpkroth Apr 13, 2023
9805566
Merge branch 'mypy-typing_mlos-core_updates' into mypy-typing-mlos_bench
bpkroth Apr 13, 2023
e1e2847
easy test def return types
bpkroth Apr 13, 2023
0137a17
tunable typing
bpkroth Apr 13, 2023
eb47503
environment typing
bpkroth Apr 13, 2023
35c6ca3
tunable typing
bpkroth Apr 13, 2023
4b0ca0d
typing for fileshare
bpkroth Apr 13, 2023
79ec1a4
wip: typing
bpkroth Apr 13, 2023
bbaa6dd
launcher typing
bpkroth Apr 13, 2023
6bd0174
more typing fixups
bpkroth Apr 13, 2023
426839c
fixups
bpkroth Apr 13, 2023
b0a0d66
fixup
bpkroth Apr 13, 2023
a90970c
optionals
bpkroth Apr 13, 2023
becbaf5
typing and fixups
bpkroth Apr 13, 2023
bd448f3
typing
bpkroth Apr 13, 2023
7758918
typing
bpkroth Apr 13, 2023
eb8cc31
typing and spelling
bpkroth Apr 13, 2023
cf82ea1
typing and fixups
bpkroth Apr 13, 2023
f4d9ef4
typing
bpkroth Apr 13, 2023
04e17d9
Merge remote-tracking branch 'upstream/main' into mypy-typing_mlos-co…
bpkroth Apr 13, 2023
73f1a06
fixups for py 3.89
bpkroth Apr 13, 2023
ff8d1f9
Merge branch 'mypy-typing_mlos-core_updates' into mypy-typing-mlos_bench
bpkroth Apr 13, 2023
304fb42
type checking
bpkroth Apr 13, 2023
ecc4d71
switch to dynamic ports for nginx
bpkroth Apr 14, 2023
6a25b0d
fixups
bpkroth Apr 14, 2023
7f96894
just use docker compose to forward ports
bpkroth Apr 14, 2023
abceaf5
move nginx port to a random port
bpkroth Apr 14, 2023
52d0870
make it work for powershell too
bpkroth Apr 14, 2023
5f07178
need the .env file to be in a different directory
bpkroth Apr 14, 2023
a9af273
fixups for pwsh
bpkroth Apr 14, 2023
7767244
also stop running the docker pull
bpkroth Apr 14, 2023
e1314c4
whitespace reorg
bpkroth Apr 14, 2023
ad0db88
fixup
bpkroth Apr 14, 2023
c9abebd
Merge branch 'devcontainer-nginx-port-fixup' into mypy-typing-mlos_bench
bpkroth Apr 14, 2023
0581d55
make the cmd more verbose
bpkroth Apr 14, 2023
1bb5293
merge conflict
bpkroth Apr 14, 2023
70206f6
more debugging
bpkroth Apr 14, 2023
e2c8e5f
ignore ipv6
bpkroth Apr 14, 2023
2bd4352
Merge branch 'devcontainer-nginx-port-fixup' into mypy-typing-mlos_bench
bpkroth Apr 14, 2023
2b90005
type fixup
bpkroth Apr 14, 2023
6ca958b
use a newer mypy to avoid some issues
bpkroth Apr 14, 2023
84e022d
fixup
bpkroth Apr 14, 2023
55b704d
fix some circular import issues
bpkroth Apr 14, 2023
f4c916b
fixups
bpkroth Apr 14, 2023
5fe88a3
spelling
bpkroth Apr 14, 2023
60fb342
wip: protocols for type checking
bpkroth Apr 14, 2023
0a11322
be more specific about error type being ignored
bpkroth Apr 16, 2023
1738706
more specific type ignore errors
bpkroth Apr 16, 2023
3d320d4
wip: implement protocols for type checking for some service mixins
bpkroth Apr 16, 2023
79699d0
type fixups
bpkroth Apr 16, 2023
6304e8e
more type fixups
bpkroth Apr 16, 2023
88c24b3
fixup ignore
bpkroth Apr 16, 2023
0c44a33
extend config loader service for more use cases
bpkroth Apr 16, 2023
5c1f44a
more minor fixups
bpkroth Apr 16, 2023
0a487e9
more protocol tweaks
bpkroth Apr 16, 2023
579f429
more protocol tweaks
bpkroth Apr 16, 2023
07548f1
fileshare type checking
bpkroth Apr 16, 2023
63b8939
pycodestyle
bpkroth Apr 16, 2023
144f178
make dmypy start before the jobs for it
bpkroth Apr 16, 2023
b66fae4
wip: reorg service types
bpkroth Apr 16, 2023
c9d8cf3
wip: split out vm/os service types
bpkroth Apr 16, 2023
ac0b07f
vm ops typing
bpkroth Apr 16, 2023
77b6c45
fixups
bpkroth Apr 16, 2023
b396e66
more typing fixups, also avoid some circular imports by only importin…
bpkroth Apr 16, 2023
7ab41be
more typing (maybe the last?!)
bpkroth Apr 16, 2023
f422d41
add py.typed file
bpkroth Apr 16, 2023
c83d2f6
fixups
bpkroth Apr 16, 2023
8a078ee
fixup
bpkroth Apr 16, 2023
52142f9
update
bpkroth Apr 17, 2023
50fcfdc
fixups
bpkroth Apr 17, 2023
4d842b8
renamed method
bpkroth Apr 17, 2023
447aa6f
ignore some doc build errors
bpkroth Apr 17, 2023
60c4787
minor windows tweaks
bpkroth Apr 17, 2023
f603a49
correction
bpkroth Apr 17, 2023
bed054e
fixups for windows
bpkroth Apr 17, 2023
bcfab8a
minor tweak
bpkroth Apr 17, 2023
20349f1
unnecessary
bpkroth Apr 17, 2023
61afd3a
remove an unnecessary import
bpkroth Apr 17, 2023
503698e
Merge branch 'main' into mypy-typing-mlos_bench
bpkroth Apr 17, 2023
c56bd42
cleanup merge
bpkroth Apr 17, 2023
6b3bcb3
make all arguments named - PR feedback
bpkroth Apr 19, 2023
d665a91
pr feedback
bpkroth Apr 19, 2023
cce09c2
skip TYPE_CHECKING and just import the base libs
bpkroth Apr 19, 2023
7bdb6db
revert last change
bpkroth Apr 19, 2023
c6333ad
comments
bpkroth Apr 19, 2023
6692c7c
fixup mocking and type ignores
bpkroth Apr 19, 2023
a053218
minor cleanup
bpkroth Apr 19, 2023
9159ad9
more generic types
bpkroth Apr 19, 2023
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
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// vim: set ft=jsonc:
{
"makefile.extensionOutputFolder": "./.vscode",
"python.defaultInterpreterPath": "${env:HOME}${env:USERPROFILE}/.conda/envs/mlos_core/bin/python",
// Note: this only works in WSL/Linux currently.
"python.defaultInterpreterPath": "${env:HOME}/.conda/envs/mlos_core/bin/python",
// For Windows it should be this instead:
//"python.defaultInterpreterPath": "${env:USERPROFILE}/.conda/envs/mlos_core/python.exe",
"python.testing.pytestEnabled": true,
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
Expand Down
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ MLOS_BENCH_PYTHON_FILES := $(shell find ./mlos_bench/ -type f -name '*.py' 2>/de

DOCKER := $(shell which docker)
# Make sure the build directory exists.
MKDIR_BUILD := $(shell mkdir -p build)
MKDIR_BUILD := $(shell test -d build || mkdir build)

# Allow overriding the default verbosity of conda for CI jobs.
#CONDA_INFO_LEVEL ?= -q
Expand Down Expand Up @@ -113,7 +113,7 @@ build/pylint.%.${CONDA_ENV_NAME}.build-stamp: build/conda-env.${CONDA_ENV_NAME}.
touch $@

.PHONY: mypy
mypy: conda-env build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp # TODO: build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp
mypy: conda-env build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp

build/mypy.mlos_core.${CONDA_ENV_NAME}.build-stamp: $(MLOS_CORE_PYTHON_FILES)
build/mypy.mlos_bench.${CONDA_ENV_NAME}.build-stamp: $(MLOS_BENCH_PYTHON_FILES)
Expand Down Expand Up @@ -339,6 +339,7 @@ build/check-doc.build-stamp: doc/build/html/index.html doc/build/html/htmlcov/in
-e 'Problems with "include" directive path:' \
-e 'duplicate object description' \
-e "document isn't included in any toctree" \
-e "more than one target found for cross-reference" \
-e "toctree contains reference to nonexisting document 'auto_examples/index'" \
-e "failed to import function 'create' from module '(SpaceAdapter|Optimizer)Factory'" \
-e "No module named '(SpaceAdapter|Optimizer)Factory'" \
Expand Down
2 changes: 1 addition & 1 deletion doc/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM nginx:latest
RUN apt-get update && apt-get install -y --no-install-recommends linklint curl
# Our ngxinx config overrides the default listening port.
# Our nginx config overrides the default listening port.
ARG NGINX_PORT=81
ENV NGINX_PORT=${NGINX_PORT}
EXPOSE ${NGINX_PORT}
6 changes: 6 additions & 0 deletions doc/source/overview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,12 @@ Service Mix-ins

Service
FileShareService

.. currentmodule:: mlos_bench.service.config_persistence
.. autosummary::
:toctree: generated/
:template: class.rst

ConfigPersistenceService

Local Services
Expand Down
2 changes: 1 addition & 1 deletion mlos_bench/config/applications/generate_redis_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import argparse


def _main(fname_input: str, fname_output: str):
def _main(fname_input: str, fname_output: str) -> None:
with open(fname_input, "rt", encoding="utf-8") as fh_tunables, \
open(fname_output, "wt", encoding="utf-8", newline="") as fh_config:
for (key, val) in json.load(fh_tunables).items():
Expand Down
2 changes: 1 addition & 1 deletion mlos_bench/config/applications/process_redis_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import pandas as pd


def _main(input_file: str, output_file: str):
def _main(input_file: str, output_file: str) -> None:
"""
Re-shape Redis benchmark CSV results from wide to long.
"""
Expand Down
2 changes: 1 addition & 1 deletion mlos_bench/config/linux-boot/generate_grub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import argparse


def _main(fname_input: str, fname_output: str):
def _main(fname_input: str, fname_output: str) -> None:
with open(fname_input, "rt", encoding="utf-8") as fh_tunables, \
open(fname_output, "wt", encoding="utf-8", newline="") as fh_config:
for (key, val) in json.load(fh_tunables).items():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import argparse


def _main(fname_input: str, fname_output: str):
def _main(fname_input: str, fname_output: str) -> None:
with open(fname_input, "rt", encoding="utf-8") as fh_tunables, \
open(fname_output, "wt", encoding="utf-8", newline="") as fh_config:
for (key, val) in json.load(fh_tunables).items():
Expand Down
54 changes: 40 additions & 14 deletions mlos_bench/mlos_bench/environment/base_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,33 @@
import abc
import json
import logging
from typing import Optional, Tuple
from typing import Dict, Optional, Tuple

from mlos_bench.environment.status import Status
from mlos_bench.service.base_service import Service
from mlos_bench.service.types.config_loader_type import SupportsConfigLoading
from mlos_bench.tunables.tunable import TunableValue
from mlos_bench.tunables.tunable_groups import TunableGroups
from mlos_bench.util import instantiate_from_config

_LOG = logging.getLogger(__name__)


class Environment(metaclass=abc.ABCMeta):
# pylint: disable=too-many-instance-attributes
"""
An abstract base of all benchmark environments.
"""

@classmethod
def new(cls, env_name, class_name, config, global_config=None, tunables=None, service=None):
def new(cls,
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
env_name: str,
class_name: str,
config: dict,
global_config: Optional[dict] = None,
tunables: Optional[TunableGroups] = None,
service: Optional[Service] = None,
) -> "Environment":
# pylint: disable=too-many-arguments
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
"""
Factory method for a new environment with a given config.
Expand Down Expand Up @@ -58,7 +69,12 @@ def new(cls, env_name, class_name, config, global_config=None, tunables=None, se
return instantiate_from_config(cls, class_name, env_name, config,
global_config, tunables, service)

def __init__(self, name, config, global_config=None, tunables=None, service=None):
def __init__(self,
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
name: str,
config: dict,
global_config: Optional[dict] = None,
tunables: Optional[TunableGroups] = None,
service: Optional[Service] = None):
# pylint: disable=too-many-arguments
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
"""
Create a new environment with a given config.
Expand All @@ -84,10 +100,17 @@ def __init__(self, name, config, global_config=None, tunables=None, service=None
self.config = config
self._service = service
self._is_ready = False
self._params = {}
self._params: Dict[str, TunableValue] = {}

self._config_loader_service: SupportsConfigLoading
if self._service is not None and isinstance(self._service, SupportsConfigLoading):
bpkroth marked this conversation as resolved.
Show resolved Hide resolved
self._config_loader_service = self._service

if global_config is None:
global_config = {}

self._const_args = config.get("const_args", {})
for key in set(self._const_args).intersection(global_config or {}):
for key in set(self._const_args).intersection(global_config):
self._const_args[key] = global_config[key]

for key in config.get("required_args", []):
Expand All @@ -110,13 +133,13 @@ def __init__(self, name, config, global_config=None, tunables=None, service=None
_LOG.debug("Config for: %s\n%s",
name, json.dumps(self.config, indent=2))

def __str__(self):
def __str__(self) -> str:
return self.name

def __repr__(self):
def __repr__(self) -> str:
return f"Env: {self.__class__} :: '{self.name}'"

def _combine_tunables(self, tunables):
def _combine_tunables(self, tunables: TunableGroups) -> Dict[str, TunableValue]:
"""
Plug tunable values into the base config. If the tunable group is unknown,
ignore it (it might belong to another environment). This method should
Expand All @@ -130,14 +153,14 @@ def _combine_tunables(self, tunables):

Returns
-------
params : dict
params : Dict[str, Union[int, float, str]]
Free-format dictionary that contains the new environment configuration.
"""
return tunables.get_param_values(
group_names=self._tunable_params.get_names(),
group_names=list(self._tunable_params.get_names()),
into_params=self._const_args.copy())

def tunable_params(self):
def tunable_params(self) -> TunableGroups:
"""
Get the configuration space of the given environment.

Expand All @@ -148,7 +171,7 @@ def tunable_params(self):
"""
return self._tunable_params

def setup(self, tunables: TunableGroups, global_config: dict = None) -> bool:
def setup(self, tunables: TunableGroups, global_config: Optional[dict] = None) -> bool:
"""
Set up a new benchmark environment, if necessary. This method must be
idempotent, i.e., calling it several times in a row should be
Expand All @@ -170,15 +193,18 @@ def setup(self, tunables: TunableGroups, global_config: dict = None) -> bool:
_LOG.info("Setup %s :: %s", self, tunables)
assert isinstance(tunables, TunableGroups)

if global_config is None:
global_config = {}

self._params = self._combine_tunables(tunables)
for key in set(self._params).intersection(global_config or {}):
for key in set(self._params).intersection(global_config):
self._params[key] = global_config[key]
if _LOG.isEnabledFor(logging.DEBUG):
_LOG.debug("Combined parameters:\n%s", json.dumps(self._params, indent=2))

return True

def teardown(self):
def teardown(self) -> None:
"""
Tear down the benchmark environment. This method must be idempotent,
i.e., calling it several times in a row should be equivalent to a
Expand Down
18 changes: 9 additions & 9 deletions mlos_bench/mlos_bench/environment/composite_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"""

import logging
from typing import Optional, Tuple
from typing import List, Optional, Tuple

from mlos_bench.service.base_service import Service
from mlos_bench.environment.status import Status
Expand All @@ -22,8 +22,8 @@ class CompositeEnv(Environment):
Composite benchmark environment.
"""

def __init__(self, name: str, config: dict, global_config: dict = None,
tunables: TunableGroups = None, service: Service = None):
def __init__(self, name: str, config: dict, global_config: Optional[dict] = None,
tunables: Optional[TunableGroups] = None, service: Optional[Service] = None):
# pylint: disable=too-many-arguments
"""
Create a new environment with a given config.
Expand All @@ -46,29 +46,29 @@ def __init__(self, name: str, config: dict, global_config: dict = None,
"""
super().__init__(name, config, global_config, tunables, service)

self._children = []
self._children: List[Environment] = []

for child_config_file in config.get("include_children", []):
for env in self._service.load_environment_list(
for env in self._config_loader_service.load_environment_list(
child_config_file, global_config, tunables, self._service):
self._add_child(env)

for child_config in config.get("children", []):
self._add_child(self._service.build_environment(
self._add_child(self._config_loader_service.build_environment(
child_config, global_config, tunables, self._service))

if not self._children:
raise ValueError("At least one child environment must be present")

def _add_child(self, env: Environment):
def _add_child(self, env: Environment) -> None:
"""
Add a new child environment to the composite environment.
This method is called from the constructor only.
"""
self._children.append(env)
self._tunable_params.update(env.tunable_params())

def setup(self, tunables: TunableGroups, global_config: dict = None) -> bool:
def setup(self, tunables: TunableGroups, global_config: Optional[dict] = None) -> bool:
"""
Set up the children environments.

Expand All @@ -92,7 +92,7 @@ def setup(self, tunables: TunableGroups, global_config: dict = None) -> bool:
)
return self._is_ready

def teardown(self):
def teardown(self) -> None:
"""
Tear down the children environments. This method is idempotent,
i.e., calling it several times is equivalent to a single call.
Expand Down
Loading