IS there access to Python built ins in pants macro...
# general
p
IS there access to Python built ins in pants macros, or would I need to create a plugin for that?
For example, I want to do something like this:
Copy code
def myorg_docker_image(**kwargs):
   # If someone specifies a source and does not embed instructions into BUILD file, fail fast
   if kwargs['source'] or not kwargs['instructions']:
       raise ValueError("Cannot use Dockerfiles")
    if not are_dependencies_encoded_in_instructions(kwargs['instructions']):
        raise ValueError("Must encode dependencies of docker image into instructions kwarg")
    docker_image(**kwargs)
w
unfortunately, raising exceptions isn’t currently supported, although it really should be: https://github.com/pantsbuild/pants/issues/15420
b
That issue is on my shortlist to look into
w
in the meantime, you could define an
object
which raises the relevant exception type… trying to find an example
@bitter-ability-32190: yea, that would be helpful.
p
I guess in a broader sense then, what capabilities do I have in a macro? Can I define functions? Access python built-ins? Or is what I'm trying to do in the realm of "extending an existing target via a plugin" rather than "write a macro"
w
the example you’ve given should definitely be in scope for a macro: it’s an oversight that you can’t raise exceptions… the builtins in scope are intentionally quite limited, but we should definitely punch holes through for this kind of case.
p
Can I make the target fail in some other way then?
e
Does
--build-file-prelude-globs
with a file that just does `from builtins import *`work?
w
so: here is an example of defining an `object`: https://github.com/pantsbuild/pants/blob/9ca84b5eb6ff66e224ee4f4e0a5a7aec0c922843/src/python/pants/backend/python/register.py#L57-L58 … the alias you give will be in scope in all
BUILD
files. so as a workaround for https://github.com/pantsbuild/pants/issues/15420, you could define an
object
for an exception type
@enough-analyst-54434: i don’t think so, because
import
is banned
e
Even in a prelude?!
w
maybe not... i don’t see enforcement there.
p
Just tried
from builtins import *
and it doesn't appear to work. Little confused by the example (first foray into customizing pants) but I'll see if I can poke at it for a bit and make something work
w
does the
objects
example make sense? it would involve creating a very tiny plugin, with a
register.py
file. see https://www.pantsbuild.org/docs/plugins-overview#enabling-plugins-with-registerpy (in particular, the second tab in that code block), and defining a
def build_file_aliases
function in it.
e
Don't try this at home:
Copy code
$ cat expose-builtins 
exec(f"from builtins {'IMPORT'.lower()} *")

$ cat macro-uses-builtins 
def foo(name=None):
  if not name:
     raise Exception("A name is required.")
  python_sources(name=name)
   
$ cat BUILD.example 
foo(name="jake")
foo()

$ ./pants --build-file-prelude-globs='*-builtins' list :
15:12:53.20 [ERROR] 1 Exception encountered:

Engine traceback:
  in select
  in pants.backend.project_info.list_targets.list_targets
  in pants.engine.internals.specs_rules.resolve_addresses_from_specs
  in pants.engine.internals.specs_rules.resolve_addresses_from_raw_specs
  in pants.engine.internals.specs_rules.addresses_from_raw_specs_without_file_owners
  in pants.engine.internals.build_files.ensure_address_family ()
  in pants.engine.internals.build_files.parse_address_family ()
Traceback (most recent call last):
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/mapper.py", line 47, in parse
    target_adaptors = parser.parse(filepath, build_file_content, extra_symbols, defaults)
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/parser.py", line 167, in parse
    exec(build_file_content, global_symbols)
  File "<string>", line 2, in <module>
  File "macro-uses-builtins", line 3, in foo
    raise Exception("A name is required.")
Exception: A name is required.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/selectors.py", line 705, in native_engine_generator_send
    res = func.send(arg)
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/build_files.py", line 181, in parse_address_family
    for fc in digest_contents
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/build_files.py", line 181, in <listcomp>
    for fc in digest_contents
  File "/home/jsirois/dev/pantsbuild/pants/src/python/pants/engine/internals/mapper.py", line 49, in parse
    raise MappingError(f"Failed to parse ./{filepath}:\n{e}")
pants.base.exceptions.MappingError: Failed to parse ./BUILD.example:
A name is required.
😵 1
p
Ah, just got it to work! THanks for the help here, the example does make sense. I had some files in the wrong place for a minute but just got it all sorted
e
So tis is nasty, but backwards compatible. When we support builtins, just remove the
expose-builtins
thing.
Also, you'll want to ensure that is the 1st prelude glob. It must be parsed before those others that will use it.
I think.
I guess not if the raises are all inside functions.
p
The tiny plugin approach seems cleaner and is working at this point so I'm gonna head down that road, but thanks for showing me this neat workaround.
New question: With this tiny plugin approach and in macros, how do I get access to config file options?
w
unfortunately, consuming options currently requires a
@rule
. we definitely need to clean up the boundary between
macros
and
@rules
before stabilizing the plugin API.
are you trying to consume global options, or new options that you have declared?
p
Global options, but that answers my question. Looks like you need to "request" the options before you can use then, which you can only do from a
rule
?
w
that’s right. which is because when options values change,
@rules
are invalidated. and the synchronous API of macros doesn’t have a way to declare its dependencies (…and thus isn’t allowed to have dependencies currently)
p
Gotcha, that makes sense. I have a quick hack in place with a value hardcoded just to demonstrate my point for a POC I'm working on, so I'm good for now. If we make it through the POC with pants I'll revisit this in the future. Thanks for your help with this!
w
sure thing. thanks for the patience. i’ll make sure we have a bug filed for the options-access aspect of this.