Q about the Pants codebase - is it possible to inv...
# development
b
Q about the Pants codebase - is it possible to invoke rules directly within a
classmethod
/
classproperty
? I know https://github.com/pantsbuild/pants/issues/19730 is ongoing, but I was trying to invoke an async rule inside a
classproperty
which doesn’t seem to happen anywhere else in the codebase.
I guess on a related note, is there a good way to invoke async rules from sync code in the Pants codebase? What I’m looking to do is parse a PEX lockfile inside a classmethod; there’s already a rule for this here but it seems challenging to invoke this from a synchronous classmethod and the method I’m creating would be invoked async
h
rules are expected to be invoked by the engine, with caching and concurrency etc.
So generally no
👍 1
And you wouldn't get all the context, the Params injection, etc
What is the use case for doing this in a classmethod?
b
I’m working on this issue: https://github.com/pantsbuild/pants/issues/20722 and the context for the classmethod is this: > Suggestion: have
PythonToolRequirementsBase
dynamically argument the subsystem’s help text by reading the lockfile. So what I was planning to do is create a classmethod on `PythonToolRequirementsBase`called
help_extended
that contains the version read from the lockfile.
b
Can we manage without a rule here? Potentially read the file with
open
and manually parse "just enough" of the PEX json to extract the info required?
(Thanks for taking on that issue, btw 👍 )
b
Yeah, that's what I did as a backup
👍 1
But it felt really stupid because there was already code to parse the lockfile elsewhere, so I figured it would be better to reuse it if possible
👍 1
h
I guess you can always refactor the code so that the interesting bit is available outside the rule?
b
It’s slightly tricky because the calls to rules are interleaved into the rest of the code, so I ended up just making a separate function instead. Original code:
Copy code
parts = urlparse(lockfile.url)
    # urlparse retains the leading / in URLs with a netloc.
    lockfile_path = parts.path[1:] if parts.path.startswith("/") else parts.path
    if parts.scheme in {"", "file"}:
        synthetic_lock = False
        lockfile_digest = await Get(
            Digest,
            PathGlobs(
                [lockfile_path],
                glob_match_error_behavior=GlobMatchErrorBehavior.error,
                description_of_origin=lockfile.url_description_of_origin,
            ),
        )
        _digest_contents = await Get(DigestContents, Digest, lockfile_digest)
        lock_bytes = _digest_contents[0].content
    elif parts.scheme == "resource":
        synthetic_lock = True
        _fc = FileContent(
            lockfile_path,
            # The "netloc" in our made-up "resource://" scheme is the package.
            importlib.resources.read_binary(parts.netloc, lockfile_path),
        )
        lockfile_path, lock_bytes = (_fc.path, _fc.content)
        lockfile_digest = await Get(Digest, CreateDigest([_fc]))
    else:
        raise ValueError(
            f"Unsupported scheme {parts.scheme} for lockfile URL: {lockfile.url} "
            f"(origin: {lockfile.url_description_of_origin})"
        )
New code:
Copy code
lockfile = cls.pex_requirements_for_default_lockfile()
        parts = urlparse(lockfile.url)
        # urlparse retains the leading / in URLs with a netloc.
        lockfile_path = parts.path[1:] if parts.path.startswith("/") else parts.path
        if parts.scheme in {"", "file"}:
            with open(lockfile_path, "rb") as fp:
                lock_bytes = fp.read()
        elif parts.scheme == "resource":
            _fc = FileContent(
                lockfile_path,
                # The "netloc" in our made-up "resource://" scheme is the package.
                importlib.resources.read_binary(parts.netloc, lockfile_path),
            )
            lockfile_path, lock_bytes = (_fc.path, _fc.content)
        else:
            raise ValueError(
                f"Unsupported scheme {parts.scheme} for lockfile URL: {lockfile.url} "
                f"(origin: {lockfile.url_description_of_origin})"
            )