Generates non-null type (t!)

    >>> class TypeWithNonNullFields(Type):
    ...     a_int = non_null(int)
    ...     a_float = non_null(Float)
    ...     a_string = Field(non_null(String))
    ...
    >>> TypeWithNonNullFields
    type TypeWithNonNullFields {
      aInt: Int!
      aFloat: Float!
      aString: String!
    }

    Giving proper JSON data:

    >>> json_data = {'aInt': 1, 'aFloat': 2.1, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)
    >>> obj
    TypeWithNonNullFields(a_int=1, a_float=2.1, a_string='hello')

    Giving incorrect JSON data:

    >>> json_data = {'aInt': None, 'aFloat': 2.1, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_int': ...
    >>> json_data = {'aInt': 1, 'aFloat': None, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_float': ...
    >>> json_data = {'aInt': 1, 'aFloat': 2.1, 'aString': None}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_string': ...

    .. note::

       Note that **missing** keys in JSON data are not considered
       ``None``, and they won't show in ``iter(obj)``, ``__str__()``
       or ``__repr__()``

       >>> json_data = {'aInt': 1, 'aFloat': 2.1}
       >>> obj = TypeWithNonNullFields(json_data)
       >>> obj # repr()
       TypeWithNonNullFields(a_int=1, a_float=2.1)
       >>> for field_name in obj:
       ...     print(field_name, repr(obj[field_name]))
       ...
       a_int 1
       a_float 2.1

def non_null(t):
    '''Generates non-null type (t!)

    >>> class TypeWithNonNullFields(Type):
    ...     a_int = non_null(int)
    ...     a_float = non_null(Float)
    ...     a_string = Field(non_null(String))
    ...
    >>> TypeWithNonNullFields
    type TypeWithNonNullFields {
      aInt: Int!
      aFloat: Float!
      aString: String!
    }

    Giving proper JSON data:

    >>> json_data = {'aInt': 1, 'aFloat': 2.1, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)
    >>> obj
    TypeWithNonNullFields(a_int=1, a_float=2.1, a_string='hello')

    Giving incorrect JSON data:

    >>> json_data = {'aInt': None, 'aFloat': 2.1, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_int': ...
    >>> json_data = {'aInt': 1, 'aFloat': None, 'aString': 'hello'}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_float': ...
    >>> json_data = {'aInt': 1, 'aFloat': 2.1, 'aString': None}
    >>> obj = TypeWithNonNullFields(json_data)  # doctest: +ELLIPSIS
    Traceback (most recent call last):
      ...
    ValueError: TypeWithNonNullFields selection 'a_string': ...

    .. note::

       Note that **missing** keys in JSON data are not considered
       ``None``, and they won't show in ``iter(obj)``, ``__str__()``
       or ``__repr__()``

       >>> json_data = {'aInt': 1, 'aFloat': 2.1}
       >>> obj = TypeWithNonNullFields(json_data)
       >>> obj # repr()
       TypeWithNonNullFields(a_int=1, a_float=2.1)
       >>> for field_name in obj:
       ...     print(field_name, repr(obj[field_name]))
       ...
       a_int 1
       a_float 2.1

    '''
    if isinstance(t, str):
        return Lazy(t, t + '!', non_null)
    elif isinstance(t, Lazy):
        return Lazy(t.target_name, t.target_name + '!', non_null, t)

    t = BaseType.__ensure__(t)
    name = t.__name__ + '!'
    try:
        return t.__schema__.__cache__[name]
    except KeyError:
        pass

    wrapper = _create_non_null_wrapper(name, t)
    t.__schema__.__cache__[name] = wrapper
    return wrapper