# Buggy code
def build_python_component(
    component_func,
    target_image,
    base_image=None,
    dependency=[],
    staging_gcs_path=None,
    timeout=600,
    namespace=None,
    target_component_file=None,
    python_version="python3",
):
    """build_component automatically builds a container image for the component_func based on the base_image and pushes to the target_image.

    Args:
      component_func (python function): The python function to build components upon
      base_image (str): Docker image to use as a base image
      target_image (str): Full URI to push the target image
      staging_gcs_path (str): GCS blob that can store temporary build files
      target_image (str): target image path
      timeout (int): the timeout for the image build(in secs), default is 600 seconds
      namespace (str): the namespace within which to run the kubernetes kaniko job. If the
      job is running on GKE and value is None the underlying functions will use the default namespace from GKE.  .
      dependency (list): a list of VersionedDependency, which includes the package name and versions, default is empty
      python_version (str): choose python2 or python3, default is python3

    Raises:
      ValueError: The function is not decorated with python_component decorator or the python_version is neither python2 nor python3
    """

    _configure_logger(logging.getLogger())

    if component_func is None:
        raise ValueError("component_func must not be None")
    if target_image is None:
        raise ValueError("target_image must not be None")

    if python_version not in ["python2", "python3"]:
        raise ValueError("python_version has to be either python2 or python3")

    if staging_gcs_path is None:
        raise ValueError("staging_gcs_path must not be None")

    if base_image is None:
        base_image = getattr(component_func, "_component_base_image", None)
    if base_image is None:
        from ..components._python_op import default_base_image_or_builder

        base_image = default_base_image_or_builder
        if isinstance(base_image, Callable):
            base_image = base_image()

    logging.info(
        "Build an image that is based on "
        + base_image
        + " and push the image to "
        + target_image
    )

    component_spec = _func_to_component_spec(component_func, base_image=base_image)
    command_line_args = component_spec.implementation.container.command

    dash_c_index = command_line_args.index("-c")
    program_code_index = dash_c_index + 1
    program_code = command_line_args[program_code_index]
    program_rel_path = "ml/main.py"
    program_container_path = "/" + program_rel_path

    # Replacing the inline code with calling a local program
    # Before: python3 -u -c 'import sys ...' --param1 ...
    # After:  python3 -u main.py --param1 ...
    command_line_args[program_code_index] = program_container_path
    command_line_args.pop(dash_c_index)

    if python_version == "python2":
        import warnings

        warnings.warn("Python2 is not longer supported")
        # Replacing the python interpreter
        python_interpreter_index = command_line_args.index("python3")
        command_line_args[python_interpreter_index] = python_version

    arc_docker_filename = "Dockerfile"
    arc_requirement_filename = "requirements.txt"

    with tempfile.TemporaryDirectory() as local_build_dir:
        # Write the program code to a file in the context directory
        local_python_filepath = os.path.join(local_build_dir, program_rel_path)
        os.makedirs(os.path.dirname(local_python_filepath), exist_ok=True)
        with open(local_python_filepath, "w") as f:
            f.write(program_code)

        # Generate the python package requirements file in the context directory
        local_requirement_filepath = os.path.join(
            local_build_dir, arc_requirement_filename
        )
        _dependency_to_requirements(dependency, local_requirement_filepath)

        # Generate Dockerfile in the context directory
        local_docker_filepath = os.path.join(local_build_dir, arc_docker_filename)
        _generate_dockerfile(
            local_docker_filepath,
            base_image,
            python_version,
            arc_requirement_filename,
            add_files={program_rel_path: program_container_path},
        )

        logging.info("Building and pushing container image.")
        container_builder = ContainerBuilder(staging_gcs_path, target_image, namespace)
        image_name_with_digest = container_builder.build(
            local_build_dir, arc_docker_filename, target_image, timeout
        )

    component_spec.implementation.container.image = image_name_with_digest

    # Optionally writing the component definition to a local file for sharing
    target_component_file = target_component_file or getattr(
        component_func, "_component_target_component_file", None
    )
    if target_component_file:
        component_spec.save(target_component_file)

    task_factory_function = _create_task_factory_from_component_spec(component_spec)
    return task_factory_function


# Traceback (OSError)
Traceback (most recent call last):
File "/opt/conda/lib/python3.8/site-packages/torch/_utils_internal.py", line 49, in get_source_lines_and_file
sourcelines, file_lineno = inspect.getsourcelines(obj)
File "/opt/conda/lib/python3.8/inspect.py", line 967, in getsourcelines
lines, lnum = findsource(object)
File "/opt/conda/lib/python3.8/inspect.py", line 798, in findsource
raise OSError('could not get source code')
OSError: could not get source code
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<string>", line 55, in <module>
File "<string>", line 44, in create_fully_connected_pytorch_network
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_script.py", line 897, in script
return torch.jit._recursive.create_script_module(
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_recursive.py", line 352, in create_script_module
return create_script_module_impl(nn_module, concrete_type, stubs_fn)
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_recursive.py", line 364, in create_script_module_impl
method_stubs = stubs_fn(nn_module)
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_recursive.py", line 591, in infer_methods_to_compile
stubs.append(make_stub_from_method(nn_module, method))
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_recursive.py", line 52, in make_stub_from_method
return make_stub(func, method_name)
File "/opt/conda/lib/python3.8/site-packages/torch/jit/_recursive.py", line 37, in make_stub
ast = get_jit_def(func, name, self_name="RecursiveScriptModule")
File "/opt/conda/lib/python3.8/site-packages/torch/jit/frontend.py", line 197, in get_jit_def
sourcelines, file_lineno, filename = get_source_lines_and_file(fn, torch._C.ErrorReport.call_stack())
File "/opt/conda/lib/python3.8/site-packages/torch/_utils_internal.py", line 56, in get_source_lines_and_file
raise OSError(msg) from e
OSError: Can't get source for <bound method create_fully_connected_pytorch_network.<locals>.FullyConnectedNetwork.forward of FullyConnectedNetwork(
(layers): ModuleList(
(0): Linear(in_features=10, out_features=100, bias=True)
(1): Linear(in_features=100, out_features=10, bias=True)
(2): Linear(in_features=10, out_features=1, bias=True)
)
)>. TorchScript requires source access in order to carry out compilation, make sure original .py files are available.

# Fixed code
def build_python_component(
    component_func,
    target_image,
    base_image=None,
    dependency=[],
    staging_gcs_path=None,
    timeout=600,
    namespace=None,
    target_component_file=None,
    python_version="python3",
):
    """build_component automatically builds a container image for the component_func based on the base_image and pushes to the target_image.

    Args:
      component_func (python function): The python function to build components upon
      base_image (str): Docker image to use as a base image
      target_image (str): Full URI to push the target image
      staging_gcs_path (str): GCS blob that can store temporary build files
      target_image (str): target image path
      timeout (int): the timeout for the image build(in secs), default is 600 seconds
      namespace (str): the namespace within which to run the kubernetes kaniko job. If the
      job is running on GKE and value is None the underlying functions will use the default namespace from GKE.  .
      dependency (list): a list of VersionedDependency, which includes the package name and versions, default is empty
      python_version (str): choose python2 or python3, default is python3

    Raises:
      ValueError: The function is not decorated with python_component decorator or the python_version is neither python2 nor python3
    """

    _configure_logger(logging.getLogger())

    if component_func is None:
        raise ValueError("component_func must not be None")
    if target_image is None:
        raise ValueError("target_image must not be None")

    if python_version not in ["python2", "python3"]:
        raise ValueError("python_version has to be either python2 or python3")

    if staging_gcs_path is None:
        raise ValueError("staging_gcs_path must not be None")

    if base_image is None:
        base_image = getattr(component_func, "_component_base_image", None)
    if base_image is None:
        from ..components._python_op import default_base_image_or_builder

        base_image = default_base_image_or_builder
        if isinstance(base_image, Callable):
            base_image = base_image()

    logging.info(
        "Build an image that is based on "
        + base_image
        + " and push the image to "
        + target_image
    )

    component_spec = _func_to_component_spec(component_func, base_image=base_image)
    command_line_args = component_spec.implementation.container.command

    program_launcher_index = command_line_args.index(
        'program_path=$(mktemp)\necho -n "$0" > "$program_path"\npython3 -u "$program_path" "$@"\n'
    )
    assert program_launcher_index in [2, 3]

    program_code_index = program_launcher_index + 1
    program_code = command_line_args[program_code_index]
    program_rel_path = "ml/main.py"
    program_container_path = "/" + program_rel_path

    # Replacing the inline code with calling a local program
    # Before: sh -ec '... && python3 -u ...' 'import sys ...' --param1 ...
    # After:  python3 -u main.py --param1 ...
    command_line_args[program_code_index] = program_container_path
    command_line_args.pop(program_launcher_index)
    command_line_args[program_launcher_index - 1] = "-u"  # -ec => -u
    command_line_args[program_launcher_index - 2] = python_version  # sh => python3

    if python_version == "python2":
        import warnings

        warnings.warn("Python2 is not longer supported")

    arc_docker_filename = "Dockerfile"
    arc_requirement_filename = "requirements.txt"

    with tempfile.TemporaryDirectory() as local_build_dir:
        # Write the program code to a file in the context directory
        local_python_filepath = os.path.join(local_build_dir, program_rel_path)
        os.makedirs(os.path.dirname(local_python_filepath), exist_ok=True)
        with open(local_python_filepath, "w") as f:
            f.write(program_code)

        # Generate the python package requirements file in the context directory
        local_requirement_filepath = os.path.join(
            local_build_dir, arc_requirement_filename
        )
        _dependency_to_requirements(dependency, local_requirement_filepath)

        # Generate Dockerfile in the context directory
        local_docker_filepath = os.path.join(local_build_dir, arc_docker_filename)
        _generate_dockerfile(
            local_docker_filepath,
            base_image,
            python_version,
            arc_requirement_filename,
            add_files={program_rel_path: program_container_path},
        )

        logging.info("Building and pushing container image.")
        container_builder = ContainerBuilder(staging_gcs_path, target_image, namespace)
        image_name_with_digest = container_builder.build(
            local_build_dir, arc_docker_filename, target_image, timeout
        )

    component_spec.implementation.container.image = image_name_with_digest

    # Optionally writing the component definition to a local file for sharing
    target_component_file = target_component_file or getattr(
        component_func, "_component_target_component_file", None
    )
    if target_component_file:
        component_spec.save(target_component_file)

    task_factory_function = _create_task_factory_from_component_spec(component_spec)
    return task_factory_function