async def create_python_binary( field_set: PythonBinaryFieldSet, python_binary_defaults: PythonBinaryDefaults ) -> CreatedBinary: entry_point = field_set.entry_point.value if entry_point is None: # TODO: This is overkill? We don't need to hydrate the sources and strip snapshots, # we only need the path relative to the source root. binary_sources = await Get(HydratedSources, HydrateSourcesRequest(field_set.sources)) stripped_binary_sources = await Get( StrippedSourceFiles, SourceFiles(binary_sources.snapshot, ()) ) entry_point = PythonBinarySources.translate_source_file_to_entry_point( stripped_binary_sources.snapshot.files ) output_filename = f"{field_set.address.target_name}.pex" two_step_pex = await Get( TwoStepPex, TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=[field_set.address], entry_point=entry_point, platforms=PexPlatforms.create_from_platforms_field(field_set.platforms), output_filename=output_filename, additional_args=field_set.generate_additional_args(python_binary_defaults), ) ), ) pex = two_step_pex.pex return CreatedBinary(digest=pex.digest, binary_name=pex.output_filename)
async def create_python_binary( config: PythonBinaryConfiguration) -> CreatedBinary: entry_point: Optional[str] if config.entry_point.value is not None: entry_point = config.entry_point.value else: source_files = await Get[SourceFiles](AllSourceFilesRequest( [config.sources], strip_source_roots=True)) # NB: `PythonBinarySources` enforces that we have 0-1 sources. if len(source_files.files) == 1: module_name = source_files.files[0] entry_point = PythonBinary.translate_source_path_to_py_module_specifier( module_name) else: entry_point = None output_filename = f"{config.address.target_name}.pex" two_step_pex = await Get[TwoStepPex](TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=Addresses([config.address]), entry_point=entry_point, platforms=PexPlatforms.create_from_platforms_field( config.platforms), output_filename=output_filename, additional_args=config.generate_additional_args(), ))) pex = two_step_pex.pex return CreatedBinary(digest=pex.directory_digest, binary_name=pex.output_filename)
async def run_python_repl(repl: PythonRepl) -> ReplBinary: addresses = Addresses(tgt.address for tgt in repl.targets) two_step_pex = await Get[TwoStepPex]( TwoStepPexFromTargetsRequest( PexFromTargetsRequest(addresses=addresses, output_filename="python-repl.pex",) ) ) repl_pex = two_step_pex.pex return ReplBinary(digest=repl_pex.digest, binary_name=repl_pex.output_filename)
async def create_python_awslambda( field_set: PythonAwsLambdaFieldSet, lambdex_setup: LambdexSetup) -> CreatedAWSLambda: # Lambdas typically use the .zip suffix, so we use that instead of .pex. pex_filename = f"{field_set.address.target_name}.zip" # We hardcode the platform value to the appropriate one for each AWS Lambda runtime. # (Running the "hello world" lambda in the example code will report the platform, and can be # used to verify correctness of these platform strings.) py_major, py_minor = field_set.runtime.to_interpreter_version() platform = f"linux_x86_64-cp-{py_major}{py_minor}-cp{py_major}{py_minor}" # set pymalloc ABI flag - this was removed in python 3.8 https://bugs.python.org/issue36707 if py_major <= 3 and py_minor < 8: platform += "m" if (py_major, py_minor) == (2, 7): platform += "u" pex_request = TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=[field_set.address], internal_only=False, entry_point=None, output_filename=pex_filename, platforms=PexPlatforms([platform]), additional_args=[ # Ensure we can resolve manylinux wheels in addition to any AMI-specific wheels. "--manylinux=manylinux2014", # When we're executing Pex on Linux, allow a local interpreter to be resolved if # available and matching the AMI platform. "--resolve-local-platforms", ], )) pex_result = await Get(TwoStepPex, TwoStepPexFromTargetsRequest, pex_request) input_digest = await Get( Digest, MergeDigests( (pex_result.pex.digest, lambdex_setup.requirements_pex.digest))) # NB: Lambdex modifies its input pex in-place, so the input file is also the output file. result = await Get( ProcessResult, PexProcess( lambdex_setup.requirements_pex, argv=("build", "-e", field_set.handler.value, pex_filename), input_digest=input_digest, output_files=(pex_filename, ), description=f"Setting up handler in {pex_filename}", ), ) return CreatedAWSLambda( digest=result.output_digest, zip_file_relpath=pex_filename, runtime=field_set.runtime.value, # The AWS-facing handler function is always lambdex_handler.handler, which is the wrapper # injected by lambdex that manages invocation of the actual handler. handler="lambdex_handler.handler", )
async def run_ipython_repl(repl: IPythonRepl, ipython: IPython) -> ReplBinary: addresses = Addresses(tgt.address for tgt in repl.targets) two_step_pex = await Get[TwoStepPex](TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=addresses, output_filename="ipython-repl.pex", entry_point=ipython.get_entry_point(), additional_requirements=ipython.get_requirement_specs(), ))) repl_pex = two_step_pex.pex return ReplBinary(digest=repl_pex.digest, binary_name=repl_pex.output_filename)
async def create_python_awslambda( field_set: PythonAwsLambdaFieldSet, lambdex_setup: LambdexSetup, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, ) -> CreatedAWSLambda: # Lambdas typically use the .zip suffix, so we use that instead of .pex. pex_filename = f"{field_set.address.target_name}.zip" # We hardcode the platform value to the appropriate one for each AWS Lambda runtime. # (Running the "hello world" lambda in the example code will report the platform, and can be # used to verify correctness of these platform strings.) py_major, py_minor = field_set.runtime.to_interpreter_version() platform = f"manylinux2014_x86_64-cp-{py_major}{py_minor}-cp{py_major}{py_minor}" # set pymalloc ABI flag - this was removed in python 3.8 https://bugs.python.org/issue36707 if py_major <= 3 and py_minor < 8: platform += "m" if (py_major, py_minor) == (2, 7): platform += "u" pex_request = TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=Addresses([field_set.address]), entry_point=None, output_filename=pex_filename, platforms=PexPlatforms([platform]), )) pex_result = await Get[TwoStepPex](TwoStepPexFromTargetsRequest, pex_request) input_digest = await Get[Digest](MergeDigests( (pex_result.pex.digest, lambdex_setup.requirements_pex.digest))) # NB: Lambdex modifies its input pex in-place, so the input file is also the output file. lambdex_args = ("build", "-e", field_set.handler.value, pex_filename) process = lambdex_setup.requirements_pex.create_process( python_setup=python_setup, subprocess_encoding_environment=subprocess_encoding_environment, pex_path="./lambdex.pex", pex_args=lambdex_args, input_digest=input_digest, output_files=(pex_filename, ), description=f"Setting up handler in {pex_filename}", ) result = await Get[ProcessResult](Process, process) # Note that the AWS-facing handler function is always lambdex_handler.handler, which # is the wrapper injected by lambdex that manages invocation of the actual handler. return CreatedAWSLambda( digest=result.output_digest, name=pex_filename, runtime=field_set.runtime.value, handler="lambdex_handler.handler", )
async def create_python_binary( field_set: PythonBinaryFieldSet) -> CreatedBinary: entry_point = field_set.entry_point.value if entry_point is None: source_files = await Get[SourceFiles](AllSourceFilesRequest( [field_set.sources], strip_source_roots=True)) entry_point = PythonBinarySources.translate_source_file_to_entry_point( source_files.files) output_filename = f"{field_set.address.target_name}.pex" two_step_pex = await Get[TwoStepPex](TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=Addresses([field_set.address]), entry_point=entry_point, platforms=PexPlatforms.create_from_platforms_field( field_set.platforms), output_filename=output_filename, additional_args=field_set.generate_additional_args(), ))) pex = two_step_pex.pex return CreatedBinary(digest=pex.digest, binary_name=pex.output_filename)
async def create_python_awslambda( config: PythonAwsLambdaConfiguration, lambdex_setup: LambdexSetup, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment, ) -> CreatedAWSLambda: # TODO: We must enforce that everything is built for Linux, no matter the local platform. pex_filename = f"{config.address.target_name}.pex" pex_request = TwoStepPexFromTargetsRequest( PexFromTargetsRequest( addresses=Addresses([config.address]), entry_point=None, output_filename=pex_filename, )) pex_result = await Get[TwoStepPex](TwoStepPexFromTargetsRequest, pex_request) merged_input_files = await Get[Digest](DirectoriesToMerge(directories=( pex_result.pex.directory_digest, lambdex_setup.requirements_pex.directory_digest, ))) # NB: Lambdex modifies its input pex in-place, so the input file is also the output file. lambdex_args = ("build", "-e", config.handler.value, pex_filename) process_request = lambdex_setup.requirements_pex.create_execute_request( python_setup=python_setup, subprocess_encoding_environment=subprocess_encoding_environment, pex_path="./lambdex.pex", pex_args=lambdex_args, input_files=merged_input_files, output_files=(pex_filename, ), description=f"Run Lambdex for {config.address.reference()}", ) result = await Get[ExecuteProcessResult](ExecuteProcessRequest, process_request) return CreatedAWSLambda(digest=result.output_directory_digest, name=pex_filename)