Skip to content

Commit

Permalink
Merge branch 'main' into proper-global-var-singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
unkcpz committed Nov 26, 2024
2 parents e8919dc + 36eab77 commit aec9321
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 45 deletions.
30 changes: 0 additions & 30 deletions .github/workflows/ci-style.yml

This file was deleted.

12 changes: 1 addition & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ repos:
.docker/.*|
docs/.*|
utils/.*|
tests/.*|
src/aiida/calculations/arithmetic/add.py|
src/aiida/calculations/diff_tutorial/calculations.py|
Expand Down Expand Up @@ -191,17 +192,6 @@ repos:
src/aiida/transports/plugins/local.py|
src/aiida/transports/plugins/ssh.py|
src/aiida/workflows/arithmetic/multiply_add.py|
tests/conftest.py|
tests/repository/conftest.py|
tests/repository/test_repository.py|
tests/sphinxext/sources/workchain/conf.py|
tests/sphinxext/sources/workchain_broken/conf.py|
tests/storage/psql_dos/migrations/conftest.py|
tests/storage/psql_dos/migrations/django_branch/test_0026_0027_traj_data.py|
tests/test_calculation_node.py|
tests/test_nodes.py|
)$
- id: dm-generate-all
Expand Down
7 changes: 4 additions & 3 deletions src/aiida/orm/nodes/data/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""`Data` sub class to represent a list."""

from collections.abc import MutableSequence
from typing import Any

from .base import to_aiida_type
from .data import Data
Expand Down Expand Up @@ -81,15 +82,15 @@ def remove(self, value):
self.set_list(data)
return item

def pop(self, **kwargs): # type: ignore[override]
def pop(self, index: int = -1) -> Any:
"""Remove and return item at index (default last)."""
data = self.get_list()
item = data.pop(**kwargs)
item = data.pop(index)
if not self._using_list_reference():
self.set_list(data)
return item

def index(self, value): # type: ignore[override]
def index(self, value: Any, start: int = 0, stop: int = 0) -> int:
"""Return first index of value.."""
return self.get_list().index(value)

Expand Down
2 changes: 1 addition & 1 deletion src/aiida/tools/pytest_fixtures/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def test(submit_and_await):
from aiida.engine import ProcessState

def factory(
submittable: type[Process] | ProcessBuilder | ProcessNode | t.Any,
submittable: type[Process] | ProcessBuilder | ProcessNode,
state: ProcessState = ProcessState.FINISHED,
timeout: int = 20,
**kwargs,
Expand Down
161 changes: 161 additions & 0 deletions tests/orm/test_querybuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"""Tests for the QueryBuilder."""

import copy
import json
import uuid
import warnings
from collections import defaultdict
Expand Down Expand Up @@ -1702,3 +1703,163 @@ def test_statistics_default_class(self, aiida_localhost):
# data are correct
res = next(iter(qb.dict()[0].values()))
assert res == expected_dict


class TestJsonFilters:
@pytest.mark.parametrize(
'data,filters,is_match',
(
# contains different types of element
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': [1]}}, True),
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': ['2']}}, True),
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': [None]}}, True),
# contains multiple elements of various types
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': [1, None]}}, True),
# contains non-exist elements
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': [114514]}}, False),
# contains empty set
({'arr': [1, '2', None]}, {'attributes.arr': {'contains': []}}, True),
({'arr': []}, {'attributes.arr': {'contains': []}}, True),
# nested arrays
({'arr': [[1, 0], [0, 2]]}, {'attributes.arr': {'contains': [[1, 0]]}}, True),
({'arr': [[2, 3], [0, 1], []]}, {'attributes.arr': {'contains': [[1, 0]]}}, True),
({'arr': [[2, 3], [1]]}, {'attributes.arr': {'contains': [[4]]}}, False),
({'arr': [[1, 0], [0, 2]]}, {'attributes.arr': {'contains': [[3]]}}, False),
({'arr': [[1, 0], [0, 2]]}, {'attributes.arr': {'contains': [3]}}, False),
({'arr': [[1, 0], [0, 2]]}, {'attributes.arr': {'contains': [[2]]}}, True),
({'arr': [[1, 0], [0, 2]]}, {'attributes.arr': {'contains': [2]}}, False),
({'arr': [[1, 0], [0, 2], 3]}, {'attributes.arr': {'contains': [[3]]}}, False),
({'arr': [[1, 0], [0, 2], 3]}, {'attributes.arr': {'contains': [3]}}, True),
# negations
({'arr': [1, '2', None]}, {'attributes.arr': {'!contains': [1]}}, False),
({'arr': [1, '2', None]}, {'attributes.arr': {'!contains': []}}, False),
({'arr': [1, '2', None]}, {'attributes.arr': {'!contains': [114514]}}, True),
({'arr': [1, '2', None]}, {'attributes.arr': {'!contains': [1, 114514]}}, True),
# TODO: these pass, but why? are these behaviors expected?
# non-exist `attr_key`s
({'foo': []}, {'attributes.arr': {'contains': []}}, False),
({'foo': []}, {'attributes.arr': {'!contains': []}}, False),
),
ids=json.dumps,
)
@pytest.mark.usefixtures('aiida_profile_clean')
@pytest.mark.requires_psql
def test_json_filters_contains_arrays(self, data, filters, is_match):
"""Test QueryBuilder filter `contains` for JSON array fields"""
orm.Dict(data).store()
qb = orm.QueryBuilder().append(orm.Dict, filters=filters)
assert qb.count() in {0, 1}
found = qb.count() == 1
assert found == is_match

@pytest.mark.parametrize(
'data,filters,is_match',
(
# contains different types of values
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'contains': {'k1': 1}}},
True,
),
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'contains': {'k1': 1, 'k2': '2'}}},
True,
),
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'contains': {'k3': None}}},
True,
),
# contains empty set
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'contains': {}}},
True,
),
# doesn't contain non-exist entries
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'contains': {'k1': 1, 'k': 'v'}}},
False,
),
# negations
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'!contains': {'k1': 1}}},
False,
),
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'!contains': {'k1': 1, 'k': 'v'}}},
True,
),
(
{
'dict': {
'k1': 1,
'k2': '2',
'k3': None,
}
},
{'attributes.dict': {'!contains': {}}},
False,
),
# TODO: these pass, but why? are these behaviors expected?
# non-exist `attr_key`s
({'map': {}}, {'attributes.dict': {'contains': {}}}, False),
({'map': {}}, {'attributes.dict': {'!contains': {}}}, False),
),
ids=json.dumps,
)
@pytest.mark.usefixtures('aiida_profile_clean')
@pytest.mark.requires_psql
def test_json_filters_contains_object(self, data, filters, is_match):
"""Test QueryBuilder filter `contains` for JSON object fields"""
orm.Dict(data).store()
qb = orm.QueryBuilder().append(orm.Dict, filters=filters)
assert qb.count() in {0, 1}
found = qb.count() == 1
assert found == is_match
56 changes: 56 additions & 0 deletions utils/patch-release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/bash

# Script: patch-release.sh
# Description:
# Cherry-picks a list of commits, amends each with the original commit hash for tracking,
# and generates a summary from the short github commit messages with links to each commit.
#
# Usage:
# ./patch-release.sh <commit1> <commit2> ...
#
# Example:
# ./patch-release.sh abc1234 def5678

set -e

# Check if at least two arguments are provided (repo and at least one commit)
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <commit1> <commit2> ..."
echo "Example: $0 abc1234 def5678"
exit 1
fi

GITHUB_REPO="aiidateam/aiida-core"

# Create an array to store commit summaries
declare -a commit_summaries=()

# Loop through each commit hash
for commit in "$@"; do
# Cherry-pick the commit
if git cherry-pick "$commit"; then
# If cherry-pick succeeds, get the short message and short hash
commit_message=$(git log -1 --pretty=format:"%B" HEAD)
original_short_hash=$(git log -1 --pretty=format:"%h" "$commit")
original_long_hash=$(git rev-parse $original_short_hash)

# Amend the cherry-picked commit to include the original commit ID for tracking
git commit --amend -m "$commit_message" -m "Cherry-pick: $original_long_hash"

# Format the output as a Markdown list item and add to the array
short_commit_message=$(git log -1 --pretty=format:"%s" HEAD)
cherry_picked_hash=$(git log -1 --pretty=format:"%h" HEAD)
commit_summaries+=("- $short_commit_message [[${commit}]](https://github.com/$GITHUB_REPO/commit/${original_long_hash})")
else
echo "Failed to cherry-pick commit $commit"
# Abort the cherry-pick in case of conflict
git cherry-pick --abort
exit 1
fi
done

# Print the summary
echo -e "\n### Cherry-Picked Commits Summary:\n"
for summary in "${commit_summaries[@]}"; do
echo "$summary"
done

0 comments on commit aec9321

Please sign in to comment.