Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge v 0.35.x to master #4693

Merged
merged 3 commits into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/changes/0.35.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
QCoDeS 0.35.1 (2022-10-05)
==========================

QCoDeS 0.35.1 has been yanked due to an incorrect tag.
5 changes: 5 additions & 0 deletions docs/changes/0.35.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
QCoDeS 0.35.2 (2022-10-05)
==========================

This is a bugfix to fix an issue where the ``qcodes.utils.helpers`` module had an unexpected dependency
on ``pytest``.
2 changes: 2 additions & 0 deletions docs/changes/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ Changelogs

.. toctree::
Unreleased <unreleased>
0.35.2 <0.35.2>
0.35.1 <0.35.1>
0.35.0 <0.35.0>
0.35.0b1 <0.35.0b1>
0.34.1 <0.34.1>
Expand Down
80 changes: 79 additions & 1 deletion qcodes/utils/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Please do not import from this in any new code
"""
import logging
from typing import Any, Dict, Hashable, Optional, Tuple

# for backwards compatibility since this module used
# to contain logic that would abstract between yaml
Expand All @@ -15,7 +16,7 @@
from qcodes.parameters.sequence_helpers import is_sequence, is_sequence_of
from qcodes.parameters.sweep_values import make_sweep
from qcodes.parameters.val_mapping import create_on_off_val_mapping
from qcodes.tests.common import compare_dictionaries
from qcodes.utils.deprecate import deprecate

from .abstractmethod import qcodes_abstractmethod as abstractmethod
from .attribute_helpers import (
Expand All @@ -39,3 +40,80 @@
def warn_units(class_name: str, instance: object) -> None:
logging.warning('`units` is deprecated for the `' + class_name +
'` class, use `unit` instead. ' + repr(instance))


@deprecate("Internal function no longer part of the public qcodes api")
def compare_dictionaries(
dict_1: Dict[Hashable, Any],
dict_2: Dict[Hashable, Any],
dict_1_name: Optional[str] = "d1",
dict_2_name: Optional[str] = "d2",
path: str = "",
) -> Tuple[bool, str]:
"""
Compare two dictionaries recursively to find non matching elements.

Args:
dict_1: First dictionary to compare.
dict_2: Second dictionary to compare.
dict_1_name: Optional name of the first dictionary used in the
differences string.
dict_2_name: Optional name of the second dictionary used in the
differences string.
Returns:
Tuple: Are the dicts equal and the difference rendered as
a string.

"""
err = ""
key_err = ""
value_err = ""
old_path = path
for k in dict_1.keys():
path = old_path + "[%s]" % k
if k not in dict_2.keys():
key_err += f"Key {dict_1_name}{path} not in {dict_2_name}\n"
else:
if isinstance(dict_1[k], dict) and isinstance(dict_2[k], dict):
err += compare_dictionaries(
dict_1[k], dict_2[k], dict_1_name, dict_2_name, path
)[1]
else:
match = dict_1[k] == dict_2[k]

# if values are equal-length numpy arrays, the result of
# "==" is a bool array, so we need to 'all' it.
# In any other case "==" returns a bool
# TODO(alexcjohnson): actually, if *one* is a numpy array
# and the other is another sequence with the same entries,
# this will compare them as equal. Do we want this, or should
# we require exact type match?
if hasattr(match, "all"):
match = match.all()

if not match:
value_err += (
'Value of "{}{}" ("{}", type"{}") not same as\n'
' "{}{}" ("{}", type"{}")\n\n'
).format(
dict_1_name,
path,
dict_1[k],
type(dict_1[k]),
dict_2_name,
path,
dict_2[k],
type(dict_2[k]),
)

for k in dict_2.keys():
path = old_path + f"[{k}]"
if k not in dict_1.keys():
key_err += f"Key {dict_2_name}{path} not in {dict_1_name}\n"

dict_differences = key_err + value_err + err
if len(dict_differences) == 0:
dicts_equal = True
else:
dicts_equal = False
return dicts_equal, dict_differences