# Path: xmanager/xm/job_blocks.py
# class SequentialArgs:
#   class _RegularItem:
#   class _KeywordItem:
# class ExecutableSpec(abc.ABC):
# class Executable(abc.ABC):
# class ExecutorSpec(abc.ABC):
# class Executor(abc.ABC):
# class Packageable:
# class Constraint(abc.ABC):
# class Job:
# class JobGroup:
#   def __init__(self) -> None:
#   def _ingest_regular_item(self, value: Any) -> None:
#   def _ingest_keyword_item(self, name: str, value: Any) -> None:
#   def _merge_from(self, args: 'SequentialArgs') -> None:
#     def import_regular_item(item: SequentialArgs._RegularItem):
#     def import_keyword_item(item: SequentialArgs._KeywordItem):
#   def from_collection(collection: Optional[UserArgs]) -> 'SequentialArgs':
#     def check_for_string(args: str) -> None:
#     def import_sequential_args(args: SequentialArgs) -> None:
#     def import_mapping(collection: Mapping[Any, Any]) -> None:
#     def import_sequence(collection: Sequence[Any]) -> None:
#   def to_list(
#       self,
#       escaper: Callable[[Any], str],
#       kwargs_joiner: Callable[[str, str], str] = utils.trivial_kwargs_joiner
#   ) -> List[str]:
#     def export_regular_item(item: SequentialArgs._RegularItem) -> str:
#     def export_keyword_item(item: SequentialArgs._KeywordItem) -> str:
#   def to_dict(self, kwargs_only: bool = False) -> Dict[str, Any]:
#     def export_regular_item(
#         item: SequentialArgs._RegularItem) -> Tuple[str, Any]:
#     def export_keyword_item(
#         item: SequentialArgs._KeywordItem) -> Tuple[str, Any]:
#   def __eq__(self, other) -> bool:
#   def __repr__(self) -> str:
# def merge_args(*operands: Union[SequentialArgs, UserArgs]) -> SequentialArgs:
#   def name(self) -> str:
#   def Spec(cls) -> ExecutorSpec:  # pylint: disable=invalid-name
#   def __init__(self,
#                *,
#                constraints: Optional[Sequence[Constraint]] = None,
#                **jobs: JobType) -> None:
# 
# Path: xmanager/xm/pattern_matching.py
# R = TypeVar('R')
# class Case(Generic[R]):
#   def __init__(
#       self,
#       kind: Iterable[Type[Any]],
#       handler: Callable[..., R],
#   ) -> None:
#   def matches(self, *values: Any) -> bool:
# def _deduce_types(handler: Callable[..., Any]) -> Tuple[Type[Any]]:
#   def get_arg_type(arg: str):
# def match(*handlers: Union[Case[R], Callable[..., R]]) -> Callable[..., R]:
#   def apply(*values: Any) -> R:
# def async_match(*handlers: Callable[..., R]) -> Callable[..., Awaitable[R]]:


import copy
import itertools
import attr
from typing import Any, Callable, List, Sequence, Tuple
from xmanager.xm import job_blocks
from xmanager.xm import pattern_matching




def shallow_copy_job_type(
    job_type: job_blocks.JobTypeVar) -> job_blocks.JobTypeVar:
  """Creates a shallow copy of the job structure."""

  def apply_to_job_group(job_group: job_blocks.JobGroup) -> job_blocks.JobGroup:
    job_group = copy.copy(job_group)
    job_group.jobs = {key: matcher(job) for key, job in job_group.jobs.items()}
    return job_group

  matcher = pattern_matching.match(
      pattern_matching.Case([job_blocks.Job], copy.copy),
      apply_to_job_group,
      pattern_matching.Case([job_blocks.JobGeneratorType],
                            lambda generator: generator),
  )
  return matcher(job_type)


def populate_job_names(job_type: job_blocks.JobTypeVar) -> None:
  """Assigns default names to the given jobs."""

  def apply_to_job(prefix: Sequence[str], target: job_blocks.Job) -> None:
    if target.name is None:
      target.name = '_'.join(prefix) if prefix else target.executable.name

  def apply_to_job_group(prefix: Sequence[str],

# Path: xmanager/xm/job_blocks.py
# class SequentialArgs:
#   class _RegularItem:
#   class _KeywordItem:
# class ExecutableSpec(abc.ABC):
# class Executable(abc.ABC):
# class ExecutorSpec(abc.ABC):
# class Executor(abc.ABC):
# class Packageable:
# class Constraint(abc.ABC):
# class Job:
# class JobGroup:
#   def __init__(self) -> None:
#   def _ingest_regular_item(self, value: Any) -> None:
#   def _ingest_keyword_item(self, name: str, value: Any) -> None:
#   def _merge_from(self, args: 'SequentialArgs') -> None:
#     def import_regular_item(item: SequentialArgs._RegularItem):
#     def import_keyword_item(item: SequentialArgs._KeywordItem):
#   def from_collection(collection: Optional[UserArgs]) -> 'SequentialArgs':
#     def check_for_string(args: str) -> None:
#     def import_sequential_args(args: SequentialArgs) -> None:
#     def import_mapping(collection: Mapping[Any, Any]) -> None:
#     def import_sequence(collection: Sequence[Any]) -> None:
#   def to_list(
#       self,
#       escaper: Callable[[Any], str],
#       kwargs_joiner: Callable[[str, str], str] = utils.trivial_kwargs_joiner
#   ) -> List[str]:
#     def export_regular_item(item: SequentialArgs._RegularItem) -> str:
#     def export_keyword_item(item: SequentialArgs._KeywordItem) -> str:
#   def to_dict(self, kwargs_only: bool = False) -> Dict[str, Any]:
#     def export_regular_item(
#         item: SequentialArgs._RegularItem) -> Tuple[str, Any]:
#     def export_keyword_item(
#         item: SequentialArgs._KeywordItem) -> Tuple[str, Any]:
#   def __eq__(self, other) -> bool:
#   def __repr__(self) -> str:
# def merge_args(*operands: Union[SequentialArgs, UserArgs]) -> SequentialArgs:
#   def name(self) -> str:
#   def Spec(cls) -> ExecutorSpec:  # pylint: disable=invalid-name
#   def __init__(self,
#                *,
#                constraints: Optional[Sequence[Constraint]] = None,
#                **jobs: JobType) -> None:
# 
# Path: xmanager/xm/pattern_matching.py
# R = TypeVar('R')
# class Case(Generic[R]):
#   def __init__(
#       self,
#       kind: Iterable[Type[Any]],
#       handler: Callable[..., R],
#   ) -> None:
#   def matches(self, *values: Any) -> bool:
# def _deduce_types(handler: Callable[..., Any]) -> Tuple[Type[Any]]:
#   def get_arg_type(arg: str):
# def match(*handlers: Union[Case[R], Callable[..., R]]) -> Callable[..., R]:
#   def apply(*values: Any) -> R:
# def async_match(*handlers: Callable[..., R]) -> Callable[..., Awaitable[R]]:


# Path: xmanager/xm/job_operators.py
import copy
import itertools
import attr
from typing import Any, Callable, List, Sequence, Tuple
from xmanager.xm import job_blocks
from xmanager.xm import pattern_matching





def shallow_copy_job_type(
    job_type: job_blocks.JobTypeVar) -> job_blocks.JobTypeVar:
  """Creates a shallow copy of the job structure."""

  def apply_to_job_group(job_group: job_blocks.JobGroup) -> job_blocks.JobGroup:
    job_group = copy.copy(job_group)
    job_group.jobs = {key: matcher(job) for key, job in job_group.jobs.items()}
    return job_group

  matcher = pattern_matching.match(
      pattern_matching.Case([job_blocks.Job], copy.copy),
      apply_to_job_group,
      pattern_matching.Case([job_blocks.JobGeneratorType],
                            lambda generator: generator),
  )
  return matcher(job_type)


def populate_job_names(job_type: job_blocks.JobTypeVar) -> None:
  """Assigns default names to the given jobs."""

  def apply_to_job(prefix: Sequence[str], target: job_blocks.Job) -> None:
    if target.name is None:
      target.name = '_'.join(prefix) if prefix else target.executable.name

  def apply_to_job_group(prefix: Sequence[str],

                         target: job_blocks.JobGroup) -> None: