GitCop: There were the following issues with your Pull Request

 * Commit: a2e553b013c36998d69c086281ac2156d71481d3
  * Your commit message body contains a line that is longer than 80 characters

Guidelines are available at https://github.com/zhmcclient/python-zhmcclient/blob/master/CONTRIBUTING.rst

---
This message was auto-generated by https://gitcop.com

GitCop: There were the following issues with your Pull Request

 * Commit: 56a1eaed0dc89da51487a141e15dc7912f86a9af
  * Your commit message body contains a line that is longer than 80 characters

Guidelines are available at https://github.com/zhmcclient/python-zhmcclient/blob/master/CONTRIBUTING.rst

---
This message was auto-generated by https://gitcop.com

diff --git a/docs/changes.rst b/docs/changes.rst
index f6dccff..51adb06 100755
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -27,6 +27,10 @@ Released: not yet
 
 **Incompatible changes:**
 
+* Changed the return value of ``TimeStatsKeeper.snapshot()`` from a list of
+  key/value tuples to a dictionary. This is more flexible and reduces the
+  number of data structure conversions in different scenarios. See issue #269.
+
 **Deprecations:**
 
 **Bug fixes:**
diff --git a/zhmcclient/_timestats.py b/zhmcclient/_timestats.py
index e0d9c3d..07dc648 100644
--- a/zhmcclient/_timestats.py
+++ b/zhmcclient/_timestats.py
@@ -280,13 +280,13 @@ class TimeStatsKeeper(object):
 
         Returns:
 
-          : A list of tuples (name, stats) with:
+         dict: A dictionary of the time statistics by operation, where:
 
-          - name (:term:`string`): Name of the operation
-          - stats (:class:`~zhmcclient.TimeStats`): Time statistics for the
+          - key (:term:`string`): Name of the operation
+          - value (:class:`~zhmcclient.TimeStats`): Time statistics for the
             operation
         """
-        return copy.deepcopy(self._time_stats).items()
+        return copy.deepcopy(self._time_stats)
 
     def __str__(self):
         """
@@ -303,7 +303,8 @@ class TimeStatsKeeper(object):
         ret = "Time statistics (times in seconds):\n"
         if self.enabled:
             ret += "Count  Average  Minimum  Maximum  Operation name\n"
-            snapshot_by_avg = sorted(self.snapshot(),
+            stats_dict = self.snapshot()
+            snapshot_by_avg = sorted(stats_dict.items(),
                                      key=lambda item: item[1].avg_time,
                                      reverse=True)
             for name, stats in snapshot_by_avg:

TimeStatsKeeper.snapshot() result not very handy
The `TimeStatsKeeper.snapshot()` method returns a list of tuples (op_name, TimeStats), which it produces by appliying the `items()` method on the internal dictionary.

Most uses of the snapshot I have seen so far, transform that back into a dictionary by using `dict(snapshot)`.

It would be more efficient and more convenient if snapshot() simply returned (a copy of) the dictionary directly.

Note that this would be an incompatible change.
diff --git a/tests/unit/test_timestats.py b/tests/unit/test_timestats.py
index 1155489..1733f6f 100755
--- a/tests/unit/test_timestats.py
+++ b/tests/unit/test_timestats.py
@@ -142,7 +142,9 @@ class TimeStatsTests(unittest.TestCase):
         stats = keeper.get_stats('foo')
         dur = measure(stats, duration)
 
-        for _, stats in keeper.snapshot():
+        stats_dict = keeper.snapshot()
+        for op_name in stats_dict:
+            stats = stats_dict[op_name]
             self.assertEqual(stats.count, 1)
             self.assertLess(time_abs_delta(stats.avg_time, dur), delta,
                             "avg time: actual: %f, expected: %f, delta: %f" %
@@ -174,7 +176,9 @@ class TimeStatsTests(unittest.TestCase):
         time.sleep(duration)
         stats.end()
 
-        for _, stats in keeper.snapshot():
+        stats_dict = keeper.snapshot()
+        for op_name in stats_dict:
+            stats = stats_dict[op_name]
             self.assertEqual(stats.count, 0)
             self.assertEqual(stats.avg_time, 0)
             self.assertEqual(stats.min_time, float('inf'))
@@ -196,7 +200,7 @@ class TimeStatsTests(unittest.TestCase):
         stats.end()
 
         # take the snapshot
-        snapshot = keeper.snapshot()
+        snap_stats_dict = keeper.snapshot()
 
         # produce a second data item
         stats.begin()
@@ -204,7 +208,8 @@ class TimeStatsTests(unittest.TestCase):
         stats.end()
 
         # verify that only the first data item is in the snapshot
-        for _, snap_stats in snapshot:
+        for op_name in snap_stats_dict:
+            snap_stats = snap_stats_dict[op_name]
             self.assertEqual(snap_stats.count, 1)
 
         # verify that both data items are in the original stats object
@@ -230,7 +235,9 @@ class TimeStatsTests(unittest.TestCase):
         max_dur = max(m_durations)
         avg_dur = sum(m_durations) / float(count)
 
-        for _, stats in keeper.snapshot():
+        stats_dict = keeper.snapshot()
+        for op_name in stats_dict:
+            stats = stats_dict[op_name]
             self.assertEqual(stats.count, 3)
             self.assertLess(time_abs_delta(stats.avg_time, avg_dur), delta,
                             "avg time: actual: %f, expected: %f, delta: %f" %

pip install -e .[dev]
parse_log_pytest
requirements.txt
pytest pytest-cov pytest-mock pytest-xdist
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
charset-normalizer==2.0.12
click==8.0.4
click-repl==0.3.0
click-spinner==0.1.10
coverage==6.2
decorator==5.1.1
docopt==0.6.2
execnet==1.9.0
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
packaging==21.3
pbr==6.1.1
pluggy==1.0.0
progressbar2==3.55.0
prompt-toolkit==3.0.36
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-cov==4.0.0
pytest-mock==3.6.1
pytest-xdist==3.0.2
python-utils==3.5.2
requests==2.27.1
six==1.17.0
stomp.py==8.1.0
tabulate==0.8.10
tomli==1.2.3
typing_extensions==4.1.1
urllib3==1.26.20
wcwidth==0.2.13
websocket-client==1.3.1
-e git+https://github.com/zhmcclient/python-zhmcclient.git@077e1ada5272d57143f1d453568ac5dd9daa6a8c#egg=zhmcclient
zipp==3.6.0

name: python-zhmcclient
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - charset-normalizer==2.0.12
      - click==8.0.4
      - click-repl==0.3.0
      - click-spinner==0.1.10
      - coverage==6.2
      - decorator==5.1.1
      - docopt==0.6.2
      - execnet==1.9.0
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - packaging==21.3
      - pbr==6.1.1
      - pluggy==1.0.0
      - progressbar2==3.55.0
      - prompt-toolkit==3.0.36
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-cov==4.0.0
      - pytest-mock==3.6.1
      - pytest-xdist==3.0.2
      - python-utils==3.5.2
      - requests==2.27.1
      - six==1.17.0
      - stomp-py==8.1.0
      - tabulate==0.8.10
      - tomli==1.2.3
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - wcwidth==0.2.13
      - websocket-client==1.3.1
      - zipp==3.6.0
prefix: /opt/conda/envs/python-zhmcclient

tests/unit/test_timestats.py::TimeStatsTests::test_measure_avg_min_max tests/unit/test_timestats.py::TimeStatsTests::test_measure_enabled tests/unit/test_timestats.py::TimeStatsTests::test_snapshot
tests/unit/test_timestats.py::TimeStatsTests::test_enabling tests/unit/test_timestats.py::TimeStatsTests::test_get tests/unit/test_timestats.py::TimeStatsTests::test_measure_disabled tests/unit/test_timestats.py::TimeStatsTests::test_str_disabled tests/unit/test_timestats.py::TimeStatsTests::test_str_empty
docs/changes.rst zhmcclient/_timestats.py
docs/changes.rst zhmcclient/_timestats.py