@@ -43,6 +43,25 @@ def __init__(self, name, field_type, mode='NULLABLE',
4343 self ._description = description
4444 self ._fields = tuple (fields )
4545
46+ @classmethod
47+ def from_api_repr (cls , api_repr ):
48+ """Return a ``SchemaField`` object deserialized from a dictionary.
49+
50+ Args:
51+ api_repr (Mapping[str, str]): The serialized representation
52+ of the SchemaField, such as what is output by
53+ :meth:`to_api_repr`.
54+
55+ Returns:
56+ SchemaField: The ``SchemaField`` object.
57+ """
58+ return cls (
59+ field_type = api_repr ['type' ].upper (),
60+ fields = [cls .from_api_repr (f ) for f in api_repr .get ('fields' , ())],
61+ mode = api_repr ['mode' ].upper (),
62+ name = api_repr ['name' ],
63+ )
64+
4665 @property
4766 def name (self ):
4867 """str: The name of the field."""
@@ -84,6 +103,28 @@ def fields(self):
84103 """
85104 return self ._fields
86105
106+ def to_api_repr (self ):
107+ """Return a dictionary representing this schema field.
108+
109+ Returns:
110+ dict: A dictionary representing the SchemaField in a serialized
111+ form.
112+ """
113+ # Put together the basic representation. See http://bit.ly/2hOAT5u.
114+ answer = {
115+ 'mode' : self .mode .lower (),
116+ 'name' : self .name ,
117+ 'type' : self .field_type .lower (),
118+ }
119+
120+ # If this is a RECORD type, then sub-fields are also included,
121+ # add this to the serialized representation.
122+ if self .field_type .upper () == 'RECORD' :
123+ answer ['fields' ] = [f .to_api_repr () for f in self .fields ]
124+
125+ # Done; return the serialized dictionary.
126+ return answer
127+
87128 def _key (self ):
88129 """A tuple key that unique-ly describes this field.
89130
0 commit comments