parameters: (input_args: argparse.Namespace, *,
                        base: str,
                        output_stages: typing.MutableMapping[str, hpccm.Stage])
docstring: Add the stage(s) necessary for the requested venvs.
  
      One intermediate build stage is created for each venv (see --venv option).
  
      Each stage partially populates Python installations and venvs in the home
      directory. The home directory is collected by the 'pyenv' stage for use by
      the main build stage.
docstring_summary: Add the stage(s) necessary for the requested venvs.
docstring_tokens: Add the stage ( s ) necessary for the requested venvs .
function: def add_python_stages(input_args: argparse.Namespace, *,
                        base: str,
                        output_stages: typing.MutableMapping[str, hpccm.Stage]):
      """Add the stage(s) necessary for the requested venvs.
  
      One intermediate build stage is created for each venv (see --venv option).
  
      Each stage partially populates Python installations and venvs in the home
      directory. The home directory is collected by the 'pyenv' stage for use by
      the main build stage.
      """
      if len(input_args.venvs) < 1:
          raise RuntimeError('No venvs to build...')
      if output_stages is None or not isinstance(output_stages, collections.abc.Mapping):
          raise RuntimeError('Need a container for output stages.')
  
      # Main Python stage that collects the environments from individual stages.
      # We collect the stages individually, rather than chaining them, because the
      # copy is a bit slow and wastes local Docker image space for each filesystem
      # layer.
      pyenv_stage = hpccm.Stage()
      pyenv_stage += hpccm.primitives.baseimage(image=base,
                                                _distro=hpccm_distro_name(input_args),
                                                _as='pyenv')
      pyenv_stage += hpccm.building_blocks.packages(ospackages=_python_extra_packages)
  
      for version in [StrictVersion(py_ver) for py_ver in sorted(input_args.venvs)]:
          stage_name = 'py' + str(version)
          stage = hpccm.Stage()
          stage += hpccm.primitives.baseimage(image=base,
                                              _distro=hpccm_distro_name(input_args),
                                              _as=stage_name)
          stage += hpccm.building_blocks.packages(ospackages=_python_extra_packages)
  
          # TODO: Use a non-root user for testing and Python virtual environments.
          stage += hpccm.primitives.shell(commands=[
              'curl https://pyenv.run | bash',
              """echo 'export PYENV_ROOT="$HOME/.pyenv"' >> $HOME/.bashrc""",
              """echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> $HOME/.bashrc""",
              """echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc""",
              """echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc"""])
          pyenv = '$HOME/.pyenv/bin/pyenv'
          commands = [f'PYTHON_CONFIGURE_OPTS="--enable-shared" {pyenv} install -s {version}']
          stage += hpccm.primitives.shell(commands=commands)
  
          commands = prepare_venv(version)
          stage += hpccm.primitives.shell(commands=commands)
  
          # TODO: Update user home directory.
          pyenv_stage += hpccm.primitives.copy(_from=stage_name, _mkdir=True, src=['/root/'],
                                               dest='/root')
  
          # Add the intermediate build stage to the sequence
          output_stages[stage_name] = stage
  
      # TODO: If we activate pyenv for login shells, the `global` "version" should be full-featured.
      # # `version` should be a system installation or pyenv environment (or pyenv-virtualenv)
      # # with the dependencies for all of the Python aspects of CMake-driven builds.
      # commands = '{pyenv} global {version}'.format(
      #             pyenv=pyenv,
      #             version=...)
      # pyenv_stage += hpccm.primitives.shell(commands=commands)
  
      # Add the aggregating build stage to the sequence. This allows the main stage to copy
      # the files in a single stage, potentially reducing the overall output image size.
      output_stages['pyenv'] = pyenv_stage
function_tokens: def add_python_stages ( input_args : argparse . Namespace , * , base : str , output_stages : typing . MutableMapping [ str , hpccm . Stage ] ) : if len ( input_args . venvs ) < 1 : raise RuntimeError ( 'No venvs to build...' ) if output_stages is None or not isinstance ( output_stages , collections . abc . Mapping ) : raise RuntimeError ( 'Need a container for output stages.' ) # Main Python stage that collects the environments from individual stages. # We collect the stages individually, rather than chaining them, because the # copy is a bit slow and wastes local Docker image space for each filesystem # layer. pyenv_stage = hpccm . Stage ( ) pyenv_stage += hpccm . primitives . baseimage ( image = base , _distro = hpccm_distro_name ( input_args ) , _as = 'pyenv' ) pyenv_stage += hpccm . building_blocks . packages ( ospackages = _python_extra_packages ) for version in [ StrictVersion ( py_ver ) for py_ver in sorted ( input_args . venvs ) ] : stage_name = 'py' + str ( version ) stage = hpccm . Stage ( ) stage += hpccm . primitives . baseimage ( image = base , _distro = hpccm_distro_name ( input_args ) , _as = stage_name ) stage += hpccm . building_blocks . packages ( ospackages = _python_extra_packages ) # TODO: Use a non-root user for testing and Python virtual environments. stage += hpccm . primitives . shell ( commands = [ 'curl https://pyenv.run | bash' , """echo 'export PYENV_ROOT="$HOME/.pyenv"' >> $HOME/.bashrc""" , """echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> $HOME/.bashrc""" , """echo 'eval "$(pyenv init -)"' >> $HOME/.bashrc""" , """echo 'eval "$(pyenv virtualenv-init -)"' >> $HOME/.bashrc""" ] ) pyenv = '$HOME/.pyenv/bin/pyenv' commands = [ f'PYTHON_CONFIGURE_OPTS="--enable-shared" {pyenv} install -s {version}' ] stage += hpccm . primitives . shell ( commands = commands ) commands = prepare_venv ( version ) stage += hpccm . primitives . shell ( commands = commands ) # TODO: Update user home directory. pyenv_stage += hpccm . primitives . copy ( _from = stage_name , _mkdir = True , src = [ '/root/' ] , dest = '/root' ) # Add the intermediate build stage to the sequence output_stages [ stage_name ] = stage # TODO: If we activate pyenv for login shells, the `global` "version" should be full-featured. # # `version` should be a system installation or pyenv environment (or pyenv-virtualenv) # # with the dependencies for all of the Python aspects of CMake-driven builds. # commands = '{pyenv} global {version}'.format( #             pyenv=pyenv, #             version=...) # pyenv_stage += hpccm.primitives.shell(commands=commands) # Add the aggregating build stage to the sequence. This allows the main stage to copy # the files in a single stage, potentially reducing the overall output image size. output_stages [ 'pyenv' ] = pyenv_stage