Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bd9e37a
bump emmet-core into next rc segment
tsmathis Oct 2, 2026
423ae5a
handle some warnings in tests
tsmathis Oct 2, 2026
9d80519
drop 3.11
tsmathis Oct 2, 2026
b3915cf
setuptools -> hatchling
tsmathis Oct 2, 2026
c63ebed
auto dependency upgrades
invalid-email-address Oct 2, 2026
fa79aa3
make client more forwards compatible
tsmathis Oct 5, 2026
32c3a00
rm logging handler + formatter
tsmathis Oct 6, 2026
764ce53
reimplement deltalake integration
tsmathis Oct 6, 2026
40f2778
some 3.12 cleanups
tsmathis Oct 7, 2026
5d252ef
tqdm -> rich
tsmathis Oct 8, 2026
931d214
enable retrieving versioned datasets
tsmathis Oct 8, 2026
6d76448
more cohesive client->user communication
tsmathis Oct 8, 2026
77289df
bit of styling for db version overview
tsmathis Oct 8, 2026
9ed9e8f
communicate better to the user about what the client is doing when ha…
tsmathis Oct 8, 2026
72e2486
linting
tsmathis Oct 8, 2026
2031ee7
bump emmet
tsmathis Oct 8, 2026
538bcfc
auto dependency upgrades
invalid-email-address Oct 8, 2026
be6eb94
keep dev x-api-key out of shared session headers
tsmathis Oct 9, 2026
550cadd
forward per-request headers on POST/PATCH
tsmathis Oct 9, 2026
d95b552
don't reconfigure adapters on a caller-supplied session
tsmathis Oct 9, 2026
33cc532
mypy
tsmathis Oct 9, 2026
b776632
missed updates to nomad test after updates to client communication model
tsmathis Oct 9, 2026
27b191a
wrap comms from external libraries to fit client communication model
tsmathis Oct 14, 2026
18a0f8c
adopt strict validation from emmet-core for ids
tsmathis Oct 14, 2026
93a391d
linting
tsmathis Oct 14, 2026
f72e2e1
auto dependency upgrades
invalid-email-address Oct 14, 2026
26b960f
bump emmet-core into stable segment of next minor ver
tsmathis Oct 16, 2026
ea81407
fix ordering of entries during comparisions for testing get_entries
tsmathis Oct 19, 2026
eb7da77
more descriptive doc str for get_entries
tsmathis Oct 19, 2026
b270e2b
linting
tsmathis Oct 19, 2026
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/upgrade_dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
matrix:
os: ['ubuntu-latest']
package: ["mp-api"]
python-version: ["3.11", "3.12", "3.13", "3.14"]
python-version: ["3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

[![testing](https://github.com/materialsproject/api/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/materialsproject/api/actions?query=workflow%3Atesting+branch%3Amain)
[![codecov](https://codecov.io/gh/materialsproject/api/branch/main/graph/badge.svg)](https://codecov.io/gh/materialsproject/api)
![python](https://img.shields.io/badge/Python-3.11+-blue.svg?logo=python&logoColor=white)
![python](https://img.shields.io/badge/Python-3.12+-blue.svg?logo=python&logoColor=white)

This repository is the development environment for the new Materials Project API. A core client implementation will reside here. For information on how to use the API, please see the updated [documentation](https://docs.materialsproject.org/downloading-data/how-do-i-download-the-materials-project-database).
8 changes: 4 additions & 4 deletions mp_api/_test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def client_search_testing(
alt_name_dict (dict[str, str]): Alternative names for parameters used in the projection and subsequent data checking
custom_field_tests (dict[str, Any]): Custom queries for specific fields.
sub_doc_fields (list[str]): Prefixes for fields to check in resulting data. Useful when data to be tested is nested.
int_bounds (tuple[int,int]) : integer bounds to use in testing int-type query arguments
float_bounds (tuple[float,float]) : float bounds to use in testing float-type query arguments
int_bounds (tuple[int, int]) : integer bounds to use in testing int-type query arguments
float_bounds (tuple[float, float]) : float bounds to use in testing float-type query arguments
"""
if search_method is None:
return
Expand All @@ -58,7 +58,8 @@ def client_search_testing(
for entry in param_tuples:
param = entry[0]

if param not in excluded_params + ["return"]:
# `db_version` selects a dataset version rather than filtering docs
if param not in excluded_params + ["return", "db_version"]:
param_type = entry[1]
q: dict[str, Any] = {"chunk_size": 1, "num_chunks": 1}

Expand Down Expand Up @@ -139,7 +140,6 @@ def _normalize(doc, field: str):
if k not in ("_page", "_sort_fields", "chunk_size", "fields")
}
for sort_field in [sort_fields] if isinstance(sort_fields, str) else sort_fields:

asc = search_method(
_page=1,
_sort_fields=sort_field,
Expand Down
11 changes: 8 additions & 3 deletions mp_api/client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@

from __future__ import annotations

import logging
import os
from importlib.metadata import PackageNotFoundError, version

from mp_api.client.core._display import (
_configure_from_settings,
enable_logging,
is_quiet,
quiet,
)
from mp_api.client.core.exceptions import MPRestError
from mp_api.client.mprester import MPRester

__all__ = ["MPRestError", "MPRester"]
__all__ = ["MPRestError", "MPRester", "enable_logging", "is_quiet", "quiet"]

try:
__version__ = version("mp_api")
except PackageNotFoundError: # pragma: no cover
__version__ = os.getenv("SETUPTOOLS_SCM_PRETEND_VERSION", "")

logging.getLogger(__name__).addHandler(logging.NullHandler())
_configure_from_settings()
88 changes: 20 additions & 68 deletions mp_api/client/contribs/_logger.py
Original file line number Diff line number Diff line change
@@ -1,97 +1,49 @@
"""Logger for the MPContribs client.

Records go through the `mp_api.client` logger's default handler (stderr),
see `mp_api.client.core._display`. No handlers or level are set here: the
level is configured once, for the whole client, with `MPRESTER_LOG_LEVEL`.
"""

from __future__ import annotations

import logging
import os
import sys
from io import StringIO

from mp_api.client.contribs.settings import MPCC_SETTINGS


class LogFilter(logging.Filter):
def __init__(self, level: int, *args, **kwargs) -> None:
"""Start an instance of logging.Filter.

Args:
level (int) : logging level
*args : args to pass to logging.Filter
**kwargs : kwargs to pass to logging.Filter
"""
self.level = level
super().__init__(*args, **kwargs)

def filter(self, record: logging.LogRecord) -> bool:
"""Filter whether a message is logged.

Args:
record (logging.LogRecord) : message to test if it
meets threshold for logging.

Returns:
bool : True if message should be suppressed.
"""
return record.levelno < self.level
from mp_api.client.core._display import mp_deprecation


class CustomLoggerAdapter(logging.LoggerAdapter):
"""Adapter for logger to enable prefixing."""
"""Prefix messages with the supervisor group/process, if running under supervisor."""

def process(self, msg, kwargs):
"""Prefix logging message.

Args:
msg (str) : logging message
kwargs : args to pass to logging.LoggerAdapter
"""
prefix = self.extra.get("prefix")
prefix = self.extra.get("prefix") # type: ignore[union-attr]
return f"[{prefix}] {msg}" if prefix else msg, kwargs


def get_logger(name: str = "mp_api.client.contribs") -> CustomLoggerAdapter:
"""Get the default MPContribs logger.
"""Get the contribs logger.

Args:
name (str) : name of the logger
name (str) : logger name, a child of `mp_api.client`

Returns:
CustomLoggerAdapter
"""
logger = logging.getLogger(name)
process = os.environ.get("SUPERVISOR_PROCESS_NAME")
group = os.environ.get("SUPERVISOR_GROUP_NAME")
cfg = {"prefix": f"{group}/{process}"} if process and group else {}
info_handler = logging.StreamHandler(sys.stdout)
error_handler = logging.StreamHandler(sys.stderr)
info_handler.addFilter(LogFilter(logging.WARNING))
error_handler.setLevel(max(logging.DEBUG, logging.WARNING))
logger.handlers = [info_handler, error_handler]
logger.setLevel(MPCC_SETTINGS.CLIENT_LOG_LEVEL)
return CustomLoggerAdapter(logger, cfg)


MPCC_LOGGER = get_logger()


class TqdmToLogger(StringIO):
logger: logging.LoggerAdapter = MPCC_LOGGER
level: int | str = MPCC_SETTINGS.CLIENT_LOG_LEVEL
buf: str = ""

def __init__(
self, logger: logging.LoggerAdapter = MPCC_LOGGER, level: int | None = None
) -> None:
"""Start an instance of a TQDM logger.
if MPCC_SETTINGS.CLIENT_LOG_LEVEL is not None:
mp_deprecation(
"MPCONTRIBS_CLIENT_LOG_LEVEL is deprecated and ignored, use MPRESTER_LOG_LEVEL "
"(which sets the level for the whole client) instead.",
stacklevel=2,
)

Args:
logger (logging.Logger) : Logger to pass through
level (int) : logging level
"""
super().__init__()
self.logger = logger
self.level = level or logging.INFO

def write(self, buf: str) -> int:
self.buf = buf.strip("\r\n\t ")
return 1

def flush(self) -> None:
self.logger.log(self.level, self.buf) # type: ignore[arg-type]
MPCC_LOGGER = get_logger()
5 changes: 4 additions & 1 deletion mp_api/client/contribs/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ def display(self):
try:
allowed_kwargs = getfullargspec(line_chart).args
attrs = {k: v for k, v in self.attrs.items() if k in allowed_kwargs}
return self.plot(**attrs)
# Plot with plotly directly, rather than changing the
# process-wide pandas plotting backend / plotly template.
attrs.setdefault("template", "simple_white")
return line_chart(self, **attrs)
except Exception as e:
MPCC_LOGGER.error(f"Can't display table: {e}")

Expand Down
Loading
Loading