Skip to content

API Reference

Core Components

NewType Factory

newtype.NewType(base_type, **_context)

Create a new type that preserves type information through all operations.

This is the main factory function for creating new types. It wraps an existing type and ensures that all operations on instances of the new type preserve their type information.

Parameters:

Name Type Description Default
base_type T

The base type to wrap

required
**context

Additional context for type creation (reserved for future use)

required

Returns

A new type that inherits from the base type and preserves type information
Example
class ValidatedStr(NewType(str)):
    def __init__(self, val: str) -> None:
        if not val.strip():
            raise ValueError("String cannot be empty")


# All operations preserve ValidatedStr type
x = ValidatedStr("hello")
y = x.upper()  # y is ValidatedStr, not str
Technical Details
  • Uses a global cache to prevent duplicate type creation
  • Properly handles slots and descriptors
  • Maintains all original type functionality
  • Provides proper type hints for IDE support
Source code in newtype/newtype.py
def NewType(base_type: T, **_context: "Dict[str, Any]") -> "T":  # noqa: N802, C901
    """Create a new type that preserves type information through all operations.

    This is the main factory function for creating new types. It wraps an existing
    type and ensures that all operations on instances of the new type preserve
    their type information.

    Args:
        base_type: The base type to wrap
        **context: Additional context for type creation (reserved for future use)

    Returns
    -------
        A new type that inherits from the base type and preserves type information

    Example:
        ```python
        class ValidatedStr(NewType(str)):
            def __init__(self, val: str) -> None:
                if not val.strip():
                    raise ValueError("String cannot be empty")


        # All operations preserve ValidatedStr type
        x = ValidatedStr("hello")
        y = x.upper()  # y is ValidatedStr, not str
        ```

    Technical Details:
        - Uses a global cache to prevent duplicate type creation
        - Properly handles slots and descriptors
        - Maintains all original type functionality
        - Provides proper type hints for IDE support
    """
    # Add a type check for base_type
    if not isinstance(base_type, type):
        raise TypeError(f"Expected a type, got {type(base_type).__name__}")

    try:
        # we try to see if it is cached, if it is not, no problem either
        if base_type in __GLOBAL_INTERNAL_TYPE_CACHE__:
            return cast(T, __GLOBAL_INTERNAL_TYPE_CACHE__[base_type])
    except KeyError:
        pass

    class BaseNewType(base_type):  # type: ignore[valid-type, misc]
        """Base class for all NewType instances.

        This class provides the core functionality for type preservation and
        method interception. It handles:
        - Proper initialization of new instances
        - Method wrapping for type preservation
        - Slot handling for optimized memory usage
        - Attribute access and modification
        """

        if hasattr(base_type, "__slots__"):
            __slots__ = (
                *base_type.__slots__,
                NEWTYPE_INIT_ARGS_STR,
                NEWTYPE_INIT_KWARGS_STR,
            )
        else:
            if can_subclass_have___slots__(base_type):
                __slots__ = (
                    NEWTYPE_INIT_ARGS_STR,
                    NEWTYPE_INIT_KWARGS_STR,
                )

        def __init_subclass__(cls, **init_subclass_context: Any) -> None:
            """Initialize a subclass of BaseNewType.

            This method is called when creating a new subclass of BaseNewType.
            It handles:
            - Method wrapping setup
            - Attribute copying from base type
            - Proper method resolution order
            - Constructor initialization

            Args:
                **context: Additional context for subclass initialization
            """
            super().__init_subclass__(**init_subclass_context)

            constructor = cls.__init__
            original_cls_dict: "Dict[str, Any]" = {}  # noqa: UP037
            original_cls_dict.update(cls.__dict__)
            for k, v in base_type.__dict__.items():
                if callable(v) and (k not in object.__dict__) and (k not in original_cls_dict):
                    setattr(cls, k, NewTypeMethod(v, base_type))
                elif k not in object.__dict__:
                    if k == "__dict__":
                        continue
                    setattr(cls, k, v)
            for k, v in original_cls_dict.items():
                if (
                    callable(v)
                    and k != "__init__"
                    and k in base_type.__dict__
                    and not func_is_excluded(v)
                ):
                    setattr(cls, k, NewTypeMethod(v, base_type))
                else:
                    if k == "__dict__":
                        continue
                    setattr(cls, k, v)
            cls.__init__ = NewTypeInit(constructor)  # type: ignore[method-assign]

        def __new__(cls, value: Any = None, *_args: Any, **_kwargs: Any) -> "BaseNewType":
            """Create a new instance of BaseNewType.

            This method handles the creation of new instances, ensuring that
            type information is preserved.

            Args:
                value: The value to initialize the instance with
                *_args: Additional positional arguments
                **_kwargs: Additional keyword arguments
            """
            if base_type.__new__ == object.__new__:
                inst = object.__new__(cls)

                # copy all the attributes in `__dict__`
                value_dict: Union[dict, object] = getattr(value, "__dict__", {})

                if isinstance(value_dict, dict):
                    for k, v in value_dict.items():
                        setattr(inst, k, v)

                # copy all the attributes in `__slots__`
                value_slots: Sequence[str] = getattr(value, "__slots__", ())
                for k in value_slots:
                    v = getattr(value, k, UNDEFINED)
                    if v is not UNDEFINED:
                        setattr(inst, k, v)
            else:
                inst = cast("BaseNewType", base_type.__new__(cls, value))
            return inst

        def __init__(self, _value: Any = None, *_args: Any, **_kwargs: Any) -> None:
            """Initialize an instance of BaseNewType.

            This method is called when an instance is created. It handles
            the initialization of the instance, ensuring that type information
            is preserved.

            Args:
                _value: The value to initialize the instance with
                *_args: Additional positional arguments
                **_kwargs: Additional keyword arguments
            """
            # avoid python from calling `object.__init__`
            ...

    try:
        # we try to store it in a cache, if it fails, no problem either
        if base_type not in __GLOBAL_INTERNAL_TYPE_CACHE__:
            __GLOBAL_INTERNAL_TYPE_CACHE__[base_type] = BaseNewType
    except KeyError:  # noqa: S110
        pass

    return cast(T, BaseNewType)

newtype_exclude Decorator

newtype.newtype_exclude(func)

Decorator to exclude a method from type wrapping.

This decorator marks methods that should not be wrapped by NewTypeMethod, allowing them to maintain their original behavior without type preservation.

Parameters:

Name Type Description Default
func Callable[..., Any]

The function to be excluded from type wrapping

required

Returns

The original function, marked with an exclusion flag
Example
class SafeStr(NewType(str)):
    @newtype_exclude
    def dangerous_operation(self) -> str:
        # This method will return a regular str, not a SafeStr
        return str(self)
Source code in newtype/newtype.py
def newtype_exclude(func: "Callable[..., Any]") -> "Callable[..., Any]":
    """Decorator to exclude a method from type wrapping.

    This decorator marks methods that should not be wrapped by NewTypeMethod,
    allowing them to maintain their original behavior without type preservation.

    Args:
        func: The function to be excluded from type wrapping

    Returns
    -------
        The original function, marked with an exclusion flag

    Example:
        ```python
        class SafeStr(NewType(str)):
            @newtype_exclude
            def dangerous_operation(self) -> str:
                # This method will return a regular str, not a SafeStr
                return str(self)
        ```
    """
    setattr(func, NEWTYPE_EXCLUDE_FUNC_STR, True)
    return func

Type System Components

These are internal components that power python-newtype. While they're not typically used directly, understanding them can be helpful for advanced usage or debugging.

NewTypeInit Descriptor

newtype.NewTypeInit

Descriptor class for handling NewType subclass initialization.

This class is responsible for intercepting instance creation of NewType subclasses and ensuring proper type preservation. It implements both the descriptor protocol and the callable interface.

Parameters:

Name Type Description Default
func Callable[..., Any]

The initialization function to be wrapped, typically the init method of the NewType subclass.

required

Attributes

func_get: The bound method if the wrapped function is a descriptor
has_get: Boolean indicating if the wrapped function has __get__
obj: The instance being initialized (None for unbound calls)
cls: The class being initialized
Source code in newtype/extensions/newtypeinit.pyi
class NewTypeInit:
    """Descriptor class for handling NewType subclass initialization.

    This class is responsible for intercepting instance creation of NewType subclasses
    and ensuring proper type preservation. It implements both the descriptor protocol
    and the callable interface.

    Args:
        func (Callable[..., Any]): The initialization function to be wrapped,
            typically the __init__ method of the NewType subclass.

    Attributes
    ----------
        func_get: The bound method if the wrapped function is a descriptor
        has_get: Boolean indicating if the wrapped function has __get__
        obj: The instance being initialized (None for unbound calls)
        cls: The class being initialized
    """

    def __init__(self, func: Callable[..., Any]) -> None: ...
    def __get__(self, inst: Any | None, owner: type[Any] | None) -> NewTypeInit:
        """Implement the descriptor protocol for method binding.

        This method is called when accessing the initialization method on either
        the class or an instance. It ensures proper method binding and type preservation.

        Args:
            inst: The instance the method is being accessed from (None for class access)
            owner: The class that owns this method

        Returns
        -------
            A bound or unbound NewTypeInit instance
        """
        ...

    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        """Handle the actual initialization call.

        This method is called when creating a new instance of a NewType subclass.
        It ensures that:
        1. The parent class's __new__ is called properly
        2. The instance's __init__ is called with the provided arguments
        3. The correct type is preserved throughout the process

        Args:
            *args: Positional arguments for initialization
            **kwargs: Keyword arguments for initialization

        Returns
        -------
            A properly initialized instance of the NewType subclass
        """
        ...

__call__(*args, **kwargs)

Handle the actual initialization call.

This method is called when creating a new instance of a NewType subclass. It ensures that: 1. The parent class's new is called properly 2. The instance's init is called with the provided arguments 3. The correct type is preserved throughout the process

Parameters:

Name Type Description Default
*args Any

Positional arguments for initialization

()
**kwargs Any

Keyword arguments for initialization

{}
Returns
A properly initialized instance of the NewType subclass
Source code in newtype/extensions/newtypeinit.pyi
def __call__(self, *args: Any, **kwargs: Any) -> Any:
    """Handle the actual initialization call.

    This method is called when creating a new instance of a NewType subclass.
    It ensures that:
    1. The parent class's __new__ is called properly
    2. The instance's __init__ is called with the provided arguments
    3. The correct type is preserved throughout the process

    Args:
        *args: Positional arguments for initialization
        **kwargs: Keyword arguments for initialization

    Returns
    -------
        A properly initialized instance of the NewType subclass
    """
    ...

__get__(inst, owner)

Implement the descriptor protocol for method binding.

This method is called when accessing the initialization method on either the class or an instance. It ensures proper method binding and type preservation.

Parameters:

Name Type Description Default
inst Any | None

The instance the method is being accessed from (None for class access)

required
owner type[Any] | None

The class that owns this method

required
Returns
A bound or unbound NewTypeInit instance
Source code in newtype/extensions/newtypeinit.pyi
def __get__(self, inst: Any | None, owner: type[Any] | None) -> NewTypeInit:
    """Implement the descriptor protocol for method binding.

    This method is called when accessing the initialization method on either
    the class or an instance. It ensures proper method binding and type preservation.

    Args:
        inst: The instance the method is being accessed from (None for class access)
        owner: The class that owns this method

    Returns
    -------
        A bound or unbound NewTypeInit instance
    """
    ...

NewTypeMethod Descriptor

newtype.extensions.NewTypeMethod

Descriptor class for handling NewType subclass method calls.

This class is responsible for intercepting method calls on NewType subclasses and ensuring proper type preservation. It implements both the descriptor protocol and the callable interface.

Parameters:

Name Type Description Default
func Callable[..., Any]

The method to be wrapped

required
wrapped_cls Type[Any]

The NewType subclass that owns this method

required

Attributes

func_get: The bound method if the wrapped function is a descriptor
has_get: Boolean indicating if the wrapped function has __get__
obj: The instance the method is bound to (None for unbound calls)
cls: The class that owns this method
wrapped_cls: The NewType subclass this method belongs to
Source code in newtype/extensions/newtypemethod.pyi
class NewTypeMethod:
    """Descriptor class for handling NewType subclass method calls.

    This class is responsible for intercepting method calls on NewType subclasses
    and ensuring proper type preservation. It implements both the descriptor protocol
    and the callable interface.

    Args:
        func (Callable[..., Any]): The method to be wrapped
        wrapped_cls (Type[Any]): The NewType subclass that owns this method

    Attributes
    ----------
        func_get: The bound method if the wrapped function is a descriptor
        has_get: Boolean indicating if the wrapped function has __get__
        obj: The instance the method is bound to (None for unbound calls)
        cls: The class that owns this method
        wrapped_cls: The NewType subclass this method belongs to
    """

    def __init__(self, func: Callable[..., Any], wrapped_cls: type[Any]) -> None: ...
    def __get__(self, inst: Any | None, owner: type[Any] | None) -> NewTypeMethod:
        """Implement the descriptor protocol for method binding.

        This method is called when accessing a method on either the class or an
        instance. It ensures proper method binding and type preservation.

        Args:
            inst: The instance the method is being accessed from (None for class access)
            owner: The class that owns this method

        Returns
        -------
            A bound or unbound NewTypeMethod instance
        """
        ...

    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        """Handle the actual method call.

        This method is called when invoking a method on a NewType subclass instance.
        It ensures that:
        1. The original method is called with proper arguments
        2. The return value maintains the correct type
        3. Type information is preserved for method chaining

        Args:
            *args: Positional arguments for the method call
            **kwargs: Keyword arguments for the method call

        Returns
        -------
            The result of the method call, properly typed as the NewType subclass
        """
        ...

__call__(*args, **kwargs)

Handle the actual method call.

This method is called when invoking a method on a NewType subclass instance. It ensures that: 1. The original method is called with proper arguments 2. The return value maintains the correct type 3. Type information is preserved for method chaining

Parameters:

Name Type Description Default
*args Any

Positional arguments for the method call

()
**kwargs Any

Keyword arguments for the method call

{}
Returns
The result of the method call, properly typed as the NewType subclass
Source code in newtype/extensions/newtypemethod.pyi
def __call__(self, *args: Any, **kwargs: Any) -> Any:
    """Handle the actual method call.

    This method is called when invoking a method on a NewType subclass instance.
    It ensures that:
    1. The original method is called with proper arguments
    2. The return value maintains the correct type
    3. Type information is preserved for method chaining

    Args:
        *args: Positional arguments for the method call
        **kwargs: Keyword arguments for the method call

    Returns
    -------
        The result of the method call, properly typed as the NewType subclass
    """
    ...

__get__(inst, owner)

Implement the descriptor protocol for method binding.

This method is called when accessing a method on either the class or an instance. It ensures proper method binding and type preservation.

Parameters:

Name Type Description Default
inst Any | None

The instance the method is being accessed from (None for class access)

required
owner type[Any] | None

The class that owns this method

required
Returns
A bound or unbound NewTypeMethod instance
Source code in newtype/extensions/newtypemethod.pyi
def __get__(self, inst: Any | None, owner: type[Any] | None) -> NewTypeMethod:
    """Implement the descriptor protocol for method binding.

    This method is called when accessing a method on either the class or an
    instance. It ensures proper method binding and type preservation.

    Args:
        inst: The instance the method is being accessed from (None for class access)
        owner: The class that owns this method

    Returns
    -------
        A bound or unbound NewTypeMethod instance
    """
    ...

Constants

NEWTYPE_INIT_ARGS_STR

Internal string constant used to store initialization arguments.

NEWTYPE_INIT_KWARGS_STR

Internal string constant used to store initialization keyword arguments.

NEWTYPE_EXCLUDE_FUNC_STR

Internal string constant used to mark functions that should not be wrapped.

Type Variables

T

Type variable used for generic type hints in the implementation.

Logging

The library uses Python's standard logging module for debugging and error reporting. The logger name is 'newtype'.