Skip to content

Commit

Permalink
Merge pull request #714 from DanielYang59/declare-opt-dependency
Browse files Browse the repository at this point in the history
Declare required and optional dependency
  • Loading branch information
shyuep authored Oct 21, 2024
2 parents 1270c7b + 8a4d33f commit 189b6e6
Show file tree
Hide file tree
Showing 20 changed files with 79 additions and 86 deletions.
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 @@ def install_excepthook(hook_type: str = "color", **kwargs) -> int:
"""
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

# 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
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 @@ def default(self, o) -> dict:
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()

if _check_type(o, "pandas.core.frame.DataFrame"):
return {
Expand Down Expand Up @@ -668,7 +659,7 @@ def default(self, o) -> dict:
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 @@ def process_decoded(self, d):
).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 @@ def jsanitize(
)
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 @@ def jsanitize(
]
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


def imap_tqdm(nprocs: int, func: Callable, iterable: Iterable, *args, **kwargs) -> list:
Expand All @@ -28,8 +28,6 @@ def imap_tqdm(nprocs: int, func: Callable, iterable: Iterable, *args, **kwargs)
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

0 comments on commit 189b6e6

Please sign in to comment.