Skip to content

Commit

Permalink
Merge branch 'main' into ianna/3337-deprecationwarning-datetime_datet…
Browse files Browse the repository at this point in the history
…ime_utcfromtimestamp
  • Loading branch information
ianna authored Dec 21, 2024
2 parents 3a765ee + 288851a commit 88e56b5
Show file tree
Hide file tree
Showing 24 changed files with 760 additions and 389 deletions.
108 changes: 1 addition & 107 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,106 +17,6 @@ env:
SOURCE_DATE_EPOCH: "1668811211"

jobs:
pyodide-python-version:
name: Determine Pyodide Python version
runs-on: ubuntu-22.04
outputs:
python-version: ${{ steps.retrieve-python-version.outputs.python-version }}
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Cache python version
id: cache-pyodide-python-version
uses: actions/cache@v4
with:
path: pyodide-python-version
key: ${{ runner.os }}-docs-pyodide-python-version-${{ hashFiles('docs/requirements-wasm.txt') }}

- name: Setup Python
if: steps.cache-pyodide-python-version.outputs.cache-hit != 'true'
uses: actions/setup-python@v5
with:
python-version: "${{ env.X86_64_PYTHON_VERSION }}"

- name: Install dependencies
if: steps.cache-pyodide-python-version.outputs.cache-hit != 'true'
run: python3 -m pip install -r docs/requirements-wasm.txt

- name: Determine Python version
if: steps.cache-pyodide-python-version.outputs.cache-hit != 'true'
id: compute-python-version
run: |
# Save Python version
PYTHON_VERSION=$(pyodide config get python_version)
echo $PYTHON_VERSION > pyodide-python-version
- name: Retrieve Python version
id: retrieve-python-version
run: |
PYTHON_VERSION=$(cat pyodide-python-version)
echo "python-version=$PYTHON_VERSION" >> "$GITHUB_OUTPUT"
awkward-cpp-wasm:
name: Build C++ WASM
runs-on: ubuntu-22.04
needs: [pyodide-python-version]
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "${{ needs.pyodide-python-version.outputs.python-version }}"

- name: Generate build files
run: pipx run nox -s prepare -- --headers --signatures

- name: Cache wheel
id: cache-awkward-cpp-wasm-wheel
uses: actions/cache@v4
with:
path: ./awkward-cpp/dist
key: ${{ runner.os }}-"${{ needs.pyodide-python-version.outputs.python-version }}-awkward-cpp-wasm-${{ hashFiles('awkward-cpp/**') }}

- name: Install dependencies
if: steps.cache-awkward-cpp-wasm-wheel.outputs.cache-hit != 'true'
run: python3 -m pip install -r docs/requirements-wasm.txt

- name: Determine EMSDK version
if: steps.cache-awkward-cpp-wasm-wheel.outputs.cache-hit != 'true'
id: compute-emsdk-version
run: |
# Prepare xbuild environment (side-effect)
pyodide config list
# Save EMSDK version
EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version)
echo "emsdk-version=$EMSCRIPTEN_VERSION" >> $GITHUB_OUTPUT
working-directory: awkward-cpp

- name: Install EMSDK
uses: mymindstorm/setup-emsdk@v14
if: steps.cache-awkward-cpp-wasm-wheel.outputs.cache-hit != 'true'
with:
version: ${{ steps.compute-emsdk-version.outputs.emsdk-version }}

- name: Build wheel
if: steps.cache-awkward-cpp-wasm-wheel.outputs.cache-hit != 'true'
id: build-awkward-cpp-wasm-wheel
run: |
# pyodide-build doesn't work out of the box with pipx
CFLAGS=-fexceptions LDFLAGS=-fexceptions pyodide build --exports whole_archive
working-directory: awkward-cpp

- name: Upload wheel
uses: actions/upload-artifact@v4
with:
name: awkward-cpp-wasm
path: awkward-cpp/dist/awkward*wasm32.whl

awkward-cpp-x86-64:
runs-on: ubuntu-22.04
name: Build C++ x86
Expand Down Expand Up @@ -241,7 +141,7 @@ jobs:

build-docs:
runs-on: ubuntu-22.04
needs: [awkward-cpp-wasm, awkward-cpp-x86-64, awkward, execute-cppyy]
needs: [awkward-cpp-x86-64, awkward, execute-cppyy]
name: Build Docs
defaults:
run:
Expand Down Expand Up @@ -285,12 +185,6 @@ jobs:
mkdir -p docs/lite/pypi/
cp dist/awkward*.whl docs/lite/pypi/
- name: Download & copy awkward-cpp WASM wheel to JupyterLite
uses: actions/download-artifact@v4
with:
name: awkward-cpp-wasm
path: docs/lite/pypi

- name: Download awkward-cpp x86_64 wheel
uses: actions/download-artifact@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion docs/user-guide/how-to-create-missing.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,6 @@ def faster_example():
data, mask = faster_example()
array = ak.Array(data).mask[mask]
array = ak.mask(data, mask)
array
```
46 changes: 46 additions & 0 deletions src/awkward/_attrs.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# BSD 3-Clause License; see https://github.com/scikit-hep/awkward-1.0/blob/main/LICENSE
from __future__ import annotations

import weakref
from collections.abc import Mapping
from types import MappingProxyType

from awkward._typing import Any, JSONMapping

Expand Down Expand Up @@ -42,3 +44,47 @@ def attrs_of(*arrays, attrs: Mapping | None = None) -> Mapping:

def without_transient_attrs(attrs: dict[str, Any]) -> JSONMapping:
return {k: v for k, v in attrs.items() if not k.startswith("@")}


class Attrs(Mapping):
def __init__(self, ref, data: Mapping[str, Any]):
self._ref = weakref.ref(ref)
self._data = _freeze_attrs(
{_enforce_str_key(k): v for k, v in _unfreeze_attrs(data).items()}
)

def __getitem__(self, key: str):
return self._data[key]

def __setitem__(self, key: str, value: Any):
ref = self._ref()
if ref is None:
msg = "The reference array has been deleted. If you still need to set attributes, convert this 'Attrs' instance to a dict with '.to_dict()'."
raise ValueError(msg)
ref._attrs = _unfreeze_attrs(self._data) | {_enforce_str_key(key): value}

def __iter__(self):
return iter(self._data)

def __len__(self):
return len(self._data)

def __repr__(self):
return f"Attrs({_unfreeze_attrs(self._data)!r})"

def to_dict(self):
return _unfreeze_attrs(self._data)


def _enforce_str_key(key: Any) -> str:
if not isinstance(key, str):
raise TypeError(f"'attrs' keys must be strings, got: {key!r}")
return key


def _freeze_attrs(attrs: Mapping[str, Any]) -> Mapping[str, Any]:
return MappingProxyType(attrs)


def _unfreeze_attrs(attrs: Mapping[str, Any]) -> dict[str, Any]:
return dict(attrs)
2 changes: 1 addition & 1 deletion src/awkward/_categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class HashableDict:
def __init__(self, obj):
self.keys = tuple(sorted(obj))
self.values = tuple(as_hashable(obj[k]) for k in self.keys)
self.hash = hash((HashableDict, *self.keys), self.values)
self.hash = hash((HashableDict, self.keys, self.values))

def __hash__(self):
return self.hash
Expand Down
62 changes: 19 additions & 43 deletions src/awkward/_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from __future__ import annotations

import builtins
import sys
import threading
import warnings
from collections.abc import Callable, Collection, Iterable, Mapping
Expand Down Expand Up @@ -51,11 +49,6 @@ def __call__(self):
return self.func(*self.args, **self.kwargs)


class KeyError(builtins.KeyError):
def __str__(self):
return super(Exception, self).__str__()


class ErrorContext:
# Any other threads should get a completely independent _slate.
_slate = threading.local()
Expand All @@ -75,50 +68,33 @@ def __enter__(self):
self._slate.__dict__["__primary_context__"] = self

def __exit__(self, exception_type, exception_value, traceback):
try:
if (
exception_type is not None
and issubclass(exception_type, Exception)
and self.primary() is self
):
# Step out of the way so that another ErrorContext can become primary.
# Is this necessary to do here? (We're about to raise an exception anyway)
self._slate.__dict__.clear()
# Handle caught exception
if (
exception_type is not None
and issubclass(exception_type, Exception)
and self.primary() is self
):
self.handle_exception(exception_type, exception_value)
finally:
raise self.decorate_exception(exception_type, exception_value)
else:
# Step out of the way so that another ErrorContext can become primary.
if self.primary() is self:
self._slate.__dict__.clear()

def handle_exception(self, cls: type[E], exception: E):
if sys.version_info >= (3, 11, 0, "final"):
self.decorate_exception(cls, exception)
else:
raise self.decorate_exception(cls, exception)

def decorate_exception(self, cls: type[E], exception: E) -> Exception:
if sys.version_info >= (3, 11, 0, "final"):
if issubclass(cls, (NotImplementedError, AssertionError)):
exception.add_note(
"\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
)
def _add_note(exception: E, note: str) -> E:
if hasattr(exception, "add_note"):
exception.add_note(note)
else:
exception.add_note(self.note)
exception.__notes__ = [note]
return exception
else:
new_exception: Exception
if issubclass(cls, (NotImplementedError, AssertionError)):
# Raise modified exception
new_exception = cls(
str(exception)
+ "\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
)
new_exception.__cause__ = exception
elif issubclass(cls, builtins.KeyError):
new_exception = KeyError(self.format_exception(exception))
new_exception.__cause__ = exception
else:
new_exception = cls(self.format_exception(exception))
new_exception.__cause__ = exception
return new_exception

note = self.note
if issubclass(cls, (NotImplementedError, AssertionError)):
note = "\n\nSee if this has been reported at https://github.com/scikit-hep/awkward/issues"
return _add_note(exception, note)

def format_argument(self, width, value):
from awkward import contents, highlevel, record
Expand Down
2 changes: 1 addition & 1 deletion src/awkward/_nplikes/array_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ def reshape(
) -> ArrayLikeT | PlaceholderArray:
if isinstance(x, PlaceholderArray):
next_shape = self._compute_compatible_shape(shape, x.shape)
return PlaceholderArray(self, next_shape, x.dtype)
return PlaceholderArray(self, next_shape, x.dtype, x._field_path)

if copy is None:
return self._module.reshape(x, shape)
Expand Down
31 changes: 25 additions & 6 deletions src/awkward/_nplikes/placeholder.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,21 @@


class PlaceholderArray(ArrayLike):
def __init__(self, nplike: NumpyLike, shape: tuple[ShapeItem, ...], dtype: DType):
def __init__(
self,
nplike: NumpyLike,
shape: tuple[ShapeItem, ...],
dtype: DType,
field_path: tuple[str, ...] = (),
):
self._nplike = nplike
self._shape = shape
self._dtype = np.dtype(dtype)
self._field_path = field_path

@property
def field_path(self) -> str:
return ".".join(self._field_path)

@property
def dtype(self) -> DType:
Expand Down Expand Up @@ -67,7 +78,7 @@ def view(self, dtype: DTypeLike) -> Self:
shape = self._shape[:-1] + (last,)
else:
shape = self._shape
return type(self)(self._nplike, shape, dtype)
return type(self)(self._nplike, shape, dtype, self._field_path)

def __getitem__(self, index):
# Typetracers permit slices that don't touch data or shapes
Expand All @@ -92,11 +103,19 @@ def __getitem__(self, index):
start, stop, step = index.indices(length)
new_length = (stop - start) // step

return type(self)(self._nplike, (new_length,), self._dtype)
else:
raise TypeError(
f"{type(self).__name__} supports only trivial slices, not {type(index).__name__}"
return type(self)(
self._nplike, (new_length,), self._dtype, self._field_path
)
else:
msg = f"{type(self).__name__} supports only trivial slices, not {type(index).__name__}"
if self.field_path:
msg += f"\n\nAwkward-array attempted to access a field '{self.field_path}', but "
msg += (
"it has been excluded during a pre-run phase (possibly by Dask). "
)
msg += "If this was supposed to happen automatically (e.g. you're using Dask), "
msg += "please report it to the developers at: https://github.com/scikit-hep/awkward/issues"
raise TypeError(msg)

def __setitem__(self, key, value):
raise RuntimeError
Expand Down
Loading

0 comments on commit 88e56b5

Please sign in to comment.