python-openstackclient 8.3.0__py3-none-any.whl → 10.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.
Files changed (292) hide show
  1. openstackclient/__init__.py +2 -6
  2. openstackclient/api/api.py +41 -23
  3. openstackclient/api/compute_v2.py +44 -25
  4. openstackclient/api/object_store_v1.py +75 -97
  5. openstackclient/api/volume_v2.py +2 -1
  6. openstackclient/api/volume_v3.py +2 -1
  7. openstackclient/common/availability_zone.py +58 -42
  8. openstackclient/common/clientmanager.py +56 -29
  9. openstackclient/common/configuration.py +10 -3
  10. openstackclient/common/envvars.py +2 -2
  11. openstackclient/common/extension.py +14 -5
  12. openstackclient/common/limits.py +10 -5
  13. openstackclient/common/module.py +14 -6
  14. openstackclient/common/pagination.py +8 -2
  15. openstackclient/common/progressbar.py +7 -6
  16. openstackclient/common/project_cleanup.py +13 -7
  17. openstackclient/common/quota.py +126 -114
  18. openstackclient/common/versions.py +8 -2
  19. openstackclient/compute/client.py +7 -3
  20. openstackclient/compute/v2/agent.py +17 -10
  21. openstackclient/compute/v2/aggregate.py +36 -22
  22. openstackclient/compute/v2/console.py +14 -8
  23. openstackclient/compute/v2/console_connection.py +11 -3
  24. openstackclient/compute/v2/flavor.py +39 -21
  25. openstackclient/compute/v2/host.py +14 -6
  26. openstackclient/compute/v2/hypervisor.py +14 -5
  27. openstackclient/compute/v2/hypervisor_stats.py +10 -2
  28. openstackclient/compute/v2/keypair.py +29 -14
  29. openstackclient/compute/v2/server.py +251 -171
  30. openstackclient/compute/v2/server_backup.py +10 -4
  31. openstackclient/compute/v2/server_event.py +21 -12
  32. openstackclient/compute/v2/server_group.py +21 -11
  33. openstackclient/compute/v2/server_image.py +19 -10
  34. openstackclient/compute/v2/server_migration.py +24 -10
  35. openstackclient/compute/v2/server_share.py +274 -0
  36. openstackclient/compute/v2/server_volume.py +10 -4
  37. openstackclient/compute/v2/service.py +14 -7
  38. openstackclient/compute/v2/usage.py +26 -21
  39. openstackclient/identity/client.py +8 -3
  40. openstackclient/identity/common.py +103 -41
  41. openstackclient/identity/v2_0/catalog.py +14 -7
  42. openstackclient/identity/v2_0/ec2creds.py +21 -10
  43. openstackclient/identity/v2_0/endpoint.py +23 -11
  44. openstackclient/identity/v2_0/project.py +25 -14
  45. openstackclient/identity/v2_0/role.py +28 -14
  46. openstackclient/identity/v2_0/role_assignment.py +9 -3
  47. openstackclient/identity/v2_0/service.py +26 -12
  48. openstackclient/identity/v2_0/token.py +12 -5
  49. openstackclient/identity/v2_0/user.py +26 -15
  50. openstackclient/identity/v3/access_rule.py +26 -12
  51. openstackclient/identity/v3/application_credential.py +59 -24
  52. openstackclient/identity/v3/catalog.py +14 -7
  53. openstackclient/identity/v3/consumer.py +22 -11
  54. openstackclient/identity/v3/credential.py +36 -16
  55. openstackclient/identity/v3/domain.py +37 -18
  56. openstackclient/identity/v3/ec2creds.py +25 -12
  57. openstackclient/identity/v3/endpoint.py +42 -20
  58. openstackclient/identity/v3/endpoint_group.py +28 -17
  59. openstackclient/identity/v3/federation_protocol.py +71 -50
  60. openstackclient/identity/v3/group.py +55 -32
  61. openstackclient/identity/v3/identity_provider.py +92 -57
  62. openstackclient/identity/v3/implied_role.py +21 -9
  63. openstackclient/identity/v3/limit.py +115 -92
  64. openstackclient/identity/v3/mapping.py +26 -13
  65. openstackclient/identity/v3/policy.py +23 -12
  66. openstackclient/identity/v3/project.py +211 -122
  67. openstackclient/identity/v3/region.py +36 -16
  68. openstackclient/identity/v3/registered_limit.py +116 -109
  69. openstackclient/identity/v3/role.py +61 -31
  70. openstackclient/identity/v3/role_assignment.py +23 -6
  71. openstackclient/identity/v3/service.py +36 -16
  72. openstackclient/identity/v3/service_provider.py +37 -15
  73. openstackclient/identity/v3/tag.py +23 -17
  74. openstackclient/identity/v3/token.py +30 -14
  75. openstackclient/identity/v3/trust.py +32 -14
  76. openstackclient/identity/v3/unscoped_saml.py +10 -2
  77. openstackclient/identity/v3/user.py +49 -26
  78. openstackclient/image/client.py +7 -3
  79. openstackclient/image/v1/image.py +33 -26
  80. openstackclient/image/v2/cache.py +14 -9
  81. openstackclient/image/v2/image.py +76 -49
  82. openstackclient/image/v2/info.py +7 -1
  83. openstackclient/image/v2/metadef_namespaces.py +109 -13
  84. openstackclient/image/v2/metadef_objects.py +28 -15
  85. openstackclient/image/v2/metadef_properties.py +24 -13
  86. openstackclient/image/v2/metadef_resource_type_association.py +14 -7
  87. openstackclient/image/v2/metadef_resource_types.py +7 -1
  88. openstackclient/image/v2/task.py +15 -6
  89. openstackclient/locale/tr_TR/LC_MESSAGES/openstackclient.po +7 -192
  90. openstackclient/network/client.py +7 -2
  91. openstackclient/network/common.py +16 -241
  92. openstackclient/network/utils.py +36 -22
  93. openstackclient/network/v2/address_group.py +27 -16
  94. openstackclient/network/v2/address_scope.py +24 -13
  95. openstackclient/network/v2/bgpvpn/bgpvpn.py +463 -0
  96. openstackclient/network/v2/bgpvpn/constants.py +30 -0
  97. openstackclient/network/v2/bgpvpn/network_association.py +214 -0
  98. openstackclient/network/v2/bgpvpn/port_association.py +490 -0
  99. openstackclient/network/v2/bgpvpn/router_association.py +288 -0
  100. openstackclient/network/v2/default_security_group_rule.py +19 -10
  101. openstackclient/network/v2/floating_ip.py +110 -159
  102. openstackclient/network/v2/floating_ip_port_forwarding.py +30 -18
  103. openstackclient/network/v2/fwaas/__init__.py +0 -0
  104. openstackclient/network/v2/fwaas/group.py +466 -0
  105. openstackclient/network/v2/fwaas/policy.py +518 -0
  106. openstackclient/network/v2/fwaas/rule.py +574 -0
  107. openstackclient/network/v2/ip_availability.py +13 -5
  108. openstackclient/network/v2/l3_conntrack_helper.py +22 -13
  109. openstackclient/network/v2/local_ip.py +24 -13
  110. openstackclient/network/v2/local_ip_association.py +14 -7
  111. openstackclient/network/v2/ndp_proxy.py +20 -11
  112. openstackclient/network/v2/network.py +129 -196
  113. openstackclient/network/v2/network_agent.py +46 -25
  114. openstackclient/network/v2/network_auto_allocated_topology.py +22 -11
  115. openstackclient/network/v2/network_flavor.py +27 -16
  116. openstackclient/network/v2/network_flavor_profile.py +23 -12
  117. openstackclient/network/v2/network_meter.py +21 -10
  118. openstackclient/network/v2/network_meter_rule.py +21 -11
  119. openstackclient/network/v2/network_qos_policy.py +25 -15
  120. openstackclient/network/v2/network_qos_rule.py +32 -17
  121. openstackclient/network/v2/network_qos_rule_type.py +13 -5
  122. openstackclient/network/v2/network_rbac.py +23 -12
  123. openstackclient/network/v2/network_segment.py +20 -11
  124. openstackclient/network/v2/network_segment_range.py +56 -29
  125. openstackclient/network/v2/network_service_provider.py +7 -1
  126. openstackclient/network/v2/network_trunk.py +38 -22
  127. openstackclient/network/v2/port.py +54 -29
  128. openstackclient/network/v2/router.py +75 -52
  129. openstackclient/network/v2/security_group.py +87 -157
  130. openstackclient/network/v2/security_group_rule.py +100 -280
  131. openstackclient/network/v2/subnet.py +49 -28
  132. openstackclient/network/v2/subnet_pool.py +30 -17
  133. openstackclient/network/v2/taas/tap_flow.py +22 -11
  134. openstackclient/network/v2/taas/tap_mirror.py +22 -11
  135. openstackclient/network/v2/taas/tap_service.py +23 -12
  136. openstackclient/object/client.py +7 -2
  137. openstackclient/object/v1/account.py +13 -6
  138. openstackclient/object/v1/container.py +25 -15
  139. openstackclient/object/v1/object.py +25 -15
  140. openstackclient/py.typed +0 -0
  141. openstackclient/shell.py +46 -10
  142. openstackclient/tests/functional/base.py +55 -20
  143. openstackclient/tests/functional/common/test_extension.py +4 -0
  144. openstackclient/tests/functional/common/test_quota.py +3 -1
  145. openstackclient/tests/functional/compute/v2/common.py +14 -13
  146. openstackclient/tests/functional/compute/v2/test_flavor.py +3 -1
  147. openstackclient/tests/functional/compute/v2/test_server.py +3 -0
  148. openstackclient/tests/functional/identity/v2/common.py +10 -6
  149. openstackclient/tests/functional/identity/v2/test_role.py +4 -4
  150. openstackclient/tests/functional/identity/v3/common.py +25 -19
  151. openstackclient/tests/functional/identity/v3/test_group.py +20 -20
  152. openstackclient/tests/functional/identity/v3/test_idp.py +3 -1
  153. openstackclient/tests/functional/identity/v3/test_limit.py +47 -0
  154. openstackclient/tests/functional/identity/v3/test_project.py +10 -10
  155. openstackclient/tests/functional/identity/v3/test_role.py +18 -18
  156. openstackclient/tests/functional/identity/v3/test_role_assignment.py +12 -12
  157. openstackclient/tests/functional/identity/v3/test_user.py +8 -8
  158. openstackclient/tests/functional/image/base.py +1 -6
  159. openstackclient/tests/functional/image/v2/test_metadef_objects.py +69 -0
  160. openstackclient/tests/functional/network/v2/common.py +5 -2
  161. openstackclient/tests/functional/network/v2/test_floating_ip.py +10 -4
  162. openstackclient/tests/functional/network/v2/test_ip_availability.py +4 -0
  163. openstackclient/tests/functional/network/v2/test_network_meter_rule.py +3 -2
  164. openstackclient/tests/functional/network/v2/test_network_segment.py +5 -0
  165. openstackclient/tests/functional/network/v2/test_subnet.py +13 -9
  166. openstackclient/tests/functional/object/v1/common.py +4 -0
  167. openstackclient/tests/functional/volume/v2/common.py +4 -0
  168. openstackclient/tests/functional/volume/v2/test_volume_snapshot.py +27 -11
  169. openstackclient/tests/functional/volume/v2/test_volume_type.py +2 -2
  170. openstackclient/tests/functional/volume/v3/common.py +4 -0
  171. openstackclient/tests/functional/volume/v3/test_volume_snapshot.py +56 -138
  172. openstackclient/tests/functional/volume/v3/test_volume_type.py +2 -2
  173. openstackclient/tests/unit/common/test_availability_zone.py +35 -49
  174. openstackclient/tests/unit/common/test_extension.py +2 -2
  175. openstackclient/tests/unit/common/test_module.py +12 -7
  176. openstackclient/tests/unit/common/test_project_cleanup.py +3 -1
  177. openstackclient/tests/unit/common/test_quota.py +62 -23
  178. openstackclient/tests/unit/compute/v2/fakes.py +25 -0
  179. openstackclient/tests/unit/compute/v2/test_flavor.py +28 -2
  180. openstackclient/tests/unit/compute/v2/test_keypair.py +6 -6
  181. openstackclient/tests/unit/compute/v2/test_server.py +17 -104
  182. openstackclient/tests/unit/compute/v2/test_server_share.py +287 -0
  183. openstackclient/tests/unit/identity/v3/fakes.py +3 -0
  184. openstackclient/tests/unit/identity/v3/test_group.py +4 -14
  185. openstackclient/tests/unit/identity/v3/test_identity_provider.py +303 -299
  186. openstackclient/tests/unit/identity/v3/test_limit.py +197 -145
  187. openstackclient/tests/unit/identity/v3/test_project.py +831 -512
  188. openstackclient/tests/unit/identity/v3/test_protocol.py +97 -88
  189. openstackclient/tests/unit/identity/v3/test_registered_limit.py +355 -220
  190. openstackclient/tests/unit/identity/v3/test_user.py +4 -4
  191. openstackclient/tests/unit/image/v2/test_image.py +16 -16
  192. openstackclient/tests/unit/image/v2/test_metadef_namespaces.py +105 -6
  193. openstackclient/tests/unit/network/test_common.py +0 -155
  194. openstackclient/tests/unit/network/v2/bgpvpn/__init__.py +0 -0
  195. openstackclient/tests/unit/network/v2/bgpvpn/fakes.py +179 -0
  196. openstackclient/tests/unit/network/v2/bgpvpn/test_bgpvpn.py +584 -0
  197. openstackclient/tests/unit/network/v2/bgpvpn/test_network_association.py +285 -0
  198. openstackclient/tests/unit/network/v2/bgpvpn/test_port_association.py +384 -0
  199. openstackclient/tests/unit/network/v2/bgpvpn/test_router_association.py +297 -0
  200. openstackclient/tests/unit/network/v2/fwaas/__init__.py +0 -0
  201. openstackclient/tests/unit/network/v2/fwaas/test_group.py +897 -0
  202. openstackclient/tests/unit/network/v2/fwaas/test_policy.py +869 -0
  203. openstackclient/tests/unit/network/v2/fwaas/test_rule.py +980 -0
  204. openstackclient/tests/unit/network/v2/taas/{test_osc_tap_flow.py → test_tap_flow.py} +18 -25
  205. openstackclient/tests/unit/network/v2/taas/{test_osc_tap_mirror.py → test_tap_mirror.py} +19 -29
  206. openstackclient/tests/unit/network/v2/taas/{test_osc_tap_service.py → test_tap_service.py} +19 -29
  207. openstackclient/tests/unit/network/v2/test_address_group.py +2 -2
  208. openstackclient/tests/unit/network/v2/{test_floating_ip_network.py → test_floating_ip.py} +3 -2
  209. openstackclient/tests/unit/network/v2/test_floating_ip_port_forwarding.py +13 -13
  210. openstackclient/tests/unit/network/v2/test_network_agent.py +8 -4
  211. openstackclient/tests/unit/network/v2/test_network_auto_allocated_topology.py +3 -3
  212. openstackclient/tests/unit/network/v2/test_network_flavor.py +2 -2
  213. openstackclient/tests/unit/network/v2/test_network_qos_policy.py +1 -1
  214. openstackclient/tests/unit/network/v2/test_network_qos_rule.py +2 -2
  215. openstackclient/tests/unit/network/v2/test_network_rbac.py +1 -1
  216. openstackclient/tests/unit/network/v2/test_network_segment.py +1 -1
  217. openstackclient/tests/unit/network/v2/test_network_segment_range.py +7 -10
  218. openstackclient/tests/unit/network/v2/test_network_trunk.py +1 -1
  219. openstackclient/tests/unit/network/v2/test_router.py +8 -9
  220. openstackclient/tests/unit/network/v2/{test_security_group_network.py → test_security_group.py} +1 -20
  221. openstackclient/tests/unit/network/v2/{test_security_group_rule_network.py → test_security_group_rule.py} +7 -41
  222. openstackclient/tests/unit/network/v2/test_subnet.py +2 -1
  223. openstackclient/tests/unit/network/v2/test_subnet_pool.py +2 -1
  224. openstackclient/tests/unit/object/v1/fakes.py +8 -7
  225. openstackclient/tests/unit/object/v1/test_container.py +65 -101
  226. openstackclient/tests/unit/object/v1/test_container_all.py +8 -1
  227. openstackclient/tests/unit/object/v1/test_object.py +44 -84
  228. openstackclient/tests/unit/object/v1/test_object_all.py +8 -1
  229. openstackclient/tests/unit/test_hacking.py +108 -0
  230. openstackclient/tests/unit/volume/v2/fakes.py +1 -0
  231. openstackclient/tests/unit/volume/v2/test_consistency_group.py +8 -2
  232. openstackclient/tests/unit/volume/v2/test_volume.py +7 -6
  233. openstackclient/tests/unit/volume/v2/test_volume_backup.py +1 -5
  234. openstackclient/tests/unit/volume/v2/test_volume_snapshot.py +2 -1
  235. openstackclient/tests/unit/volume/v2/test_volume_type.py +2 -4
  236. openstackclient/tests/unit/volume/v3/fakes.py +1 -0
  237. openstackclient/tests/unit/volume/v3/test_volume.py +94 -15
  238. openstackclient/tests/unit/volume/v3/test_volume_attachment.py +1 -1
  239. openstackclient/tests/unit/volume/v3/test_volume_backup.py +1 -5
  240. openstackclient/tests/unit/volume/v3/test_volume_snapshot.py +55 -1
  241. openstackclient/tests/unit/volume/v3/test_volume_type.py +2 -4
  242. openstackclient/volume/client.py +7 -3
  243. openstackclient/volume/v2/backup_record.py +15 -6
  244. openstackclient/volume/v2/consistency_group.py +37 -25
  245. openstackclient/volume/v2/consistency_group_snapshot.py +27 -12
  246. openstackclient/volume/v2/qos_specs.py +30 -19
  247. openstackclient/volume/v2/service.py +17 -6
  248. openstackclient/volume/v2/volume.py +69 -34
  249. openstackclient/volume/v2/volume_backend.py +19 -6
  250. openstackclient/volume/v2/volume_backup.py +48 -22
  251. openstackclient/volume/v2/volume_host.py +6 -4
  252. openstackclient/volume/v2/volume_snapshot.py +52 -26
  253. openstackclient/volume/v2/volume_transfer_request.py +33 -15
  254. openstackclient/volume/v2/volume_type.py +46 -27
  255. openstackclient/volume/v3/block_storage_cleanup.py +11 -3
  256. openstackclient/volume/v3/block_storage_cluster.py +19 -7
  257. openstackclient/volume/v3/block_storage_log_level.py +15 -6
  258. openstackclient/volume/v3/block_storage_manage.py +10 -4
  259. openstackclient/volume/v3/block_storage_resource_filter.py +17 -5
  260. openstackclient/volume/v3/service.py +16 -6
  261. openstackclient/volume/v3/volume.py +103 -46
  262. openstackclient/volume/v3/volume_attachment.py +43 -21
  263. openstackclient/volume/v3/volume_backup.py +55 -26
  264. openstackclient/volume/v3/volume_group.py +23 -13
  265. openstackclient/volume/v3/volume_group_snapshot.py +32 -13
  266. openstackclient/volume/v3/volume_group_type.py +26 -13
  267. openstackclient/volume/v3/volume_message.py +15 -7
  268. openstackclient/volume/v3/volume_snapshot.py +71 -34
  269. openstackclient/volume/v3/volume_transfer_request.py +33 -15
  270. openstackclient/volume/v3/volume_type.py +45 -27
  271. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/METADATA +6 -6
  272. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/RECORD +279 -267
  273. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/WHEEL +1 -1
  274. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/entry_points.txt +53 -1
  275. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/licenses/AUTHORS +9 -0
  276. python_openstackclient-10.0.0.dist-info/pbr.json +1 -0
  277. openstackclient/api/image_v1.py +0 -69
  278. openstackclient/api/image_v2.py +0 -79
  279. openstackclient/network/v2/floating_ip_pool.py +0 -38
  280. openstackclient/tests/functional/image/v1/test_image.py +0 -97
  281. openstackclient/tests/unit/api/test_image_v1.py +0 -96
  282. openstackclient/tests/unit/api/test_image_v2.py +0 -96
  283. openstackclient/tests/unit/network/v2/test_floating_ip_compute.py +0 -248
  284. openstackclient/tests/unit/network/v2/test_floating_ip_pool_compute.py +0 -49
  285. openstackclient/tests/unit/network/v2/test_floating_ip_pool_network.py +0 -39
  286. openstackclient/tests/unit/network/v2/test_network_compute.py +0 -404
  287. openstackclient/tests/unit/network/v2/test_security_group_compute.py +0 -392
  288. openstackclient/tests/unit/network/v2/test_security_group_rule_compute.py +0 -555
  289. python_openstackclient-8.3.0.dist-info/pbr.json +0 -1
  290. /openstackclient/{tests/functional/image/v1 → network/v2/bgpvpn}/__init__.py +0 -0
  291. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/licenses/LICENSE +0 -0
  292. {python_openstackclient-8.3.0.dist-info → python_openstackclient-10.0.0.dist-info}/top_level.txt +0 -0
@@ -14,7 +14,10 @@
14
14
 
15
15
  """Volume v2 consistency group snapshot action implementations"""
16
16
 
17
+ import argparse
17
18
  import logging
19
+ from collections.abc import Iterable, Sequence
20
+ from typing import Any
18
21
 
19
22
  from osc_lib import exceptions
20
23
  from osc_lib import utils
@@ -29,7 +32,7 @@ LOG = logging.getLogger(__name__)
29
32
  class CreateConsistencyGroupSnapshot(command.ShowOne):
30
33
  _description = _("Create new consistency group snapshot.")
31
34
 
32
- def get_parser(self, prog_name):
35
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
33
36
  parser = super().get_parser(prog_name)
34
37
  parser.add_argument(
35
38
  "snapshot_name",
@@ -52,7 +55,9 @@ class CreateConsistencyGroupSnapshot(command.ShowOne):
52
55
  )
53
56
  return parser
54
57
 
55
- def take_action(self, parsed_args):
58
+ def take_action(
59
+ self, parsed_args: argparse.Namespace
60
+ ) -> tuple[Sequence[str], Iterable[Any]]:
56
61
  volume_client = self.app.client_manager.volume
57
62
  consistency_group = parsed_args.consistency_group
58
63
  if not parsed_args.consistency_group:
@@ -68,13 +73,16 @@ class CreateConsistencyGroupSnapshot(command.ShowOne):
68
73
  description=parsed_args.description,
69
74
  )
70
75
 
71
- return zip(*sorted(consistency_group_snapshot._info.items()))
76
+ col_headers, col_data = zip(
77
+ *sorted(consistency_group_snapshot._info.items())
78
+ )
79
+ return col_headers, col_data
72
80
 
73
81
 
74
82
  class DeleteConsistencyGroupSnapshot(command.Command):
75
83
  _description = _("Delete consistency group snapshot(s).")
76
84
 
77
- def get_parser(self, prog_name):
85
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
78
86
  parser = super().get_parser(prog_name)
79
87
  parser.add_argument(
80
88
  "consistency_group_snapshot",
@@ -84,7 +92,7 @@ class DeleteConsistencyGroupSnapshot(command.Command):
84
92
  )
85
93
  return parser
86
94
 
87
- def take_action(self, parsed_args):
95
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
88
96
  volume_client = self.app.client_manager.volume
89
97
  result = 0
90
98
 
@@ -101,8 +109,8 @@ class DeleteConsistencyGroupSnapshot(command.Command):
101
109
  _(
102
110
  "Failed to delete consistency group snapshot "
103
111
  "with name or ID '%(snapshot)s': %(e)s"
104
- )
105
- % {'snapshot': snapshot, 'e': e}
112
+ ),
113
+ {'snapshot': snapshot, 'e': e},
106
114
  )
107
115
 
108
116
  if result > 0:
@@ -117,7 +125,7 @@ class DeleteConsistencyGroupSnapshot(command.Command):
117
125
  class ListConsistencyGroupSnapshot(command.Lister):
118
126
  _description = _("List consistency group snapshots.")
119
127
 
120
- def get_parser(self, prog_name):
128
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
121
129
  parser = super().get_parser(prog_name)
122
130
  parser.add_argument(
123
131
  '--all-projects',
@@ -153,7 +161,9 @@ class ListConsistencyGroupSnapshot(command.Lister):
153
161
  )
154
162
  return parser
155
163
 
156
- def take_action(self, parsed_args):
164
+ def take_action(
165
+ self, parsed_args: argparse.Namespace
166
+ ) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
157
167
  if parsed_args.long:
158
168
  columns = [
159
169
  'ID',
@@ -194,7 +204,7 @@ class ListConsistencyGroupSnapshot(command.Lister):
194
204
  class ShowConsistencyGroupSnapshot(command.ShowOne):
195
205
  _description = _("Display consistency group snapshot details")
196
206
 
197
- def get_parser(self, prog_name):
207
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
198
208
  parser = super().get_parser(prog_name)
199
209
  parser.add_argument(
200
210
  "consistency_group_snapshot",
@@ -203,9 +213,14 @@ class ShowConsistencyGroupSnapshot(command.ShowOne):
203
213
  )
204
214
  return parser
205
215
 
206
- def take_action(self, parsed_args):
216
+ def take_action(
217
+ self, parsed_args: argparse.Namespace
218
+ ) -> tuple[Sequence[str], Iterable[Any]]:
207
219
  volume_client = self.app.client_manager.volume
208
220
  consistency_group_snapshot = utils.find_resource(
209
221
  volume_client.cgsnapshots, parsed_args.consistency_group_snapshot
210
222
  )
211
- return zip(*sorted(consistency_group_snapshot._info.items()))
223
+ col_headers, col_data = zip(
224
+ *sorted(consistency_group_snapshot._info.items())
225
+ )
226
+ return col_headers, col_data
@@ -15,7 +15,10 @@
15
15
 
16
16
  """Volume v2 QoS action implementations"""
17
17
 
18
+ import argparse
18
19
  import logging
20
+ from collections.abc import Iterable, Sequence
21
+ from typing import Any
19
22
 
20
23
  from osc_lib.cli import format_columns
21
24
  from osc_lib.cli import parseractions
@@ -32,7 +35,7 @@ LOG = logging.getLogger(__name__)
32
35
  class AssociateQos(command.Command):
33
36
  _description = _("Associate a QoS specification to a volume type")
34
37
 
35
- def get_parser(self, prog_name):
38
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
36
39
  parser = super().get_parser(prog_name)
37
40
  parser.add_argument(
38
41
  'qos_spec',
@@ -46,7 +49,7 @@ class AssociateQos(command.Command):
46
49
  )
47
50
  return parser
48
51
 
49
- def take_action(self, parsed_args):
52
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
50
53
  volume_client = self.app.client_manager.volume
51
54
  qos_spec = utils.find_resource(
52
55
  volume_client.qos_specs, parsed_args.qos_spec
@@ -61,7 +64,7 @@ class AssociateQos(command.Command):
61
64
  class CreateQos(command.ShowOne):
62
65
  _description = _("Create new QoS specification")
63
66
 
64
- def get_parser(self, prog_name):
67
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
65
68
  parser = super().get_parser(prog_name)
66
69
  parser.add_argument(
67
70
  'name',
@@ -93,7 +96,9 @@ class CreateQos(command.ShowOne):
93
96
  )
94
97
  return parser
95
98
 
96
- def take_action(self, parsed_args):
99
+ def take_action(
100
+ self, parsed_args: argparse.Namespace
101
+ ) -> tuple[Sequence[str], Iterable[Any]]:
97
102
  volume_client = self.app.client_manager.volume
98
103
  specs = {}
99
104
  specs.update({'consumer': parsed_args.consumer})
@@ -110,13 +115,14 @@ class CreateQos(command.ShowOne):
110
115
  )
111
116
  }
112
117
  )
113
- return zip(*sorted(qos_spec._info.items()))
118
+ col_headers, col_data = zip(*sorted(qos_spec._info.items()))
119
+ return col_headers, col_data
114
120
 
115
121
 
116
122
  class DeleteQos(command.Command):
117
123
  _description = _("Delete QoS specification")
118
124
 
119
- def get_parser(self, prog_name):
125
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
120
126
  parser = super().get_parser(prog_name)
121
127
  parser.add_argument(
122
128
  'qos_specs',
@@ -132,7 +138,7 @@ class DeleteQos(command.Command):
132
138
  )
133
139
  return parser
134
140
 
135
- def take_action(self, parsed_args):
141
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
136
142
  volume_client = self.app.client_manager.volume
137
143
  result = 0
138
144
 
@@ -146,8 +152,8 @@ class DeleteQos(command.Command):
146
152
  _(
147
153
  "Failed to delete QoS specification with "
148
154
  "name or ID '%(qos)s': %(e)s"
149
- )
150
- % {'qos': i, 'e': e}
155
+ ),
156
+ {'qos': i, 'e': e},
151
157
  )
152
158
 
153
159
  if result > 0:
@@ -161,7 +167,7 @@ class DeleteQos(command.Command):
161
167
  class DisassociateQos(command.Command):
162
168
  _description = _("Disassociate a QoS specification from a volume type")
163
169
 
164
- def get_parser(self, prog_name):
170
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
165
171
  parser = super().get_parser(prog_name)
166
172
  parser.add_argument(
167
173
  'qos_spec',
@@ -183,7 +189,7 @@ class DisassociateQos(command.Command):
183
189
 
184
190
  return parser
185
191
 
186
- def take_action(self, parsed_args):
192
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
187
193
  volume_client = self.app.client_manager.volume
188
194
  qos_spec = utils.find_resource(
189
195
  volume_client.qos_specs, parsed_args.qos_spec
@@ -201,7 +207,9 @@ class DisassociateQos(command.Command):
201
207
  class ListQos(command.Lister):
202
208
  _description = _("List QoS specifications")
203
209
 
204
- def take_action(self, parsed_args):
210
+ def take_action(
211
+ self, parsed_args: argparse.Namespace
212
+ ) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
205
213
  volume_client = self.app.client_manager.volume
206
214
  qos_specs_list = volume_client.qos_specs.list()
207
215
 
@@ -249,7 +257,7 @@ class ListQos(command.Lister):
249
257
  class SetQos(command.Command):
250
258
  _description = _("Set QoS specification properties")
251
259
 
252
- def get_parser(self, prog_name):
260
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
253
261
  parser = super().get_parser(prog_name)
254
262
  parser.add_argument(
255
263
  'qos_spec',
@@ -277,7 +285,7 @@ class SetQos(command.Command):
277
285
  )
278
286
  return parser
279
287
 
280
- def take_action(self, parsed_args):
288
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
281
289
  volume_client = self.app.client_manager.volume
282
290
  qos_spec = utils.find_resource(
283
291
  volume_client.qos_specs, parsed_args.qos_spec
@@ -311,7 +319,7 @@ class SetQos(command.Command):
311
319
  class ShowQos(command.ShowOne):
312
320
  _description = _("Display QoS specification details")
313
321
 
314
- def get_parser(self, prog_name):
322
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
315
323
  parser = super().get_parser(prog_name)
316
324
  parser.add_argument(
317
325
  'qos_spec',
@@ -320,7 +328,9 @@ class ShowQos(command.ShowOne):
320
328
  )
321
329
  return parser
322
330
 
323
- def take_action(self, parsed_args):
331
+ def take_action(
332
+ self, parsed_args: argparse.Namespace
333
+ ) -> tuple[Sequence[str], Iterable[Any]]:
324
334
  volume_client = self.app.client_manager.volume
325
335
  qos_spec = utils.find_resource(
326
336
  volume_client.qos_specs, parsed_args.qos_spec
@@ -342,13 +352,14 @@ class ShowQos(command.ShowOne):
342
352
  }
343
353
  )
344
354
 
345
- return zip(*sorted(qos_spec._info.items()))
355
+ col_headers, col_data = zip(*sorted(qos_spec._info.items()))
356
+ return col_headers, col_data
346
357
 
347
358
 
348
359
  class UnsetQos(command.Command):
349
360
  _description = _("Unset QoS specification properties")
350
361
 
351
- def get_parser(self, prog_name):
362
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
352
363
  parser = super().get_parser(prog_name)
353
364
  parser.add_argument(
354
365
  'qos_spec',
@@ -367,7 +378,7 @@ class UnsetQos(command.Command):
367
378
  )
368
379
  return parser
369
380
 
370
- def take_action(self, parsed_args):
381
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
371
382
  volume_client = self.app.client_manager.volume
372
383
  qos_spec = utils.find_resource(
373
384
  volume_client.qos_specs, parsed_args.qos_spec
@@ -14,6 +14,11 @@
14
14
 
15
15
  """Service action implementations"""
16
16
 
17
+ import argparse
18
+ from collections.abc import Iterable, Sequence
19
+ from typing import Any
20
+
21
+ from openstack import utils as sdk_utils
17
22
  from osc_lib import exceptions
18
23
  from osc_lib import utils
19
24
 
@@ -24,7 +29,7 @@ from openstackclient.i18n import _
24
29
  class ListService(command.Lister):
25
30
  _description = _("List service command")
26
31
 
27
- def get_parser(self, prog_name):
32
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
28
33
  parser = super().get_parser(prog_name)
29
34
  parser.add_argument(
30
35
  "--host",
@@ -44,8 +49,12 @@ class ListService(command.Lister):
44
49
  )
45
50
  return parser
46
51
 
47
- def take_action(self, parsed_args):
48
- volume_client = self.app.client_manager.sdk_connection.volume
52
+ def take_action(
53
+ self, parsed_args: argparse.Namespace
54
+ ) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
55
+ volume_client = sdk_utils.ensure_service_version(
56
+ self.app.client_manager.sdk_connection.volume, '2'
57
+ )
49
58
 
50
59
  columns: tuple[str, ...] = (
51
60
  "binary",
@@ -86,7 +95,7 @@ class ListService(command.Lister):
86
95
  class SetService(command.Command):
87
96
  _description = _("Set volume service properties")
88
97
 
89
- def get_parser(self, prog_name):
98
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
90
99
  parser = super().get_parser(prog_name)
91
100
  parser.add_argument(
92
101
  "host",
@@ -115,7 +124,7 @@ class SetService(command.Command):
115
124
  )
116
125
  return parser
117
126
 
118
- def take_action(self, parsed_args):
127
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
119
128
  if parsed_args.disable_reason and not parsed_args.disable:
120
129
  msg = _(
121
130
  "Cannot specify option --disable-reason without "
@@ -123,7 +132,9 @@ class SetService(command.Command):
123
132
  )
124
133
  raise exceptions.CommandError(msg)
125
134
 
126
- volume_client = self.app.client_manager.sdk_connection.volume
135
+ volume_client = sdk_utils.ensure_service_version(
136
+ self.app.client_manager.sdk_connection.volume, '2'
137
+ )
127
138
 
128
139
  service = volume_client.find_service(
129
140
  parsed_args.service, ignore_missing=False, host=parsed_args.host
@@ -18,11 +18,13 @@ import argparse
18
18
  import copy
19
19
  import functools
20
20
  import logging
21
- import typing as ty
21
+ from collections.abc import Iterable, Sequence
22
+ from typing import Any
22
23
 
23
24
  from cliff import columns as cliff_columns
24
25
  from openstack.block_storage.v2 import volume as _volume
25
26
  from openstack import exceptions as sdk_exceptions
27
+ from openstack import utils as sdk_utils
26
28
  from osc_lib.cli import format_columns
27
29
  from osc_lib.cli import parseractions
28
30
  from osc_lib import exceptions
@@ -43,14 +45,20 @@ class KeyValueHintAction(argparse.Action):
43
45
 
44
46
  APPEND_KEYS = ('same_host', 'different_host')
45
47
 
46
- def __init__(self, *args, **kwargs):
48
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
47
49
  self._key_value_action = parseractions.KeyValueAction(*args, **kwargs)
48
50
  self._key_value_append_action = parseractions.KeyValueAppendAction(
49
51
  *args, **kwargs
50
52
  )
51
53
  super().__init__(*args, **kwargs)
52
54
 
53
- def __call__(self, parser, namespace, values, option_string=None):
55
+ def __call__(
56
+ self,
57
+ parser: argparse.ArgumentParser,
58
+ namespace: argparse.Namespace,
59
+ values: Any,
60
+ option_string: str | None = None,
61
+ ) -> None:
54
62
  if values.startswith(self.APPEND_KEYS):
55
63
  self._key_value_append_action(
56
64
  parser, namespace, values, option_string=option_string
@@ -61,7 +69,7 @@ class KeyValueHintAction(argparse.Action):
61
69
  )
62
70
 
63
71
 
64
- class AttachmentsColumn(cliff_columns.FormattableColumn[list[ty.Any]]):
72
+ class AttachmentsColumn(cliff_columns.FormattableColumn[list[Any]]):
65
73
  """Formattable column for attachments column.
66
74
 
67
75
  Unlike the parent FormattableColumn class, the initializer of the
@@ -72,11 +80,13 @@ class AttachmentsColumn(cliff_columns.FormattableColumn[list[ty.Any]]):
72
80
  ``functools.partial(AttachmentsColumn, server_cache)``.
73
81
  """
74
82
 
75
- def __init__(self, value, server_cache=None):
83
+ def __init__(
84
+ self, value: list[Any], server_cache: dict[str, Any] | None = None
85
+ ) -> None:
76
86
  super().__init__(value)
77
87
  self._server_cache = server_cache or {}
78
88
 
79
- def human_readable(self):
89
+ def human_readable(self) -> str:
80
90
  """Return a formatted string of a volume's attached instances
81
91
 
82
92
  :rtype: a string of formatted instances
@@ -92,7 +102,7 @@ class AttachmentsColumn(cliff_columns.FormattableColumn[list[ty.Any]]):
92
102
  return msg
93
103
 
94
104
 
95
- def _format_volume(volume: _volume.Volume) -> dict[str, ty.Any]:
105
+ def _format_volume(volume: _volume.Volume) -> dict[str, Any]:
96
106
  # Some columns returned by openstacksdk should not be shown because they're
97
107
  # either irrelevant or duplicates
98
108
  ignored_columns = {
@@ -137,7 +147,7 @@ class CreateVolume(command.ShowOne):
137
147
  _description = _("Create new volume")
138
148
 
139
149
  @staticmethod
140
- def _check_size_arg(args):
150
+ def _check_size_arg(args: argparse.Namespace) -> None:
141
151
  """Check whether --size option is required or not.
142
152
 
143
153
  Require size parameter only in case when snapshot or source
@@ -151,7 +161,7 @@ class CreateVolume(command.ShowOne):
151
161
  )
152
162
  raise exceptions.CommandError(msg)
153
163
 
154
- def get_parser(self, prog_name):
164
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
155
165
  parser = super().get_parser(prog_name)
156
166
  parser.add_argument(
157
167
  "name",
@@ -262,7 +272,9 @@ class CreateVolume(command.ShowOne):
262
272
  )
263
273
  return parser
264
274
 
265
- def take_action(self, parsed_args):
275
+ def take_action(
276
+ self, parsed_args: argparse.Namespace
277
+ ) -> tuple[Sequence[str], Iterable[Any]]:
266
278
  self._check_size_arg(parsed_args)
267
279
  # size is validated in the above call to
268
280
  # _check_size_arg where we check that size
@@ -270,7 +282,9 @@ class CreateVolume(command.ShowOne):
270
282
  # volume from snapshot or source volume
271
283
  size = parsed_args.size
272
284
 
273
- volume_client = self.app.client_manager.sdk_connection.volume
285
+ volume_client = sdk_utils.ensure_service_version(
286
+ self.app.client_manager.sdk_connection.volume, '2'
287
+ )
274
288
  image_client = self.app.client_manager.image
275
289
 
276
290
  source_volume = None
@@ -366,13 +380,14 @@ class CreateVolume(command.ShowOne):
366
380
  )
367
381
 
368
382
  data = _format_volume(volume)
369
- return zip(*sorted(data.items()))
383
+ col_headers, col_data = zip(*sorted(data.items()))
384
+ return col_headers, col_data
370
385
 
371
386
 
372
387
  class DeleteVolume(command.Command):
373
388
  _description = _("Delete volume(s)")
374
389
 
375
- def get_parser(self, prog_name):
390
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
376
391
  parser = super().get_parser(prog_name)
377
392
  parser.add_argument(
378
393
  "volumes",
@@ -390,16 +405,25 @@ class DeleteVolume(command.Command):
390
405
  ),
391
406
  )
392
407
  group.add_argument(
393
- "--purge",
408
+ "--cascade",
394
409
  action="store_true",
395
410
  help=_(
396
411
  "Remove any snapshots along with volume(s) (defaults to False)"
397
412
  ),
398
413
  )
414
+ group.add_argument(
415
+ # now called "cascade", accept old arg for compatibility
416
+ "--purge",
417
+ action="store_true",
418
+ help=argparse.SUPPRESS,
419
+ dest='cascade',
420
+ )
399
421
  return parser
400
422
 
401
- def take_action(self, parsed_args):
402
- volume_client = self.app.client_manager.sdk_connection.volume
423
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
424
+ volume_client = sdk_utils.ensure_service_version(
425
+ self.app.client_manager.sdk_connection.volume, '2'
426
+ )
403
427
  result = 0
404
428
 
405
429
  for volume in parsed_args.volumes:
@@ -410,7 +434,7 @@ class DeleteVolume(command.Command):
410
434
  volume_client.delete_volume(
411
435
  volume_obj.id,
412
436
  force=parsed_args.force,
413
- cascade=parsed_args.purge,
437
+ cascade=parsed_args.cascade,
414
438
  )
415
439
  except Exception as e:
416
440
  result += 1
@@ -434,7 +458,7 @@ class DeleteVolume(command.Command):
434
458
  class ListVolume(command.Lister):
435
459
  _description = _("List volumes")
436
460
 
437
- def get_parser(self, prog_name):
461
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
438
462
  parser = super().get_parser(prog_name)
439
463
  parser.add_argument(
440
464
  '--project',
@@ -473,7 +497,9 @@ class ListVolume(command.Lister):
473
497
  pagination.add_marker_pagination_option_to_parser(parser)
474
498
  return parser
475
499
 
476
- def take_action(self, parsed_args):
500
+ def take_action(
501
+ self, parsed_args: argparse.Namespace
502
+ ) -> tuple[Sequence[str], Iterable[tuple[Any, ...]]]:
477
503
  volume_client = self.app.client_manager.volume
478
504
  identity_client = self.app.client_manager.identity
479
505
 
@@ -548,7 +574,7 @@ class ListVolume(command.Lister):
548
574
  compute_client = self.app.client_manager.compute
549
575
  for s in compute_client.servers():
550
576
  server_cache[s.id] = s
551
- except sdk_exceptions.SDKException: # noqa: S110
577
+ except sdk_exceptions.SDKException:
552
578
  # Just forget it if there's any trouble
553
579
  pass
554
580
  AttachmentsColumnWithCache = functools.partial(
@@ -578,7 +604,7 @@ class ListVolume(command.Lister):
578
604
  class MigrateVolume(command.Command):
579
605
  _description = _("Migrate volume to a new host")
580
606
 
581
- def get_parser(self, prog_name):
607
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
582
608
  parser = super().get_parser(prog_name)
583
609
  parser.add_argument(
584
610
  'volume',
@@ -612,8 +638,11 @@ class MigrateVolume(command.Command):
612
638
  )
613
639
  return parser
614
640
 
615
- def take_action(self, parsed_args):
616
- volume_client = self.app.client_manager.sdk_connection.volume
641
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
642
+ volume_client = sdk_utils.ensure_service_version(
643
+ self.app.client_manager.sdk_connection.volume, '2'
644
+ )
645
+
617
646
  volume = volume_client.find_volume(
618
647
  parsed_args.volume, ignore_missing=False
619
648
  )
@@ -628,7 +657,7 @@ class MigrateVolume(command.Command):
628
657
  class SetVolume(command.Command):
629
658
  _description = _("Set volume properties")
630
659
 
631
- def get_parser(self, prog_name):
660
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
632
661
  parser = super().get_parser(prog_name)
633
662
  parser.add_argument(
634
663
  'volume',
@@ -781,7 +810,7 @@ class SetVolume(command.Command):
781
810
  )
782
811
  return parser
783
812
 
784
- def take_action(self, parsed_args):
813
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
785
814
  volume_client = self.app.client_manager.volume
786
815
  volume = utils.find_resource(volume_client.volumes, parsed_args.volume)
787
816
 
@@ -910,12 +939,12 @@ class SetVolume(command.Command):
910
939
  elif policy:
911
940
  # If the "--migration-policy" is specified without "--type"
912
941
  LOG.warning(
913
- _("'%s' option will not work without '--type' option")
914
- % (
942
+ _("'%s' option will not work without '--type' option"),
943
+ (
915
944
  '--migration-policy'
916
945
  if parsed_args.migration_policy
917
946
  else '--retype-policy'
918
- )
947
+ ),
919
948
  )
920
949
 
921
950
  kwargs = {}
@@ -945,7 +974,7 @@ class SetVolume(command.Command):
945
974
  class ShowVolume(command.ShowOne):
946
975
  _description = _("Display volume details")
947
976
 
948
- def get_parser(self, prog_name):
977
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
949
978
  parser = super().get_parser(prog_name)
950
979
  parser.add_argument(
951
980
  'volume',
@@ -954,20 +983,26 @@ class ShowVolume(command.ShowOne):
954
983
  )
955
984
  return parser
956
985
 
957
- def take_action(self, parsed_args):
958
- volume_client = self.app.client_manager.sdk_connection.volume
986
+ def take_action(
987
+ self, parsed_args: argparse.Namespace
988
+ ) -> tuple[Sequence[str], Iterable[Any]]:
989
+ volume_client = sdk_utils.ensure_service_version(
990
+ self.app.client_manager.sdk_connection.volume, '2'
991
+ )
992
+
959
993
  volume = volume_client.find_volume(
960
994
  parsed_args.volume, ignore_missing=False
961
995
  )
962
996
 
963
997
  data = _format_volume(volume)
964
- return zip(*sorted(data.items()))
998
+ col_headers, col_data = zip(*sorted(data.items()))
999
+ return col_headers, col_data
965
1000
 
966
1001
 
967
1002
  class UnsetVolume(command.Command):
968
1003
  _description = _("Unset volume properties")
969
1004
 
970
- def get_parser(self, prog_name):
1005
+ def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
971
1006
  parser = super().get_parser(prog_name)
972
1007
  parser.add_argument(
973
1008
  'volume',
@@ -996,7 +1031,7 @@ class UnsetVolume(command.Command):
996
1031
  )
997
1032
  return parser
998
1033
 
999
- def take_action(self, parsed_args):
1034
+ def take_action(self, parsed_args: argparse.Namespace) -> None:
1000
1035
  volume_client = self.app.client_manager.volume
1001
1036
  volume = utils.find_resource(volume_client.volumes, parsed_args.volume)
1002
1037