#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

"""Environments concepts.

For internal use only. No backwards compatibility guarantees."""

# pytype: skip-file

import json
import logging
import sys
import tempfile
from collections.abc import Callable
from collections.abc import Iterable
from collections.abc import Iterator
from collections.abc import Mapping
from types import MappingProxyType
from typing import TYPE_CHECKING
from typing import Any
from typing import Optional
from typing import TypeVar
from typing import Union
from typing import overload

from google.protobuf import message

from apache_beam import coders
from apache_beam.options.pipeline_options import PortableOptions
from apache_beam.options.pipeline_options import SetupOptions
from apache_beam.options.pipeline_options import StandardOptions
from apache_beam.portability import common_urns
from apache_beam.portability import python_urns
from apache_beam.portability.api import beam_runner_api_pb2
from apache_beam.portability.api import endpoints_pb2
from apache_beam.runners.portability import stager
from apache_beam.transforms.resources import resource_hints_from_options
from apache_beam.utils import proto_utils

if TYPE_CHECKING:
  from apache_beam.options.pipeline_options import PipelineOptions
  from apache_beam.runners.pipeline_context import PipelineContext

__all__ = [
    'Environment',
    'AnyOfEnvironment',
    'DefaultEnvironment',
    'DockerEnvironment',
    'ProcessEnvironment',
    'ExternalEnvironment',
    'EmbeddedPythonEnvironment',
    'EmbeddedPythonGrpcEnvironment',
    'SubprocessSDKEnvironment',
    'PyPIArtifactRegistry'
]

T = TypeVar('T')
EnvironmentT = TypeVar('EnvironmentT', bound='Environment')
ConstructorFn = Callable[[
    Optional[Any],
    Iterable[str],
    Iterable[beam_runner_api_pb2.ArtifactInformation],
    Mapping[str, bytes],
    'PipelineContext'
],
                         Any]


def looks_like_json(s):
  import re
  return re.match(r'\s*\{.*\}\s*$', s)


APACHE_BEAM_DOCKER_IMAGE_PREFIX = 'apache/beam'
APACHE_BEAM_JAVA_CONTAINER_NAME_PREFIX = 'beam_java'
SDK_VERSION_CAPABILITY_PREFIX = 'beam:version:sdk_base:'


def is_apache_beam_container(container_image):
  return container_image and container_image.startswith(
      APACHE_BEAM_DOCKER_IMAGE_PREFIX)


class Environment(object):
  """Abstract base class for environments.

  Represents a type and configuration of environment.
  Each type of Environment should have a unique urn.

  For internal use only. No backwards compatibility guarantees.
  """

  _known_urns = {}  # type: dict[str, tuple[Optional[type], ConstructorFn]]
  _urn_to_env_cls = {}  # type: dict[str, type]

  def __init__(
      self,
      capabilities=(),  # type: Iterable[str]
      artifacts=(),  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints=None,  # type: Optional[Mapping[str, bytes]]
  ):
    # type: (...) -> None
    self._capabilities = capabilities
    self._artifacts = sorted(artifacts, key=lambda x: x.SerializeToString())
    # Hints on created environments should be immutable since pipeline context
    # stores environments in hash maps and we use hints to compute the hash.
    self._resource_hints = MappingProxyType(
        dict(resource_hints) if resource_hints else {})

  def __eq__(self, other):
    return (
        self.__class__ == other.__class__ and
        self._artifacts == other._artifacts
        # Assuming that we don't have instances of the same Environment subclass
        # with different set of capabilities.
        and self._resource_hints == other._resource_hints)

  def __hash__(self):
    # type: () -> int
    return hash((self.__class__, frozenset(self._resource_hints.items())))

  def artifacts(self):
    # type: () -> Iterable[beam_runner_api_pb2.ArtifactInformation]
    return self._artifacts

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, Optional[Union[message.Message, bytes, str]]]
    raise NotImplementedError

  def capabilities(self):
    # type: () -> Iterable[str]
    return self._capabilities

  def resource_hints(self):
    # type: () -> Mapping[str, bytes]
    return self._resource_hints

  @classmethod
  @overload
  def register_urn(
      cls,
      urn,  # type: str
      parameter_type,  # type: type[T]
  ):
    # type: (...) -> Callable[[Union[type, Callable[[T, Iterable[str], PipelineContext], Any]]], Callable[[T, Iterable[str], PipelineContext], Any]]
    pass

  @classmethod
  @overload
  def register_urn(
      cls,
      urn,  # type: str
      parameter_type,  # type: None
  ):
    # type: (...) -> Callable[[Union[type, Callable[[bytes, Iterable[str], Iterable[beam_runner_api_pb2.ArtifactInformation], PipelineContext], Any]]], Callable[[bytes, Iterable[str], PipelineContext], Any]]
    pass

  @classmethod
  @overload
  def register_urn(
      cls,
      urn,  # type: str
      parameter_type,  # type: type[T]
      constructor  # type: Callable[[T, Iterable[str], Iterable[beam_runner_api_pb2.ArtifactInformation], PipelineContext], Any]
  ):
    # type: (...) -> None
    pass

  @classmethod
  @overload
  def register_urn(
      cls,
      urn,  # type: str
      parameter_type,  # type: None
      constructor  # type: Callable[[bytes, Iterable[str], Iterable[beam_runner_api_pb2.ArtifactInformation], PipelineContext], Any]
  ):
    # type: (...) -> None
    pass

  @classmethod
  def register_urn(cls, urn, parameter_type, constructor=None):
    def register(constructor):
      if isinstance(constructor, type):
        constructor.from_runner_api_parameter = register(
            constructor.from_runner_api_parameter)
        # register environment urn to environment class
        cls._urn_to_env_cls[urn] = constructor
        return constructor

      else:
        cls._known_urns[urn] = parameter_type, constructor
        return staticmethod(constructor)

    if constructor:
      # Used as a statement.
      register(constructor)
    else:
      # Used as a decorator.
      return register

  @classmethod
  def get_env_cls_from_urn(cls, urn):
    # type: (str) -> type[Environment]
    return cls._urn_to_env_cls[urn]

  def to_runner_api(self, context):
    # type: (PipelineContext) -> beam_runner_api_pb2.Environment
    urn, typed_param = self.to_runner_api_parameter(context)
    return beam_runner_api_pb2.Environment(
        urn=urn,
        payload=typed_param.SerializeToString() if isinstance(
            typed_param, message.Message) else typed_param if
        (isinstance(typed_param, bytes) or
         typed_param is None) else typed_param.encode('utf-8'),
        capabilities=self.capabilities(),
        dependencies=self.artifacts(),
        resource_hints=self.resource_hints())

  @classmethod
  def from_runner_api(
      cls,
      proto,  # type: Optional[beam_runner_api_pb2.Environment]
      context  # type: PipelineContext
  ):
    # type: (...) -> Optional[Environment]
    if proto is None or not proto.urn:
      return None
    parameter_type, constructor = cls._known_urns[proto.urn]

    return constructor(
        proto_utils.parse_Bytes(proto.payload, parameter_type),
        proto.capabilities,
        proto.dependencies,
        proto.resource_hints,
        context)

  @classmethod
  def from_options(cls, options):
    # type: (type[EnvironmentT], PortableOptions) -> EnvironmentT

    """Creates an Environment object from PortableOptions.

    Args:
      options: The PortableOptions object.
    """
    if cls != Environment:
      raise NotImplementedError

    portable_options = options.view_as(PortableOptions)
    environment_type = portable_options.environment_type
    if not environment_type:
      environment_urn = common_urns.environments.DOCKER.urn
    elif environment_type.startswith('beam:env:'):
      environment_urn = environment_type
    elif environment_type == 'LOOPBACK':
      environment_urn = python_urns.EMBEDDED_PYTHON_LOOPBACK
    else:
      try:
        environment_urn = getattr(
            common_urns.environments, environment_type).urn
      except AttributeError:
        raise ValueError('Unknown environment type: %s' % environment_type)

    env_class = Environment.get_env_cls_from_urn(environment_urn)
    return env_class.from_options(portable_options)  # type: ignore


@Environment.register_urn(common_urns.environments.DEFAULT.urn, None)
class DefaultEnvironment(Environment):
  """Used as a stub when context is missing a default environment."""
  def to_runner_api_parameter(self, context):
    return common_urns.environments.DEFAULT.urn, None

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: beam_runner_api_pb2.DockerPayload
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> DefaultEnvironment
    return DefaultEnvironment(
        capabilities=capabilities,
        artifacts=artifacts,
        resource_hints=resource_hints)


@Environment.register_urn(
    common_urns.environments.DOCKER.urn, beam_runner_api_pb2.DockerPayload)
class DockerEnvironment(Environment):
  def __init__(
      self,
      container_image=None,  # type: Optional[str]
      capabilities=(),  # type: Iterable[str]
      artifacts=(),  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints=None,  # type: Optional[Mapping[str, bytes]]
  ):
    super().__init__(capabilities, artifacts, resource_hints)
    if container_image:
      logging.debug(
          'Using provided Python SDK container image: %s' % (container_image))
      self.container_image = container_image
    else:
      logging.debug('No image given, using default Python SDK image')
      self.container_image = self.default_docker_image()

    logging.debug(
        'Python SDK container image set to "%s" for Docker environment' %
        (self.container_image))

  def __eq__(self, other):
    return (
        super().__eq__(other) and self.container_image == other.container_image)

  def __hash__(self):
    return hash((super().__hash__(), self.container_image))

  def __repr__(self):
    return 'DockerEnvironment(container_image=%s)' % self.container_image

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, beam_runner_api_pb2.DockerPayload]
    return (
        common_urns.environments.DOCKER.urn,
        beam_runner_api_pb2.DockerPayload(container_image=self.container_image))

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: beam_runner_api_pb2.DockerPayload
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> DockerEnvironment
    return DockerEnvironment(
        container_image=payload.container_image,
        capabilities=capabilities,
        artifacts=artifacts,
        resource_hints=resource_hints)

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> DockerEnvironment
    if options.view_as(SetupOptions).prebuild_sdk_container_engine:
      # Imported here to avoid circular dependencies.
      # pylint: disable=wrong-import-order, wrong-import-position
      from apache_beam.runners.portability.sdk_container_builder import SdkContainerImageBuilder
      prebuilt_container_image = SdkContainerImageBuilder.build_container_image(
          options)
      return cls.from_container_image(
          container_image=prebuilt_container_image,
          artifacts=python_sdk_dependencies(options),
          resource_hints=resource_hints_from_options(options),
      )
    return cls.from_container_image(
        container_image=options.lookup_environment_option(
            'docker_container_image') or options.environment_config,
        artifacts=python_sdk_dependencies(options),
        resource_hints=resource_hints_from_options(options),
    )

  @classmethod
  def from_container_image(
      cls, container_image, artifacts=(), resource_hints=None):
    # type: (str, Iterable[beam_runner_api_pb2.ArtifactInformation], Optional[Mapping[str, bytes]]) -> DockerEnvironment
    return cls(
        container_image=container_image,
        capabilities=python_sdk_docker_capabilities(),
        artifacts=artifacts,
        resource_hints=resource_hints)

  @staticmethod
  def default_docker_image():
    # type: () -> str
    from apache_beam import version as beam_version

    sdk_version = beam_version.__version__
    version_suffix = '.'.join([str(i) for i in sys.version_info[0:2]])

    image = (
        APACHE_BEAM_DOCKER_IMAGE_PREFIX +
        '_python{version_suffix}_sdk:{tag}'.format(
            version_suffix=version_suffix, tag=sdk_version))
    return image


@Environment.register_urn(
    common_urns.environments.PROCESS.urn, beam_runner_api_pb2.ProcessPayload)
class ProcessEnvironment(Environment):
  def __init__(
      self,
      command,  # type: str
      os='',  # type: str
      arch='',  # type: str
      env=None,  # type: Optional[Mapping[str, str]]
      capabilities=(),  # type: Iterable[str]
      artifacts=(),  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints=None,  # type: Optional[Mapping[str, bytes]]
  ):
    # type: (...) -> None
    super().__init__(capabilities, artifacts, resource_hints)
    self.command = command
    self.os = os
    self.arch = arch
    self.env = env or {}

  def __eq__(self, other):
    return (
        super().__eq__(other) and self.command == other.command and
        self.os == other.os and self.arch == other.arch and
        self.env == other.env)

  def __hash__(self):
    # type: () -> int
    return hash((
        super().__hash__(),
        self.command,
        self.os,
        self.arch,
        frozenset(self.env.items())))

  def __repr__(self):
    # type: () -> str
    repr_parts = ['command=%s' % self.command]
    if self.os:
      repr_parts.append('os=%s' % self.os)
    if self.arch:
      repr_parts.append('arch=%s' % self.arch)
    repr_parts.append('env=%s' % self.env)
    return 'ProcessEnvironment(%s)' % ','.join(repr_parts)

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, beam_runner_api_pb2.ProcessPayload]
    return (
        common_urns.environments.PROCESS.urn,
        beam_runner_api_pb2.ProcessPayload(
            os=self.os, arch=self.arch, command=self.command, env=self.env))

  @staticmethod
  def from_runner_api_parameter(
      payload,
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> ProcessEnvironment
    return ProcessEnvironment(
        command=payload.command,
        os=payload.os,
        arch=payload.arch,
        env=payload.env,
        capabilities=capabilities,
        artifacts=artifacts,
        resource_hints=resource_hints,
    )

  @staticmethod
  def parse_environment_variables(variables):
    env = {}
    for var in variables:
      try:
        name, value = var.split('=', 1)
        env[name] = value
      except ValueError:
        raise ValueError(
            'Invalid process_variables "%s" (expected assignment in the '
            'form "FOO=bar").' % var)
    return env

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> ProcessEnvironment
    if options.environment_config:
      config = json.loads(options.environment_config)
      return cls(
          config.get('command'),
          os=config.get('os', ''),
          arch=config.get('arch', ''),
          env=config.get('env', ''),
          capabilities=python_sdk_capabilities(),
          artifacts=python_sdk_dependencies(options),
          resource_hints=resource_hints_from_options(options),
      )
    env = cls.parse_environment_variables(
        options.lookup_environment_option('process_variables').split(',')
        if options.lookup_environment_option('process_variables') else [])
    return cls(
        options.lookup_environment_option('process_command'),
        env=env,
        capabilities=python_sdk_capabilities(),
        artifacts=python_sdk_dependencies(options),
        resource_hints=resource_hints_from_options(options),
    )


@Environment.register_urn(
    common_urns.environments.EXTERNAL.urn, beam_runner_api_pb2.ExternalPayload)
class ExternalEnvironment(Environment):
  def __init__(
      self,
      url,  # type: str
      params=None,  # type: Optional[Mapping[str, str]]
      capabilities=(),  # type: Iterable[str]
      artifacts=(),  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints=None,  # type: Optional[Mapping[str, bytes]]
  ):
    super().__init__(capabilities, artifacts, resource_hints)
    self.url = url
    self.params = params

  def __eq__(self, other):
    return (
        super().__eq__(other) and self.url == other.url and
        self.params == other.params)

  def __hash__(self):
    # type: () -> int
    return hash((
        super().__hash__(),
        self.url,
        frozenset(self.params.items()) if self.params is not None else None))

  def __repr__(self):
    # type: () -> str
    return 'ExternalEnvironment(url=%s,params=%s)' % (self.url, self.params)

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, beam_runner_api_pb2.ExternalPayload]
    return (
        common_urns.environments.EXTERNAL.urn,
        beam_runner_api_pb2.ExternalPayload(
            endpoint=endpoints_pb2.ApiServiceDescriptor(url=self.url),
            params=self.params))

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: beam_runner_api_pb2.ExternalPayload
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> ExternalEnvironment
    return ExternalEnvironment(
        payload.endpoint.url,
        params=payload.params or None,
        capabilities=capabilities,
        artifacts=artifacts,
        resource_hints=resource_hints)

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> ExternalEnvironment
    if looks_like_json(options.environment_config):
      config = json.loads(options.environment_config)
      url = config.get('url')
      if not url:
        raise ValueError('External environment endpoint must be set.')
      params = config.get('params')
    elif options.environment_config:
      url = options.environment_config
      params = None
    else:
      url = options.lookup_environment_option('external_service_address')
      params = None

    return cls(
        url,
        params=params,
        capabilities=python_sdk_capabilities(),
        artifacts=python_sdk_dependencies(options),
        resource_hints=resource_hints_from_options(options))


def expand_anyof_environments(env_proto):
  if env_proto.urn == common_urns.environments.ANYOF.urn:
    for alt in beam_runner_api_pb2.AnyOfEnvironmentPayload.FromString(
        env_proto.payload).environments:
      yield from expand_anyof_environments(alt)
  else:
    yield env_proto


def resolve_anyof_environment(env_proto, *preferred_types):
  all_environments = list(expand_anyof_environments(env_proto))
  for preferred_type in preferred_types:
    for env in all_environments:
      if env.urn == preferred_type:
        return env
  return all_environments[0]


@Environment.register_urn(python_urns.EMBEDDED_PYTHON, None)
class EmbeddedPythonEnvironment(Environment):
  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, None]
    return python_urns.EMBEDDED_PYTHON, None

  @staticmethod
  def from_runner_api_parameter(
      unused_payload,  # type: None
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> EmbeddedPythonEnvironment
    return EmbeddedPythonEnvironment(capabilities, artifacts, resource_hints)

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> EmbeddedPythonEnvironment
    return cls(
        capabilities=python_sdk_capabilities(),
        artifacts=python_sdk_dependencies(options),
        resource_hints=resource_hints_from_options(options),
    )

  @classmethod
  def default(cls):
    # type: () -> EmbeddedPythonEnvironment
    return cls(capabilities=python_sdk_capabilities(), artifacts=())


@Environment.register_urn(python_urns.EMBEDDED_PYTHON_GRPC, bytes)
class EmbeddedPythonGrpcEnvironment(Environment):
  def __init__(
      self,
      state_cache_size=None,
      data_buffer_time_limit_ms=None,
      capabilities=(),
      artifacts=(),
      resource_hints=None,
  ):
    super().__init__(capabilities, artifacts, resource_hints)
    self.state_cache_size = state_cache_size
    self.data_buffer_time_limit_ms = data_buffer_time_limit_ms

  def __eq__(self, other):
    return (
        super().__eq__(other) and
        self.state_cache_size == other.state_cache_size and
        self.data_buffer_time_limit_ms == other.data_buffer_time_limit_ms)

  def __hash__(self):
    # type: () -> int
    return hash((
        super().__hash__(),
        self.state_cache_size,
        self.data_buffer_time_limit_ms))

  def __repr__(self):
    # type: () -> str
    repr_parts = []
    if not self.state_cache_size is None:
      repr_parts.append('state_cache_size=%d' % self.state_cache_size)
    if not self.data_buffer_time_limit_ms is None:
      repr_parts.append(
          'data_buffer_time_limit_ms=%d' % self.data_buffer_time_limit_ms)
    return 'EmbeddedPythonGrpcEnvironment(%s)' % ','.join(repr_parts)

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, bytes]
    params = {}
    if self.state_cache_size is not None:
      params['state_cache_size'] = self.state_cache_size
    if self.data_buffer_time_limit_ms is not None:
      params['data_buffer_time_limit_ms'] = self.data_buffer_time_limit_ms
    payload = json.dumps(params).encode('utf-8')
    return python_urns.EMBEDDED_PYTHON_GRPC, payload

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: bytes
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> EmbeddedPythonGrpcEnvironment
    if payload:
      config = EmbeddedPythonGrpcEnvironment.parse_config(
          payload.decode('utf-8'))
      return EmbeddedPythonGrpcEnvironment(
          state_cache_size=config.get('state_cache_size'),
          data_buffer_time_limit_ms=config.get('data_buffer_time_limit_ms'),
          capabilities=capabilities,
          artifacts=artifacts,
          resource_hints=resource_hints)
    else:
      return EmbeddedPythonGrpcEnvironment()

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> EmbeddedPythonGrpcEnvironment
    if options.environment_config:
      config = EmbeddedPythonGrpcEnvironment.parse_config(
          options.environment_config)
      return cls(
          state_cache_size=config.get('state_cache_size'),
          data_buffer_time_limit_ms=config.get('data_buffer_time_limit_ms'),
          capabilities=python_sdk_capabilities(),
          artifacts=python_sdk_dependencies(options))
    else:
      return cls(
          capabilities=python_sdk_capabilities(),
          artifacts=python_sdk_dependencies(options),
          resource_hints=resource_hints_from_options(options))

  @staticmethod
  def parse_config(s):
    # type: (str) -> dict[str, Any]
    if looks_like_json(s):
      config_dict = json.loads(s)
      if 'state_cache_size' in config_dict:
        config_dict['state_cache_size'] = int(config_dict['state_cache_size'])

      if 'data_buffer_time_limit_ms' in config_dict:
        config_dict['data_buffer_time_limit_ms'] = \
          int(config_dict['data_buffer_time_limit_ms'])
      return config_dict
    else:
      return {'state_cache_size': int(s)}

  @classmethod
  def default(cls):
    # type: () -> EmbeddedPythonGrpcEnvironment
    return cls(capabilities=python_sdk_capabilities(), artifacts=())


@Environment.register_urn(python_urns.EMBEDDED_PYTHON_LOOPBACK, None)
class PythonLoopbackEnvironment(EmbeddedPythonEnvironment):
  """Used as a stub when the loopback worker has not yet been started."""
  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, None]
    return python_urns.EMBEDDED_PYTHON_LOOPBACK, None

  @staticmethod
  def from_runner_api_parameter(
      unused_payload,  # type: None
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> PythonLoopbackEnvironment
    return PythonLoopbackEnvironment(
        capabilities=capabilities,
        artifacts=artifacts,
        resource_hints=resource_hints)


@Environment.register_urn(python_urns.SUBPROCESS_SDK, bytes)
class SubprocessSDKEnvironment(Environment):
  def __init__(
      self,
      command_string,  # type: str
      capabilities=(),  # type: Iterable[str]
      artifacts=(),  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints=None,  # type: Optional[Mapping[str, bytes]]
  ):
    super().__init__(capabilities, artifacts, resource_hints)
    self.command_string = command_string

  def __eq__(self, other):
    return (
        super().__eq__(other) and self.command_string == other.command_string)

  def __hash__(self):
    # type: () -> int
    return hash((super().__hash__(), self.command_string))

  def __repr__(self):
    # type: () -> str
    return 'SubprocessSDKEnvironment(command_string=%s)' % self.command_string

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, bytes]
    return python_urns.SUBPROCESS_SDK, self.command_string.encode('utf-8')

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: bytes
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> SubprocessSDKEnvironment
    return SubprocessSDKEnvironment(
        payload.decode('utf-8'), capabilities, artifacts, resource_hints)

  @classmethod
  def from_options(cls, options):
    # type: (PortableOptions) -> SubprocessSDKEnvironment
    return cls(
        options.environment_config,
        capabilities=python_sdk_capabilities(),
        artifacts=python_sdk_dependencies(options),
        resource_hints=resource_hints_from_options(options))

  @classmethod
  def from_command_string(cls, command_string):
    # type: (str) -> SubprocessSDKEnvironment
    return cls(
        command_string, capabilities=python_sdk_capabilities(), artifacts=())


@Environment.register_urn(
    common_urns.environments.ANYOF.urn,
    beam_runner_api_pb2.AnyOfEnvironmentPayload)
class AnyOfEnvironment(Environment):
  def __init__(self, environments):
    self._environments = environments

  def to_runner_api_parameter(self, context):
    # type: (PipelineContext) -> tuple[str, beam_runner_api_pb2.AnyOfEnvironmentPayload]
    return (
        common_urns.environments.ANYOF.urn,
        beam_runner_api_pb2.AnyOfEnvironmentPayload(
            environments=[
                env.to_runner_api(context) for env in self._environments
            ]))

  @staticmethod
  def from_runner_api_parameter(
      payload,  # type: beam_runner_api_pb2.AnyOfEnvironmentPayload
      capabilities,  # type: Iterable[str]
      artifacts,  # type: Iterable[beam_runner_api_pb2.ArtifactInformation]
      resource_hints,  # type: Mapping[str, bytes]
      context  # type: PipelineContext
  ):
    # type: (...) -> AnyOfEnvironment
    return AnyOfEnvironment([
        Environment.from_runner_api(env, context)
        for env in payload.environments
    ])

  @staticmethod
  def create_proto(
      environments: Iterable[beam_runner_api_pb2.Environment]
  ) -> beam_runner_api_pb2.Environment:
    return beam_runner_api_pb2.Environment(
        urn=common_urns.environments.ANYOF.urn,
        payload=beam_runner_api_pb2.AnyOfEnvironmentPayload(
            environments=environments).SerializeToString())

  def __hash__(self):
    return sum(hash(env) for env in self._environments)

  def __eq__(self, other):
    return (
        isinstance(other, AnyOfEnvironment) and
        set(self._environments) == set(other._environments))

  def to_runner_api(self, context):
    return self.create_proto(
        [env.to_runner_api(context) for env in self._environments])


class PyPIArtifactRegistry(object):
  _registered_artifacts = set()  # type: set[tuple[str, str]]

  @classmethod
  def register_artifact(cls, name, version):
    cls._registered_artifacts.add((name, version))

  @classmethod
  def get_artifacts(cls):
    for artifact in cls._registered_artifacts:
      yield artifact


def python_sdk_capabilities():
  # type: () -> list[str]
  return list(_python_sdk_capabilities_iter())


def python_sdk_docker_capabilities():
  return python_sdk_capabilities() + [common_urns.protocols.SIBLING_WORKERS.urn]


def sdk_base_version_capability():
  return (
      SDK_VERSION_CAPABILITY_PREFIX + DockerEnvironment.default_docker_image())


def _python_sdk_capabilities_iter():
  # type: () -> Iterator[str]
  for urn_spec in common_urns.coders.__dict__.values():
    if getattr(urn_spec, 'urn', None) in coders.Coder._known_urns:
      yield urn_spec.urn
  yield common_urns.protocols.LEGACY_PROGRESS_REPORTING.urn
  yield common_urns.protocols.HARNESS_MONITORING_INFOS.urn
  yield common_urns.protocols.WORKER_STATUS.urn
  yield python_urns.PACKED_COMBINE_FN
  yield sdk_base_version_capability()
  yield common_urns.sdf_components.TRUNCATE_SIZED_RESTRICTION.urn
  yield common_urns.primitives.TO_STRING.urn
  yield common_urns.protocols.DATA_SAMPLING.urn
  yield common_urns.protocols.SDK_CONSUMING_RECEIVED_DATA.urn
  yield common_urns.protocols.ORDERED_LIST_STATE.urn


def python_sdk_dependencies(options, tmp_dir=None):
  if tmp_dir is None:
    tmp_dir = tempfile.mkdtemp()
  skip_prestaged_dependencies = options.view_as(
      SetupOptions).prebuild_sdk_container_engine is not None
  runner = options.view_as(
      StandardOptions).runner or StandardOptions.DEFAULT_RUNNER
  log_submission_env_dependencies = runner.split(
      '.')[-1] not in StandardOptions.LOCAL_RUNNERS
  return stager.Stager.create_job_resources(
      options,
      tmp_dir,
      pypi_requirements=[
          artifact[0] + artifact[1]
          for artifact in PyPIArtifactRegistry.get_artifacts()
      ],
      skip_prestaged_dependencies=skip_prestaged_dependencies,
      log_submission_env_dependencies=log_submission_env_dependencies)
