iqm-pulla 7.23.0__py3-none-any.whl → 8.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
iqm/pulla/calibration.py CHANGED
@@ -16,9 +16,14 @@
16
16
 
17
17
  from copy import deepcopy
18
18
  import logging
19
+ import uuid
19
20
 
21
+ from exa.common.data.value import ObservationValue
20
22
  from iqm.pulla.interface import CalibrationSet, CalibrationSetId
21
- from iqm.station_control.client.station_control import StationControlClient
23
+ from iqm.pulla.utils import calset_from_observations
24
+ from iqm.station_control.client.iqm_server.iqm_server_client import IqmServerClient
25
+ from iqm.station_control.interface.models import ObservationSetData
26
+ from iqm.station_control.interface.station_control import StationControlInterface
22
27
 
23
28
  logger = logging.getLogger(__name__)
24
29
 
@@ -28,8 +33,8 @@ CalibrationDataFetchException = RuntimeError
28
33
  class CalibrationDataProvider:
29
34
  """Access calibration info via station control client and cache data in memory."""
30
35
 
31
- def __init__(self, station_control_client: StationControlClient):
32
- self._station_control_client = station_control_client
36
+ def __init__(self, station_control: StationControlInterface):
37
+ self._station_control = station_control
33
38
  self._calibration_sets: dict[CalibrationSetId, CalibrationSet] = {}
34
39
 
35
40
  def get_calibration_set(self, cal_set_id: CalibrationSetId) -> CalibrationSet:
@@ -37,7 +42,7 @@ class CalibrationDataProvider:
37
42
  logger.debug("Get the calibration set from the database: cal_set_id=%s", cal_set_id)
38
43
  try:
39
44
  if cal_set_id not in self._calibration_sets:
40
- cal_set_values = self._station_control_client.get_calibration_set_values(cal_set_id)
45
+ cal_set_values = self.get_calibration_set_values(cal_set_id)
41
46
  self._calibration_sets[cal_set_id] = cal_set_values
42
47
  return deepcopy(self._calibration_sets[cal_set_id])
43
48
  except Exception as e:
@@ -47,10 +52,44 @@ class CalibrationDataProvider:
47
52
  """Get the latest calibration set id for chip label from the database."""
48
53
  logger.debug("Get the latest calibration set for chip label: chip_label=%s", chip_label)
49
54
  try:
50
- latest_cal_set_id = self._station_control_client.get_latest_calibration_set_id(chip_label)
55
+ if isinstance(self._station_control, IqmServerClient):
56
+ latest_cal_set_id = self._station_control.get_latest_calibration_set_id(chip_label)
57
+ latest_calibration_set = self.get_calibration_set(latest_cal_set_id), latest_cal_set_id
58
+ else:
59
+ latest_calibration_set = self._get_latest_calibration_set(chip_label)
51
60
  except Exception as e:
52
61
  raise CalibrationDataFetchException(
53
62
  f"Could not fetch latest calibration set id from the database: {e}"
54
63
  ) from e
64
+ return latest_calibration_set, latest_calibration_set.observation_set_id
55
65
 
56
- return self.get_calibration_set(latest_cal_set_id), latest_cal_set_id
66
+ def _get_latest_calibration_set(self, dut_label: str) -> ObservationSetData:
67
+ observation_sets = self._station_control.query_observation_sets(
68
+ observation_set_type="calibration-set",
69
+ dut_label=dut_label,
70
+ invalid=False,
71
+ end_timestamp__isnull=False, # Finalized
72
+ order_by="-end_timestamp",
73
+ limit=1,
74
+ )
75
+ return observation_sets[0]
76
+
77
+ def get_calibration_set_values(self, calibration_set_id: uuid.UUID) -> dict[str, ObservationValue]:
78
+ """Get saved calibration set observations by UUID
79
+
80
+ Args:
81
+ calibration_set_id: UUID of the calibration set to retrieve.
82
+
83
+ Returns:
84
+ Dictionary of observations belonging to the given calibration set.
85
+
86
+ """
87
+ if isinstance(self._station_control, IqmServerClient):
88
+ calibration_set_values = self._station_control.get_calibration_set_values(calibration_set_id)
89
+ else:
90
+ observation_set = self._station_control.get_observation_set(calibration_set_id)
91
+ if observation_set.observation_set_type != "calibration-set":
92
+ raise ValueError("Observation set type is not 'calibration-set'")
93
+ observations = self._station_control.get_observation_set_observations(calibration_set_id)
94
+ calibration_set_values = calset_from_observations(observations)
95
+ return calibration_set_values
iqm/pulla/pulla.py CHANGED
@@ -47,10 +47,8 @@ from iqm.pulla.interface import (
47
47
  from iqm.pulla.utils import extract_readout_controller_result_names, map_sweep_results_to_logical_qubits
48
48
  from iqm.pulse.playlist.channel import ChannelProperties, get_channel_properties_from_station_settings
49
49
  from iqm.pulse.playlist.playlist import Playlist
50
- from iqm.station_control.client.station_control import StationControlClient
51
- from iqm.station_control.client.utils import get_progress_bar_callback
52
- from iqm.station_control.interface.models import JobExecutorStatus
53
- from iqm.station_control.interface.models.sweep import SweepDefinition
50
+ from iqm.station_control.client.utils import get_progress_bar_callback, init_station_control
51
+ from iqm.station_control.interface.models import JobExecutorStatus, SweepDefinition
54
52
 
55
53
  # ██████ ██ ██ ██ ██ █████
56
54
  # ██ ██ ██ ██ ██ ██ ██ ██
@@ -88,14 +86,15 @@ class Pulla:
88
86
 
89
87
  # SC Client to be used for fetching calibration data, submitting sweeps, and retrieving results.
90
88
  try:
91
- self._station_control_client = StationControlClient.init(
89
+ self._station_control = init_station_control(
92
90
  station_control_url, get_token_callback=self.get_token_callback, **kwargs
93
91
  )
92
+
94
93
  except Exception as e:
95
94
  logger.error("Failed to initialize Station Control Client: %s", e)
96
95
  raise ValueError("Failed to initialize Station Control Client") from e
97
96
  # Separate wrapper on top of SC Client to simplify calibration data fetching.
98
- self._calibration_data_provider = CalibrationDataProvider(self._station_control_client)
97
+ self._calibration_data_provider = CalibrationDataProvider(self._station_control)
99
98
 
100
99
  # Data needed for the compiler.
101
100
  self._station_control_settings: SettingNode | None = None
@@ -159,9 +158,12 @@ class Pulla:
159
158
  return calibration_set
160
159
 
161
160
  def get_chip_label(self) -> str:
162
- """Returns the chip label of the current quantum computer. The chip label is fetched from the Station Control API.""" # noqa: E501
161
+ """Returns the chip label of the current quantum computer.
162
+
163
+ The chip label is fetched from the Station Control API.
164
+ """
163
165
  try:
164
- duts = self._station_control_client.get_duts()
166
+ duts = self._station_control.get_duts()
165
167
  except requests.RequestException as e:
166
168
  raise ChipLabelRetrievalException(f"Failed to retrieve the chip label: {e}") from e
167
169
 
@@ -172,7 +174,7 @@ class Pulla:
172
174
  def get_chip_topology(self) -> ChipTopology:
173
175
  """Returns chip topology that was fetched from the IQM server during Pulla initialization."""
174
176
  try:
175
- record = self._station_control_client.get_chip_design_record(self.get_chip_label())
177
+ record = self._station_control.get_chip_design_record(self.get_chip_label())
176
178
  except Exception as e:
177
179
  raise CHADRetrievalException("Could not fetch chip design record") from e
178
180
  return ChipTopology.from_chip_design_record(record)
@@ -182,7 +184,7 @@ class Pulla:
182
184
  if self._station_control_settings is None:
183
185
  # request the station settings, cache the results
184
186
  try:
185
- self._station_control_settings = self._station_control_client.get_settings()
187
+ self._station_control_settings = self._station_control.get_settings()
186
188
  except Exception as e:
187
189
  raise SettingsRetrievalException("Could not fetch station settings") from e
188
190
  return self._station_control_settings
@@ -227,7 +229,7 @@ class Pulla:
227
229
  if k == "readout":
228
230
  readout_components.append(v)
229
231
 
230
- sweep_response = self._station_control_client.sweep(
232
+ sweep_response = self._station_control.sweep(
231
233
  SweepDefinition(
232
234
  sweep_id=uuid.uuid4(),
233
235
  playlist=playlist,
@@ -246,15 +248,13 @@ class Pulla:
246
248
  logger.info("Waiting for the job to finish...")
247
249
 
248
250
  while True:
249
- sweep_data = self._station_control_client.get_sweep(job_id)
251
+ sweep_data = self._station_control.get_sweep(job_id)
250
252
  sc_result = StationControlResult(sweep_id=job_id, task_id=job_id, status=TaskStatus.PENDING)
251
253
 
252
254
  if sweep_data.job_status <= JobExecutorStatus.EXECUTION_STARTED:
253
255
  # Wait in the task queue while showing a progress bar
254
256
 
255
- interrupted = self._station_control_client._wait_job_completion(
256
- str(job_id), get_progress_bar_callback()
257
- )
257
+ interrupted = self._station_control._wait_job_completion(str(job_id), get_progress_bar_callback())
258
258
  if interrupted:
259
259
  raise KeyboardInterrupt
260
260
 
@@ -263,7 +263,7 @@ class Pulla:
263
263
 
264
264
  sc_result.status = TaskStatus.READY
265
265
  sc_result.result = map_sweep_results_to_logical_qubits(
266
- self._station_control_client.get_sweep_results(job_id),
266
+ self._station_control.get_sweep_results(job_id),
267
267
  context["readout_mappings"],
268
268
  context["options"].heralding_mode,
269
269
  )
@@ -284,7 +284,7 @@ class Pulla:
284
284
  sweep_data.begin_timestamp.isoformat() if sweep_data.begin_timestamp else None
285
285
  )
286
286
  sc_result.end_time = sweep_data.end_timestamp.isoformat() if sweep_data.end_timestamp else None
287
- job = self._station_control_client.get_job(job_id)
287
+ job = self._station_control.get_job(job_id)
288
288
  sc_result.message = job["job_error"]
289
289
  logger.error("Submission failed! Error: %s", sc_result.message)
290
290
  return sc_result
@@ -295,7 +295,7 @@ class Pulla:
295
295
  sweep_data.begin_timestamp.isoformat() if sweep_data.begin_timestamp else None
296
296
  )
297
297
  sc_result.end_time = sweep_data.end_timestamp.isoformat() if sweep_data.end_timestamp else None
298
- job = self._station_control_client.get_job(job_id)
298
+ job = self._station_control.get_job(job_id)
299
299
  sc_result.message = job["job_error"]
300
300
  logger.error("Submission was revoked!")
301
301
  return sc_result
@@ -304,7 +304,7 @@ class Pulla:
304
304
 
305
305
  except KeyboardInterrupt as exc:
306
306
  logger.info("Caught KeyboardInterrupt, revoking job %s", job_id)
307
- self._station_control_client.abort_job(job_id)
307
+ self._station_control.abort_job(job_id)
308
308
  raise KeyboardInterrupt from exc
309
309
 
310
310
 
@@ -0,0 +1,142 @@
1
+ """Methods for creating static and dynamic quantum architectures."""
2
+
3
+ from collections import Counter
4
+ import logging
5
+ from uuid import UUID
6
+
7
+ from exa.common.qcm_data.chip_topology import ChipTopology, sort_components
8
+ from iqm.pulse.builder import build_quantum_ops
9
+ from iqm.station_control.interface.models import (
10
+ DynamicQuantumArchitecture,
11
+ GateImplementationInfo,
12
+ GateInfo,
13
+ Locus,
14
+ ObservationLite,
15
+ StaticQuantumArchitecture,
16
+ )
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ def create_static_quantum_architecture(chip_topology: ChipTopology) -> StaticQuantumArchitecture:
22
+ """Creates a static quantum architecture (SQA) for the given chip topology.
23
+
24
+ Args:
25
+ chip_topology: The chip topology.
26
+
27
+ Returns:
28
+ Static quantum architecture containing information about qubits, computational resonators, and connectivity.
29
+
30
+ """
31
+ # Components within each connection are sorted by coupler_to_components
32
+ unsorted_connections = list(chip_topology.coupler_to_components.values())
33
+ # Sort connections first based on the first component, then the second component etc. of each connection
34
+ sorted_components = sort_components({component for connection in unsorted_connections for component in connection})
35
+ component_to_index = {component: index for index, component in enumerate(sorted_components)}
36
+
37
+ def sort_key(connection: tuple[str, ...]) -> tuple[int, ...]:
38
+ return tuple(component_to_index[component] for component in connection)
39
+
40
+ # The components in each connection are already sorted, now we sort the connections
41
+ connectivity = sorted(unsorted_connections, key=sort_key)
42
+ return StaticQuantumArchitecture(
43
+ qubits=chip_topology.qubits_sorted,
44
+ computational_resonators=chip_topology.computational_resonators_sorted,
45
+ connectivity=connectivity,
46
+ )
47
+
48
+
49
+ def create_dynamic_quantum_architecture(
50
+ calibration_set_id: UUID,
51
+ observations: list[ObservationLite],
52
+ chip_topology: ChipTopology,
53
+ ) -> DynamicQuantumArchitecture:
54
+ """Creates a dynamic quantum architecture (DQA) for the given calibration set.
55
+
56
+ Args:
57
+ calibration_set_id: ID of the calibration set used to create the DQA.
58
+ observations: Calibration set observations used to create the DQA.
59
+ chip_topology: The chip topology.
60
+
61
+ Returns:
62
+ Dynamic quantum architecture containing information about calibrated gates/operations.
63
+
64
+ """
65
+ qubits: set[str] = set()
66
+ computational_resonators: set[str] = set()
67
+ gates: dict[str, GateInfo] = {}
68
+
69
+ # known gates and implementations
70
+ quantum_op_table = build_quantum_ops({})
71
+
72
+ # error reporting
73
+ unknown_ops: set[str] = set()
74
+ unknown_implementations: set[str] = set()
75
+
76
+ def analyze_observation(obs_name: str) -> None:
77
+ """Deduce ops/implementations/loci and used QPU components from the gate cal data."""
78
+ parts = obs_name.split(".")
79
+ if parts[0] == "gates":
80
+ gate_name, gate_implementation, gate_locus = parts[1:4]
81
+ # ignore unknown gates and implementations (for backwards and forwards compatibility)
82
+ if (quantum_op := quantum_op_table.get(gate_name)) is None:
83
+ unknown_ops.add(gate_name)
84
+ return
85
+ if gate_implementation not in quantum_op.implementations:
86
+ unknown_implementations.add(f"{gate_name}.{gate_implementation}")
87
+ return
88
+
89
+ gate_info = gates.setdefault(
90
+ gate_name,
91
+ GateInfo(
92
+ implementations={},
93
+ default_implementation="",
94
+ override_default_implementation={},
95
+ ),
96
+ )
97
+ gate_implementation_info = gate_info.implementations.setdefault(
98
+ gate_implementation, GateImplementationInfo(loci=tuple())
99
+ )
100
+ gate_locus_components = tuple(gate_locus.split("__"))
101
+ if gate_locus_components not in gate_implementation_info.loci:
102
+ gate_implementation_info.loci += (gate_locus_components,)
103
+ for locus_component in gate_locus_components:
104
+ if chip_topology.is_qubit(locus_component):
105
+ qubits.add(locus_component)
106
+ if chip_topology.is_computational_resonator(locus_component):
107
+ computational_resonators.add(locus_component)
108
+
109
+ for observation in observations:
110
+ analyze_observation(observation.dut_field)
111
+
112
+ for name in unknown_ops:
113
+ logger.info("Unknown operation '%s' found in calibration set %s", name, str(calibration_set_id))
114
+ for name in unknown_implementations:
115
+ logger.info("Unknown implementation '%s' found in calibration set %s", name, str(calibration_set_id))
116
+
117
+ # Now ``gates`` only contains known gates and implementations, and each implementation has
118
+ # at least one locus. Pick a default implementations for each available (gate, locus).
119
+ for gate_name, gate_info in gates.items():
120
+ locus_default_implementations: dict[Locus, str] = {}
121
+
122
+ # pick the default implementation for each locus using the hardcoded priority order
123
+ for implementation in quantum_op_table[gate_name].implementations:
124
+ if implementation in gate_info.implementations:
125
+ for locus in gate_info.implementations[implementation].loci:
126
+ locus_default_implementations.setdefault(locus, implementation)
127
+
128
+ # choose default implementation to be the most common locus-specific default,
129
+ # and add the other locus-specific defaults to override_default_implementation
130
+ gate_info.default_implementation = Counter(locus_default_implementations.values()).most_common(1)[0][0]
131
+ gate_info.override_default_implementation = {
132
+ locus: implementation
133
+ for locus, implementation in locus_default_implementations.items()
134
+ if implementation != gate_info.default_implementation
135
+ }
136
+
137
+ return DynamicQuantumArchitecture(
138
+ calibration_set_id=calibration_set_id,
139
+ qubits=sort_components(qubits),
140
+ computational_resonators=sort_components(computational_resonators),
141
+ gates=gates,
142
+ )
iqm/pulla/utils.py CHANGED
@@ -42,7 +42,6 @@ from iqm.pulse.playlist.channel import ChannelProperties
42
42
  from iqm.pulse.playlist.instructions import Instruction
43
43
  from iqm.pulse.playlist.schedule import Schedule, Segment
44
44
  from iqm.pulse.timebox import TimeBox
45
- from iqm.station_control.client import utils as station_control_client_utils
46
45
  from iqm.station_control.interface.models.observation import ObservationBase
47
46
 
48
47
  LOCUS_SEPARATOR = "__" # EXA uses this, currently
@@ -602,4 +601,4 @@ def calset_from_observations(calset_observations: Iterable[ObservationBase]) ->
602
601
  calibration set
603
602
 
604
603
  """
605
- return station_control_client_utils.calset_from_observations(calset_observations)
604
+ return {obs.dut_field: obs.value for obs in calset_observations}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-pulla
3
- Version: 7.23.0
3
+ Version: 8.0.0
4
4
  Summary: Client library for pulse-level access to an IQM quantum computer
5
5
  Author-email: IQM Finland Oy <developers@meetiqm.com>
6
6
  License: Apache License
@@ -217,30 +217,30 @@ Description-Content-Type: text/x-rst
217
217
  License-File: LICENSE.txt
218
218
  License-File: AUTHORS.rst
219
219
  Requires-Dist: iqm-exa-common <27,>=26
220
- Requires-Dist: iqm-station-control-client <9,>=8
220
+ Requires-Dist: iqm-station-control-client <10,>=9
221
221
  Requires-Dist: iqm-pulse <10,>=9
222
- Requires-Dist: iqm-data-definitions <3.0,>=2.6
222
+ Requires-Dist: iqm-data-definitions <3.0,>=2.13
223
223
  Requires-Dist: pylatexenc ==2.10
224
224
  Requires-Dist: pydantic <3.0,>=2.10.4
225
225
  Provides-Extra: notebook
226
226
  Requires-Dist: iqm-exa-common <27,>=26 ; extra == 'notebook'
227
- Requires-Dist: iqm-station-control-client <9,>=8 ; extra == 'notebook'
227
+ Requires-Dist: iqm-station-control-client <10,>=9 ; extra == 'notebook'
228
228
  Requires-Dist: iqm-pulse <10,>=9 ; extra == 'notebook'
229
229
  Requires-Dist: notebook <7,>=6.4.11 ; extra == 'notebook'
230
230
  Requires-Dist: matplotlib <4,>=3.6.3 ; extra == 'notebook'
231
231
  Requires-Dist: nbclient ~=0.5.10 ; extra == 'notebook'
232
232
  Provides-Extra: qir
233
233
  Requires-Dist: iqm-exa-common <27,>=26 ; extra == 'qir'
234
- Requires-Dist: iqm-station-control-client <9,>=8 ; extra == 'qir'
234
+ Requires-Dist: iqm-station-control-client <10,>=9 ; extra == 'qir'
235
235
  Requires-Dist: iqm-pulse <10,>=9 ; extra == 'qir'
236
236
  Requires-Dist: iqm-pyqir ==0.12.0 ; extra == 'qir'
237
237
  Requires-Dist: iqm-qiskit-qir ==0.8.0 ; extra == 'qir'
238
238
  Provides-Extra: qiskit
239
239
  Requires-Dist: iqm-exa-common <27,>=26 ; extra == 'qiskit'
240
- Requires-Dist: iqm-station-control-client <9,>=8 ; extra == 'qiskit'
240
+ Requires-Dist: iqm-station-control-client <10,>=9 ; extra == 'qiskit'
241
241
  Requires-Dist: iqm-pulse <10,>=9 ; extra == 'qiskit'
242
- Requires-Dist: iqm-client <29,>=28 ; extra == 'qiskit'
243
- Requires-Dist: iqm-client[qiskit] <29,>=28 ; extra == 'qiskit'
242
+ Requires-Dist: iqm-client[qiskit] <30,>=29 ; extra == 'qiskit'
243
+ Requires-Dist: iqm-client <30,>=29 ; extra == 'qiskit'
244
244
 
245
245
  IQM Pulla
246
246
  #########
@@ -10,17 +10,18 @@ iqm/cpc/compiler/station_settings.py,sha256=VuwD2TkraCXJql59nRE3RgiQXEmor8oCor1P
10
10
  iqm/cpc/interface/__init__.py,sha256=mvhNx1I9K5Sg40CwPntWj35M3Bni__23PWEw_qYaXtQ,611
11
11
  iqm/cpc/interface/compiler.py,sha256=VBIAU3J4_BvC4tPwapLEUNe6OSwIW7LID7RJ7yRWCHc,10036
12
12
  iqm/pulla/__init__.py,sha256=fj5Qh8R9K-z6q5g9-CySBZsG8d33nU7hCHrqIIB8_-0,901
13
- iqm/pulla/calibration.py,sha256=9hWTsFg8cjvI-6k-he8cimKuR4WhIpoJX1f5g-VxyVY,2597
13
+ iqm/pulla/calibration.py,sha256=tZJ_q9i1ndRxuPZIaDCyznxNu1LIUIwJ53Vf3t9VOkY,4537
14
14
  iqm/pulla/interface.py,sha256=yymQo4REHYcUOWgPxPYq9IixS9bBZ27LXLQgJhzET58,5400
15
- iqm/pulla/pulla.py,sha256=DS8epOSO99pd9fV9PYK-EXbIvx0C-CG2Y0dh_7qd48w,14245
16
- iqm/pulla/utils.py,sha256=3mEbX16wyqUfn9jDQ7JmKmdss9qqJ9zKTNTpTtyMw3U,24712
15
+ iqm/pulla/pulla.py,sha256=PTSU0ft0Q0gt4k6n_gj4sznxnT9cAgd37eGeDhu9S5A,14007
16
+ iqm/pulla/quantum_architecture.py,sha256=T3rrv4sg1zD6bCY5Jb6Lp8yE3E0YVTh2nK0KZttjK6s,6208
17
+ iqm/pulla/utils.py,sha256=ZIJCmdufUjV_OJnaKTGWy64rhPOPDS0PYt1LtYdpTIc,24618
17
18
  iqm/pulla/utils_cirq.py,sha256=8SBy6w7cr4AmnCgKwh7dBWwBGfGKxnoEMv9-1yfKs0A,777
18
19
  iqm/pulla/utils_dd.py,sha256=SxYAuRBgvYELKjeXpFbP4mM0xCCivDk7WUHw7oEXfMo,1695
19
20
  iqm/pulla/utils_qir.py,sha256=6-VrdSXGZJnr2gNy9VEg449hIRv_P59iEvsFZPUlIn4,10018
20
21
  iqm/pulla/utils_qiskit.py,sha256=SG_YHHlQnmutlXiDayh-U1aYl4r2dJJHmAX0l5q0BdQ,10078
21
- iqm_pulla-7.23.0.dist-info/AUTHORS.rst,sha256=iCStz7WP5Jk7uMnn9jRA4ybS14X4yeUW2SsWE-OTaRk,328
22
- iqm_pulla-7.23.0.dist-info/LICENSE.txt,sha256=cCj_biRA4Q8A77vxR8AuvAf-DZ5G79yxR_3lYY6TrmA,11333
23
- iqm_pulla-7.23.0.dist-info/METADATA,sha256=NWEQYCKy99PCIZhLy9CENsSYSgYzxtRvyYrktRYOKNg,17687
24
- iqm_pulla-7.23.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
25
- iqm_pulla-7.23.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
26
- iqm_pulla-7.23.0.dist-info/RECORD,,
22
+ iqm_pulla-8.0.0.dist-info/AUTHORS.rst,sha256=iCStz7WP5Jk7uMnn9jRA4ybS14X4yeUW2SsWE-OTaRk,328
23
+ iqm_pulla-8.0.0.dist-info/LICENSE.txt,sha256=cCj_biRA4Q8A77vxR8AuvAf-DZ5G79yxR_3lYY6TrmA,11333
24
+ iqm_pulla-8.0.0.dist-info/METADATA,sha256=1HJknYlgrrfOHwaq8LP659CX9lyMqICX5IJzO7hVp_Y,17691
25
+ iqm_pulla-8.0.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
26
+ iqm_pulla-8.0.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
27
+ iqm_pulla-8.0.0.dist-info/RECORD,,