@@ -110,29 +110,69 @@ def _get_json_type_for_field(field):
110110 return json_type , fmt
111111
112112
113- def field2choices (field ):
114- """Return the set of valid choices for a :class:`Field <marshmallow.fields.Field>`,
115- or ``None`` if no choices are specified.
113+ def field2choices (field , ** kwargs ):
114+ """Return the dictionary of swagger field attributes for valid choices definition
116115
117116 :param Field field: A marshmallow field.
118- :rtype: set
117+ :rtype: dict
119118 """
120- comparable = {
119+ attributes = {}
120+
121+ comparable = [
121122 validator .comparable for validator in field .validators
122123 if hasattr (validator , 'comparable' )
123- }
124+ ]
124125 if comparable :
125- return comparable
126+ attributes ['enum' ] = comparable
127+ else :
128+ choices = [
129+ OrderedSet (validator .choices ) for validator in field .validators
130+ if hasattr (validator , 'choices' )
131+ ]
132+ if choices :
133+ attributes ['enum' ] = list (functools .reduce (operator .and_ , choices ))
134+
135+ return attributes
126136
127- choices = [
128- OrderedSet (validator .choices ) for validator in field .validators
129- if hasattr (validator , 'choices' )
130- ]
131- if choices :
132- return functools .reduce (operator .and_ , choices )
133137
138+ def field2read_only (field , ** kwargs ):
139+ """Return the dictionary of swagger field attributes for a dump_only field.
134140
135- def field2range (field ):
141+ :param Field field: A marshmallow field.
142+ :rtype: dict
143+ """
144+ attributes = {}
145+ if field .dump_only :
146+ attributes ['readOnly' ] = True
147+ return attributes
148+
149+
150+ def field2write_only (field , ** kwargs ):
151+ """Return the dictionary of swagger field attributes for a load_only field.
152+
153+ :param Field field: A marshmallow field.
154+ :rtype: dict
155+ """
156+ attributes = {}
157+ if field .load_only and kwargs ['openapi_major_version' ] >= 3 :
158+ attributes ['writeOnly' ] = True
159+ return attributes
160+
161+
162+ def field2nullable (field , ** kwargs ):
163+ """Return the dictionary of swagger field attributes for a nullable field.
164+
165+ :param Field field: A marshmallow field.
166+ :rtype: dict
167+ """
168+ attributes = {}
169+ if field .allow_none :
170+ omv = kwargs ['openapi_major_version' ]
171+ attributes ['x-nullable' if omv < 3 else 'nullable' ] = True
172+ return attributes
173+
174+
175+ def field2range (field , ** kwargs ):
136176 """Return the dictionary of swagger field attributes for a set of
137177 :class:`Range <marshmallow.validators.Range>` validators.
138178
@@ -168,7 +208,7 @@ def field2range(field):
168208 attributes ['maximum' ] = validator .max
169209 return attributes
170210
171- def field2length (field ):
211+ def field2length (field , ** kwargs ):
172212 """Return the dictionary of swagger field attributes for a set of
173213 :class:`Length <marshmallow.validators.Length>` validators.
174214
@@ -269,6 +309,12 @@ def field2property(field, spec=None, use_refs=True, dump=True, name=None):
269309 :param str name: The definition name, if applicable, used to construct the $ref value.
270310 :rtype: dict, a Property Object
271311 """
312+ if spec :
313+ openapi_major_version = spec .openapi_version .version [0 ]
314+ else :
315+ # Default to 2 for backward compatibility
316+ openapi_major_version = 2
317+
272318 from apispec .ext .marshmallow import resolve_schema_dict
273319 type_ , fmt = _get_json_type_for_field (field )
274320
@@ -286,18 +332,16 @@ def field2property(field, spec=None, use_refs=True, dump=True, name=None):
286332 else :
287333 ret ['default' ] = default
288334
289- choices = field2choices (field )
290- if choices :
291- ret ['enum' ] = list (choices )
292-
293- if field .dump_only :
294- ret ['readOnly' ] = True
295-
296- if field .allow_none :
297- ret ['x-nullable' ] = True
298-
299- ret .update (field2range (field ))
300- ret .update (field2length (field ))
335+ for attr_func in (
336+ field2choices ,
337+ field2read_only ,
338+ field2write_only ,
339+ field2nullable ,
340+ field2range ,
341+ field2length ,
342+ ):
343+ ret .update (attr_func (
344+ field , openapi_major_version = openapi_major_version ))
301345
302346 if isinstance (field , marshmallow .fields .Nested ):
303347 del ret ['type' ]
@@ -313,7 +357,7 @@ def field2property(field, spec=None, use_refs=True, dump=True, name=None):
313357 raise ValueError ('Must pass `name` argument for self-referencing Nested fields.' )
314358 # We need to use the `name` argument when the field is self-referencing and
315359 # unbound (doesn't have `parent` set) because we can't access field.schema
316- ref_path = get_ref_path (spec . openapi_version . version [ 0 ] )
360+ ref_path = get_ref_path (openapi_major_version )
317361 ref_name = '#/{ref_path}/{name}' .format (ref_path = ref_path ,
318362 name = name )
319363 ref_schema = {'$ref' : ref_name }
0 commit comments