def create_from_adaptors( cls, adaptors: Tuple[PythonTargetAdaptor, ...], python_setup: PythonSetup) -> 'PexInterpreterContraints': interpreter_constraints = frozenset( constraint for target_adaptor in adaptors for constraint in python_setup.compatibility_or_constraints( getattr(target_adaptor, 'compatibility', None))) return PexInterpreterContraints(constraint_set=interpreter_constraints)
def create_from_adaptors(cls, adaptors: Iterable[PythonTargetAdaptor], python_setup: PythonSetup) -> 'PexInterpreterConstraints': interpreter_constraints = { constraint for target_adaptor in adaptors for constraint in python_setup.compatibility_or_constraints( getattr(target_adaptor, 'compatibility', None) ) } return PexInterpreterConstraints(constraint_set=tuple(sorted(interpreter_constraints)))
def run_python_test( test_target: PythonTestsAdaptor, pytest: PyTest, python_setup: PythonSetup, subprocess_encoding_environment: SubprocessEncodingEnvironment ) -> TestResult: """Runs pytest for one target.""" # TODO(7726): replace this with a proper API to get the `closure` for a # TransitiveHydratedTarget. transitive_hydrated_targets = yield Get( TransitiveHydratedTargets, BuildFileAddresses((test_target.address, ))) all_targets = transitive_hydrated_targets.closure interpreter_constraints = { constraint for target_adaptor in all_targets for constraint in python_setup.compatibility_or_constraints( getattr(target_adaptor, 'compatibility', None)) } # Produce a pex containing pytest and all transitive 3rdparty requirements. output_pytest_requirements_pex_filename = 'pytest-with-requirements.pex' all_target_requirements = [] for t in all_targets: maybe_python_req_lib = t.adaptor # This is a python_requirement()-like target. if hasattr(maybe_python_req_lib, 'requirement'): all_target_requirements.append( str(maybe_python_req_lib.requirement)) # This is a python_requirement_library()-like target. if hasattr(maybe_python_req_lib, 'requirements'): for py_req in maybe_python_req_lib.requirements: all_target_requirements.append(str(py_req.requirement)) all_requirements = all_target_requirements + list( pytest.get_requirement_strings()) resolved_requirements_pex = yield Get( Pex, CreatePex( output_filename=output_pytest_requirements_pex_filename, requirements=tuple(sorted(all_requirements)), interpreter_constraints=tuple(sorted(interpreter_constraints)), entry_point="pytest:main", )) # Get the file names for the test_target, adjusted for the source root. This allows us to # specify to Pytest which files to test and thus to avoid the test auto-discovery defined by # https://pytest.org/en/latest/goodpractices.html#test-discovery. In addition to a performance # optimization, this ensures that any transitive sources, such as a test project file named # test_fail.py, do not unintentionally end up being run as tests. source_root_stripped_test_target_sources = yield Get( SourceRootStrippedSources, Address, test_target.address.to_address()) source_root_stripped_sources = yield [ Get(SourceRootStrippedSources, HydratedTarget, target_adaptor) for target_adaptor in all_targets ] stripped_sources_digests = [ stripped_sources.snapshot.directory_digest for stripped_sources in source_root_stripped_sources ] sources_digest = yield Get( Digest, DirectoriesToMerge(directories=tuple(stripped_sources_digests)), ) inits_digest = yield Get(InjectedInitDigest, Digest, sources_digest) all_input_digests = [ sources_digest, inits_digest.directory_digest, resolved_requirements_pex.directory_digest, ] merged_input_files = yield Get( Digest, DirectoriesToMerge, DirectoriesToMerge(directories=tuple(all_input_digests)), ) test_target_sources_file_names = sorted( source_root_stripped_test_target_sources.snapshot.files) # NB: we use the hardcoded and generic bin name `python`, rather than something dynamic like # `sys.executable`, to ensure that the interpreter may be discovered both locally and in remote # execution (so long as `env` is populated with a `PATH` env var and `python` is discoverable # somewhere on that PATH). This is only used to run the downloaded PEX tool; it is not # necessarily the interpreter that PEX will use to execute the generated .pex file. request = resolved_requirements_pex.create_execute_request( python_setup=python_setup, subprocess_encoding_environment=subprocess_encoding_environment, pex_path=f'./{output_pytest_requirements_pex_filename}', pex_args=test_target_sources_file_names, input_files=merged_input_files, description=f'Run Pytest for {test_target.address.reference()}', ) result = yield Get(FallibleExecuteProcessResult, ExecuteProcessRequest, request) status = Status.SUCCESS if result.exit_code == 0 else Status.FAILURE yield TestResult( status=status, stdout=result.stdout.decode(), stderr=result.stderr.decode(), )