Hi all, I'm beginning the journey into writing my ...
# plugins
f
Hi all, I'm beginning the journey into writing my first pants plugin. I'm looking to create a custom
python_sources
-like target, with some additional custom fields, and with a hardcoded
resolve
, non-overridable value. I've set up a custom target class which uses the
python_sources
target's fields, but hardcodes the
resolve
field. When I run
pants check pants-plugins/my_plugin::
, I get the following error indicating that pants is not distinguishing between my custom target, and the regular
python_sources
target. Is there a way to avoid this situation? In other words, how can I define my target so pants knows the difference between it and the python_sources target?
Copy code
InvalidFieldChoiceException: Values for the 'resolve' field in target pants-plugins/my_plugin#__defaults__ must be one of ["hardcoded-resolve-value"], but "my_plugin" was provided.
the custom target I wrote is following the recommended pattern here (see the django code example in that link), where I rely on the field definitions, rather than strictly subclassing. My custom target class looks like:
Copy code
class MyCustomTarget(Target):
    alias = "my_custom_target"
    core_fields = (
        *(FrozenOrderedSet(PythonSourcesGeneratorTarget.core_fields) - {PythonResolveField}),
        MyHardcodedResolveField,
        SomeOtherCustomField,
    )
and my custom resolve field looks like:
Copy code
class MyHardcodedResolveField(PythonResolveField):
    default = "hardcoded-resolve-value"
    valid_choices = ("hardcoded-resolve-value,)
w
Can you show the example usage of it?
You're also using the PythonSourcesGeneratorTarget there - but wouldn’t you want to use the singular target version?
f
So my intent is for my target to offer similar functionality as the
python_sources
target, but with some additional, non-python files attached as
extra_sources
. (Concretely, but likely way too in the weeds answer: I'm trying to define a custom target which will define an Airflow dag bundle, which is basically a collection of python files along with peripheral non-python/non-resource files). I'm defining this target in a multi-resolve mono-repo, and we only allow for Airflow code to run within a dedicated resolve, hence the need for hardcoding and validating the resolve value.
w
Ah, okay, I just mean, if you make a single target, and then turn that into a generator
Also, just quick question..... Could a macro suffice? Super easy to make/maintain
f
> If you make a single target, and turn that into a generator Ah I see now. Is that the recommended approach when dealing with a "plural" target? I wasn't seeing examples of that in the plugins docs, so I didn't know if that was an internal pattern. > Could a macro suffice? So I was hoping a macro would suffice, but in my initial attempt I found that wasn't expressive enough for our needs. Basically (again, without getting into the weeds) airflow has an extremely unusual source root(s) setup where basically the core airflow pythonpath is distinct and unique from a dag bundle, and we will have dag files scattered across arbitrary directories.
w
Ah I see now. Is that the recommended approach when dealing with a "plural" target? I wasn't seeing examples of that in the plugins docs, so I didn't know if that was an internal pattern.
That's the one I've seen/used myself. But that doesn't mean much other than I likely cargo culted it
we will have dag files scattered across arbitrary directories
Ah, got it. There are ways to do work recursively, but maybe a plugin isn't the worst idea, given that it feels like there will be "more" to do once you get this out of the way
gratitude thank you 1
f
Yeah, I think I'm bound for the plugin approach given the need for some non-standard sources gathering logic.
As a more general question: Is there any reason not to subclass an existing pants target class for a custom target, rather than copying a subset of the
core_fields
of the existing target (like this doc section recommends)? I'd like to create a target that is very nearly the same as pants'
PythonSourceTarget
, but with some custom dependency gathering logic along with extra fields, and some hardcoded core fields. To me it seems subclassing is the cleaner, clearer approach.
w
Cleanliness and clarity isnt something we can chime in on for your domain. Idiomatic plugin usage recommends field composition over target inheritance, so expect that to be the best supported plugin-implementation from newer versions of pants when you upgrade!
👍 1
f
Ok, after digging through a lot more source code examples and re-reading the docs a few more times, it "clicked" for me why the field-based approach is desirable. Thanks!