1919#
2020
2121import re
22+ from typing import Dict , List , Optional , TypedDict , Union
23+ from typing_extensions import Required , NotRequired
24+
2225
2326# Matches on a string specifying memory size
2427MEM = re .compile ('^[1-9][0-9]*[MGTP]$' )
6164SNAKE2 = re .compile ('([a-z0-9])([A-Z])' )
6265
6366
64- def parse (constraints ):
67+ ParsedValue = Union [int , bool , str ]
68+
69+
70+ class ConstraintsDict (TypedDict , total = False ):
71+ allocate_public_ip : ParsedValue
72+ arch : ParsedValue
73+ container : ParsedValue
74+ cores : ParsedValue
75+ cpu_cores : ParsedValue
76+ cpu_power : ParsedValue
77+ instance_role : ParsedValue
78+ instance_type : ParsedValue
79+ mem : ParsedValue
80+ root_disk : ParsedValue
81+ root_dist_source : ParsedValue
82+ spaces : List [ParsedValue ]
83+ tags : List [ParsedValue ]
84+ virt_type : ParsedValue
85+ zones : List [ParsedValue ]
86+
87+
88+ def parse (constraints : Union [str , ConstraintsDict ]) -> Optional [ConstraintsDict ]:
6589 """
6690 Constraints must be expressed as a string containing only spaces
6791 and key value pairs joined by an '='.
@@ -74,7 +98,7 @@ def parse(constraints):
7498 # Fowards compatibilty: already parsed
7599 return constraints
76100
77- normalized_constraints = {}
101+ normalized_constraints : ConstraintsDict = {}
78102 for s in constraints .split (" " ):
79103 if "=" not in s :
80104 raise ValueError ("malformed constraint %s" % s )
@@ -89,7 +113,7 @@ def parse(constraints):
89113 return normalized_constraints
90114
91115
92- def normalize_key (orig_key ) :
116+ def normalize_key (orig_key : str ) -> str :
93117 key = orig_key .strip ()
94118
95119 key = key .replace ("-" , "_" ) # Our _client lib wants "_" in place of "-"
@@ -103,7 +127,7 @@ def normalize_key(orig_key):
103127 return key
104128
105129
106- def normalize_value (value ) :
130+ def normalize_value (value : str ) -> Union [ int , bool , str ] :
107131 value = value .strip ()
108132
109133 if MEM .match (value ):
@@ -121,7 +145,7 @@ def normalize_value(value):
121145 return value
122146
123147
124- def normalize_list_value (value ) :
148+ def normalize_list_value (value : str ) -> List [ ParsedValue ] :
125149 values = value .strip ().split (',' )
126150 return [normalize_value (value ) for value in values ]
127151
@@ -130,8 +154,14 @@ def normalize_list_value(value):
130154 '(?:(?:^|(?<=,))(?:|(?P<pool>[a-zA-Z]+[-?a-zA-Z0-9]*)|(?P<count>-?[0-9]+)|(?:(?P<size>-?[0-9]+(?:\\ .[0-9]+)?)(?P<size_exp>[MGTPEZY])(?:i?B)?))(?:$|,))' )
131155
132156
133- def parse_storage_constraint (constraint ):
134- storage = {'count' : 1 }
157+ class StorageConstraintDict (TypedDict ):
158+ count : Required [int ] # >= 1
159+ pool : NotRequired [str ]
160+ size : NotRequired [int ]
161+
162+
163+ def parse_storage_constraint (constraint : str ) -> StorageConstraintDict :
164+ storage : StorageConstraintDict = {'count' : 1 }
135165 for m in STORAGE .finditer (constraint ):
136166 pool = m .group ('pool' )
137167 if pool :
@@ -153,11 +183,17 @@ def parse_storage_constraint(constraint):
153183ATTR = re .compile (';?(?P<key>[^=]+)=(?P<value>[^;]+)' )
154184
155185
156- def parse_device_constraint (constraint ):
186+ class DeviceConstraintDict (TypedDict ):
187+ count : Required [int ]
188+ type : Required [str ]
189+ attributes : NotRequired [Dict [str , str ]]
190+
191+
192+ def parse_device_constraint (constraint : str ) -> DeviceConstraintDict :
157193 m = DEVICE .match (constraint )
158194 if m is None :
159195 raise ValueError ("device constraint does not match" )
160- device = {}
196+ device : DeviceConstraintDict = {}
161197 count = m .group ('count' )
162198 if count :
163199 count = int (count )
0 commit comments