Skip to content

Commit

Permalink
Revert "Merge branch 'master' into consistent-ruff"
Browse files Browse the repository at this point in the history
This reverts commit f93ec86, reversing
changes made to 7fb24cd.
  • Loading branch information
DanielYang59 committed Dec 11, 2024
1 parent 8fa3713 commit 3c0e537
Show file tree
Hide file tree
Showing 9 changed files with 22 additions and 153 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
fail-fast: false
max-parallel: 20
matrix:
os: [ubuntu-latest, macos-14] #, windows-latest]
os: [ubuntu-latest, macos-14, windows-latest]
python-version: ["3.10", "3.12"]

runs-on: ${{ matrix.os }}
Expand Down
7 changes: 0 additions & 7 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
# Change log

## 2024.12.10
- zopen changes: forbid implicit binary/text mode, signature change, default UTF-8 encoding in text mode, drop .z
support after one-year. (@DanielYang59)
- Add support for extended JSON to MontyDecoder (@esoteric-ephemera)
- Fix jsanitize when recursive_msonable=True (@Andrew-S-Rosen)
- Fix custom dict overriding in collections (@DanielYang59)

## 2024.10.21
* Lazily import torch/pydantic in json module, speedup from monty.json import by 10x (@DanielYang59)
* Fix missing monty.os package. (@eamanu)
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ Monty is created to serve as a complement to the Python standard library. It
provides suite of tools to solve many common problems, and hopefully,
be a resource to collect the best solutions.

Monty supports Python 3.10+.
Monty supports Python 3.x.

Please visit the [official docs](https://materialsvirtuallab.github.io/monty) for more information.
3 changes: 3 additions & 0 deletions docs/monty.functools.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ becomes
The decorated main accepts two new arguments:

> prof_file: Name of the output file with profiling data
> ```none
> If not given, a temporary file is created.
> ```
> sortby: Profiling data are sorted according to this value.
> ```none
> default is “time”. See sort_stats.
> ```
Expand Down
1 change: 1 addition & 0 deletions docs/monty.os.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ performing some tasks, and returns to the original working directory
afterwards. E.g.,

> with cd(“/my/path/”):
> ```none
> do_something()
> ```
Expand Down
2 changes: 2 additions & 0 deletions docs/monty.re.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ A powerful regular expression version of grep.
* **Returns**

> {key1: [[[matches…], lineno], [[matches…], lineno],
> ```none
> [[matches…], lineno], …],
> ```
> key2: …}
For reverse reads, the lineno is given as a -ve number. Please note
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ dependencies = [
"ruamel.yaml",
"numpy",
]
version = "2024.12.10"
version = "2024.10.21"

[project.optional-dependencies]
ci = [
Expand Down
27 changes: 13 additions & 14 deletions src/monty/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from enum import Enum
from hashlib import sha1
from importlib import import_module
from inspect import getfullargspec, isclass
from inspect import getfullargspec
from pathlib import Path
from typing import TYPE_CHECKING
from uuid import UUID, uuid4
Expand Down Expand Up @@ -70,12 +70,12 @@ def _load_redirect(redirect_file) -> dict:
return dict(redirect_dict)


def _check_type(obj: object, type_str: tuple[str, ...] | str) -> bool:
def _check_type(obj, type_str: tuple[str, ...] | str) -> bool:
"""Alternative to isinstance that avoids imports.
Checks whether obj is an instance of the type defined by type_str. This
removes the need to explicitly import type_str. Handles subclasses like
isinstance does. E.g.:
isinstance does. E.g.::
class A:
pass
Expand All @@ -90,22 +90,21 @@ class B(A):
assert isinstance(b, A)
assert not isinstance(a, B)
type_str: str | tuple[str]
Note for future developers: the type_str is not always obvious for an
object. For example, pandas.DataFrame is actually "pandas.core.frame.DataFrame".
object. For example, pandas.DataFrame is actually pandas.core.frame.DataFrame.
To find out the type_str for an object, run type(obj).mro(). This will
list all the types that an object can resolve to in order of generality
(all objects have the "builtins.object" as the last one).
(all objects have the builtins.object as the last one).
"""
# This function is intended as an alternative of "isinstance",
# therefore wouldn't check class
if isclass(obj):
return False

type_str = type_str if isinstance(type_str, tuple) else (type_str,)

mro = type(obj).mro()

return any(f"{o.__module__}.{o.__qualname__}" == ts for o in mro for ts in type_str)
# I believe this try-except is only necessary for callable types
try:
mro = type(obj).mro()
except TypeError:
return False
return any(f"{o.__module__}.{o.__name__}" == ts for o in mro for ts in type_str)


class MSONable:
Expand Down
129 changes: 0 additions & 129 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
MontyDecoder,
MontyEncoder,
MSONable,
_check_type,
_load_redirect,
jsanitize,
load,
Expand Down Expand Up @@ -1082,134 +1081,6 @@ def test_enum(self):
na2 = EnumAsDict.from_dict(d_)
assert na2 == na1


class TestCheckType:
def test_check_subclass(self):
class A:
pass

class B(A):
pass

a, b = A(), B()

class_name_A = f"{type(a).__module__}.{type(a).__qualname__}"
class_name_B = f"{type(b).__module__}.{type(b).__qualname__}"

# a is an instance of A, but not B
assert _check_type(a, class_name_A)
assert isinstance(a, A)
assert not _check_type(a, class_name_B)
assert not isinstance(a, B)

# b is an instance of both B and A
assert _check_type(b, class_name_B)
assert isinstance(b, B)
assert _check_type(b, class_name_A)
assert isinstance(b, A)

def test_check_class(self):
"""This should not work for classes."""

class A:
pass

class B(A):
pass

class_name_A = f"{A.__module__}.{A.__qualname__}"
class_name_B = f"{B.__module__}.{B.__qualname__}"

# Test class behavior (should return False, like isinstance does)
assert not _check_type(A, class_name_A)
assert not _check_type(B, class_name_B)
assert not _check_type(B, class_name_A)

def test_callable(self):
# Test function
def my_function():
pass

callable_class_name = (
f"{type(my_function).__module__}.{type(my_function).__qualname__}"
)

assert _check_type(my_function, callable_class_name), callable_class_name
assert isinstance(my_function, type(my_function))

# Test callable class
class MyCallableClass:
def __call__(self):
pass

callable_instance = MyCallableClass()
assert callable(callable_instance)

callable_class_instance_name = f"{type(callable_instance).__module__}.{type(callable_instance).__qualname__}"

assert _check_type(
callable_instance, callable_class_instance_name
), callable_class_instance_name
assert isinstance(callable_instance, MyCallableClass)

def test_numpy(self):
# Test NumPy array
arr = np.array([1, 2, 3])

assert _check_type(arr, "numpy.ndarray")
assert isinstance(arr, np.ndarray)

# Test NumPy generic
scalar = np.float64(3.14)

assert _check_type(scalar, "numpy.generic")
assert isinstance(scalar, np.generic)

@pytest.mark.skipif(pd is None, reason="pandas is not installed")
def test_pandas(self):
# Test pandas DataFrame
df = pd.DataFrame({"a": [1, 2, 3]})

assert _check_type(df, "pandas.core.frame.DataFrame")
assert isinstance(df, pd.DataFrame)

assert _check_type(df, "pandas.core.base.PandasObject")
assert isinstance(df, pd.core.base.PandasObject)

# Test pandas Series
series = pd.Series([1, 2, 3])

assert _check_type(series, "pandas.core.series.Series")
assert isinstance(series, pd.Series)

assert _check_type(series, "pandas.core.base.PandasObject")
assert isinstance(series, pd.core.base.PandasObject)

@pytest.mark.skipif(torch is None, reason="torch is not installed")
def test_torch(self):
tensor = torch.tensor([1, 2, 3])

assert _check_type(tensor, "torch.Tensor")
assert isinstance(tensor, torch.Tensor)

@pytest.mark.skipif(pydantic is None, reason="pydantic is not installed")
def test_pydantic(self):
class MyModel(pydantic.BaseModel):
name: str

model_instance = MyModel(name="Alice")

assert _check_type(model_instance, "pydantic.main.BaseModel")
assert isinstance(model_instance, pydantic.BaseModel)

@pytest.mark.skipif(pint is None, reason="pint is not installed")
def test_pint(self):
ureg = pint.UnitRegistry()
qty = 3 * ureg.meter

assert _check_type(qty, "pint.registry.Quantity")
assert isinstance(qty, pint.Quantity)

@pytest.mark.skipif(ObjectId is None, reason="bson not present")
def test_extended_json(self):
from bson import json_util
Expand Down

0 comments on commit 3c0e537

Please sign in to comment.