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

Remove native.py and properly type check scheduler.py #11706

Merged
merged 3 commits into from
Mar 16, 2021

Conversation

Eric-Arellano
Copy link
Contributor

Now that we use CPython instead of CFFI, there is no need for native.py - it was unnecessary boilerplate.

This also fixes the type hints related to native_engine.so and scheduler.py. Before, there was too much boilerplate to justify it, but now things are fully typed.

[ci skip-build-wheels]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Copy link
Contributor Author

@Eric-Arellano Eric-Arellano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pardon the size of the diff. Lmk if you'd like me to split it out into some precursors.

Comment on lines -28 to +27
class DaemonPantsRunner(RawFdRunner):
class DaemonPantsRunner:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RawFdRunner is a Protocol, which means you do not need to subclass it. MyPy only checks that the required interface is implemented.

EMPTY_DIGEST = Digest(fingerprint=_EMPTY_FINGERPRINT, serialized_bytes_length=0)
EMPTY_DIGEST: Digest = Digest(fingerprint=_EMPTY_FINGERPRINT, serialized_bytes_length=0)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why MyPy wanted me to do this. It complained in a callsite that it couldn't figure out the type for EMPTY_DIGEST.

Comment on lines -82 to +176
def __init__(self, **kwargs: Any) -> None: ...
pass
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't implement __new__ in interface.rs, so this type hint was a lie.

@@ -155,19 +156,47 @@ def __init__(
interactive_process_result=InteractiveProcessResult,
engine_aware_parameter=EngineAwareParameter,
)
remoting_options = PyRemotingOptions(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is copy and pasted from native.py, no changes made.

executor=executor,
execution_options=execution_options,
types=types,
self._py_scheduler = native_engine.scheduler_create(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the rename from ._scheduler to ._py_scheduler, which clears up one of my biggest confusions: what did Scheduler._scheduler mean?

Comment on lines -329 to +314
self._session = session
self._py_session = session
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note this change.

Comment on lines -348 to -357
def new_run_id(self):
"""Assigns a new "run id" to this Session, without creating a new Session.

Usually each Session corresponds to one end user "run", but there are exceptions: notably,
the `--loop` feature uses one Session, but would like to observe new values for uncacheable
nodes in each iteration of its loop.
"""
self._scheduler._native.lib.session_new_run_id(self._session)

def set_per_session(self):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

set_per_session() was unused and duplicated new_run_id(). Deleted.

Comment on lines -424 to -425
def node_count(self):
return self._scheduler.graph_len()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused. The only caller was internal to this class, and we can call self._scheduler.graph_len() directly.

Comment on lines -462 to -463
returns = tuple((root, state) for root, state in roots if type(state) is Return)
throws = tuple((root, state) for root, state in roots if type(state) is Throw)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MyPy didn't like that type check. Replaced with isinstance().

logger.debug(
"computed %s nodes in %f seconds. there are %s total nodes.",
len(roots),
time.time() - start_time,
self._scheduler.graph_len(),
)

returns = tuple((root, state) for root, state in roots if type(state) is Return)
throws = tuple((root, state) for root, state in roots if type(state) is Throw)
return cast(Tuple[Tuple[Return, ...], Tuple[Throw, ...]], (returns, throws))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return type was wrong. The method signature is now correct, and MyPy was able to figure it out :)

Copy link
Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff! Thanks!

Comment on lines -28 to +27
class DaemonPantsRunner(RawFdRunner):
class DaemonPantsRunner:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is the only actual usage of the RawFdRunner type: would be good to add it back to signal that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two reasons I don't think we should not do that:

  1. Now that the protocol is defined in native_engine.pyi, we can't import it. I couldn't think of a good spot to define that protocol in a .py file.
  2. It was an abuse of Protocol. You should not subclass Protocol, and in fact, doing so was hiding a deviation from our expected API that the protocol said stdin_fd instead of stdin_fileno.

Comment on lines 251 to 252
# NB: Watchman no longer triggers events when children are created/deleted under a
# directory, so we always need to invalidate the direct parent as well.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reference to watchman is, but the logic we implement to invalidate the parent directory may or may not be. We avoided changing "what" we invalidate when we switched from watchman to the notify crate, but we probably have better precision now, and could invalidate fewer things without affecting correctness.

Opened #11707

# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@Eric-Arellano Eric-Arellano merged commit 64a69b8 into pantsbuild:master Mar 16, 2021
@Eric-Arellano Eric-Arellano deleted the native-lib branch March 16, 2021 19:37
@benjyw benjyw mentioned this pull request Mar 20, 2021
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