Repository: pydantic/pydantic

Issue:
Rename Schema to Field?
Currently we have the class `Schema` for when you need to define more stuff on a field than just the type and default.

But this is a confusing name since not all it's arguments refer to the schema. It'll get more confusing if we want to add more arguments to `Schema/Field`, eg. a more complex alias system #477.

Therefore we should rename it to `Field`.

This would require:
* renaming the current `Field` class, perhaps renaming the entire `fields.py` module.
* `Schema` needs to carry on working for a while but with a deprecation warning

What does everyone thing?

@tiangolo `Schema` was your work originally, are you ok with this?


Comments:
Thanks for tagging me. Yep. I think it makes sense.

If we can keep supporting it for a while with a deprecation warning, we should be fine.

And thinking about it, it actually makes more sense for it to be `Field`.

---

Slightly related, currently `Schema` (soon to be `Field`) is a class. When declaring a Pydantic field with:

```Python
a: int = Schema(...)
```

`mypy` complains that `a` should be of type `int` but is being of type `Schema`.

One way I'm "hacking" it in FastAPI (for stuff that inherits from `Schema`) is to create a function with a return type annotation of `Any` (while it is returning a `Schema` instance).

Then because the return of the function is annotated as `Any`, `mypy` accepts it.

I think this is something that could be interesting to have here too, maybe worth considering during this change.
In favour of this change too.

This seems to align better with dataclass terminology too, https://docs.python.org/3/library/dataclasses.html#dataclasses.field. 

For consideration: is there a possibility that the similarity would be a bad thing, rather than good?
I agree with @jasonkuhrt that using a `field` function would be nice. Being a function that actually returns a class would fix `mypy` errors when using `Schema` (or the next, `Field`), as a function can be typed to return `Any`. In fact, I'm doing something like that in FastAPI.

Also, by implementing a `field` function right away we could update the docs and show the new interface to new users, even while `Schema` is not yet renamed to `Field` (and the current `Field` to something else).

I wanna take a shot at this.

I have some naming questions:

* Is it OK a `field` function exposed as the main interface instead of the corresponding class?
    * Would you prefer another function name? Or a capitalized version (a function `Field`) that simulates the class name, even while it's a function?
* What would be an acceptable name for the current `Field` class?

---

On the other side, having just a function `field` that returns a `Schema` class would solve the visible naming issue for users, that could be enough, without needing to rename the underlying classes. The drawback is that the internal names would be more difficult for newcomer contributors to the internal code.
I think the function should be called `Field`, it should have an alias called `Schema` that also returns a `Field` but also raises a warning.

The only question is what do we call the class? It would be confusing to also call it `Field`, how about `FieldInfo`?

Please take a shot. I want to work on v1 features once v0.32 is released.
Perfect.

So, the *current* `Schema` class will be called `FieldInfo`?

And how should the *current* `Field` class be called? `FieldAttr`, `FieldObject`, `FieldElement`, `Attr`, (something else). Or should we keep it just `Field`?

---

In summary, the next parts will be:

* A `Field` *function* that returns a `FieldInfo` *class* instance.
* A `Schema` *function* that returns a `FieldInfo` *class* instance and logs a warning.
* A `FieldInfo` *class* that will replace the current `Schema` *class*.
* A (what?) *class* that will replace the current `Field` *class* (or do we just keep this `Field` *class*)?
Looks good, I think current field becomes `Attribute`, we should also rename that file.
Correction, `Attribute` is a dumb name since then you would have `model.__fields__: Dict[str, Attribute]` which is confusing.

Better to rename what used to be called `Field` as `ModelField`?
+1 for `ModelField`, `FieldInfo`, and `Field` function that returns a `FieldInfo`
This may be controversial, but the library **attrs** supported typing (before python 3.6) using a type parameter.  `Field` could have two positional arguments (type and default) then the `Field` function could actually return the correct type (using a Generic).

```python
class Foo(BaseModel):
  maximum = Field(int, 100)

# this would require a different code path
class Bar(BaseModel):
  maximum: int

# this would be bad but possible
class Foo(BaseModel):
  maximum: int = Field(str, "100")
```

Would having the type as an arg to the `Field` method provide any additional benefits?
I see a variety of approaches to the possible signature of the `Field` function; I've included my breakdown below. (I use `FieldType` to refer to the type of the object actually returned by `Field`.)

I'm most in favor of one of the first two approaches, and would be fine with the first one (the current proposal).

* Proposed implementation: `def Field(default: Any, **etc) -> Any`
    * (All pros/cons below are relative to this implementation)
* The following overloaded approach (which may require some minor tweaks)
    ```python
    @overload
    def Field(default: T, **etc) -> T: ...
    @overload
    def Field(default: None, **etc) -> Any: ...
    @overload
    def Field(default: Ellipsis, **etc) -> Any: ...
    def Field(default: Any, **etc) -> Any: ...
    ```
    * Pro: type-checks default value against the annotated type where possible
    * Con: Incorrect type hint if you actually want to treat the result as a `FieldType`
    * Conclusion: currently my favorite alternative to the proposed implementation; depends on whether we might ever want to work with the returned value of the `Field` function as a `FieldType`.
* `def Field(type_: Type[T], default: T, **etc) -> T`
    * Pro: type-checks the default value against the specified type
    * Con: Incorrect type hint if you actually want to treat the result as a `FieldType`
    * Con: Requires you to repeat the type if you want to use an annotation. **If you *don't* use an annotation, then the fields may occur out of order, potentially leading to confusing validation errors.**
    * Conclusion: Given the second con, I would probably prefer the prior approach.
* `def Field(type_: Type[T], default: T, **etc) -> Any`
    * Pro: type-checks the default value against the specified type
    * Con: Even more so than the previous example, encourages you to drop the annotation to prevent them from getting out of sync (since there is no check they are equal)
    * Conclusion: given the field-ordering issue described above, I would probably prefer the overload-heavy implementation (despite getting an incorrect type hint for `FieldType`)
* Approaches where `FieldType` is generic and `Field` returns a `FieldType[T]` (this is actually what `attrs` does, though the library mechanics are sufficiently different to cause different issues)
    * E.g.:
        * `def Field(default: T, **etc) -> FieldType[T]`        
        * `def Field(default: T, type_: Type[T], **etc) -> FieldType[T]`
    * Pro: provides the type checker with the most accurate information
    * Con: will cause mypy errors when used to annotate fields in the absence of a mypy plugin; *with* a mypy plugin, this is probably unnecessary anyway.
    * Conclusion: Probably not even an improvement over the current implementation

@skewty do those points change your thinking at all?
@dmontagu I hadn't mentally considered "Con: Incorrect type hint if you actually want to treat the result as a FieldType".  Thank you.

Given the above, I would choose method 1.


@skewty for what it’s worth, I’m not sure it’s actually that big of a downside for the following reasons:

1. You can always use the `FieldType` class directly
1. Internally, there is little reason to use the `Field` function anyway
1. Externally, there is little reason to need to interact with the result of `Field` as a `FieldType` anyway
1. Type hinting as Any prevents any type safety benefits anyway, so if `Field` is going to be rarely/never used to produce something interacted with as a  `FieldType`, it might make sense to just use `# type: ignore` in the few places you use for that purpose anyway.



Patch:
diff --git a/docs/examples/schema1.py b/docs/examples/schema1.py
--- a/docs/examples/schema1.py
+++ b/docs/examples/schema1.py
@@ -1,5 +1,5 @@
 from enum import Enum
-from pydantic import BaseModel, Schema
+from pydantic import BaseModel, Field
 
 class FooBar(BaseModel):
     count: int
@@ -15,12 +15,9 @@ class MainModel(BaseModel):
     """
     This is the description of the main model
     """
-    foo_bar: FooBar = Schema(...)
-    gender: Gender = Schema(
-        None,
-        alias='Gender',
-    )
-    snap: int = Schema(
+    foo_bar: FooBar = Field(...)
+    gender: Gender = Field(None, alias='Gender')
+    snap: int = Field(
         42,
         title='The Snap',
         description='this is the value of snap',
diff --git a/pydantic/__init__.py b/pydantic/__init__.py
--- a/pydantic/__init__.py
+++ b/pydantic/__init__.py
@@ -4,10 +4,9 @@
 from .env_settings import BaseSettings
 from .error_wrappers import ValidationError
 from .errors import *
-from .fields import Required
+from .fields import Field, Required, Schema
 from .main import *
 from .networks import *
 from .parse import Protocol
-from .schema import Schema
 from .types import *
 from .version import VERSION
diff --git a/pydantic/class_validators.py b/pydantic/class_validators.py
--- a/pydantic/class_validators.py
+++ b/pydantic/class_validators.py
@@ -31,10 +31,10 @@ def __init__(
 
 if TYPE_CHECKING:  # pragma: no cover
     from .main import BaseConfig
-    from .fields import Field
+    from .fields import ModelField
     from .types import ModelOrDc
 
-    ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], Field, Type[BaseConfig]], Any]
+    ValidatorCallable = Callable[[Optional[ModelOrDc], Any, Dict[str, Any], ModelField, Type[BaseConfig]], Any]
     ValidatorsList = List[ValidatorCallable]
     ValidatorListDict = Dict[str, List[Validator]]
 
diff --git a/pydantic/fields.py b/pydantic/fields.py
--- a/pydantic/fields.py
+++ b/pydantic/fields.py
@@ -1,3 +1,4 @@
+import warnings
 from typing import (
     TYPE_CHECKING,
     Any,
@@ -38,13 +39,131 @@
     from .class_validators import ValidatorsList  # noqa: F401
     from .error_wrappers import ErrorList
     from .main import BaseConfig, BaseModel  # noqa: F401
-    from .schema import Schema  # noqa: F401
     from .types import ModelOrDc  # noqa: F401
 
     ValidateReturn = Tuple[Optional[Any], Optional[ErrorList]]
     LocStr = Union[Tuple[Union[int, str], ...], str]
 
 
+class FieldInfo:
+    """
+    Captures extra information about a field.
+    """
+
+    __slots__ = (
+        'default',
+        'alias',
+        'title',
+        'description',
+        'const',
+        'gt',
+        'ge',
+        'lt',
+        'le',
+        'multiple_of',
+        'min_items',
+        'max_items',
+        'min_length',
+        'max_length',
+        'regex',
+        'extra',
+    )
+
+    def __init__(self, default: Any, **kwargs: Any) -> None:
+        self.default = default
+        self.alias = kwargs.pop('alias', None)
+        self.title = kwargs.pop('title', None)
+        self.description = kwargs.pop('description', None)
+        self.const = kwargs.pop('const', None)
+        self.gt = kwargs.pop('gt', None)
+        self.ge = kwargs.pop('ge', None)
+        self.lt = kwargs.pop('lt', None)
+        self.le = kwargs.pop('le', None)
+        self.multiple_of = kwargs.pop('multiple_of', None)
+        self.min_items = kwargs.pop('min_items', None)
+        self.max_items = kwargs.pop('max_items', None)
+        self.min_length = kwargs.pop('min_length', None)
+        self.max_length = kwargs.pop('max_length', None)
+        self.regex = kwargs.pop('regex', None)
+        self.extra = kwargs
+
+    def __repr__(self) -> str:
+        attrs = ((s, getattr(self, s)) for s in self.__slots__)
+        return 'FieldInfo({})'.format(', '.join(f'{a}: {v!r}' for a, v in attrs if v is not None))
+
+
+def Field(
+    default: Any,
+    *,
+    alias: str = None,
+    title: str = None,
+    description: str = None,
+    const: bool = None,
+    gt: float = None,
+    ge: float = None,
+    lt: float = None,
+    le: float = None,
+    multiple_of: float = None,
+    min_items: int = None,
+    max_items: int = None,
+    min_length: int = None,
+    max_length: int = None,
+    regex: str = None,
+    **extra: Any,
+) -> Any:
+    """
+    Used to provide extra information about a field, either for the model schema or complex valiation. Some arguments
+    apply only to number fields (``int``, ``float``, ``Decimal``) and some apply only to ``str``.
+
+    :param default: since this is replacing the field’s default, its first argument is used
+      to set the default, use ellipsis (``...``) to indicate the field is required
+    :param alias: the public name of the field
+    :param title: can be any string, used in the schema
+    :param description: can be any string, used in the schema
+    :param const: this field is required and *must* take it's default value
+    :param gt: only applies to numbers, requires the field to be "greater than". The schema
+      will have an ``exclusiveMinimum`` validation keyword
+    :param ge: only applies to numbers, requires the field to be "greater than or equal to". The
+      schema will have a ``minimum`` validation keyword
+    :param lt: only applies to numbers, requires the field to be "less than". The schema
+      will have an ``exclusiveMaximum`` validation keyword
+    :param le: only applies to numbers, requires the field to be "less than or equal to". The
+      schema will have a ``maximum`` validation keyword
+    :param multiple_of: only applies to numbers, requires the field to be "a multiple of". The
+      schema will have a ``multipleOf`` validation keyword
+    :param min_length: only applies to strings, requires the field to have a minimum length. The
+      schema will have a ``maximum`` validation keyword
+    :param max_length: only applies to strings, requires the field to have a maximum length. The
+      schema will have a ``maxLength`` validation keyword
+    :param regex: only applies to strings, requires the field match agains a regular expression
+      pattern string. The schema will have a ``pattern`` validation keyword
+    :param **extra: any additional keyword arguments will be added as is to the schema
+    """
+    return FieldInfo(
+        default,
+        alias=alias,
+        title=title,
+        description=description,
+        const=const,
+        gt=gt,
+        ge=ge,
+        lt=lt,
+        le=le,
+        multiple_of=multiple_of,
+        min_items=min_items,
+        max_items=max_items,
+        min_length=min_length,
+        max_length=max_length,
+        regex=regex,
+        **extra,
+    )
+
+
+def Schema(default: Any, **kwargs: Any) -> Any:
+    warnings.warn('`Schema` is deprecated, use `Field` instead', DeprecationWarning)
+    return Field(default, **kwargs)
+
+
 # used to be an enum but changed to int's for small performance improvement as less access overhead
 SHAPE_SINGLETON = 1
 SHAPE_LIST = 2
@@ -56,7 +175,7 @@
 SHAPE_FROZENSET = 8
 
 
-class Field:
+class ModelField:
     __slots__ = (
         'type_',
         'sub_fields',
@@ -70,7 +189,7 @@ class Field:
         'name',
         'alias',
         'has_alias',
-        'schema',
+        'field_info',
         'validate_always',
         'allow_none',
         'shape',
@@ -88,7 +207,7 @@ def __init__(
         default: Any = None,
         required: bool = True,
         alias: str = None,
-        schema: Optional['Schema'] = None,
+        field_info: Optional[FieldInfo] = None,
     ) -> None:
 
         self.name: str = name
@@ -99,12 +218,12 @@ def __init__(
         self.default: Any = default
         self.required: bool = required
         self.model_config = model_config
-        self.schema: Optional['Schema'] = schema
+        self.field_info: Optional[FieldInfo] = field_info
 
         self.allow_none: bool = False
         self.validate_always: bool = False
-        self.sub_fields: Optional[List[Field]] = None
-        self.key_field: Optional[Field] = None
+        self.sub_fields: Optional[List[ModelField]] = None
+        self.key_field: Optional[ModelField] = None
         self.validators: 'ValidatorsList' = []
         self.pre_validators: Optional['ValidatorsList'] = None
         self.post_validators: Optional['ValidatorsList'] = None
@@ -121,36 +240,36 @@ def infer(
         annotation: Any,
         class_validators: Optional[Dict[str, Validator]],
         config: Type['BaseConfig'],
-    ) -> 'Field':
-        schema_from_config = config.get_field_schema(name)
-        from .schema import Schema, get_annotation_from_schema  # noqa: F811
+    ) -> 'ModelField':
+        field_info_from_config = config.get_field_info(name)
+        from .schema import get_annotation_from_field_info
 
-        if isinstance(value, Schema):
-            schema = value
-            value = schema.default
+        if isinstance(value, FieldInfo):
+            field_info = value
+            value = field_info.default
         else:
-            schema = Schema(value, **schema_from_config)  # type: ignore
-        schema.alias = schema.alias or schema_from_config.get('alias')
+            field_info = FieldInfo(value, **field_info_from_config)
+        field_info.alias = field_info.alias or field_info_from_config.get('alias')
         required = value == Required
-        annotation = get_annotation_from_schema(annotation, schema)
+        annotation = get_annotation_from_field_info(annotation, field_info)
         return cls(
             name=name,
             type_=annotation,
-            alias=schema.alias,
+            alias=field_info.alias,
             class_validators=class_validators,
             default=None if required else value,
             required=required,
             model_config=config,
-            schema=schema,
+            field_info=field_info,
         )
 
     def set_config(self, config: Type['BaseConfig']) -> None:
         self.model_config = config
-        schema_from_config = config.get_field_schema(self.name)
+        schema_from_config = config.get_field_info(self.name)
         if schema_from_config:
-            self.schema = cast('Schema', self.schema)
-            self.schema.alias = self.schema.alias or schema_from_config.get('alias')
-            self.alias = cast(str, self.schema.alias)
+            self.field_info = cast(FieldInfo, self.field_info)
+            self.field_info.alias = self.field_info.alias or schema_from_config.get('alias')
+            self.alias = cast(str, self.field_info.alias)
 
     @property
     def alt_alias(self) -> bool:
@@ -266,7 +385,7 @@ def _type_analysis(self) -> None:  # noqa: C901 (ignore complexity)
         # type_ has been refined eg. as the type of a List and sub_fields needs to be populated
         self.sub_fields = [self._create_sub_type(self.type_, '_' + self.name)]
 
-    def _create_sub_type(self, type_: AnyType, name: str, *, for_keys: bool = False) -> 'Field':
+    def _create_sub_type(self, type_: AnyType, name: str, *, for_keys: bool = False) -> 'ModelField':
         return self.__class__(
             type_=type_,
             name=name,
@@ -288,7 +407,7 @@ def _populate_validators(self) -> None:
         # Add const validator
         self.pre_validators = []
         self.post_validators = []
-        if self.schema and self.schema.const:
+        if self.field_info and self.field_info.const:
             self.pre_validators = [make_generic_validator(constant_validator)]
 
         if class_validators_:
@@ -488,7 +607,7 @@ def is_complex(self) -> bool:
         )
 
     def __repr__(self) -> str:
-        return f'<Field({self})>'
+        return f'<ModelField({self})>'
 
     def __str__(self) -> str:
         parts = [self.name, 'type=' + display_as_type(self.type_)]
diff --git a/pydantic/main.py b/pydantic/main.py
--- a/pydantic/main.py
+++ b/pydantic/main.py
@@ -12,7 +12,7 @@
 from .class_validators import ROOT_KEY, ValidatorGroup, extract_root_validators, extract_validators, inherit_validators
 from .error_wrappers import ErrorWrapper, ValidationError
 from .errors import ConfigError, DictError, ExtraError, MissingError
-from .fields import SHAPE_MAPPING, Field
+from .fields import SHAPE_MAPPING, ModelField
 from .json import custom_pydantic_encoder, pydantic_encoder
 from .parse import Protocol, load_file, load_str_bytes
 from .schema import model_schema
@@ -73,16 +73,16 @@ class BaseConfig:
     json_encoders: Dict[AnyType, AnyCallable] = {}
 
     @classmethod
-    def get_field_schema(cls, name: str) -> Dict[str, str]:
-        field_config = cls.fields.get(name) or {}
-        if isinstance(field_config, str):
-            field_config = {'alias': field_config}
-        elif cls.alias_generator and 'alias' not in field_config:
+    def get_field_info(cls, name: str) -> Dict[str, str]:
+        field_info = cls.fields.get(name) or {}
+        if isinstance(field_info, str):
+            field_info = {'alias': field_info}
+        elif cls.alias_generator and 'alias' not in field_info:
             alias = cls.alias_generator(name)
             if not isinstance(alias, str):
                 raise TypeError(f'Config.alias_generator must return str, not {type(alias)}')
-            field_config['alias'] = alias
-        return field_config
+            field_info['alias'] = alias
+        return field_info
 
 
 def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType') -> 'ConfigType':
@@ -112,7 +112,7 @@ def is_valid_field(name: str) -> bool:
     return ROOT_KEY == name
 
 
-def validate_custom_root_type(fields: Dict[str, Field]) -> None:
+def validate_custom_root_type(fields: Dict[str, ModelField]) -> None:
     if len(fields) > 1:
         raise ValueError('__root__ cannot be mixed with other fields')
     if fields[ROOT_KEY].shape == SHAPE_MAPPING:
@@ -125,7 +125,7 @@ def validate_custom_root_type(fields: Dict[str, Field]) -> None:
 class MetaModel(ABCMeta):
     @no_type_check  # noqa C901
     def __new__(mcs, name, bases, namespace):
-        fields: Dict[str, Field] = {}
+        fields: Dict[str, ModelField] = {}
         config = BaseConfig
         validators: 'ValidatorListDict' = {}
         pre_root_validators, post_root_validators = [], []
@@ -164,7 +164,7 @@ def __new__(mcs, name, bases, namespace):
                     value = namespace.get(ann_name, ...)
                     if isinstance(value, untouched_types) and ann_type != PyObject:
                         continue
-                    fields[ann_name] = Field.infer(
+                    fields[ann_name] = ModelField.infer(
                         name=ann_name,
                         value=value,
                         annotation=ann_type,
@@ -180,7 +180,7 @@ def __new__(mcs, name, bases, namespace):
                     and var_name not in class_vars
                 ):
                     validate_field_name(bases, var_name)
-                    inferred = Field.infer(
+                    inferred = ModelField.infer(
                         name=var_name,
                         value=value,
                         annotation=annotations.get(var_name),
@@ -220,7 +220,7 @@ def __new__(mcs, name, bases, namespace):
 class BaseModel(metaclass=MetaModel):
     if TYPE_CHECKING:  # pragma: no cover
         # populated by the metaclass, defined here to help IDEs only
-        __fields__: Dict[str, Field] = {}
+        __fields__: Dict[str, ModelField] = {}
         __validators__: Dict[str, AnyCallable] = {}
         __pre_root_validators__: List[AnyCallable]
         __post_root_validators__: List[AnyCallable]
@@ -441,7 +441,7 @@ def copy(
         return m
 
     @property
-    def fields(self) -> Dict[str, Field]:
+    def fields(self) -> Dict[str, ModelField]:
         return self.__fields__
 
     @classmethod
diff --git a/pydantic/networks.py b/pydantic/networks.py
--- a/pydantic/networks.py
+++ b/pydantic/networks.py
@@ -15,7 +15,7 @@
 from .validators import constr_length_validator, str_validator
 
 if TYPE_CHECKING:  # pragma: no cover
-    from .fields import Field
+    from .fields import ModelField
     from .main import BaseConfig  # noqa: F401
     from .typing import AnyCallable
 
@@ -143,7 +143,7 @@ def __get_validators__(cls) -> 'CallableGenerator':
         yield cls.validate
 
     @classmethod
-    def validate(cls, value: Any, field: 'Field', config: 'BaseConfig') -> 'AnyUrl':
+    def validate(cls, value: Any, field: 'ModelField', config: 'BaseConfig') -> 'AnyUrl':
         if type(value) == cls:
             return value
         value = str_validator(value)
diff --git a/pydantic/schema.py b/pydantic/schema.py
--- a/pydantic/schema.py
+++ b/pydantic/schema.py
@@ -12,7 +12,7 @@
 from pydantic.color import Color
 
 from .class_validators import ROOT_KEY
-from .fields import SHAPE_LIST, SHAPE_MAPPING, SHAPE_SET, SHAPE_SINGLETON, SHAPE_TUPLE, Field
+from .fields import SHAPE_LIST, SHAPE_MAPPING, SHAPE_SET, SHAPE_SINGLETON, SHAPE_TUPLE, FieldInfo, ModelField
 from .json import pydantic_encoder
 from .networks import AnyUrl, EmailStr, IPvAnyAddress, IPvAnyInterface, IPvAnyNetwork, NameEmail
 from .types import (
@@ -43,121 +43,9 @@
 if TYPE_CHECKING:  # pragma: no cover
     from .main import BaseModel  # noqa: F401
 
-
-__all__ = [
-    'Schema',
-    'schema',
-    'model_schema',
-    'field_schema',
-    'get_model_name_map',
-    'get_flat_models_from_model',
-    'get_flat_models_from_field',
-    'get_flat_models_from_fields',
-    'get_flat_models_from_models',
-    'get_long_model_name',
-    'field_type_schema',
-    'model_process_schema',
-    'model_type_schema',
-    'field_singleton_sub_fields_schema',
-    'field_singleton_schema',
-    'get_annotation_from_schema',
-]
-
 default_prefix = '#/definitions/'
 
 
-class Schema:
-    """
-    Used to provide extra information about a field in a model schema. The parameters will be
-    converted to validations and will add annotations to the generated JSON Schema. Some arguments
-    apply only to number fields (``int``, ``float``, ``Decimal``) and some apply only to ``str``
-
-    :param default: since the Schema is replacing the field’s default, its first argument is used
-      to set the default, use ellipsis (``...``) to indicate the field is required
-    :param alias: the public name of the field
-    :param title: can be any string, used in the schema
-    :param description: can be any string, used in the schema
-    :param const: this field is required and *must* take it's default value
-    :param gt: only applies to numbers, requires the field to be "greater than". The schema
-      will have an ``exclusiveMinimum`` validation keyword
-    :param ge: only applies to numbers, requires the field to be "greater than or equal to". The
-      schema will have a ``minimum`` validation keyword
-    :param lt: only applies to numbers, requires the field to be "less than". The schema
-      will have an ``exclusiveMaximum`` validation keyword
-    :param le: only applies to numbers, requires the field to be "less than or equal to". The
-      schema will have a ``maximum`` validation keyword
-    :param multiple_of: only applies to numbers, requires the field to be "a multiple of". The
-      schema will have a ``multipleOf`` validation keyword
-    :param min_length: only applies to strings, requires the field to have a minimum length. The
-      schema will have a ``maximum`` validation keyword
-    :param max_length: only applies to strings, requires the field to have a maximum length. The
-      schema will have a ``maxLength`` validation keyword
-    :param regex: only applies to strings, requires the field match agains a regular expression
-      pattern string. The schema will have a ``pattern`` validation keyword
-    :param **extra: any additional keyword arguments will be added as is to the schema
-    """
-
-    __slots__ = (
-        'default',
-        'alias',
-        'title',
-        'description',
-        'const',
-        'gt',
-        'ge',
-        'lt',
-        'le',
-        'multiple_of',
-        'min_items',
-        'max_items',
-        'min_length',
-        'max_length',
-        'regex',
-        'extra',
-    )
-
-    def __init__(
-        self,
-        default: Any,
-        *,
-        alias: str = None,
-        title: str = None,
-        description: str = None,
-        const: bool = None,
-        gt: float = None,
-        ge: float = None,
-        lt: float = None,
-        le: float = None,
-        multiple_of: float = None,
-        min_items: int = None,
-        max_items: int = None,
-        min_length: int = None,
-        max_length: int = None,
-        regex: str = None,
-        **extra: Any,
-    ) -> None:
-        self.default = default
-        self.alias = alias
-        self.title = title
-        self.description = description
-        self.const = const
-        self.extra = extra
-        self.gt = gt
-        self.ge = ge
-        self.lt = lt
-        self.le = le
-        self.multiple_of = multiple_of
-        self.min_items = min_items
-        self.max_items = max_items
-        self.min_length = min_length
-        self.max_length = max_length
-        self.regex = regex
-
-    def __repr__(self) -> str:
-        attrs = ((s, getattr(self, s)) for s in self.__slots__)
-        return 'Schema({})'.format(', '.join(f'{a}: {v!r}' for a, v in attrs if v is not None))
-
-
 def schema(
     models: Sequence[Type['BaseModel']],
     *,
@@ -234,7 +122,7 @@ def model_schema(model: Type['BaseModel'], by_alias: bool = True, ref_prefix: Op
 
 
 def field_schema(
-    field: Field,
+    field: ModelField,
     *,
     by_alias: bool = True,
     model_name_map: Dict[Type['BaseModel'], str],
@@ -247,7 +135,7 @@ def field_schema(
     is a model and has sub-models, and those sub-models don't have overrides (as ``title``, ``default``, etc), they
     will be included in the definitions and referenced in the schema instead of included recursively.
 
-    :param field: a Pydantic ``Field``
+    :param field: a Pydantic ``ModelField``
     :param by_alias: use the defined alias (if any) in the returned schema
     :param model_name_map: used to generate the JSON Schema references to other models included in the definitions
     :param ref_prefix: the JSON Pointer prefix to use for references to other schemas, if None, the default of
@@ -257,16 +145,20 @@ def field_schema(
     """
     ref_prefix = ref_prefix or default_prefix
     schema_overrides = False
-    schema = cast('Schema', field.schema)
-    s = dict(title=schema.title or field.alias.title().replace('_', ' '))
-    if schema.title:
+    field_info = cast(FieldInfo, field.field_info)
+    s = dict(title=field_info.title or field.alias.title().replace('_', ' '))
+    if field_info.title:
         schema_overrides = True
 
-    if schema.description:
-        s['description'] = schema.description
+    if field_info.description:
+        s['description'] = field_info.description
         schema_overrides = True
 
-    if not field.required and not (field.schema is not None and field.schema.const) and field.default is not None:
+    if (
+        not field.required
+        and not (field.field_info is not None and field.field_info.const)
+        and field.default is not None
+    ):
         s['default'] = encode_default(field.default)
         schema_overrides = True
 
@@ -307,27 +199,27 @@ def field_schema(
 )
 
 
-def get_field_schema_validations(field: Field) -> Dict[str, Any]:
+def get_field_schema_validations(field: ModelField) -> Dict[str, Any]:
     """
     Get the JSON Schema validation keywords for a ``field`` with an annotation of
-    a Pydantic ``Schema`` with validation arguments.
+    a Pydantic ``FieldInfo`` with validation arguments.
     """
     f_schema: Dict[str, Any] = {}
     if lenient_issubclass(field.type_, (str, bytes)):
         for attr_name, t, keyword in _str_types_attrs:
-            attr = getattr(field.schema, attr_name, None)
+            attr = getattr(field.field_info, attr_name, None)
             if isinstance(attr, t):
                 f_schema[keyword] = attr
     if lenient_issubclass(field.type_, numeric_types) and not issubclass(field.type_, bool):
         for attr_name, t, keyword in _numeric_types_attrs:
-            attr = getattr(field.schema, attr_name, None)
+            attr = getattr(field.field_info, attr_name, None)
             if isinstance(attr, t):
                 f_schema[keyword] = attr
-    if field.schema is not None and field.schema.const:
+    if field.field_info is not None and field.field_info.const:
         f_schema['const'] = field.default
-    schema = cast('Schema', field.schema)
-    if schema.extra:
-        f_schema.update(schema.extra)
+    field_info = cast(FieldInfo, field.field_info)
+    if field_info.extra:
+        f_schema.update(field_info.extra)
     return f_schema
 
 
@@ -376,20 +268,20 @@ def get_flat_models_from_model(
     flat_models: Set[Type['BaseModel']] = set()
     flat_models.add(model)
     known_models |= flat_models
-    fields = cast(Sequence[Field], model.__fields__.values())
+    fields = cast(Sequence[ModelField], model.__fields__.values())
     flat_models |= get_flat_models_from_fields(fields, known_models=known_models)
     return flat_models
 
 
-def get_flat_models_from_field(field: Field, known_models: Set[Type['BaseModel']]) -> Set[Type['BaseModel']]:
+def get_flat_models_from_field(field: ModelField, known_models: Set[Type['BaseModel']]) -> Set[Type['BaseModel']]:
     """
-    Take a single Pydantic ``Field`` (from a model) that could have been declared as a sublcass of BaseModel
+    Take a single Pydantic ``ModelField`` (from a model) that could have been declared as a sublcass of BaseModel
     (so, it could be a submodel), and generate a set with its model and all the sub-models in the tree.
     I.e. if you pass a field that was declared to be of type ``Foo`` (subclass of BaseModel) as ``field``, and that
     model ``Foo`` has a field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of
     type ``Baz`` (also subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``.
 
-    :param field: a Pydantic ``Field``
+    :param field: a Pydantic ``ModelField``
     :param known_models: used to solve circular references
     :return: a set with the model used in the declaration for this field, if any, and all its sub-models
     """
@@ -408,16 +300,16 @@ def get_flat_models_from_field(field: Field, known_models: Set[Type['BaseModel']
 
 
 def get_flat_models_from_fields(
-    fields: Sequence[Field], known_models: Set[Type['BaseModel']]
+    fields: Sequence[ModelField], known_models: Set[Type['BaseModel']]
 ) -> Set[Type['BaseModel']]:
     """
-    Take a list of Pydantic  ``Field``s (from a model) that could have been declared as sublcasses of ``BaseModel``
+    Take a list of Pydantic  ``ModelField``s (from a model) that could have been declared as sublcasses of ``BaseModel``
     (so, any of them could be a submodel), and generate a set with their models and all the sub-models in the tree.
     I.e. if you pass a the fields of a model ``Foo`` (subclass of ``BaseModel``) as ``fields``, and on of them has a
     field of type ``Bar`` (also subclass of ``BaseModel``) and that model ``Bar`` has a field of type ``Baz`` (also
     subclass of ``BaseModel``), the return value will be ``set([Foo, Bar, Baz])``.
 
-    :param fields: a list of Pydantic ``Field``s
+    :param fields: a list of Pydantic ``ModelField``s
     :param known_models: used to solve circular references
     :return: a set with any model declared in the fields, and all their sub-models
     """
@@ -444,7 +336,7 @@ def get_long_model_name(model: Type['BaseModel']) -> str:
 
 
 def field_type_schema(
-    field: Field,
+    field: ModelField,
     *,
     by_alias: bool,
     model_name_map: Dict[Type['BaseModel'], str],
@@ -477,7 +369,7 @@ def field_type_schema(
         return {'type': 'array', 'uniqueItems': True, 'items': f_schema}, definitions, nested_models
     elif field.shape == SHAPE_MAPPING:
         dict_schema: Dict[str, Any] = {'type': 'object'}
-        key_field = cast(Field, field.key_field)
+        key_field = cast(ModelField, field.key_field)
         regex = getattr(key_field.type_, 'regex', None)
         f_schema, f_definitions, f_nested_models = field_singleton_schema(
             field, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, known_models=known_models
@@ -494,7 +386,7 @@ def field_type_schema(
         return dict_schema, definitions, nested_models
     elif field.shape == SHAPE_TUPLE:
         sub_schema = []
-        sub_fields = cast(List[Field], field.sub_fields)
+        sub_fields = cast(List[ModelField], field.sub_fields)
         for sf in sub_fields:
             sf_schema, sf_definitions, sf_nested_models = field_type_schema(
                 sf, by_alias=by_alias, model_name_map=model_name_map, ref_prefix=ref_prefix, known_models=known_models
@@ -600,7 +492,7 @@ def model_type_schema(
 
 
 def field_singleton_sub_fields_schema(
-    sub_fields: Sequence[Field],
+    sub_fields: Sequence[ModelField],
     *,
     by_alias: bool,
     model_name_map: Dict[Type['BaseModel'], str],
@@ -611,7 +503,7 @@ def field_singleton_sub_fields_schema(
     """
     This function is indirectly used by ``field_schema()``, you probably should be using that function.
 
-    Take a list of Pydantic ``Field`` from the declaration of a type with parameters, and generate their
+    Take a list of Pydantic ``ModelField`` from the declaration of a type with parameters, and generate their
     schema. I.e., fields used as "type parameters", like ``str`` and ``int`` in ``Tuple[str, int]``.
     """
     ref_prefix = ref_prefix or default_prefix
@@ -706,7 +598,7 @@ def field_singleton_sub_fields_schema(
 
 
 def field_singleton_schema(  # noqa: C901 (ignore complexity)
-    field: Field,
+    field: ModelField,
     *,
     by_alias: bool,
     model_name_map: Dict[Type['BaseModel'], str],
@@ -717,7 +609,7 @@ def field_singleton_schema(  # noqa: C901 (ignore complexity)
     """
     This function is indirectly used by ``field_schema()``, you should probably be using that function.
 
-    Take a single Pydantic ``Field``, and return its schema and any additional definitions from sub-models.
+    Take a single Pydantic ``ModelField``, and return its schema and any additional definitions from sub-models.
     """
     from .main import BaseModel  # noqa: F811
 
@@ -741,7 +633,7 @@ def field_singleton_schema(  # noqa: C901 (ignore complexity)
     if is_callable_type(field.type_):
         raise SkipField(f'Callable {field.name} was excluded from schema since JSON schema has no equivalent type.')
     f_schema: Dict[str, Any] = {}
-    if field.schema is not None and field.schema.const:
+    if field.field_info is not None and field.field_info.const:
         f_schema['const'] = field.default
     field_type = field.type_
     if is_new_type(field_type):
@@ -811,12 +703,12 @@ def encode_default(dft: Any) -> Any:
 _map_types_constraint: Dict[Any, Callable[..., type]] = {int: conint, float: confloat, Decimal: condecimal}
 
 
-def get_annotation_from_schema(annotation: Any, schema: Schema) -> Type[Any]:
+def get_annotation_from_field_info(annotation: Any, field_info: FieldInfo) -> Type[Any]:
     """
-    Get an annotation with validation implemented for numbers and strings based on the schema.
+    Get an annotation with validation implemented for numbers and strings based on the field_info.
 
     :param annotation: an annotation from a field specification, as ``str``, ``ConstrainedStr``
-    :param schema: an instance of Schema, possibly with declarations for validations and JSON Schema
+    :param field_info: an instance of FieldInfo, possibly with declarations for validations and JSON Schema
     :return: the same ``annotation`` if unmodified or a new annotation with validation in place
     """
     if isinstance(annotation, type):
@@ -838,7 +730,7 @@ def get_annotation_from_schema(annotation: Any, schema: Schema) -> Type[Any]:
         if attrs:
             kwargs = {
                 attr_name: attr
-                for attr_name, attr in ((attr_name, getattr(schema, attr_name)) for attr_name in attrs)
+                for attr_name, attr in ((attr_name, getattr(field_info, attr_name)) for attr_name in attrs)
                 if attr is not None
             }
             if kwargs:
diff --git a/pydantic/types.py b/pydantic/types.py
--- a/pydantic/types.py
+++ b/pydantic/types.py
@@ -74,7 +74,6 @@
 OptionalIntFloatDecimal = Union[OptionalIntFloat, Decimal]
 
 if TYPE_CHECKING:  # pragma: no cover
-    from .fields import Field
     from .dataclasses import DataclassType  # noqa: F401
     from .main import BaseModel, BaseConfig  # noqa: F401
     from .typing import CallableGenerator
@@ -118,7 +117,7 @@ def __get_validators__(cls) -> 'CallableGenerator':
         yield cls.list_length_validator
 
     @classmethod
-    def list_length_validator(cls, v: 'List[T]', field: 'Field', config: 'BaseConfig') -> 'List[T]':
+    def list_length_validator(cls, v: 'List[T]') -> 'List[T]':
         v_len = len(v)
 
         if cls.min_items is not None and v_len < cls.min_items:
diff --git a/pydantic/typing.py b/pydantic/typing.py
--- a/pydantic/typing.py
+++ b/pydantic/typing.py
@@ -53,7 +53,7 @@ def evaluate_forwardref(type_, globalns, localns):  # type: ignore
 
 
 if TYPE_CHECKING:  # pragma: no cover
-    from .fields import Field
+    from .fields import ModelField
 
     TupleGenerator = Generator[Tuple[str, Any], None, None]
     DictStrAny = Dict[str, Any]
@@ -183,9 +183,9 @@ def is_classvar(ann_type: AnyType) -> bool:
     return _check_classvar(ann_type) or _check_classvar(getattr(ann_type, '__origin__', None))
 
 
-def update_field_forward_refs(field: 'Field', globalns: Any, localns: Any) -> None:
+def update_field_forward_refs(field: 'ModelField', globalns: Any, localns: Any) -> None:
     """
-    Try to update ForwardRefs on fields based on this Field, globalns and localns.
+    Try to update ForwardRefs on fields based on this ModelField, globalns and localns.
     """
     if type(field.type_) == ForwardRef:
         field.type_ = evaluate_forwardref(field.type_, globalns, localns or None)
diff --git a/pydantic/validators.py b/pydantic/validators.py
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -30,7 +30,7 @@
 from .utils import almost_equal_floats, lenient_issubclass, sequence_like
 
 if TYPE_CHECKING:  # pragma: no cover
-    from .fields import Field
+    from .fields import ModelField
     from .main import BaseConfig
     from .types import ConstrainedDecimal, ConstrainedFloat, ConstrainedInt
 
@@ -127,7 +127,7 @@ def strict_float_validator(v: Any) -> float:
     raise errors.FloatError()
 
 
-def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number':
+def number_multiple_validator(v: 'Number', field: 'ModelField') -> 'Number':
     field_type: ConstrainedNumber = field.type_  # type: ignore
     if field_type.multiple_of is not None:
         mod = float(v) / float(field_type.multiple_of) % 1
@@ -136,7 +136,7 @@ def number_multiple_validator(v: 'Number', field: 'Field') -> 'Number':
     return v
 
 
-def number_size_validator(v: 'Number', field: 'Field') -> 'Number':
+def number_size_validator(v: 'Number', field: 'ModelField') -> 'Number':
     field_type: ConstrainedNumber = field.type_  # type: ignore
     if field_type.gt is not None and not v > field_type.gt:
         raise errors.NumberNotGtError(limit_value=field_type.gt)
@@ -151,7 +151,7 @@ def number_size_validator(v: 'Number', field: 'Field') -> 'Number':
     return v
 
 
-def constant_validator(v: 'Any', field: 'Field') -> 'Any':
+def constant_validator(v: 'Any', field: 'ModelField') -> 'Any':
     """Validate ``const`` fields.
 
     The value provided for a ``const`` field must be equal to the default value
@@ -238,7 +238,7 @@ def frozenset_validator(v: Any) -> FrozenSet[Any]:
         raise errors.FrozenSetError()
 
 
-def enum_validator(v: Any, field: 'Field', config: 'BaseConfig') -> Enum:
+def enum_validator(v: Any, field: 'ModelField', config: 'BaseConfig') -> Enum:
     try:
         enum_v = field.type_(v)
     except ValueError:
@@ -247,7 +247,7 @@ def enum_validator(v: Any, field: 'Field', config: 'BaseConfig') -> Enum:
     return enum_v.value if config.use_enum_values else enum_v
 
 
-def uuid_validator(v: Any, field: 'Field') -> UUID:
+def uuid_validator(v: Any, field: 'ModelField') -> UUID:
     try:
         if isinstance(v, str):
             v = UUID(v)
@@ -401,7 +401,7 @@ def literal_validator(v: Any) -> Any:
     return literal_validator
 
 
-def constr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes':
+def constr_length_validator(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes':
     v_len = len(v)
 
     min_length = field.type_.min_length or config.min_anystr_length  # type: ignore
@@ -415,7 +415,7 @@ def constr_length_validator(v: 'StrBytes', field: 'Field', config: 'BaseConfig')
     return v
 
 
-def constr_strip_whitespace(v: 'StrBytes', field: 'Field', config: 'BaseConfig') -> 'StrBytes':
+def constr_strip_whitespace(v: 'StrBytes', field: 'ModelField', config: 'BaseConfig') -> 'StrBytes':
     strip_whitespace = field.type_.strip_whitespace or config.anystr_strip_whitespace  # type: ignore
     if strip_whitespace:
         v = v.strip()


Test patch:
diff --git a/tests/mypy/success.py b/tests/mypy/success.py
--- a/tests/mypy/success.py
+++ b/tests/mypy/success.py
@@ -10,6 +10,7 @@
 
 from pydantic import BaseModel, NoneStr
 from pydantic.dataclasses import dataclass
+from pydantic.fields import Field
 from pydantic.generics import GenericModel
 
 
@@ -103,3 +104,8 @@ class WrapperModel(GenericModel, Generic[T]):
     model_instance = WrapperModel[Model](payload=m)
     model_instance.payload.list_of_ints.append(4)
     assert model_instance.payload.list_of_ints == [1, 2, 3, 4]
+
+
+class WithField(BaseModel):
+    age: int
+    first_name: str = Field('John', const=True)
diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py
--- a/tests/test_edge_cases.py
+++ b/tests/test_edge_cases.py
@@ -18,6 +18,7 @@
     validate_model,
     validator,
 )
+from pydantic.fields import Schema
 
 
 def test_str_bytes():
@@ -26,7 +27,7 @@ class Model(BaseModel):
 
     m = Model(v='s')
     assert m.v == 's'
-    assert '<Field(v type=typing.Union[str, bytes] required)>' == repr(m.fields['v'])
+    assert '<ModelField(v type=typing.Union[str, bytes] required)>' == repr(m.fields['v'])
 
     m = Model(v=b'b')
     assert m.v == 'b'
@@ -323,7 +324,7 @@ class Config:
             fields = {'a': '_a'}
 
     assert Model(_a='different').a == 'different'
-    assert repr(Model.__fields__['a']) == "<Field(a type=str default='foobar' alias=_a)>"
+    assert repr(Model.__fields__['a']) == "<ModelField(a type=str default='foobar' alias=_a)>"
 
 
 def test_alias_error():
@@ -661,8 +662,8 @@ class Model(BaseModel):
 
         class Config(BaseConfig):
             @classmethod
-            def get_field_schema(cls, name):
-                field_config = super().get_field_schema(name) or {}
+            def get_field_info(cls, name):
+                field_config = super().get_field_info(name) or {}
                 if 'alias' not in field_config:
                     field_config['alias'] = re.sub(r'(?:^|_)([a-z])', lambda m: m.group(1).upper(), name)
                 return field_config
@@ -673,12 +674,12 @@ def get_field_schema(cls, name):
     assert v == {'one_thing': 123, 'another_thing': 321}
 
 
-def test_get_field_schema_inherit():
+def test_get_field_info_inherit():
     class ModelOne(BaseModel):
         class Config(BaseConfig):
             @classmethod
-            def get_field_schema(cls, name):
-                field_config = super().get_field_schema(name) or {}
+            def get_field_info(cls, name):
+                field_config = super().get_field_info(name) or {}
                 if 'alias' not in field_config:
                     field_config['alias'] = re.sub(r'_([a-z])', lambda m: m.group(1).upper(), name)
                 return field_config
@@ -1006,3 +1007,11 @@ def check_a(cls, v):
     assert Model().a is None
     assert Model(a=None).a is None
     assert Model(a=12).a == 12
+
+
+def test_scheme_deprecated():
+
+    with pytest.warns(DeprecationWarning, match='`Schema` is deprecated, use `Field` instead'):
+
+        class Model(BaseModel):
+            foo: int = Schema(4)
diff --git a/tests/test_forward_ref.py b/tests/test_forward_ref.py
--- a/tests/test_forward_ref.py
+++ b/tests/test_forward_ref.py
@@ -257,7 +257,7 @@ def test_self_reference_json_schema(create_module):
     module = create_module(
         """
 from typing import List
-from pydantic import BaseModel, Schema
+from pydantic import BaseModel
 
 class Account(BaseModel):
   name: str
@@ -294,7 +294,7 @@ def test_self_reference_json_schema_with_future_annotations(create_module):
         """
 from __future__ import annotations
 from typing import List
-from pydantic import BaseModel, Schema
+from pydantic import BaseModel
 
 class Account(BaseModel):
   name: str
@@ -329,7 +329,7 @@ def test_circular_reference_json_schema(create_module):
     module = create_module(
         """
 from typing import List
-from pydantic import BaseModel, Schema
+from pydantic import BaseModel
 
 class Owner(BaseModel):
   account: 'Account'
@@ -378,7 +378,7 @@ def test_circular_reference_json_schema_with_future_annotations(create_module):
         """
 from __future__ import annotations
 from typing import List
-from pydantic import BaseModel, Schema
+from pydantic import BaseModel
 
 class Owner(BaseModel):
   account: Account
diff --git a/tests/test_main.py b/tests/test_main.py
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -3,7 +3,7 @@
 
 import pytest
 
-from pydantic import BaseModel, Extra, NoneBytes, NoneStr, Required, Schema, ValidationError, constr
+from pydantic import BaseModel, Extra, Field, NoneBytes, NoneStr, Required, ValidationError, constr
 
 
 def test_success():
@@ -40,7 +40,7 @@ def test_ultra_simple_failed():
 def test_ultra_simple_repr():
     m = UltraSimpleModel(a=10.2)
     assert repr(m) == '<UltraSimpleModel a=10.2 b=10>'
-    assert repr(m.fields['a']) == '<Field(a type=float required)>'
+    assert repr(m.fields['a']) == '<ModelField(a type=float required)>'
     assert dict(m) == {'a': 10.2, 'b': 10}
     assert m.dict() == {'a': 10.2, 'b': 10}
     assert m.json() == '{"a": 10.2, "b": 10}'
@@ -366,7 +366,7 @@ class Config:
 
 def test_const_validates():
     class Model(BaseModel):
-        a: int = Schema(3, const=True)
+        a: int = Field(3, const=True)
 
     m = Model(a=3)
     assert m.a == 3
@@ -374,7 +374,7 @@ class Model(BaseModel):
 
 def test_const_uses_default():
     class Model(BaseModel):
-        a: int = Schema(3, const=True)
+        a: int = Field(3, const=True)
 
     m = Model()
     assert m.a == 3
@@ -382,7 +382,7 @@ class Model(BaseModel):
 
 def test_const_with_wrong_value():
     class Model(BaseModel):
-        a: int = Schema(3, const=True)
+        a: int = Field(3, const=True)
 
     with pytest.raises(ValidationError) as exc_info:
         Model(a=4)
@@ -402,8 +402,8 @@ class SubModel(BaseModel):
         b: int
 
     class Model(BaseModel):
-        a: List[SubModel] = Schema([SubModel(b=1), SubModel(b=2), SubModel(b=3)], const=True)
-        b: List[SubModel] = Schema([{'b': 4}, {'b': 5}, {'b': 6}], const=True)
+        a: List[SubModel] = Field([SubModel(b=1), SubModel(b=2), SubModel(b=3)], const=True)
+        b: List[SubModel] = Field([{'b': 4}, {'b': 5}, {'b': 6}], const=True)
 
     m = Model()
     assert m.a == [SubModel(b=1), SubModel(b=2), SubModel(b=3)]
@@ -441,8 +441,8 @@ class SubModel(BaseModel):
         b: int
 
     class Model(BaseModel):
-        a: List[SubModel] = Schema([SubModel(b=1), SubModel(b=2), SubModel(b=3)], const=True)
-        b: List[SubModel] = Schema([{'b': 4}, {'b': 5}, {'b': 6}], const=True)
+        a: List[SubModel] = Field([SubModel(b=1), SubModel(b=2), SubModel(b=3)], const=True)
+        b: List[SubModel] = Field([{'b': 4}, {'b': 5}, {'b': 6}], const=True)
 
     with pytest.raises(ValidationError) as exc_info:
         Model(a=[{'b': 3}, {'b': 1}, {'b': 2}], b=[{'b': 6}, {'b': 5}])
@@ -492,8 +492,8 @@ class SubForm(BaseModel):
         field: int
 
     class Form(BaseModel):
-        field1: SubForm = Schema({'field': 2}, const=True)
-        field2: List[SubForm] = Schema([{'field': 2}], const=True)
+        field1: SubForm = Field({'field': 2}, const=True)
+        field2: List[SubForm] = Field([{'field': 2}], const=True)
 
     with pytest.raises(ValidationError) as exc_info:
         # Fails
@@ -780,8 +780,8 @@ class ModelB(BaseModel):
 
 def test_dict_skip_defaults_populated_by_alias():
     class MyModel(BaseModel):
-        a: str = Schema('default', alias='alias_a')
-        b: str = Schema('default', alias='alias_b')
+        a: str = Field('default', alias='alias_a')
+        b: str = Field('default', alias='alias_b')
 
         class Config:
             allow_population_by_alias = True
@@ -794,8 +794,8 @@ class Config:
 
 def test_dict_skip_defaults_populated_by_alias_with_extra():
     class MyModel(BaseModel):
-        a: str = Schema('default', alias='alias_a')
-        b: str = Schema('default', alias='alias_b')
+        a: str = Field('default', alias='alias_a')
+        b: str = Field('default', alias='alias_b')
 
         class Config:
             extra = 'allow'
@@ -821,7 +821,7 @@ class MyModel(BaseModel):
 
 def test_dict_with_extra_keys():
     class MyModel(BaseModel):
-        a: str = Schema(None, alias='alias_a')
+        a: str = Field(None, alias='alias_a')
 
         class Config:
             extra = Extra.allow
diff --git a/tests/test_parse.py b/tests/test_parse.py
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -3,7 +3,7 @@
 
 import pytest
 
-from pydantic import BaseModel, Protocol, Schema, ValidationError
+from pydantic import BaseModel, Field, Protocol, ValidationError
 
 
 class Model(BaseModel):
@@ -120,11 +120,11 @@ def test_file_pickle_no_ext(tmpdir):
 
 def test_const_differentiates_union():
     class SubModelA(BaseModel):
-        key: str = Schema('A', const=True)
+        key: str = Field('A', const=True)
         foo: int
 
     class SubModelB(BaseModel):
-        key: str = Schema('B', const=True)
+        key: str = Field('B', const=True)
         foo: int
 
     class Model(BaseModel):
diff --git a/tests/test_schema.py b/tests/test_schema.py
--- a/tests/test_schema.py
+++ b/tests/test_schema.py
@@ -11,7 +11,7 @@
 
 import pytest
 
-from pydantic import BaseModel, Extra, Schema, ValidationError, validator
+from pydantic import BaseModel, Extra, Field, ValidationError, validator
 from pydantic.color import Color
 from pydantic.networks import AnyUrl, EmailStr, IPvAnyAddress, IPvAnyInterface, IPvAnyNetwork, NameEmail, stricturl
 from pydantic.schema import (
@@ -142,8 +142,8 @@ class Bar(BaseModel):
 
 def test_schema_class():
     class Model(BaseModel):
-        foo: int = Schema(4, title='Foo is Great')
-        bar: str = Schema(..., description='this description of bar')
+        foo: int = Field(4, title='Foo is Great')
+        bar: str = Field(..., description='this description of bar')
 
     with pytest.raises(ValidationError):
         Model()
@@ -163,14 +163,14 @@ class Model(BaseModel):
 
 
 def test_schema_repr():
-    s = Schema(4, title='Foo is Great')
-    assert repr(s) == "Schema(default: 4, title: 'Foo is Great', extra: {})"
-    assert str(s) == "Schema(default: 4, title: 'Foo is Great', extra: {})"
+    s = Field(4, title='Foo is Great')
+    assert repr(s) == "FieldInfo(default: 4, title: 'Foo is Great', extra: {})"
+    assert str(s) == "FieldInfo(default: 4, title: 'Foo is Great', extra: {})"
 
 
 def test_schema_class_by_alias():
     class Model(BaseModel):
-        foo: int = Schema(4, alias='foofoo')
+        foo: int = Field(4, alias='foofoo')
 
     assert list(Model.schema()['properties'].keys()) == ['foofoo']
     assert list(Model.schema(by_alias=False)['properties'].keys()) == ['foo']
@@ -187,7 +187,7 @@ class SpamEnum(str, Enum):
     class Model(BaseModel):
         foo: FooEnum
         bar: BarEnum
-        spam: SpamEnum = Schema(None)
+        spam: SpamEnum = Field(None)
 
     assert Model.schema() == {
         'type': 'object',
@@ -287,7 +287,7 @@ class Model(BaseModel):
 
 def test_const_str():
     class Model(BaseModel):
-        a: str = Schema('some string', const=True)
+        a: str = Field('some string', const=True)
 
     assert Model.schema() == {
         'title': 'Model',
@@ -298,7 +298,7 @@ class Model(BaseModel):
 
 def test_const_false():
     class Model(BaseModel):
-        a: str = Schema('some string', const=False)
+        a: str = Field('some string', const=False)
 
     assert Model.schema() == {
         'title': 'Model',
@@ -1115,7 +1115,7 @@ class UserModel(BaseModel):
 )
 def test_constraints_schema(kwargs, type_, expected_extra):
     class Foo(BaseModel):
-        a: type_ = Schema('foo', title='A title', description='A description', **kwargs)
+        a: type_ = Field('foo', title='A title', description='A description', **kwargs)
 
     expected_schema = {
         'title': 'Foo',
@@ -1142,7 +1142,7 @@ class Foo(BaseModel):
 )
 def test_not_constraints_schema(kwargs, type_, expected):
     class Foo(BaseModel):
-        a: type_ = Schema('foo', title='A title', description='A description', **kwargs)
+        a: type_ = Field('foo', title='A title', description='A description', **kwargs)
 
     base_schema = {
         'title': 'Foo',
@@ -1190,7 +1190,7 @@ class Foo(BaseModel):
 )
 def test_constraints_schema_validation(kwargs, type_, value):
     class Foo(BaseModel):
-        a: type_ = Schema('foo', title='A title', description='A description', **kwargs)
+        a: type_ = Field('foo', title='A title', description='A description', **kwargs)
 
     assert Foo(a=value)
 
@@ -1217,7 +1217,7 @@ class Foo(BaseModel):
 )
 def test_constraints_schema_validation_raises(kwargs, type_, value):
     class Foo(BaseModel):
-        a: type_ = Schema('foo', title='A title', description='A description', **kwargs)
+        a: type_ = Field('foo', title='A title', description='A description', **kwargs)
 
     with pytest.raises(ValidationError):
         Foo(a=value)
@@ -1225,7 +1225,7 @@ class Foo(BaseModel):
 
 def test_schema_kwargs():
     class Foo(BaseModel):
-        a: str = Schema('foo', examples=['bar'])
+        a: str = Field('foo', examples=['bar'])
 
     assert Foo.schema() == {
         'title': 'Foo',
diff --git a/tests/test_settings.py b/tests/test_settings.py
--- a/tests/test_settings.py
+++ b/tests/test_settings.py
@@ -3,7 +3,7 @@
 
 import pytest
 
-from pydantic import BaseModel, BaseSettings, NoneStr, Schema, ValidationError, dataclasses
+from pydantic import BaseModel, BaseSettings, Field, NoneStr, ValidationError, dataclasses
 from pydantic.env_settings import SettingsError
 
 
@@ -137,7 +137,7 @@ class Config:
 
 def test_case_sensitive(monkeypatch):
     class Settings(BaseSettings):
-        foo: str = Schema(..., alias='foo')
+        foo: str = Field(..., alias='foo')
 
         class Config:
             case_sensitive = True