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

Refactor/logging #519

Merged
merged 59 commits into from
Aug 19, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
9a95f92
Add simple wrapper abstractions for logging tables
schroedk Aug 1, 2024
1fc3eb9
Add abstraction of a key value store, which serves as interface for s…
schroedk Aug 8, 2024
ccb46f2
Add type definitions to describe iteration, step and problem information
schroedk Aug 8, 2024
4f59893
Implement a sqlalchemy table acting as a KeyValueStore
schroedk Aug 8, 2024
12c03fb
Add sqlite implementations for iteration, step and problem store
schroedk Aug 8, 2024
d8075de
Add tests for sqlite implementations
schroedk Aug 8, 2024
3a8493f
Remove obsolete file
schroedk Aug 8, 2024
a38243c
Refactor logging types:
schroedk Aug 9, 2024
eb1cfc8
Add bound to TyepVar, remove type:ignore
schroedk Aug 9, 2024
56364e2
Add Logger class:
schroedk Aug 9, 2024
07ba628
Deprecate OptimieLogReader and redirect to SQLiteLogger
schroedk Aug 9, 2024
8c88dfa
Adapt read tests for logging to new SQLiteLogger
schroedk Aug 9, 2024
dee344c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 9, 2024
afd0795
Remove obsolete type cast
schroedk Aug 9, 2024
3d7f89a
Update environment files to include sqlalchemy-stubs
schroedk Aug 12, 2024
aadea23
Merge remote-tracking branch 'origin/0.5.0' into refactor/logging
schroedk Aug 12, 2024
0474e63
Move OptimizationStrategy type from logging.types to typing
schroedk Aug 13, 2024
79e213c
Deprecate log_options in estimate_ml and estimate_msm, change default…
schroedk Aug 13, 2024
f034d2e
Add functionality to handle deprecated parameter log_options
schroedk Aug 13, 2024
ba67eaa
Delet obsolete files
schroedk Aug 13, 2024
3c2b24d
Refactor logging subpackage:
schroedk Aug 13, 2024
c57edf0
Rename AbstractKeyValueStore to KeyValueStore
schroedk Aug 13, 2024
64082f6
Refactor logging:
schroedk Aug 13, 2024
a912d3e
Merge remote-tracking branch 'origin/0.5.0' into refactor/logging
schroedk Aug 13, 2024
164d35a
Move util functions from logging submodule to optimagic.utilities, re…
schroedk Aug 13, 2024
911dbcc
Fix issue in handling existing database file
schroedk Aug 13, 2024
a8570cd
A docstrings to dataclasses and enumerations in logging.types
schroedk Aug 13, 2024
4a83de3
Rename KeyValueStore -> _KeyValueStore, add docstrings
schroedk Aug 13, 2024
b792592
Add docstrings to Logger classes
schroedk Aug 13, 2024
7e29fe2
Add docstrings to logger.sqlalchemy submodule
schroedk Aug 13, 2024
6447d1a
Add docstrings to logger.sqlite submodule
schroedk Aug 13, 2024
4b005eb
Improve argument description of `fast_logging`
schroedk Aug 13, 2024
1f77ce8
Set default argument for fast_logging to False
schroedk Aug 13, 2024
4796604
Import SQLiteLogger and ExistenceStrategy on top level of logging module
schroedk Aug 13, 2024
74c61d4
Adpat how-to-guide for logging
schroedk Aug 13, 2024
0930bd5
Improve ValueError message for logging types
schroedk Aug 13, 2024
1449d30
Fix issue in create_engine method, due to not overriding correctly
schroedk Aug 13, 2024
365ed94
Raise warning in case table exists and if_table_exists="replace"
schroedk Aug 13, 2024
ba3a9df
Increase test coverage
schroedk Aug 13, 2024
3c332ce
Refactor logging package:
schroedk Aug 13, 2024
3dc7a05
Fix an issue in replacing the database file on windows, due to Permis…
schroedk Aug 13, 2024
1b4110d
Switch order of file removal and warning in try block
schroedk Aug 13, 2024
ce504c1
Move history return types to optimagic.typing
schroedk Aug 14, 2024
d98c240
Do not store flattened pytrees in logger stores, remove unflatten ope…
schroedk Aug 14, 2024
462e7a3
Raise ValueError instead of warning in handling og deprecated log_opt…
schroedk Aug 14, 2024
a67035f
Move metadate creation from init to cached property, due to not creat…
schroedk Aug 17, 2024
5634837
Refactor logging subpackage:
schroedk Aug 17, 2024
142060b
Improve docstrings and type annotations
schroedk Aug 19, 2024
6366692
Fix test to catch a warning
schroedk Aug 19, 2024
dade965
Adapt documentation for logging
schroedk Aug 19, 2024
bfb2dcc
Add reader creation from path to documentation
schroedk Aug 19, 2024
d6f2c62
Remove method 'from_path' from SQLiteLogReader, remove 'as_reader' fr…
schroedk Aug 19, 2024
620a62e
Improve future warning for log options handling
schroedk Aug 19, 2024
a612912
Extend CHANGES.md
schroedk Aug 19, 2024
3668e58
Rename CriterionEvaluationResult -> IterationState
schroedk Aug 19, 2024
4eb9032
Raise FileNotFoundError for SQLiteLogReader in case no db file found
schroedk Aug 19, 2024
a7d3eaa
Add tests for covering deprecation of log_options in minimize, maximi…
schroedk Aug 19, 2024
cf6f0b9
Add test for dprecated OptimizationLogReader
schroedk Aug 19, 2024
3d815fc
Fix broken test
schroedk Aug 19, 2024
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
1 change: 1 addition & 0 deletions .tools/envs/testenv-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ dependencies:
- types-cffi # dev, tests
- types-openpyxl # dev, tests
- types-jinja2 # dev, tests
- sqlalchemy-stubs # dev, tests
- -e ../../
1 change: 1 addition & 0 deletions .tools/envs/testenv-others.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ dependencies:
- types-cffi # dev, tests
- types-openpyxl # dev, tests
- types-jinja2 # dev, tests
- sqlalchemy-stubs # dev, tests
- -e ../../
1 change: 1 addition & 0 deletions .tools/envs/testenv-pandas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ dependencies:
- types-cffi # dev, tests
- types-openpyxl # dev, tests
- types-jinja2 # dev, tests
- sqlalchemy-stubs # dev, tests
- -e ../../
58 changes: 47 additions & 11 deletions docs/source/how_to/how_to_logging.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,32 @@
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In case the SQLite file already exists, this will raise a `FileExistsError` to prevent from accidentally polluting an existing database. If you want to reuse\n",
"an existing database on purpose, you must explicitly provide the corresponding option for `if_database_exists`:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from optimagic.logging import ExistenceStrategy, SQLiteLogger\n",
"\n",
"logger = SQLiteLogger(\"my_log.db\", if_database_exists=ExistenceStrategy.EXTEND)\n",
"\n",
"res = om.minimize(\n",
" fun=sphere,\n",
" params=np.arange(5),\n",
" algorithm=\"scipy_lbfgsb\",\n",
" logging=logger,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand All @@ -63,7 +89,7 @@
"\n",
"However, this makes writing logs rather slow, which becomes notable when the criterion function is very fast. \n",
"\n",
"In that case, you can enable ``\"fast_logging\"``, which is still quite safe!"
"In that case, you can enable `fast_logging`, which is still quite safe!"
]
},
{
Expand All @@ -72,12 +98,13 @@
"metadata": {},
"outputs": [],
"source": [
"logger = SQLiteLogger(\"my_log.db\", fast_logging=True)\n",
"\n",
"res = om.minimize(\n",
" fun=sphere,\n",
" params=np.arange(5),\n",
" algorithm=\"scipy_lbfgsb\",\n",
" logging=\"my_log.db\",\n",
" log_options={\"fast_logging\": True},\n",
" logging=logger,\n",
")"
]
},
Expand All @@ -87,7 +114,8 @@
"source": [
"## Handling existing tables\n",
"\n",
"By default, we only append to databases and do not overwrite data in them. You have a few options to change this:"
"By default, we also raise an exception, when a table is present a database. Again, if you want to reuse or replace an existing table, provide the corresponding option\n",
"for `if_table_exists`:"
]
},
{
Expand All @@ -96,23 +124,24 @@
"metadata": {},
"outputs": [],
"source": [
"logger = SQLiteLogger(\"my_log.db\", if_table_exists=ExistenceStrategy.EXTEND)\n",
"# or\n",
"logger = SQLiteLogger(\"my_log.db\", if_table_exists=ExistenceStrategy.REPLACE)\n",
"\n",
"res = om.minimize(\n",
" fun=sphere,\n",
" params=np.arange(5),\n",
" algorithm=\"scipy_lbfgsb\",\n",
" logging=\"my_log.db\",\n",
" log_options={\n",
" \"if_database_exists\": \"replace\", # one of \"raise\", \"replace\", \"extend\",\n",
" \"if_table_exists\": \"replace\", # one of \"raise\", \"replace\", \"extend\"\n",
" },\n",
" logging=logger,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Reading the log"
"## Reading the log\n",
"To read the log after an optimization, extract the logger from the optimization result:"
]
},
{
Expand All @@ -121,7 +150,14 @@
"metadata": {},
"outputs": [],
"source": [
"reader = om.OptimizeLogReader(\"my_log.db\")"
"res = om.minimize(\n",
" fun=sphere,\n",
" params=np.arange(5),\n",
" algorithm=\"scipy_lbfgsb\",\n",
" logging=\"my_log.db\",\n",
")\n",
"\n",
"reader = res.logger"
]
},
{
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ dependencies:
- types-cffi # dev, tests
- types-openpyxl # dev, tests
- types-jinja2 # dev, tests
- sqlalchemy-stubs # dev, tests
5 changes: 2 additions & 3 deletions src/estimagic/estimate_ml.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@ def estimate_ml(
*,
bounds=None,
constraints=None,
logging=False,
log_options=None,
logging=None,
loglike_kwargs=None,
jacobian=None,
jacobian_kwargs=None,
Expand All @@ -71,6 +70,7 @@ def estimate_ml(
hessian_numdiff_options=None,
design_info=None,
# deprecated
log_options=None,
lower_bounds=None,
upper_bounds=None,
numdiff_options=None,
Expand Down Expand Up @@ -232,7 +232,6 @@ def estimate_ml(
bounds=bounds,
constraints=constraints,
logging=logging,
log_options=log_options,
**optimize_options,
)
estimates = opt_res.params
Expand Down
5 changes: 2 additions & 3 deletions src/estimagic/estimate_msm.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ def estimate_msm(
*,
bounds=None,
constraints=None,
logging=False,
log_options=None,
logging=None,
simulate_moments_kwargs=None,
weights="diagonal",
jacobian=None,
jacobian_kwargs=None,
jacobian_numdiff_options=None,
# deprecated
log_options=None,
lower_bounds=None,
upper_bounds=None,
numdiff_options=None,
Expand Down Expand Up @@ -251,7 +251,6 @@ def estimate_msm(
bounds=bounds,
constraints=constraints,
logging=logging,
log_options=log_options,
params=params,
**funcs, # contains the criterion func and possibly more
**optimize_options,
Expand Down
40 changes: 39 additions & 1 deletion src/optimagic/deprecations.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import logging
import warnings
from dataclasses import replace
from functools import wraps
from typing import Any, Callable, ParamSpec
from pathlib import Path
from typing import Any, Callable, ParamSpec, cast

from optimagic import mark
from optimagic.constraints import Constraint, InvalidConstraintError
from optimagic.logging.logger import Logger, SQLiteLogger
from optimagic.optimization.fun_value import (
LeastSquaresFunctionValue,
LikelihoodFunctionValue,
Expand All @@ -13,6 +16,8 @@
from optimagic.parameters.bounds import Bounds
from optimagic.typing import AggregationLevel

_logger = logging.getLogger(__name__)


def throw_criterion_future_warning():
msg = (
Expand Down Expand Up @@ -461,6 +466,39 @@ def replace_and_warn_about_deprecated_derivatives(candidate, name):
return out


def handle_log_options_throw_deprecated_warning(
log_options: dict[str, Any], logger: str | Path | Logger | None
) -> str | Path | Logger | None:
msg = (
"Usage of the parameter log_options is deprecated "
"and will be removed in a future version. "
"Provide a Logger instance for the parameter `logging`, if you need to "
"configure the logging."
)
warnings.warn(msg, FutureWarning)

logging_is_path_or_string = isinstance(logger, str) or isinstance(logger, Path)
log_options_is_dict = isinstance(log_options, dict)
compatible_keys = {"fast_logging", "if_table_exists", "if_database_exists"}
log_options_is_compatible = set(log_options.keys()).issubset(compatible_keys)

if logging_is_path_or_string:
if log_options_is_dict and log_options_is_compatible:
warnings.warn(
f"\nUsing {log_options=} to create an instance of SQLiteLogger. "
f"This mechanism will be removed in the future."
)
return SQLiteLogger(cast(str | Path, logger), **log_options)
elif not log_options_is_compatible:
schroedk marked this conversation as resolved.
Show resolved Hide resolved
warnings.warn(
f"Found string or path for logger argument, but parameter"
f" {log_options=} is not compatible to {compatible_keys=}."
f"Explicitly create a Logger instance for configuration."
)

return logger


def pre_process_constraints(
constraints: list[Constraint | dict[str, Any]] | Constraint | dict[str, Any] | None,
) -> list[dict[str, Any]]:
Expand Down
2 changes: 2 additions & 0 deletions src/optimagic/logging/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .logger import SQLiteLogger as SQLiteLogger
schroedk marked this conversation as resolved.
Show resolved Hide resolved
from .types import ExistenceStrategy as ExistenceStrategy
Loading