Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: In target adaptors, populate attributes with a None value #7680

Conversation

Eric-Arellano
Copy link
Contributor

Problem

Certain attributes default to None, such as PythonTarget's compatibility defaulting to None:

def __init__(self,
address=None,
payload=None,
sources=None,
provides=None,
compatibility=None,

In the case of target adaptors, such as a PythonTarget, if the BUILD entry does not provide an explicit value for a field like compatibility, then the target adaptor will simply not have that attribute defined, as opposed to having it with None as a value.

This became an issue when working on #7679. There, we are trying to call PythonSetup.compatibility_or_constraints(hydrated_target.adaptor). This function expects the passed object to have .compatibility defined, or else it will raise an AttributeError. However, the value does not need to have a non-None value; in fact, a value of None is meaningful and means that the global constraints should be used. So, if we were to filter out the hydrated targets to only call the function on targets with .compatibility set to non-None, then we would never be considering the global interpreter constraints.

Solution

First, we must modify the engine initializer to identify and populate attributes that are not defined in the BUILD entry but who have a None value in the corresponding target class. TODO.

Second, we must modify the create() function to not filter out attributes with None.

@Eric-Arellano
Copy link
Contributor Author

Help much appreciated here.

First off, is this solution correct to aim for?

Second, any recommendations on how to go about implementing this? Here’s where I got in my investigation:
TargetAdaptor and its base classes StructWithDeps and Struct populate their kwargs() values in the __init__() function via **kwargs.

def __init__(self, abstract=False, extends=None, merges=None, type_alias=None, **kwargs):

• The Parser somehow gets kwargs passed to itself, then passes them to the init function of pants.init.engine_initializer._make_target_adaptor.<locals>.GlobsHandlingTargetAdaptor.
obj = self._object_type(**kwargs)

@stuhood stuhood requested a review from jsirois May 8, 2019 14:45
@stuhood
Copy link
Member

stuhood commented May 8, 2019

Adding @jsirois, who added the Struct API at the beginning of the v2 engine experiments.

I'll take a look in an hour or two.

@Eric-Arellano
Copy link
Contributor Author

@illicitonion and I have been discussing this extensively over Slack, but would love further feedback.

We proposed four ways to populate None attributes in target adaptors:

  1. When we make the TargetAdaptor, do some funky reflection on PythonTarget to set the default values of non-specified fields.
  2. Where we created the merged TargetAdaptor and HydratedTarget, do something similar.
  3. After the adaptor is created, provide a mechanism for casting a HydratedTarget to the relevant Target, e.g. yield Get(PythonTarget, adaptor).
    • Daniel thinks this might mean you could change your rule to take a PythonTarget instead of a HydratedTarget and it maybe would just work.
  4. Rewrite the users of the target adaptor to either populate the requested value onsite or to not expect it.
    • For example, have PythonSetup.compatibility_or_constraints first check via hasattr that compatibility is defined, or have python_test_runner.py somehow add the field to TargetAdaptor.kwargs before calling PythonSetup.compatibility_or_constraints.

We rejected #4 outright for being a leaky abstraction. We should not have to rewrite our Subsystem code etc.

For #1 and #2, I think there is value in by default having all TargetAdaptors including the None attributes for their target, as this would make it fluent for developers to work with targets in V2 world without any cognitive overhead. However, this feels magical and is probably overkill for now.

Instead, we are thinking #3 is the best solution for now. We can start by implementing #3, and then down the road we can decide let's just merge this into either #1 or #2 to automatically define None attributes.

--

So, if you all agree with those decisions, the question becomes how to implement #3.

Daniel pointed to #7661 as being highly relevant. We'd be introducing a "Target Union".

Eric-Arellano added a commit that referenced this pull request May 9, 2019
…ibility` value rather than a `PythonTarget`(#7691)

### Problem
Our V2 Target API is not fully implemented, including that we do not populate in target adaptors attributes with a default value of `None` (#7680). This limitation resulted in https://github.com/pantsbuild/pants/pull/7679/files#diff-04a0048c70898e46a42c73225c47b906R58 having to monkey patch the `.compatibility` field for the target adaptors to get `PythonSetup.interpreter_or_constraints()` to not raise an `AttributeError`.

While the underlying issue could be resolved with changing the V2 Target API, we can work around this by changing `PythonSetup.interpreter_or_constraints()` to no longer require a `Target` but rather just its `.compatibility` field.

### Solution
Change `PythonSetup.interpreter_or_constraints()` to have a more direct API of expecting the `compatibility` field itself.

#### Not using a deprecation
Neither this function nor its class `PythonSetup` have a public API. Per our deprecation policy, and confirmed via Slack, it was decided that we do not need a deprecation cycle for this change.

### Result
#7680 is unblocked.

Regardless of V2, this is also arguably a better API to only request as a parameter the field we actually need. For example, this makes testing easier because we no longer would need to create a fake `PythonTarget`.
@Eric-Arellano
Copy link
Contributor Author

Closing because I do not plan to finish this PR anytime soon. The underlying motivation still exists, however.

@Eric-Arellano Eric-Arellano deleted the target-adaptor-none-values branch May 21, 2019 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants