def test_streaming_output_failure() -> None: results = TypecheckResults([TypecheckResult(18, "stdout", "stderr")], typechecker_name="typchecker") assert results.level() == LogLevel.WARN assert results.message() == dedent("""\ failed (exit code 18). stdout stderr """)
def test_streaming_output_success() -> None: results = TypecheckResults([TypecheckResult(0, "stdout", "stderr")], typechecker_name="typchecker") assert results.level() == LogLevel.INFO assert results.message() == dedent("""\ succeeded. stdout stderr """)
async def mypy_typecheck( request: MyPyRequest, mypy: MyPy, python_setup: PythonSetup ) -> TypecheckResults: if mypy.skip: return TypecheckResults([], typechecker_name="MyPy") # We batch targets by their interpreter constraints to ensure, for example, that all Python 2 # targets run together and all Python 3 targets run together. We can only do this by setting # the `--python-version` option, but we allow the user to set it as a safety valve. We warn if # they've set the option. config_files = await Get(ConfigFiles, ConfigFilesRequest, mypy.config_request) config_content = await Get(DigestContents, Digest, config_files.snapshot.digest) python_version_configured = check_and_warn_if_python_version_configured( config=next(iter(config_content), None), args=mypy.args ) # When determining how to batch by interpreter constraints, we must consider the entire # transitive closure to get the final resulting constraints. # TODO(#10863): Improve the performance of this. transitive_targets_per_field_set = await MultiGet( Get(TransitiveTargets, TransitiveTargetsRequest([field_set.address])) for field_set in request.field_sets ) interpreter_constraints_to_transitive_targets = defaultdict(set) for transitive_targets in transitive_targets_per_field_set: interpreter_constraints = PexInterpreterConstraints.create_from_targets( transitive_targets.closure, python_setup ) or PexInterpreterConstraints(mypy.interpreter_constraints) interpreter_constraints_to_transitive_targets[interpreter_constraints].add( transitive_targets ) partitions = [] for interpreter_constraints, all_transitive_targets in sorted( interpreter_constraints_to_transitive_targets.items() ): combined_roots: OrderedSet[Target] = OrderedSet() combined_closure: OrderedSet[Target] = OrderedSet() for transitive_targets in all_transitive_targets: combined_roots.update(transitive_targets.roots) combined_closure.update(transitive_targets.closure) partitions.append( MyPyPartition( FrozenOrderedSet(combined_roots), FrozenOrderedSet(combined_closure), interpreter_constraints, python_version_already_configured=python_version_configured, ) ) partitioned_results = await MultiGet( Get(TypecheckResult, MyPyPartition, partition) for partition in partitions ) return TypecheckResults(partitioned_results, typechecker_name="MyPy")
def typecheck_results(self) -> TypecheckResults: addresses = [config.address for config in self.field_sets] return TypecheckResults( [TypecheckResult( self.exit_code(addresses), "", "", )], typechecker_name=self.typechecker_name, )
def test_streaming_output_partitions() -> None: results = TypecheckResults( [ TypecheckResult(21, "", "", partition_description="ghc8.1"), TypecheckResult( 0, "stdout", "stderr", partition_description="ghc9.2"), ], typechecker_name="typchecker", ) assert results.level() == LogLevel.WARN assert results.message() == dedent("""\ failed (exit code 21). Partition #1 - ghc8.1: Partition #2 - ghc9.2: stdout stderr """)
async def mypy_typecheck(request: MyPyRequest, mypy: MyPy) -> TypecheckResults: if mypy.skip: return TypecheckResults([], typechecker_name="MyPy") transitive_targets = await Get( TransitiveTargets, Addresses(fs.address for fs in request.field_sets)) prepared_sources_request = Get( PythonSourceFiles, PythonSourceFilesRequest(transitive_targets.closure), ) pex_request = Get( Pex, PexRequest( output_filename="mypy.pex", internal_only=True, requirements=PexRequirements(mypy.all_requirements), # NB: This only determines what MyPy is run with. The user can specify what version # their code is with `--python-version`. See # https://mypy.readthedocs.io/en/stable/config_file.html#platform-configuration. We do # not auto-configure this for simplicity and to avoid Pants magically setting values for # users. interpreter_constraints=PexInterpreterConstraints( mypy.interpreter_constraints), entry_point=mypy.entry_point, ), ) config_digest_request = Get( Digest, PathGlobs( globs=[mypy.config] if mypy.config else [], glob_match_error_behavior=GlobMatchErrorBehavior.error, description_of_origin="the option `--mypy-config`", ), ) prepared_sources, pex, config_digest = await MultiGet( prepared_sources_request, pex_request, config_digest_request) srcs_snapshot = prepared_sources.source_files.snapshot file_list_path = "__files.txt" python_files = "\n".join(f for f in srcs_snapshot.files if f.endswith(".py")) file_list_digest = await Get( Digest, CreateDigest([FileContent(file_list_path, python_files.encode())]), ) merged_input_files = await Get( Digest, MergeDigests([ file_list_digest, srcs_snapshot.digest, pex.digest, config_digest ]), ) result = await Get( FallibleProcessResult, PexProcess( pex, argv=generate_args(mypy, file_list_path=file_list_path), input_digest=merged_input_files, extra_env={ "PEX_EXTRA_SYS_PATH": ":".join(prepared_sources.source_roots) }, description= f"Run MyPy on {pluralize(len(srcs_snapshot.files), 'file')}.", level=LogLevel.DEBUG, ), ) return TypecheckResults( [TypecheckResult.from_fallible_process_result(result)], typechecker_name="MyPy")
def typecheck_results(self) -> TypecheckResults: return TypecheckResults([], typechecker_name="SkippedTypechecker")
def test_streaming_output_skip() -> None: results = TypecheckResults([], typechecker_name="typchecker") assert results.level() == LogLevel.DEBUG assert results.message() == "skipped."