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

MyPy Fixes for Worker, Workflow metaclass, Context, and some others #273

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

hatchet-temporary
Copy link
Contributor

@hatchet-temporary hatchet-temporary commented Nov 28, 2024

A couple things here:

  • AFAICT, Worker doesn't need to be a dataclass, and this was making things a bit more complicated (b/c of post_init, etc.)
  • Added hatchet_sdk/worker/worker.py to the included MyPy paths and fixed all the type hints (except for a couple tricky ones with the WorkflowMeta metaclass - we can handle those later
  • Replaced some dynamically set attributes with setattr to make the type checker happy
  • Added a Protocol for the WorkflowMeta metaclass for the same reason
  • Fixes for Workflow metaclass and Context

Will try to annotate!



@dataclass
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if I'm wrong on this and this should be a dataclass!

@hatchet-temporary hatchet-temporary marked this pull request as ready for review November 28, 2024 15:09
* feat: fix mypy for Workflow

* fix: type stub

* fix: remove any in a couple places

* fix: attempting using `Union`

* fix: try with `.Value`

* fix: name attr

* fix: remove more type: ignore

* MyPy for Context, etc. (#276)

* fix: types for config, etc.

* fix: queue type hint

* fix: typeddict items
@hatchet-temporary hatchet-temporary changed the title MyPy Fixes for Worker MyPy Fixes for Worker, Workflow metaclass, Context, and some others Nov 29, 2024
@@ -54,7 +63,7 @@ def _prepare_workflow_options(
if options is not None and "additional_metadata" in options:
meta = options["additional_metadata"]

trigger_options: TriggerWorkflowOptions = {
trigger_options: TriggerWorkflowOptions = { # type: ignore[typeddict-item]
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 here because namespace isn't set - if we do set it, it causes problems downstream. I think Pydantic here would be helpful instead of using typed dicts

for child_workflow_run in child_workflow_runs:
workflow_name = child_workflow_run["workflow_name"]
input = child_workflow_run["input"]

key = child_workflow_run.get("key")
options = child_workflow_run.get("options", {})

trigger_options = self._prepare_workflow_options(key, options, worker_id)
## TODO: figure out why this is failing
trigger_options = self._prepare_workflow_options(key, options, worker_id) # type: ignore[arg-type]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

weird type error here on the options that I'll figure out later

Comment on lines -86 to +91
## TODO: Use Protocol here to help with MyPy errors
func._step_name = name.lower() or str(func.__name__).lower() # type: ignore[attr-defined]
func._step_parents = parents # type: ignore[attr-defined]
func._step_timeout = timeout # type: ignore[attr-defined]
func._step_retries = retries # type: ignore[attr-defined]
func._step_rate_limits = limits # type: ignore[attr-defined]
func._step_name = name.lower() or str(func.__name__).lower()
func._step_parents = parents
func._step_timeout = timeout
func._step_retries = retries
func._step_rate_limits = limits
Copy link
Contributor Author

Choose a reason for hiding this comment

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

using the protocol lets us get rid of all of these type issues

config: ClientConfig = {},
config: ClientConfig = ClientConfig(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

pretty sure this default ended up being overridden downstream, but just checking the dictionary was the wrong type

def thread_action_func(self, context, action_func, action: Action):
## TODO: Stricter type hinting here
def thread_action_func(
self, context: Context, action_func: Callable[..., Any], action: Action
Copy link
Contributor Author

Choose a reason for hiding this comment

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

one note for the future - it'd be awesome to make this action_func conform to something stricter than just Callable[..., Any], but we can address that later I think

@@ -267,7 +277,7 @@ def cleanup_run_id(self, run_id: str):
def create_context(
self, action: Action, action_func: Callable[..., Any] | None
) -> Context | DurableContext:
if hasattr(action_func, "durable") and action_func.durable:
if hasattr(action_func, "durable") and getattr(action_func, "durable"):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

escape hatch

"""Terminate a python threading.Thread."""
try:
if not thread.is_alive():
return

logger.info(f"Forcefully terminating thread {thread.ident}")
ident = cast(int, thread.ident)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

according to the package docs, this is always an int. but according to their type hints, it's not 🤷 going with what the docs say and casting here, but lmk if this could ever be None

Copy link
Contributor

Choose a reason for hiding this comment

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

no idea, I've only ever seen int

Comment on lines -95 to +119
action_function.is_coroutine = True
setattr(action_function, "is_coroutine", True)
else:
action_function.is_coroutine = False
setattr(action_function, "is_coroutine", False)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

escape hatch for now - I think we can probably define another Protocol for the action_func, but will do that later

Comment on lines -45 to -49
steps: stepsType = [
(getattr(func, "_step_name"), attrs.pop(func_name))
for func_name, func in list(attrs.items())
if hasattr(func, "_step_name")
]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

factored out into a helper

Comment on lines +1 to +3
poetry run black . --color
poetry run isort .
poetry run mypy --config-file=pyproject.toml
Copy link
Contributor Author

Choose a reason for hiding this comment

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

modified this to run the linters on all the files, since it only takes a couple seconds

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