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

Declare required and optional dependency #714

Merged
merged 20 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on: [push, pull_request, workflow_call]
jobs:
build:
strategy:
fail-fast: false
max-parallel: 20
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
Expand Down
37 changes: 22 additions & 15 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,37 @@ classifiers = [
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [

"ruamel.yaml",
"numpy<2.0.0",
]
version = "2024.7.30"

[project.optional-dependencies]
ci = [
"pytest>=8",
"pytest-cov>=4",
"coverage",
"numpy<2.0.0",
"ruamel.yaml",
"msgpack",
"tqdm",
"pymongo",
"pandas",
"pint",
"orjson",
"types-orjson",
"types-requests",
"torch"
"coverage",
"monty[optional]",
"pytest>=8",
"pytest-cov>=4",
"types-requests",
]
# dev is for "dev" module, not for development
dev = ["ipython"]
docs = [
"sphinx",
"sphinx_rtd_theme",
]
json = [
"bson",
"orjson>=3.6.1",
"pandas",
"pydantic",
"pint",
"torch",
]
multiprocessing = ["tqdm"]
optional = ["monty[dev,json,multiprocessing,serialization]"]
serialization = ["msgpack"]
task = ["requests", "invoke"]

[tool.setuptools.packages.find]
where = ["src"]
Expand Down Expand Up @@ -101,3 +107,4 @@ lint.select = [
]

lint.isort.required-imports = ["from __future__ import annotations"]
lint.isort.known-first-party = ["monty"]
5 changes: 2 additions & 3 deletions src/monty/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,8 @@
"""
try:
from IPython.core import ultratb # pylint: disable=import-outside-toplevel
except ImportError:
warnings.warn("Cannot install excepthook, IPyhon.core.ultratb not available")
return 1
except ImportError as exc:
raise ImportError("Cannot install excepthook, IPython not installed") from exc

Check warning on line 235 in src/monty/dev.py

View check run for this annotation

Codecov / codecov/patch

src/monty/dev.py#L234-L235

Added lines #L234 - L235 were not covered by tests

# Select the hook.
hook = dict(
Expand Down
8 changes: 2 additions & 6 deletions src/monty/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,7 @@
import errno
import gzip
import io

try:
import lzma
except ImportError:
lzma = None # type: ignore[assignment]
import lzma
DanielYang59 marked this conversation as resolved.
Show resolved Hide resolved
import mmap
import os
import subprocess
Expand Down Expand Up @@ -49,7 +45,7 @@ def zopen(filename: Union[str, Path], *args, **kwargs) -> IO:
return bz2.open(filename, *args, **kwargs)
if ext in {".GZ", ".Z"}:
return gzip.open(filename, *args, **kwargs)
if lzma is not None and ext in {".XZ", ".LZMA"}:
if ext in {".XZ", ".LZMA"}:
return lzma.open(filename, *args, **kwargs)
return open(filename, *args, **kwargs)

Expand Down
5 changes: 1 addition & 4 deletions src/monty/itertools.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import itertools
from typing import TYPE_CHECKING

try:
import numpy as np
except ImportError:
np = None
import numpy as np

if TYPE_CHECKING:
from typing import Iterable
Expand Down
46 changes: 20 additions & 26 deletions src/monty/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@
from typing import Any
from uuid import UUID, uuid4

try:
import numpy as np
except ImportError:
np = None
import numpy as np
from ruamel.yaml import YAML

try:
import pydantic
Expand All @@ -41,17 +39,11 @@
except ImportError:
bson = None

try:
from ruamel.yaml import YAML
except ImportError:
YAML = None

try:
import orjson
except ImportError:
orjson = None


try:
import torch
except ImportError:
Expand Down Expand Up @@ -599,23 +591,22 @@
d["data"] = o.numpy().tolist()
return d

if np is not None:
if isinstance(o, np.ndarray):
if str(o.dtype).startswith("complex"):
return {
"@module": "numpy",
"@class": "array",
"dtype": str(o.dtype),
"data": [o.real.tolist(), o.imag.tolist()],
}
if isinstance(o, np.ndarray):
if str(o.dtype).startswith("complex"):
return {
"@module": "numpy",
"@class": "array",
"dtype": str(o.dtype),
"data": o.tolist(),
"data": [o.real.tolist(), o.imag.tolist()],
}
if isinstance(o, np.generic):
return o.item()
return {
"@module": "numpy",
"@class": "array",
"dtype": str(o.dtype),
"data": o.tolist(),
}
if isinstance(o, np.generic):
return o.item()

Check warning on line 609 in src/monty/json.py

View check run for this annotation

Codecov / codecov/patch

src/monty/json.py#L609

Added line #L609 was not covered by tests

if _check_type(o, "pandas.core.frame.DataFrame"):
return {
Expand Down Expand Up @@ -668,7 +659,7 @@
and dataclasses.is_dataclass(o)
):
# This handles dataclasses that are not subclasses of MSONAble.
d = dataclasses.asdict(o) # type: ignore[call-overload]
d = dataclasses.asdict(o) # type: ignore[call-overload, arg-type]
elif hasattr(o, "as_dict"):
d = o.as_dict()
elif isinstance(o, Enum):
Expand Down Expand Up @@ -813,7 +804,7 @@
).type(d["dtype"])
return torch.tensor(d["data"]).type(d["dtype"]) # pylint: disable=E1101

elif np is not None and modname == "numpy" and classname == "array":
elif modname == "numpy" and classname == "array":
if d["dtype"].startswith("complex"):
return np.array(
[
Expand Down Expand Up @@ -936,7 +927,8 @@
)
for i in obj
]
if np is not None and isinstance(obj, np.ndarray):

if isinstance(obj, np.ndarray):
try:
return [
jsanitize(
Expand All @@ -950,8 +942,10 @@
]
except TypeError:
return obj.tolist()
if np is not None and isinstance(obj, np.generic):

if isinstance(obj, np.generic):
return obj.item()

if _check_type(
obj,
(
Expand Down
6 changes: 2 additions & 4 deletions src/monty/multiprocessing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

try:
from tqdm.autonotebook import tqdm
except ImportError:
tqdm = None
except ImportError as exc:
raise ImportError("tqdm must be installed for this function.") from exc

Check warning on line 13 in src/monty/multiprocessing.py

View check run for this annotation

Codecov / codecov/patch

src/monty/multiprocessing.py#L12-L13

Added lines #L12 - L13 were not covered by tests


def imap_tqdm(nprocs: int, func: Callable, iterable: Iterable, *args, **kwargs) -> list:
Expand All @@ -28,8 +28,6 @@
Returns:
Results of Pool.imap.
"""
if tqdm is None:
raise ImportError("tqdm must be installed for this function.")
data = []
with Pool(nprocs) as pool:
try:
Expand Down
5 changes: 1 addition & 4 deletions src/monty/serialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import os
from typing import TYPE_CHECKING

try:
from ruamel.yaml import YAML
except ImportError:
YAML = None # type: ignore[arg-type]
from ruamel.yaml import YAML

from monty.io import zopen
from monty.json import MontyDecoder, MontyEncoder
Expand Down
1 change: 1 addition & 0 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import requests
from invoke import task

from monty import __version__ as ver
from monty.os import cd

Expand Down
1 change: 1 addition & 0 deletions tests/test_collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os

import pytest

from monty.collections import AttrDict, FrozenAttrDict, Namespace, frozendict, tree

TEST_DIR = os.path.join(os.path.dirname(__file__), "test_files")
Expand Down
1 change: 1 addition & 0 deletions tests/test_design_patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Any

import pytest

from monty.design_patterns import cached_class, singleton


Expand Down
1 change: 1 addition & 0 deletions tests/test_dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from unittest.mock import patch

import pytest

from monty.dev import deprecated, install_excepthook, requires

# Set all warnings to always be triggered.
Expand Down
1 change: 1 addition & 0 deletions tests/test_fractions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import pytest

from monty.fractions import gcd, gcd_float, lcm


Expand Down
1 change: 1 addition & 0 deletions tests/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import unittest

import pytest

from monty.functools import (
TimeoutError,
lazy_property,
Expand Down
1 change: 1 addition & 0 deletions tests/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from unittest.mock import patch

import pytest

from monty.io import (
FileLock,
FileLockException,
Expand Down
36 changes: 15 additions & 21 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,19 @@
from enum import Enum
from typing import Union

try:
import numpy as np
except ImportError:
np = None
import numpy as np
import pytest

from monty.json import (
MontyDecoder,
MontyEncoder,
MSONable,
_load_redirect,
jsanitize,
load,
)

from . import __version__ as TESTS_VERSION

try:
import pandas as pd
Expand All @@ -38,18 +47,6 @@
except ImportError:
ObjectId = None

import pytest
from monty.json import (
MontyDecoder,
MontyEncoder,
MSONable,
_load_redirect,
jsanitize,
load,
)

from . import __version__ as tests_version

TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_files")


Expand Down Expand Up @@ -320,7 +317,7 @@ def test_unsafe_hash(self):
def test_version(self):
obj = self.good_cls("Hello", "World", "Python")
d = obj.as_dict()
assert d["@version"] == tests_version
assert d["@version"] == TESTS_VERSION

def test_nested_to_from_dict(self):
GMC = GoodMSONClass
Expand Down Expand Up @@ -564,7 +561,6 @@ def test_nan(self):
d = json.loads(djson)
assert isinstance(d[0], float)

@pytest.mark.skipif(np is None, reason="numpy not present")
def test_numpy(self):
x = np.array([1, 2, 3], dtype="int64")
with pytest.raises(TypeError):
Expand Down Expand Up @@ -872,9 +868,7 @@ def test_jsanitize_pandas(self):
clean = jsanitize(s)
assert clean == s.to_dict()

@pytest.mark.skipif(
np is None or ObjectId is None, reason="numpy and bson not present"
)
@pytest.mark.skipif(ObjectId is None, reason="bson not present")
def test_jsanitize_numpy_bson(self):
d = {
"a": ["b", np.array([1, 2, 3])],
Expand Down
1 change: 1 addition & 0 deletions tests/test_os.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from pathlib import Path

import pytest

from monty.os import cd, makedirs_p
from monty.os.path import find_exts, zpath

Expand Down
Loading
Loading