Skip to content

Commit 4ceb377

Browse files
authored
deps: Vendor more_itertools.consecutive_groups (#613)
more_itertools package contains useful functions built on top of stdlib itertools, but we only use a single function from the package so let's vendor it and remove the dependency. This means app developers can happily use this package without worrying about version clashes with AWB. Part of #392
1 parent acf6cb6 commit 4ceb377

File tree

2 files changed

+28
-12
lines changed

2 files changed

+28
-12
lines changed

aiidalab_widgets_base/utils/__init__.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
"""Some utility functions used acrross the repository."""
22

3+
import itertools
4+
import operator
35
import threading
46
from enum import Enum
57
from typing import Any
68

9+
import ase
10+
import ase.io
711
import ipywidgets as ipw
8-
import more_itertools as mit
912
import numpy as np
10-
import traitlets
13+
import traitlets as tl
1114
from aiida.plugins import DataFactory
12-
from ase import Atoms
13-
from ase.io import read
1415

1516
CifData = DataFactory("core.cif") # pylint: disable=invalid-name
1617
StructureData = DataFactory("core.structure") # pylint: disable=invalid-name
@@ -43,24 +44,40 @@ def get_ase_from_file(fname, file_format=None): # pylint: disable=redefined-bui
4344
# store_tags parameter is useful for CIF files
4445
# https://wiki.fysik.dtu.dk/ase/ase/io/formatoptions.html#cif
4546
if file_format == "cif":
46-
traj = read(fname, format=file_format, index=":", store_tags=True)
47+
traj = ase.io.read(fname, format=file_format, index=":", store_tags=True)
4748
else:
48-
traj = read(fname, format=file_format, index=":")
49+
traj = ase.io.read(fname, format=file_format, index=":")
4950
if not traj:
5051
raise ValueError(f"Could not read any information from the file {fname}")
5152
return traj
5253

5354

5455
def find_ranges(iterable):
5556
"""Yield range of consecutive numbers."""
56-
for grp in mit.consecutive_groups(iterable):
57+
for grp in _consecutive_groups(iterable):
5758
group = list(grp)
5859
if len(group) == 1:
5960
yield group[0]
6061
else:
6162
yield group[0], group[-1]
6263

6364

65+
def _consecutive_groups(iterable, ordering=lambda x: x):
66+
"""Yield groups of consecutive items using :func:`itertools.groupby`.
67+
The *ordering* function determines whether two items are adjacent by
68+
returning their position.
69+
70+
This is a vendored version of more_itertools.consecutive_groups
71+
https://more-itertools.readthedocs.io/en/v10.3.0/_modules/more_itertools/more.html#consecutive_groups
72+
Distributed under MIT license: https://more-itertools.readthedocs.io/en/v10.3.0/license.html
73+
Thank you Bo Bayles for the original implementation. <3
74+
"""
75+
for _, g in itertools.groupby(
76+
enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
77+
):
78+
yield map(operator.itemgetter(1), g)
79+
80+
6481
def list_to_string_range(lst, shift=1):
6582
"""Converts a list like [0, 2, 3, 4] into a string like '1 3..5'.
6683
@@ -124,15 +141,15 @@ def inverse_matrix(self):
124141
return np.linalg.inv(self.matrix)
125142

126143

127-
class _StatusWidgetMixin(traitlets.HasTraits):
144+
class _StatusWidgetMixin(tl.HasTraits):
128145
"""Show temporary messages for example for status updates.
129146
This is a mixin class that is meant to be part of an inheritance
130147
tree of an actual widget with a 'value' traitlet that is used
131148
to convey a status message. See the non-private classes below
132149
for examples.
133150
"""
134151

135-
message = traitlets.Unicode(default_value="", allow_none=True)
152+
message = tl.Unicode(default_value="", allow_none=True)
136153
new_line = "\n"
137154

138155
def __init__(self, clear_after=3, *args, **kwargs):
@@ -169,7 +186,7 @@ class StatusHTML(_StatusWidgetMixin, ipw.HTML):
169186

170187
# This method should be part of _StatusWidgetMixin, but that does not work
171188
# for an unknown reason.
172-
@traitlets.observe("message")
189+
@tl.observe("message")
173190
def _observe_message(self, change):
174191
self.show_temporary_message(change["new"])
175192

@@ -201,7 +218,7 @@ def wrap_message(message, level=MessageLevel.INFO):
201218
"""
202219

203220

204-
def ase2spglib(ase_structure: Atoms) -> tuple[Any, Any, Any]:
221+
def ase2spglib(ase_structure: ase.Atoms) -> tuple[Any, Any, Any]:
205222
"""
206223
Convert ase Atoms instance to spglib cell in the format defined at
207224
https://spglib.github.io/spglib/python-spglib.html#crystal-structure-cell

setup.cfg

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ install_requires =
3030
traitlets~=5.9.0
3131
ipywidgets~=7.7
3232
widgetsnbextension<3.6.3
33-
more-itertools~=8.0
3433
pymysql~=0.9
3534
nglview~=3.0
3635
spglib>=1.14,<3

0 commit comments

Comments
 (0)