text: import builtins
  import dataclasses
  from typing import (
      Any,
      Awaitable,
      Callable,
      Dict,
      List,
      Mapping,
      Optional,
      Type,
      TypeVar,
      Union,
  )
  
  from strawberry.annotation import StrawberryAnnotation
  from strawberry.arguments import UNSET
  from strawberry.type import StrawberryType
  from strawberry.types.info import Info
  
  from .arguments import StrawberryArgument
  from .permission import BasePermission
  from .types.fields.resolver import StrawberryResolver
  from .types.types import FederationFieldParams, TypeDefinition
  from .utils.str_converters import to_camel_case
  
  
  _RESOLVER_TYPE = Union[StrawberryResolver, Callable]
  
  
  class StrawberryField(dataclasses.Field):
      def __init__(
          self,
          python_name: Optional[str] = None,
          graphql_name: Optional[str] = None,
          type_annotation: Optional[StrawberryAnnotation] = None,
          origin: Optional[Union[Type, Callable]] = None,
          is_subscription: bool = False,
          federation: FederationFieldParams = None,
          description: Optional[str] = None,
          base_resolver: Optional[StrawberryResolver] = None,
          permission_classes: List[Type[BasePermission]] = (),  # type: ignore
          default: object = UNSET,
          default_factory: Union[Callable[[], Any], object] = UNSET,
          deprecation_reason: Optional[str] = None,
      ):
          federation = federation or FederationFieldParams()
  
          # basic fields are fields with no provided resolver
          is_basic_field = not base_resolver
  
          super().__init__(  # type: ignore
              default=(default if default is not UNSET else dataclasses.MISSING),
              default_factory=(
                  # mypy is not able to understand that default factory
                  # is a callable so we do a type ignore
                  default_factory  # type: ignore
                  if default_factory is not UNSET
                  else dataclasses.MISSING
              ),
              init=is_basic_field,
              repr=is_basic_field,
              compare=is_basic_field,
              hash=None,
              metadata={},
          )
  
          self._graphql_name = graphql_name
          if python_name is not None:
              self.python_name = python_name
  
          self.type_annotation = type_annotation
  
          self.description: Optional[str] = description
          self.origin: Optional[Union[Type, Callable]] = origin
  
          self._base_resolver: Optional[StrawberryResolver] = None
          if base_resolver is not None:
              self.base_resolver = base_resolver
  
          # Note: StrawberryField.default is the same as
          # StrawberryField.default_value except that `.default` uses
          # `dataclasses.MISSING` to represent an "undefined" value and
          # `.default_value` uses `UNSET`
          self.default_value = default
  
          self.is_subscription = is_subscription
  
          self.federation: FederationFieldParams = federation
          self.permission_classes: List[Type[BasePermission]] = list(permission_classes)
  
          self.deprecation_reason = deprecation_reason
  
      def __call__(self, resolver: _RESOLVER_TYPE) -> "StrawberryField":
          """Add a resolver to the field"""
  
          # Allow for StrawberryResolvers or bare functions to be provided
          if not isinstance(resolver, StrawberryResolver):
              resolver = StrawberryResolver(resolver)
  
          self.base_resolver = resolver
  
          return self
  
      @property
      def arguments(self) -> List[StrawberryArgument]:
          if not self.base_resolver:
              return []
  
          return self.base_resolver.arguments
  
      @property
      def graphql_name(self) -> Optional[str]:
          if self._graphql_name:
              return self._graphql_name
          if self.python_name:
              return to_camel_case(self.python_name)
          if self.base_resolver:
              return to_camel_case(self.base_resolver.name)
          return None
  
      @property
      def python_name(self) -> str:
          return self.name
  
      @python_name.setter
      def python_name(self, name: str) -> None:
          self.name = name
  
      @property
      def base_resolver(self) -> Optional[StrawberryResolver]:
          return self._base_resolver
  
      @base_resolver.setter
      def base_resolver(self, resolver: StrawberryResolver) -> None:
          self._base_resolver = resolver
          self.origin = resolver.wrapped_func
  
          # Don't add field to __init__, __repr__ and __eq__ once it has a resolver
          self.init = False
          self.compare = False
          self.repr = False
  
          # TODO: See test_resolvers.test_raises_error_when_argument_annotation_missing
          #       (https://github.com/strawberry-graphql/strawberry/blob/8e102d3/tests/types/test_resolvers.py#L89-L98)
          #
          #       Currently we expect the exception to be thrown when the StrawberryField
          #       is constructed, but this only happens if we explicitly retrieve the
          #       arguments.
          #
          #       If we want to change when the exception is thrown, this line can be
          #       removed.
          _ = resolver.arguments
  
      @property  # type: ignore
      def type(self) -> Union[StrawberryType, type]:  # type: ignore
          # We are catching NameError because dataclasses tries to fetch the type
          # of the field from the class before the class is fully defined.
          # This triggers a NameError error when using forward references because
          # our `type` property tries to find the field type from the global namespace
          # but it is not yet defined.
          try:
              if self.base_resolver is not None:
                  # Handle unannotated functions (such as lambdas)
                  if self.base_resolver.type is not None:
                      return self.base_resolver.type
  
              assert self.type_annotation is not None
  
              if not isinstance(self.type_annotation, StrawberryAnnotation):
                  # TODO: This is because of dataclasses
                  return self.type_annotation
  
              return self.type_annotation.resolve()
          except NameError:
              return None  # type: ignore
  
      @type.setter
      def type(self, type_: Any) -> None:
          self.type_annotation = type_
  
      # TODO: add this to arguments (and/or move it to StrawberryType)
      @property
      def type_params(self) -> List[TypeVar]:
          if hasattr(self.type, "_type_definition"):
              parameters = getattr(self.type, "__parameters__", None)
  
              return list(parameters) if parameters else []
  
          # TODO: Consider making leaf types always StrawberryTypes, maybe a
          #       StrawberryBaseType or something
          if isinstance(self.type, StrawberryType):
              return self.type.type_params
          return []
  
      def copy_with(
          self, type_var_map: Mapping[TypeVar, Union[StrawberryType, builtins.type]]
      ) -> "StrawberryField":
          new_type: Union[StrawberryType, type]
  
          # TODO: Remove with creation of StrawberryObject. Will act same as other
          #       StrawberryTypes
          if hasattr(self.type, "_type_definition"):
              type_definition: TypeDefinition = self.type._type_definition  # type: ignore
  
              if type_definition.is_generic:
                  type_ = type_definition
                  new_type = type_.copy_with(type_var_map)
          else:
              assert isinstance(self.type, StrawberryType)
  
              new_type = self.type.copy_with(type_var_map)
  
          new_resolver = (
              self.base_resolver.copy_with(type_var_map)
              if self.base_resolver is not None
              else None
          )
  
          return StrawberryField(
              python_name=self.python_name,
              graphql_name=self.graphql_name,
              # TODO: do we need to wrap this in `StrawberryAnnotation`?
              # see comment related to dataclasses above
              type_annotation=StrawberryAnnotation(new_type),
              origin=self.origin,
              is_subscription=self.is_subscription,
              federation=self.federation,
              description=self.description,
              base_resolver=new_resolver,
              permission_classes=self.permission_classes,
              default=self.default_value,
              # ignored because of https://github.com/python/mypy/issues/6910
              default_factory=self.default_factory,  # type: ignore[misc]
              deprecation_reason=self.deprecation_reason,
          )
  
      def get_result(
          self, source: Any, info: Info, args: List[Any], kwargs: Dict[str, Any]
      ) -> Union[Awaitable[Any], Any]:
          """
          Calls the resolver defined for the StrawberryField. If the field doesn't have a
          resolver defined we default to using getattr on `source`.
          """
  
          if self.base_resolver:
              return self.base_resolver(*args, **kwargs)
  
          return getattr(source, self.python_name)
  
  
  def field(
      resolver: Optional[_RESOLVER_TYPE] = None,
      *,
      name: Optional[str] = None,
      is_subscription: bool = False,
      description: Optional[str] = None,
      permission_classes: Optional[List[Type[BasePermission]]] = None,
      federation: Optional[FederationFieldParams] = None,
      deprecation_reason: Optional[str] = None,
      default: Any = UNSET,
      default_factory: Union[Callable, object] = UNSET,
  ) -> StrawberryField:
      """Annotates a method or property as a GraphQL field.
  
      This is normally used inside a type declaration:
  
      >>> @strawberry.type:
      >>> class X:
      >>>     field_abc: str = strawberry.field(description="ABC")
  
      >>>     @strawberry.field(description="ABC")
      >>>     def field_with_resolver(self) -> str:
      >>>         return "abc"
  
      it can be used both as decorator and as a normal function.
      """
  
      field_ = StrawberryField(
          python_name=None,
          graphql_name=name,
          type_annotation=None,
          description=description,
          is_subscription=is_subscription,
          permission_classes=permission_classes or [],
          federation=federation or FederationFieldParams(),
          deprecation_reason=deprecation_reason,
          default=default,
          default_factory=default_factory,
      )
  
      if resolver:
          return field_(resolver)
      return field_
  
  
  __all__ = ["FederationFieldParams", "StrawberryField", "field"]
  