From d42d176cea12f46334343ae1d59ddfb167fe50d3 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 29 Nov 2023 13:51:00 +0100 Subject: [PATCH 01/43] Added Logging for Vscode --- src/_pytask/collect.py | 17 +++++++++++++++++ src/_pytask/execute.py | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 1986b794..7c03515d 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -4,9 +4,11 @@ import inspect import itertools import os +import requests import sys import time from pathlib import Path +from threading import Thread from typing import Any from typing import Generator from typing import Iterable @@ -31,6 +33,7 @@ from _pytask.nodes import PathNode from _pytask.nodes import PythonNode from _pytask.nodes import Task +from _pytask.nodes import PTaskWithPath from _pytask.nodes import TaskWithoutPath from _pytask.outcomes import CollectionOutcome from _pytask.outcomes import count_outcomes @@ -468,6 +471,11 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( return id_to_short_id +def send_logging_vscode(url,json,timeout): + try: + requests.post(url,json,timeout) + except requests.Timeout: + pass @hookimpl def pytask_collect_log( @@ -475,6 +483,15 @@ def pytask_collect_log( ) -> None: """Log collection.""" session.collection_end = time.time() + + if session.config['command'] == 'collect': + exitcode = 0 + for report in reports: + if report.outcome == CollectionOutcome.FAIL: + exitcode = 3 + result = [{'name' : task.name.split('/')[-1], 'path' : str(task.path)} if isinstance(task,PTaskWithPath) else {'name' : task.name, 'path' : ''} for task in tasks] + thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + thread.start() console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.") diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index ccc87d66..6418899b 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -4,9 +4,11 @@ import inspect import sys import time +from threading import Thread from typing import Any from typing import TYPE_CHECKING +from _pytask.collect import send_logging_vscode from _pytask.config import hookimpl from _pytask.config import IS_FILE_SYSTEM_CASE_SENSITIVE from _pytask.console import console @@ -35,6 +37,7 @@ from _pytask.outcomes import WouldBeExecuted from _pytask.reports import ExecutionReport from _pytask.traceback import remove_traceback_from_exc_info +from _pytask.traceback import Traceback from _pytask.tree_util import tree_leaves from _pytask.tree_util import tree_map from _pytask.tree_util import tree_structure @@ -269,9 +272,20 @@ def pytask_execute_task_process_report( return True -@hookimpl(trylast=True) +@hookimpl(trylast=False) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: """Log task outcome.""" + + if report.outcome == TaskOutcome.FAIL: + with console.capture() as capture: + console.print(Traceback(report.exc_info)) + s = capture.get() + result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome), 'exc_info' : s} + else: + result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome)} + thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + thread.start() + url_style = create_url_style_for_task( report.task.function, session.config["editor_url_scheme"] ) From ef10aab59ed918cb382309eeb7816736d2ec60c4 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 29 Nov 2023 15:03:40 +0100 Subject: [PATCH 02/43] Fixed mistake in json --- src/_pytask/collect.py | 6 +++--- src/_pytask/execute.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 7c03515d..5eababef 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -471,9 +471,9 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( return id_to_short_id -def send_logging_vscode(url,json,timeout): +def send_logging_vscode(url: str,json: dict[str,Any],timeout: float) -> None: try: - requests.post(url,json,timeout) + requests.post(url=url,json=json,timeout=timeout) except requests.Timeout: pass @@ -490,7 +490,7 @@ def pytask_collect_log( if report.outcome == CollectionOutcome.FAIL: exitcode = 3 result = [{'name' : task.name.split('/')[-1], 'path' : str(task.path)} if isinstance(task,PTaskWithPath) else {'name' : task.name, 'path' : ''} for task in tasks] - thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', {"exitcode" : exitcode, "tasks": result}, 0.00001)) thread.start() console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.") diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index 6418899b..8f855536 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -272,7 +272,7 @@ def pytask_execute_task_process_report( return True -@hookimpl(trylast=False) +@hookimpl(tryfirst=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: """Log task outcome.""" From ed38f14e9f17c39e03001625ccd79dbce5caeb17 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:14:20 +0000 Subject: [PATCH 03/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/collect.py | 35 ++++++++++++++++++++++++----------- src/_pytask/execute.py | 25 ++++++++++++++++++------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 5eababef..318ba060 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -4,7 +4,6 @@ import inspect import itertools import os -import requests import sys import time from pathlib import Path @@ -14,6 +13,7 @@ from typing import Iterable from typing import TYPE_CHECKING +import requests from _pytask.collect_utils import create_name_of_python_node from _pytask.collect_utils import parse_dependencies_from_task_function from _pytask.collect_utils import parse_products_from_task_function @@ -31,9 +31,9 @@ from _pytask.node_protocols import PPathNode from _pytask.node_protocols import PTask from _pytask.nodes import PathNode +from _pytask.nodes import PTaskWithPath from _pytask.nodes import PythonNode from _pytask.nodes import Task -from _pytask.nodes import PTaskWithPath from _pytask.nodes import TaskWithoutPath from _pytask.outcomes import CollectionOutcome from _pytask.outcomes import count_outcomes @@ -45,6 +45,7 @@ from _pytask.task_utils import task as task_decorator from _pytask.typing import is_task_function from rich.text import Text +import contextlib if TYPE_CHECKING: from _pytask.session import Session @@ -471,11 +472,11 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( return id_to_short_id -def send_logging_vscode(url: str,json: dict[str,Any],timeout: float) -> None: - try: - requests.post(url=url,json=json,timeout=timeout) - except requests.Timeout: - pass + +def send_logging_vscode(url: str, json: dict[str, Any], timeout: float) -> None: + with contextlib.suppress(requests.Timeout): + requests.post(url=url, json=json, timeout=timeout) + @hookimpl def pytask_collect_log( @@ -483,14 +484,26 @@ def pytask_collect_log( ) -> None: """Log collection.""" session.collection_end = time.time() - - if session.config['command'] == 'collect': + + if session.config["command"] == "collect": exitcode = 0 for report in reports: if report.outcome == CollectionOutcome.FAIL: exitcode = 3 - result = [{'name' : task.name.split('/')[-1], 'path' : str(task.path)} if isinstance(task,PTaskWithPath) else {'name' : task.name, 'path' : ''} for task in tasks] - thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', {"exitcode" : exitcode, "tasks": result}, 0.00001)) + result = [ + {"name": task.name.split("/")[-1], "path": str(task.path)} + if isinstance(task, PTaskWithPath) + else {"name": task.name, "path": ""} + for task in tasks + ] + thread = Thread( + target=send_logging_vscode, + args=( + "http://localhost:6000/pytask", + {"exitcode": exitcode, "tasks": result}, + 0.00001, + ), + ) thread.start() console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.") diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index 8f855536..41cdfc6f 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -275,15 +275,26 @@ def pytask_execute_task_process_report( @hookimpl(tryfirst=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: """Log task outcome.""" - if report.outcome == TaskOutcome.FAIL: - with console.capture() as capture: - console.print(Traceback(report.exc_info)) - s = capture.get() - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome), 'exc_info' : s} + with console.capture() as capture: + console.print(Traceback(report.exc_info)) + s = capture.get() + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + "exc_info": s, + } else: - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome)} - thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + } + thread = Thread( + target=send_logging_vscode, + args=("http://localhost:6000/pytask", result, 0.00001), + ) thread.start() url_style = create_url_style_for_task( From a513fa55dca4da19b83d2db5650670a6e5cc76b6 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 11:34:30 +0100 Subject: [PATCH 04/43] Moved execution logging to live.py --- src/_pytask/execute.py | 13 +------------ src/_pytask/live.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index 8f855536..f2c858ca 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -271,21 +271,10 @@ def pytask_execute_task_process_report( return True - -@hookimpl(tryfirst=True) +@hookimpl(trylast=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: """Log task outcome.""" - if report.outcome == TaskOutcome.FAIL: - with console.capture() as capture: - console.print(Traceback(report.exc_info)) - s = capture.get() - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome), 'exc_info' : s} - else: - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome)} - thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) - thread.start() - url_style = create_url_style_for_task( report.task.function, session.config["editor_url_scheme"] ) diff --git a/src/_pytask/live.py b/src/_pytask/live.py index 32974426..71d9e69e 100644 --- a/src/_pytask/live.py +++ b/src/_pytask/live.py @@ -1,17 +1,20 @@ """Contains code related to live objects.""" from __future__ import annotations +from threading import Thread from typing import Any from typing import Generator from typing import NamedTuple from typing import TYPE_CHECKING import click +from _pytask.collect import send_logging_vscode from _pytask.config import hookimpl from _pytask.console import console from _pytask.console import format_task_name from _pytask.outcomes import CollectionOutcome from _pytask.outcomes import TaskOutcome +from _pytask.traceback import Traceback from attrs import define from attrs import field from rich.box import ROUNDED @@ -168,6 +171,16 @@ def pytask_execute_task_log_start(self, task: PTask) -> bool: @hookimpl def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool: """Mark a task as being finished and update outcome.""" + console.print('hier') + if report.outcome == TaskOutcome.FAIL: + with console.capture() as capture: + console.print(Traceback(report.exc_info)) + s = capture.get() + result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome), 'exc_info' : s} + else: + result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome)} + thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + thread.start() self.update_reports(report) return True From 5f7b80ab0a333b5cfc2dc094135870c9cf8a3e72 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:48:27 +0000 Subject: [PATCH 05/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/collect.py | 2 +- src/_pytask/execute.py | 5 +---- src/_pytask/live.py | 20 ++++++++++++++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 318ba060..1581ca09 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -1,6 +1,7 @@ """Implement functionality to collect tasks.""" from __future__ import annotations +import contextlib import inspect import itertools import os @@ -45,7 +46,6 @@ from _pytask.task_utils import task as task_decorator from _pytask.typing import is_task_function from rich.text import Text -import contextlib if TYPE_CHECKING: from _pytask.session import Session diff --git a/src/_pytask/execute.py b/src/_pytask/execute.py index f2c858ca..ccc87d66 100644 --- a/src/_pytask/execute.py +++ b/src/_pytask/execute.py @@ -4,11 +4,9 @@ import inspect import sys import time -from threading import Thread from typing import Any from typing import TYPE_CHECKING -from _pytask.collect import send_logging_vscode from _pytask.config import hookimpl from _pytask.config import IS_FILE_SYSTEM_CASE_SENSITIVE from _pytask.console import console @@ -37,7 +35,6 @@ from _pytask.outcomes import WouldBeExecuted from _pytask.reports import ExecutionReport from _pytask.traceback import remove_traceback_from_exc_info -from _pytask.traceback import Traceback from _pytask.tree_util import tree_leaves from _pytask.tree_util import tree_map from _pytask.tree_util import tree_structure @@ -271,10 +268,10 @@ def pytask_execute_task_process_report( return True + @hookimpl(trylast=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: """Log task outcome.""" - url_style = create_url_style_for_task( report.task.function, session.config["editor_url_scheme"] ) diff --git a/src/_pytask/live.py b/src/_pytask/live.py index 71d9e69e..8e1e783b 100644 --- a/src/_pytask/live.py +++ b/src/_pytask/live.py @@ -171,15 +171,27 @@ def pytask_execute_task_log_start(self, task: PTask) -> bool: @hookimpl def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool: """Mark a task as being finished and update outcome.""" - console.print('hier') + console.print("hier") if report.outcome == TaskOutcome.FAIL: with console.capture() as capture: console.print(Traceback(report.exc_info)) s = capture.get() - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome), 'exc_info' : s} + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + "exc_info": s, + } else: - result = {'type': 'task', 'name' : report.task.name.split('/')[-1], 'outcome' : str(report.outcome)} - thread = Thread(target= send_logging_vscode, args= ('http://localhost:6000/pytask', result, 0.00001)) + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + } + thread = Thread( + target=send_logging_vscode, + args=("http://localhost:6000/pytask", result, 0.00001), + ) thread.start() self.update_reports(report) return True From 7846dee274bf38f9b58e17030bc9f39f1c593f7a Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 11:56:07 +0100 Subject: [PATCH 06/43] added requests as dependency --- environment.yml | 1 + pyproject.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/environment.yml b/environment.yml index 77d4d3bf..2729d43c 100644 --- a/environment.yml +++ b/environment.yml @@ -17,6 +17,7 @@ dependencies: - networkx >=2.4 - pluggy >=1.0.0 - optree >=0.9 + - requests - rich - sqlalchemy >=1.4.36 - tomli >=1.0.0 diff --git a/pyproject.toml b/pyproject.toml index 266d7d16..32cb5a32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ dependencies = [ "packaging", "pluggy>=1", "rich", + "requests", "sqlalchemy>=1.4.36", 'tomli>=1; python_version < "3.11"', 'typing-extensions; python_version < "3.9"', From ceed57fe26c7713d566f50a44a554156845ec003 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 12:22:08 +0100 Subject: [PATCH 07/43] Add Func description --- src/_pytask/collect.py | 1 + src/_pytask/live.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 1581ca09..cf1be937 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -474,6 +474,7 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( def send_logging_vscode(url: str, json: dict[str, Any], timeout: float) -> None: + """Send logging information to VSCode.""" with contextlib.suppress(requests.Timeout): requests.post(url=url, json=json, timeout=timeout) diff --git a/src/_pytask/live.py b/src/_pytask/live.py index 8e1e783b..aa7eaa74 100644 --- a/src/_pytask/live.py +++ b/src/_pytask/live.py @@ -171,7 +171,6 @@ def pytask_execute_task_log_start(self, task: PTask) -> bool: @hookimpl def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool: """Mark a task as being finished and update outcome.""" - console.print("hier") if report.outcome == TaskOutcome.FAIL: with console.capture() as capture: console.print(Traceback(report.exc_info)) From 28a43e99729a877d6adbbd8fb615520c108c20a5 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 12:36:44 +0100 Subject: [PATCH 08/43] add requests to mypy --- .pre-commit-config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d1971f59..eb3a3101 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,6 +64,7 @@ repos: click, optree, pluggy, + types-requests, rich, sqlalchemy, types-setuptools, From bb5941622162ae6ef9a9536cc452a8c559789058 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 12:56:13 +0100 Subject: [PATCH 09/43] Check for no exec info --- src/_pytask/live.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/live.py b/src/_pytask/live.py index aa7eaa74..7a404ca0 100644 --- a/src/_pytask/live.py +++ b/src/_pytask/live.py @@ -171,7 +171,7 @@ def pytask_execute_task_log_start(self, task: PTask) -> bool: @hookimpl def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool: """Mark a task as being finished and update outcome.""" - if report.outcome == TaskOutcome.FAIL: + if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: with console.capture() as capture: console.print(Traceback(report.exc_info)) s = capture.get() From bb1af380aeb89a507d5a27778d9bc11e7de1bdb5 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Dec 2023 15:27:35 +0100 Subject: [PATCH 10/43] suppress more exceptions --- src/_pytask/collect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index cf1be937..d49b36e8 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -475,7 +475,7 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( def send_logging_vscode(url: str, json: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" - with contextlib.suppress(requests.Timeout): + with contextlib.suppress(requests.exceptions.RequestException): requests.post(url=url, json=json, timeout=timeout) From 4ef51b031716bdcf51447adc1c0861d8f6697db1 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 13 Dec 2023 14:58:11 +0100 Subject: [PATCH 11/43] Add new vscode module --- environment.yml | 1 - pyproject.toml | 1 - src/_pytask/cli.py | 2 ++ src/_pytask/collect.py | 23 ------------- src/_pytask/live.py | 24 ------------- src/_pytask/vscode.py | 78 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+), 49 deletions(-) create mode 100644 src/_pytask/vscode.py diff --git a/environment.yml b/environment.yml index 2729d43c..77d4d3bf 100644 --- a/environment.yml +++ b/environment.yml @@ -17,7 +17,6 @@ dependencies: - networkx >=2.4 - pluggy >=1.0.0 - optree >=0.9 - - requests - rich - sqlalchemy >=1.4.36 - tomli >=1.0.0 diff --git a/pyproject.toml b/pyproject.toml index 32cb5a32..266d7d16 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ dependencies = [ "packaging", "pluggy>=1", "rich", - "requests", "sqlalchemy>=1.4.36", 'tomli>=1; python_version < "3.11"', 'typing-extensions; python_version < "3.9"', diff --git a/src/_pytask/cli.py b/src/_pytask/cli.py index f056b2e1..60c9c1f8 100644 --- a/src/_pytask/cli.py +++ b/src/_pytask/cli.py @@ -66,6 +66,7 @@ def pytask_add_hooks(pm: pluggy.PluginManager) -> None: from _pytask import skipping from _pytask import task from _pytask import warnings + from _pytask import vscode pm.register(build) pm.register(capture) @@ -88,6 +89,7 @@ def pytask_add_hooks(pm: pluggy.PluginManager) -> None: pm.register(skipping) pm.register(task) pm.register(warnings) + pm.register(vscode) @click.group( diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index d49b36e8..e1db3db8 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -8,7 +8,6 @@ import sys import time from pathlib import Path -from threading import Thread from typing import Any from typing import Generator from typing import Iterable @@ -32,7 +31,6 @@ from _pytask.node_protocols import PPathNode from _pytask.node_protocols import PTask from _pytask.nodes import PathNode -from _pytask.nodes import PTaskWithPath from _pytask.nodes import PythonNode from _pytask.nodes import Task from _pytask.nodes import TaskWithoutPath @@ -486,27 +484,6 @@ def pytask_collect_log( """Log collection.""" session.collection_end = time.time() - if session.config["command"] == "collect": - exitcode = 0 - for report in reports: - if report.outcome == CollectionOutcome.FAIL: - exitcode = 3 - result = [ - {"name": task.name.split("/")[-1], "path": str(task.path)} - if isinstance(task, PTaskWithPath) - else {"name": task.name, "path": ""} - for task in tasks - ] - thread = Thread( - target=send_logging_vscode, - args=( - "http://localhost:6000/pytask", - {"exitcode": exitcode, "tasks": result}, - 0.00001, - ), - ) - thread.start() - console.print(f"Collected {len(tasks)} task{'' if len(tasks) == 1 else 's'}.") failed_reports = [r for r in reports if r.outcome == CollectionOutcome.FAIL] diff --git a/src/_pytask/live.py b/src/_pytask/live.py index 7a404ca0..32974426 100644 --- a/src/_pytask/live.py +++ b/src/_pytask/live.py @@ -1,20 +1,17 @@ """Contains code related to live objects.""" from __future__ import annotations -from threading import Thread from typing import Any from typing import Generator from typing import NamedTuple from typing import TYPE_CHECKING import click -from _pytask.collect import send_logging_vscode from _pytask.config import hookimpl from _pytask.console import console from _pytask.console import format_task_name from _pytask.outcomes import CollectionOutcome from _pytask.outcomes import TaskOutcome -from _pytask.traceback import Traceback from attrs import define from attrs import field from rich.box import ROUNDED @@ -171,27 +168,6 @@ def pytask_execute_task_log_start(self, task: PTask) -> bool: @hookimpl def pytask_execute_task_log_end(self, report: ExecutionReport) -> bool: """Mark a task as being finished and update outcome.""" - if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: - with console.capture() as capture: - console.print(Traceback(report.exc_info)) - s = capture.get() - result = { - "type": "task", - "name": report.task.name.split("/")[-1], - "outcome": str(report.outcome), - "exc_info": s, - } - else: - result = { - "type": "task", - "name": report.task.name.split("/")[-1], - "outcome": str(report.outcome), - } - thread = Thread( - target=send_logging_vscode, - args=("http://localhost:6000/pytask", result, 0.00001), - ) - thread.start() self.update_reports(report) return True diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py new file mode 100644 index 00000000..19dbea1e --- /dev/null +++ b/src/_pytask/vscode.py @@ -0,0 +1,78 @@ +"""Contains Code for VSCode Logging""" + +import json +import os + +from threading import Thread +from typing import Any +from urllib import request, parse + +from _pytask.config import hookimpl +from _pytask.console import console +from _pytask.console import render_to_string +from _pytask.node_protocols import PTask +from _pytask.nodes import PTaskWithPath +from _pytask.outcomes import CollectionOutcome +from _pytask.outcomes import TaskOutcome +from _pytask.reports import CollectionReport +from _pytask.reports import ExecutionReport +from _pytask.session import Session +from _pytask.traceback import Traceback + +def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: + """Send logging information to VSCode.""" + try: + data = json.dumps(data).encode("utf-8") + req = request.Request(url, data=data) + req.add_header('Content-Type', 'application/json; charset=utf-8') + resp = request.urlopen(req, timeout=timeout) + except Exception as e: + pass + +@hookimpl(tryfirst=True) +def pytask_collect_log( + session: Session, reports: list[CollectionReport], tasks: list[PTask] +) -> None: + if os.environ.get("PYTASK_VSCODE") == 'True': + if session.config["command"] == "collect": + exitcode = 0 + for report in reports: + if report.outcome == CollectionOutcome.FAIL: + exitcode = 3 + result = [ + {"name": task.name.split("/")[-1], "path": str(task.path)} + if isinstance(task, PTaskWithPath) + else {"name": task.name, "path": ""} + for task in tasks + ] + thread = Thread( + target=send_logging_vscode, + args=( + "http://localhost:6000/pytask", + {"exitcode": exitcode, "tasks": result}, + 0.00001, + ), + ) + thread.start() + +@hookimpl(tryfirst=True) +def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: + if os.environ.get("PYTASK_VSCODE") == 'True': + if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + "exc_info": render_to_string(Traceback(report.exc_info), console), + } + else: + result = { + "type": "task", + "name": report.task.name.split("/")[-1], + "outcome": str(report.outcome), + } + thread = Thread( + target=send_logging_vscode, + args=("http://localhost:6000/pytask", result, 0.00001), + ) + thread.start() \ No newline at end of file From 945e9337ae9de626fa5be9d46bf31dd303cb2540 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 13 Dec 2023 14:02:00 +0000 Subject: [PATCH 12/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 19dbea1e..a4e09c6b 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -1,39 +1,43 @@ -"""Contains Code for VSCode Logging""" +"""Contains Code for VSCode Logging.""" +from __future__ import annotations import json import os - from threading import Thread -from typing import Any -from urllib import request, parse +from typing import Any, TYPE_CHECKING +from urllib import request from _pytask.config import hookimpl from _pytask.console import console from _pytask.console import render_to_string -from _pytask.node_protocols import PTask from _pytask.nodes import PTaskWithPath from _pytask.outcomes import CollectionOutcome from _pytask.outcomes import TaskOutcome -from _pytask.reports import CollectionReport -from _pytask.reports import ExecutionReport -from _pytask.session import Session from _pytask.traceback import Traceback +if TYPE_CHECKING: + from _pytask.reports import ExecutionReport + from _pytask.reports import CollectionReport + from _pytask.session import Session + from _pytask.node_protocols import PTask + + def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" try: data = json.dumps(data).encode("utf-8") - req = request.Request(url, data=data) - req.add_header('Content-Type', 'application/json; charset=utf-8') - resp = request.urlopen(req, timeout=timeout) - except Exception as e: + req = request.Request(url, data=data) + req.add_header("Content-Type", "application/json; charset=utf-8") + request.urlopen(req, timeout=timeout) + except Exception: pass + @hookimpl(tryfirst=True) def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] ) -> None: - if os.environ.get("PYTASK_VSCODE") == 'True': + if os.environ.get("PYTASK_VSCODE") == "True": if session.config["command"] == "collect": exitcode = 0 for report in reports: @@ -55,9 +59,10 @@ def pytask_collect_log( ) thread.start() + @hookimpl(tryfirst=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: - if os.environ.get("PYTASK_VSCODE") == 'True': + if os.environ.get("PYTASK_VSCODE") == "True": if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { "type": "task", @@ -73,6 +78,6 @@ def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> No } thread = Thread( target=send_logging_vscode, - args=("http://localhost:6000/pytask", result, 0.00001), + args=("http://localhost:6000/pytask", result, 0.00001), ) - thread.start() \ No newline at end of file + thread.start() From 24623fde24c4b858fe6fa1889a89b73d68856100 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 13:02:26 +0100 Subject: [PATCH 13/43] Suppress exceptions --- src/_pytask/vscode.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index a4e09c6b..607cbead 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -1,6 +1,7 @@ """Contains Code for VSCode Logging.""" from __future__ import annotations +import contextlib import json import os from threading import Thread @@ -24,13 +25,11 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" - try: + with contextlib.suppress(Exception): data = json.dumps(data).encode("utf-8") req = request.Request(url, data=data) req.add_header("Content-Type", "application/json; charset=utf-8") request.urlopen(req, timeout=timeout) - except Exception: - pass @hookimpl(tryfirst=True) From 8d5ca6175233ce6cc38e87137ee0a531aac9a967 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 13:08:12 +0100 Subject: [PATCH 14/43] Remove old code --- .pre-commit-config.yaml | 1 - src/_pytask/collect.py | 9 --------- 2 files changed, 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index eb3a3101..d1971f59 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -64,7 +64,6 @@ repos: click, optree, pluggy, - types-requests, rich, sqlalchemy, types-setuptools, diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index e1db3db8..66148917 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -1,7 +1,6 @@ """Implement functionality to collect tasks.""" from __future__ import annotations -import contextlib import inspect import itertools import os @@ -13,7 +12,6 @@ from typing import Iterable from typing import TYPE_CHECKING -import requests from _pytask.collect_utils import create_name_of_python_node from _pytask.collect_utils import parse_dependencies_from_task_function from _pytask.collect_utils import parse_products_from_task_function @@ -470,13 +468,6 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( return id_to_short_id - -def send_logging_vscode(url: str, json: dict[str, Any], timeout: float) -> None: - """Send logging information to VSCode.""" - with contextlib.suppress(requests.exceptions.RequestException): - requests.post(url=url, json=json, timeout=timeout) - - @hookimpl def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] From 7db35cf73e1b23a516600828cbe744fc2b7dd242 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 14:12:11 +0100 Subject: [PATCH 15/43] Remove Changes --- src/_pytask/cli.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/_pytask/cli.py b/src/_pytask/cli.py index 60c9c1f8..f056b2e1 100644 --- a/src/_pytask/cli.py +++ b/src/_pytask/cli.py @@ -66,7 +66,6 @@ def pytask_add_hooks(pm: pluggy.PluginManager) -> None: from _pytask import skipping from _pytask import task from _pytask import warnings - from _pytask import vscode pm.register(build) pm.register(capture) @@ -89,7 +88,6 @@ def pytask_add_hooks(pm: pluggy.PluginManager) -> None: pm.register(skipping) pm.register(task) pm.register(warnings) - pm.register(vscode) @click.group( From 1415d38d59422b04d85e957a8a44f2eae19eb193 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:13:05 +0000 Subject: [PATCH 16/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/collect.py | 1 + src/_pytask/vscode.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/_pytask/collect.py b/src/_pytask/collect.py index 66148917..1986b794 100644 --- a/src/_pytask/collect.py +++ b/src/_pytask/collect.py @@ -468,6 +468,7 @@ def _find_shortest_uniquely_identifiable_name_for_tasks( return id_to_short_id + @hookimpl def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 607cbead..dbb9f44b 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -5,7 +5,8 @@ import json import os from threading import Thread -from typing import Any, TYPE_CHECKING +from typing import Any +from typing import TYPE_CHECKING from urllib import request from _pytask.config import hookimpl From 4ad1d3694c7b01ec43b76a3347d9f0c78fb34bf1 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 14:33:30 +0100 Subject: [PATCH 17/43] Add vscode module --- src/_pytask/pluginmanager.py | 1 + src/_pytask/vscode.py | 43 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/_pytask/pluginmanager.py b/src/_pytask/pluginmanager.py index 931e12a8..4f6af0db 100644 --- a/src/_pytask/pluginmanager.py +++ b/src/_pytask/pluginmanager.py @@ -56,6 +56,7 @@ def pytask_add_hooks(pm: PluginManager) -> None: "_pytask.skipping", "_pytask.task", "_pytask.warnings", + "_pytask.vscode", ) register_hook_impls_from_modules(pm, builtin_hook_impl_modules) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index dbb9f44b..e8c7f3a3 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -27,7 +27,7 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" with contextlib.suppress(Exception): - data = json.dumps(data).encode("utf-8") + json = json.dumps(data).encode("utf-8") req = request.Request(url, data=data) req.add_header("Content-Type", "application/json; charset=utf-8") request.urlopen(req, timeout=timeout) @@ -37,27 +37,26 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] ) -> None: - if os.environ.get("PYTASK_VSCODE") == "True": - if session.config["command"] == "collect": - exitcode = 0 - for report in reports: - if report.outcome == CollectionOutcome.FAIL: - exitcode = 3 - result = [ - {"name": task.name.split("/")[-1], "path": str(task.path)} - if isinstance(task, PTaskWithPath) - else {"name": task.name, "path": ""} - for task in tasks - ] - thread = Thread( - target=send_logging_vscode, - args=( - "http://localhost:6000/pytask", - {"exitcode": exitcode, "tasks": result}, - 0.00001, - ), - ) - thread.start() + if os.environ.get("PYTASK_VSCODE") == "True" and session.config["command"] == "collect": + exitcode = 0 + for report in reports: + if report.outcome == CollectionOutcome.FAIL: + exitcode = 3 + result = [ + {"name": task.name.split("/")[-1], "path": str(task.path)} + if isinstance(task, PTaskWithPath) + else {"name": task.name, "path": ""} + for task in tasks + ] + thread = Thread( + target=send_logging_vscode, + args=( + "http://localhost:6000/pytask", + {"exitcode": exitcode, "tasks": result}, + 0.00001, + ), + ) + thread.start() @hookimpl(tryfirst=True) From ec09e6075ff00f4b33fca99899bd48a9bd725654 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:34:10 +0000 Subject: [PATCH 18/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index e8c7f3a3..76342e12 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -27,7 +27,7 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" with contextlib.suppress(Exception): - json = json.dumps(data).encode("utf-8") + json.dumps(data).encode("utf-8") req = request.Request(url, data=data) req.add_header("Content-Type", "application/json; charset=utf-8") request.urlopen(req, timeout=timeout) @@ -37,7 +37,10 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] ) -> None: - if os.environ.get("PYTASK_VSCODE") == "True" and session.config["command"] == "collect": + if ( + os.environ.get("PYTASK_VSCODE") == "True" + and session.config["command"] == "collect" + ): exitcode = 0 for report in reports: if report.outcome == CollectionOutcome.FAIL: From 1722f1cde68efd292aee8081d4604a4dd1ef5200 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 14:39:20 +0100 Subject: [PATCH 19/43] Fix URL error --- src/_pytask/vscode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index e8c7f3a3..7e6eb33a 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,11 +24,12 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: +def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" + url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): json = json.dumps(data).encode("utf-8") - req = request.Request(url, data=data) + req = request.Request(url, data=json) req.add_header("Content-Type", "application/json; charset=utf-8") request.urlopen(req, timeout=timeout) @@ -51,7 +52,6 @@ def pytask_collect_log( thread = Thread( target=send_logging_vscode, args=( - "http://localhost:6000/pytask", {"exitcode": exitcode, "tasks": result}, 0.00001, ), @@ -77,6 +77,6 @@ def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> No } thread = Thread( target=send_logging_vscode, - args=("http://localhost:6000/pytask", result, 0.00001), + args=( result, 0.00001), ) thread.start() From 224331f8ba2917fd2892e5dca7bdcd5ab027aaa6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:43:19 +0000 Subject: [PATCH 20/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index a8b9794c..57a988c6 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -80,6 +80,6 @@ def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> No } thread = Thread( target=send_logging_vscode, - args=( result, 0.00001), + args=(result, 0.00001), ) thread.start() From c856264c26d4d5bc8241af17a0c23b337907ecf6 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 17 Jan 2024 14:48:08 +0100 Subject: [PATCH 21/43] Check URL --- src/_pytask/vscode.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index a8b9794c..77fdc925 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -27,9 +27,11 @@ def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" + if not url.startswith(("http:", "https:")): + raise ValueError("URL must start with 'http:' or 'https:'") with contextlib.suppress(Exception): - json = json.dumps(data).encode("utf-8") - req = request.Request(url, data=json) + response = json.dumps(data).encode("utf-8") + req = request.Request(url, data=response) req.add_header("Content-Type", "application/json; charset=utf-8") request.urlopen(req, timeout=timeout) From 7d7bf215038dbeebad8b6dc9c71484715a679359 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Jan 2024 13:49:05 +0000 Subject: [PATCH 22/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index c0419341..a94ce578 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -28,7 +28,8 @@ def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" if not url.startswith(("http:", "https:")): - raise ValueError("URL must start with 'http:' or 'https:'") + msg = "URL must start with 'http:' or 'https:'" + raise ValueError(msg) with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") req = request.Request(url, data=response) From e5d38f94c99d9ada69cf75c858568d9896cd22c4 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 24 Jan 2024 14:08:03 +0100 Subject: [PATCH 23/43] Disable qa --- src/_pytask/vscode.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index c0419341..0b52fe20 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,16 +24,14 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: +def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: #noqa:S310 """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" - if not url.startswith(("http:", "https:")): - raise ValueError("URL must start with 'http:' or 'https:'") with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response) + req = request.Request(url, data=response) req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout) + request.urlopen(req, timeout=timeout) @hookimpl(tryfirst=True) @@ -65,7 +63,7 @@ def pytask_collect_log( @hookimpl(tryfirst=True) -def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: +def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: #noqa:ARG001 if os.environ.get("PYTASK_VSCODE") == "True": if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { From b9af1395d03ec10f941ae7619e034100374ff079 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:11:16 +0000 Subject: [PATCH 24/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 0b52fe20..f062f382 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,14 +24,14 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: #noqa:S310 +def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response) + req = request.Request(url, data=response) req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout) + request.urlopen(req, timeout=timeout) @hookimpl(tryfirst=True) @@ -63,7 +63,7 @@ def pytask_collect_log( @hookimpl(tryfirst=True) -def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: #noqa:ARG001 +def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa:ARG001 if os.environ.get("PYTASK_VSCODE") == "True": if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { From b0aba34aa340f59527bc1c66b8f6a2e77d20a370 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 24 Jan 2024 14:16:42 +0100 Subject: [PATCH 25/43] Add noqa --- src/_pytask/vscode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 0b52fe20..3708be69 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,14 +24,14 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: #noqa:S310 +def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response) + req = request.Request(url, data=response) #noqa:S310 req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout) + request.urlopen(req, timeout=timeout) #noqa:S310 @hookimpl(tryfirst=True) From 5a28ed6b98d02983fe93ba1be169bc39801d1cd2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:19:56 +0000 Subject: [PATCH 26/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 54b5438c..5f07db04 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,14 +24,14 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: +def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response)#noqa:S310 + req = request.Request(url, data=response) # noqa:S310 req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout)#noqa:S310 + request.urlopen(req, timeout=timeout) # noqa:S310 @hookimpl(tryfirst=True) From 2956580ee4ca4e719a64fcd42bc0cf5c87798fb9 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 24 Jan 2024 14:23:28 +0100 Subject: [PATCH 27/43] change noqa --- src/_pytask/vscode.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 54b5438c..366ae337 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -29,9 +29,9 @@ def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response)#noqa:S310 + req = request.Request(url, data=response) # noqa: S310 req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout)#noqa:S310 + request.urlopen(req, timeout=timeout) # noqa: S310 @hookimpl(tryfirst=True) @@ -63,7 +63,7 @@ def pytask_collect_log( @hookimpl(tryfirst=True) -def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa:ARG001 +def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa: ARG001 if os.environ.get("PYTASK_VSCODE") == "True": if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { From 573d39a69a292563ac9403463a47e774f07a521d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:24:53 +0000 Subject: [PATCH 28/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 6d5df3bc..ad210dd6 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -29,9 +29,9 @@ def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response) # noqa: S310 + req = request.Request(url, data=response) # noqa: S310 req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout) # noqa: S310 + request.urlopen(req, timeout=timeout) # noqa: S310 @hookimpl(tryfirst=True) From 2a856b2e10dbcd843a2ed9c45e54494ba99cf48a Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 7 Feb 2024 14:58:36 +0100 Subject: [PATCH 29/43] Add tests for vscode module --- tests/test_vscode.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/test_vscode.py diff --git a/tests/test_vscode.py b/tests/test_vscode.py new file mode 100644 index 00000000..bf5a3674 --- /dev/null +++ b/tests/test_vscode.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +import textwrap + +import pytest +import os +from pytask import cli +from pytask import build +from pytask import ExitCode + + + +@pytest.mark.end_to_end() +def test_vscode_collect(runner, tmp_path): + source = """ + def task_raises(): + return + """ + os.environ["PYTASK_VSCODE"] = "True" + tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + + result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) + assert result.exit_code == ExitCode.OK + +@pytest.mark.end_to_end() +def test_vscode_build(runner, tmp_path): + source = """ + def task_raises(): + return + """ + os.environ["PYTASK_VSCODE"] = "True" + tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + + result = runner.invoke(cli, [tmp_path.as_posix()]) + assert result.exit_code == ExitCode.OK \ No newline at end of file From ba12e7bd08e2372ea7b6ab42b40fa3bd1cdbbc77 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 7 Feb 2024 13:59:24 +0000 Subject: [PATCH 30/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_vscode.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test_vscode.py b/tests/test_vscode.py index bf5a3674..ca6633b0 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -1,15 +1,13 @@ from __future__ import annotations +import os import textwrap import pytest -import os from pytask import cli -from pytask import build from pytask import ExitCode - @pytest.mark.end_to_end() def test_vscode_collect(runner, tmp_path): source = """ @@ -22,6 +20,7 @@ def task_raises(): result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) assert result.exit_code == ExitCode.OK + @pytest.mark.end_to_end() def test_vscode_build(runner, tmp_path): source = """ @@ -32,4 +31,4 @@ def task_raises(): tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) result = runner.invoke(cli, [tmp_path.as_posix()]) - assert result.exit_code == ExitCode.OK \ No newline at end of file + assert result.exit_code == ExitCode.OK From 4d335d47febc459f0fd4ad70fb308be04e156f15 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 6 Mar 2024 15:59:27 +0100 Subject: [PATCH 31/43] Send Logging to different urls --- src/_pytask/vscode.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index ad210dd6..98ff2580 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -24,9 +24,8 @@ from _pytask.node_protocols import PTask -def send_logging_vscode(data: dict[str, Any], timeout: float) -> None: +def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to VSCode.""" - url = "http://localhost:6000/pytask" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") req = request.Request(url, data=response) # noqa: S310 @@ -52,9 +51,10 @@ def pytask_collect_log( else {"name": task.name, "path": ""} for task in tasks ] + url = "http://localhost:6000/pytask/collect" thread = Thread( target=send_logging_vscode, - args=( + args=(url, {"exitcode": exitcode, "tasks": result}, 0.00001, ), @@ -78,8 +78,9 @@ def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> No "name": report.task.name.split("/")[-1], "outcome": str(report.outcome), } + url = "http://localhost:6000/pytask/run" thread = Thread( target=send_logging_vscode, - args=(result, 0.00001), + args=(url, result, 0.00001), ) thread.start() From a3db9ae86ff5118ccabfbc83add0f00deabe91f9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 6 Mar 2024 15:02:33 +0000 Subject: [PATCH 32/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 98ff2580..8c4d0c63 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -54,7 +54,8 @@ def pytask_collect_log( url = "http://localhost:6000/pytask/collect" thread = Thread( target=send_logging_vscode, - args=(url, + args=( + url, {"exitcode": exitcode, "tasks": result}, 0.00001, ), From 2e28de7daabda363ed7cc2c2dd680a589c71a5ef Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 10:07:43 +0000 Subject: [PATCH 33/43] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytask/vscode.py | 7 ++++--- tests/test_vscode.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 8c4d0c63..efb4f4cd 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -1,12 +1,13 @@ """Contains Code for VSCode Logging.""" + from __future__ import annotations import contextlib import json import os from threading import Thread -from typing import Any from typing import TYPE_CHECKING +from typing import Any from urllib import request from _pytask.config import hookimpl @@ -18,10 +19,10 @@ from _pytask.traceback import Traceback if TYPE_CHECKING: - from _pytask.reports import ExecutionReport + from _pytask.node_protocols import PTask from _pytask.reports import CollectionReport + from _pytask.reports import ExecutionReport from _pytask.session import Session - from _pytask.node_protocols import PTask def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: diff --git a/tests/test_vscode.py b/tests/test_vscode.py index ca6633b0..656bd4e2 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -4,8 +4,8 @@ import textwrap import pytest -from pytask import cli from pytask import ExitCode +from pytask import cli @pytest.mark.end_to_end() From cde73fd678b265e94a2a9e422f6623d68499f336 Mon Sep 17 00:00:00 2001 From: mj023 Date: Thu, 20 Jun 2024 13:46:04 +0200 Subject: [PATCH 34/43] Make Port changeable --- src/_pytask/vscode.py | 26 +++++++++++++++++--------- tests/test_vscode.py | 22 ++++++++++++++++++---- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index efb4f4cd..5a07daa3 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -39,20 +39,24 @@ def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] ) -> None: if ( - os.environ.get("PYTASK_VSCODE") == "True" + os.environ.get("PYTASK_VSCODE") is not None and session.config["command"] == "collect" ): - exitcode = 0 + try: + port = int(os.environ.get("PYTASK_VSCODE")) + except ValueError: + port = 6000 + exitcode = "OK" for report in reports: if report.outcome == CollectionOutcome.FAIL: - exitcode = 3 + exitcode = "COLLECTION_FAILED" result = [ - {"name": task.name.split("/")[-1], "path": str(task.path)} + {"name": task.name, "path": str(task.path)} if isinstance(task, PTaskWithPath) else {"name": task.name, "path": ""} for task in tasks ] - url = "http://localhost:6000/pytask/collect" + url = f"http://localhost:{port}/pytask/collect" thread = Thread( target=send_logging_vscode, args=( @@ -66,21 +70,25 @@ def pytask_collect_log( @hookimpl(tryfirst=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa: ARG001 - if os.environ.get("PYTASK_VSCODE") == "True": + if os.environ.get("PYTASK_VSCODE") is not None: + try: + port = int(os.environ.get("PYTASK_VSCODE")) + except ValueError: + port = 6000 if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { "type": "task", - "name": report.task.name.split("/")[-1], + "name": report.task.name, "outcome": str(report.outcome), "exc_info": render_to_string(Traceback(report.exc_info), console), } else: result = { "type": "task", - "name": report.task.name.split("/")[-1], + "name": report.task.name, "outcome": str(report.outcome), } - url = "http://localhost:6000/pytask/run" + url = f"http://localhost:{port}/pytask/run" thread = Thread( target=send_logging_vscode, args=(url, result, 0.00001), diff --git a/tests/test_vscode.py b/tests/test_vscode.py index 656bd4e2..66963cd3 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -8,13 +8,25 @@ from pytask import cli +@pytest.mark.end_to_end() +def test_vscode_collect_failed(runner, tmp_path): + source = """ + raise Exception + """ + os.environ["PYTASK_VSCODE"] = "6000" + tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + + result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) + assert result.exit_code == ExitCode.COLLECTION_FAILED + + @pytest.mark.end_to_end() def test_vscode_collect(runner, tmp_path): source = """ def task_raises(): return """ - os.environ["PYTASK_VSCODE"] = "True" + os.environ["PYTASK_VSCODE"] = "6000" tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) @@ -24,11 +36,13 @@ def task_raises(): @pytest.mark.end_to_end() def test_vscode_build(runner, tmp_path): source = """ - def task_raises(): + def task_example(): return + def task_raises(): + raise Exception """ - os.environ["PYTASK_VSCODE"] = "True" + os.environ["PYTASK_VSCODE"] = "6000" tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) result = runner.invoke(cli, [tmp_path.as_posix()]) - assert result.exit_code == ExitCode.OK + assert result.exit_code == ExitCode.FAILED From f4b1808ccc412175f5a32703695633803f2a6b6e Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 3 Jul 2024 14:34:46 +0200 Subject: [PATCH 35/43] Fix typing mistake --- src/_pytask/vscode.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 5a07daa3..6ecfac42 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -43,7 +43,7 @@ def pytask_collect_log( and session.config["command"] == "collect" ): try: - port = int(os.environ.get("PYTASK_VSCODE")) + port = int(os.environ["PYTASK_VSCODE"]) except ValueError: port = 6000 exitcode = "OK" @@ -72,19 +72,17 @@ def pytask_collect_log( def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa: ARG001 if os.environ.get("PYTASK_VSCODE") is not None: try: - port = int(os.environ.get("PYTASK_VSCODE")) + port = int(os.environ["PYTASK_VSCODE"]) except ValueError: port = 6000 if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: result = { - "type": "task", "name": report.task.name, "outcome": str(report.outcome), "exc_info": render_to_string(Traceback(report.exc_info), console), } else: result = { - "type": "task", "name": report.task.name, "outcome": str(report.outcome), } From 698519b9d503df875e04a677c775b62ad7b2222d Mon Sep 17 00:00:00 2001 From: mj023 Date: Thu, 1 Aug 2024 18:35:24 +0200 Subject: [PATCH 36/43] Add Test for Wrong EnvVar --- tests/test_vscode.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_vscode.py b/tests/test_vscode.py index 66963cd3..0eb850e0 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -46,3 +46,16 @@ def task_raises(): result = runner.invoke(cli, [tmp_path.as_posix()]) assert result.exit_code == ExitCode.FAILED + + +@pytest.mark.end_to_end() +def test_vscode_env_variable(runner, tmp_path): + source = """ + def task_example(): + return + """ + os.environ["PYTASK_VSCODE"] = "TEST" + tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + + result = runner.invoke(cli, [tmp_path.as_posix()]) + assert result.exit_code == ExitCode.OK From 9ef13052f32a0dfba537e48e634e115a29ed93da Mon Sep 17 00:00:00 2001 From: mj023 Date: Thu, 1 Aug 2024 19:31:48 +0200 Subject: [PATCH 37/43] Add Comments for new functions --- src/_pytask/vscode.py | 10 ++++++---- tests/test_vscode.py | 5 ++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 6ecfac42..4263d825 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -25,8 +25,8 @@ from _pytask.session import Session -def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: - """Send logging information to VSCode.""" +def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: + """Send logging information to the provided port.""" with contextlib.suppress(Exception): response = json.dumps(data).encode("utf-8") req = request.Request(url, data=response) # noqa: S310 @@ -38,6 +38,7 @@ def send_logging_vscode(url: str, data: dict[str, Any], timeout: float) -> None: def pytask_collect_log( session: Session, reports: list[CollectionReport], tasks: list[PTask] ) -> None: + """Start threads to send logging information for collected tasks.""" if ( os.environ.get("PYTASK_VSCODE") is not None and session.config["command"] == "collect" @@ -58,7 +59,7 @@ def pytask_collect_log( ] url = f"http://localhost:{port}/pytask/collect" thread = Thread( - target=send_logging_vscode, + target=send_logging_info, args=( url, {"exitcode": exitcode, "tasks": result}, @@ -70,6 +71,7 @@ def pytask_collect_log( @hookimpl(tryfirst=True) def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa: ARG001 + """Start threads to send logging information for executed tasks.""" if os.environ.get("PYTASK_VSCODE") is not None: try: port = int(os.environ["PYTASK_VSCODE"]) @@ -88,7 +90,7 @@ def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> No } url = f"http://localhost:{port}/pytask/run" thread = Thread( - target=send_logging_vscode, + target=send_logging_info, args=(url, result, 0.00001), ) thread.start() diff --git a/tests/test_vscode.py b/tests/test_vscode.py index 0eb850e0..ba9dbcb4 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -23,7 +23,7 @@ def test_vscode_collect_failed(runner, tmp_path): @pytest.mark.end_to_end() def test_vscode_collect(runner, tmp_path): source = """ - def task_raises(): + def task_example(): return """ os.environ["PYTASK_VSCODE"] = "6000" @@ -57,5 +57,8 @@ def task_example(): os.environ["PYTASK_VSCODE"] = "TEST" tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) + result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) + assert result.exit_code == ExitCode.OK + result = runner.invoke(cli, [tmp_path.as_posix()]) assert result.exit_code == ExitCode.OK From e3ef5628d7bddf00c0bf25737ecc13fb8797873d Mon Sep 17 00:00:00 2001 From: Tim Mensinger Date: Fri, 2 Aug 2024 13:07:17 +0200 Subject: [PATCH 38/43] Update vscode.py --- src/_pytask/vscode.py | 75 ++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 4263d825..9b5baf96 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -8,7 +8,8 @@ from threading import Thread from typing import TYPE_CHECKING from typing import Any -from urllib import request +from urllib.request import Request +from urllib.request import urlopen from _pytask.config import hookimpl from _pytask.console import console @@ -25,13 +26,22 @@ from _pytask.session import Session +TIMEOUT = 0.00001 +DEFAULT_VSCODE_PORT = 6000 + + def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to the provided port.""" + # TODO: Can you add a unit test for this function? And mark it with + # pytest.mark.unit() + with contextlib.suppress(Exception): + # TODO: Why do you suppress all exceptions? Maybe we should fix S310 + response = json.dumps(data).encode("utf-8") - req = request.Request(url, data=response) # noqa: S310 + req = Request(url, data=response) # noqa: S310 req.add_header("Content-Type", "application/json; charset=utf-8") - request.urlopen(req, timeout=timeout) # noqa: S310 + urlopen(req, timeout=timeout) # noqa: S310 @hookimpl(tryfirst=True) @@ -46,51 +56,56 @@ def pytask_collect_log( try: port = int(os.environ["PYTASK_VSCODE"]) except ValueError: - port = 6000 + # TODO: When does this case happen? + port = DEFAULT_VSCODE_PORT + exitcode = "OK" for report in reports: if report.outcome == CollectionOutcome.FAIL: exitcode = "COLLECTION_FAILED" - result = [ - {"name": task.name, "path": str(task.path)} - if isinstance(task, PTaskWithPath) - else {"name": task.name, "path": ""} - for task in tasks - ] - url = f"http://localhost:{port}/pytask/collect" + + result = [] + for task in tasks: + path = str(task.path) if isinstance(task, PTaskWithPath) else "" + result.append({"name": task.name, "path": path}) + thread = Thread( target=send_logging_info, - args=( - url, - {"exitcode": exitcode, "tasks": result}, - 0.00001, - ), + kwargs={ + "url": f"http://localhost:{port}/pytask/collect", + "data": {"exitcode": exitcode, "tasks": result}, + "timeout": TIMEOUT, + }, ) thread.start() @hookimpl(tryfirst=True) -def pytask_execute_task_log_end(session: Session, report: ExecutionReport) -> None: # noqa: ARG001 +def pytask_execute_task_log_end( + session: Session, # noqa: ARG001 + report: ExecutionReport, +) -> None: """Start threads to send logging information for executed tasks.""" if os.environ.get("PYTASK_VSCODE") is not None: try: port = int(os.environ["PYTASK_VSCODE"]) except ValueError: - port = 6000 + # TODO: When does this case happen? + port = DEFAULT_VSCODE_PORT + + result = { + "name": report.task.name, + "outcome": str(report.outcome), + } if report.outcome == TaskOutcome.FAIL and report.exc_info is not None: - result = { - "name": report.task.name, - "outcome": str(report.outcome), - "exc_info": render_to_string(Traceback(report.exc_info), console), - } - else: - result = { - "name": report.task.name, - "outcome": str(report.outcome), - } - url = f"http://localhost:{port}/pytask/run" + result["exc_info"] = render_to_string(Traceback(report.exc_info), console) + thread = Thread( target=send_logging_info, - args=(url, result, 0.00001), + kwargs={ + "url": f"http://localhost:{port}/pytask/run", + "data": result, + "timeout": TIMEOUT, + }, ) thread.start() From 9afa75b457bd59bee1a339a25199bd72219fb9c1 Mon Sep 17 00:00:00 2001 From: mj023 Date: Tue, 6 Aug 2024 13:44:23 +0200 Subject: [PATCH 39/43] Add Unit Test --- src/_pytask/vscode.py | 10 ++-------- tests/test_vscode.py | 9 +++++++++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 9b5baf96..a357769f 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -8,6 +8,7 @@ from threading import Thread from typing import TYPE_CHECKING from typing import Any +from urllib.error import URLError from urllib.request import Request from urllib.request import urlopen @@ -32,12 +33,7 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to the provided port.""" - # TODO: Can you add a unit test for this function? And mark it with - # pytest.mark.unit() - - with contextlib.suppress(Exception): - # TODO: Why do you suppress all exceptions? Maybe we should fix S310 - + with contextlib.suppress(URLError, TimeoutError): response = json.dumps(data).encode("utf-8") req = Request(url, data=response) # noqa: S310 req.add_header("Content-Type", "application/json; charset=utf-8") @@ -56,7 +52,6 @@ def pytask_collect_log( try: port = int(os.environ["PYTASK_VSCODE"]) except ValueError: - # TODO: When does this case happen? port = DEFAULT_VSCODE_PORT exitcode = "OK" @@ -90,7 +85,6 @@ def pytask_execute_task_log_end( try: port = int(os.environ["PYTASK_VSCODE"]) except ValueError: - # TODO: When does this case happen? port = DEFAULT_VSCODE_PORT result = { diff --git a/tests/test_vscode.py b/tests/test_vscode.py index ba9dbcb4..d9109a1b 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -4,6 +4,7 @@ import textwrap import pytest +from _pytask.vscode import send_logging_info from pytask import ExitCode from pytask import cli @@ -62,3 +63,11 @@ def task_example(): result = runner.invoke(cli, [tmp_path.as_posix()]) assert result.exit_code == ExitCode.OK + + +@pytest.mark.unit() +def test_send_logging_info(): + url = "http://localhost:6000/pytask/run" + data = {"test": "test"} + timeout = 0.00001 + send_logging_info(url, data, timeout) From 686cdbe9691c3d9f15d61b3daaf571b7e5e3caab Mon Sep 17 00:00:00 2001 From: Tim Mensinger Date: Wed, 7 Aug 2024 12:38:38 +0200 Subject: [PATCH 40/43] Unfinished changes from discussion --- src/_pytask/vscode.py | 32 +++++++++++++++++++++++--------- tests/test_vscode.py | 11 ++++++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index a357769f..bfabbb1e 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -32,12 +32,30 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: - """Send logging information to the provided port.""" + """Send logging information to the provided port. + + TODO(@max): Explain why we need to suppress URLError and TimeoutError. Ideally, add + link to StackOverflow or similar. + + """ with contextlib.suppress(URLError, TimeoutError): response = json.dumps(data).encode("utf-8") req = Request(url, data=response) # noqa: S310 req.add_header("Content-Type", "application/json; charset=utf-8") urlopen(req, timeout=timeout) # noqa: S310 + + +def validate_and_return_port(port: str) -> int: + """Validate the port number.""" + try: + port = int(port) + except ValueError as e: + # TODO(@max): + # (1) Add comment to docstring, explaining why we do this + # (2) Raise ValueError with "good" error message + msg = f"Invalid port number: {port}, must be an integer." + raise ValueError(msg) from e + return port @hookimpl(tryfirst=True) @@ -49,10 +67,8 @@ def pytask_collect_log( os.environ.get("PYTASK_VSCODE") is not None and session.config["command"] == "collect" ): - try: - port = int(os.environ["PYTASK_VSCODE"]) - except ValueError: - port = DEFAULT_VSCODE_PORT + + port = validate_and_return_port(os.environ["PYTASK_VSCODE"]) exitcode = "OK" for report in reports: @@ -82,10 +98,8 @@ def pytask_execute_task_log_end( ) -> None: """Start threads to send logging information for executed tasks.""" if os.environ.get("PYTASK_VSCODE") is not None: - try: - port = int(os.environ["PYTASK_VSCODE"]) - except ValueError: - port = DEFAULT_VSCODE_PORT + + port = validate_and_return_port(os.environ["PYTASK_VSCODE"]) result = { "name": report.task.name, diff --git a/tests/test_vscode.py b/tests/test_vscode.py index d9109a1b..c9e1df41 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -4,11 +4,20 @@ import textwrap import pytest -from _pytask.vscode import send_logging_info +from _pytask.vscode import send_logging_info, validate_and_return_port from pytask import ExitCode from pytask import cli +def test_validate_and_return_port_valid_port(): + assert validate_and_return_port("6000") == 6000 + + +def test_validate_and_return_port_invalid_port(): + with pytest.raises(ValueError): + validate_and_return_port("not_an_integer") + + @pytest.mark.end_to_end() def test_vscode_collect_failed(runner, tmp_path): source = """ From bef8004e38989e3bb2637c49267ed38afdb3f4cf Mon Sep 17 00:00:00 2001 From: mj023 Date: Fri, 9 Aug 2024 19:23:11 +0200 Subject: [PATCH 41/43] Refactor Port Validation; Docstrings --- src/_pytask/vscode.py | 35 ++++++++++++++++++++--------------- tests/test_vscode.py | 31 +++++++++++++++++++------------ 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index bfabbb1e..5c33938e 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -33,27 +33,34 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to the provided port. - - TODO(@max): Explain why we need to suppress URLError and TimeoutError. Ideally, add - link to StackOverflow or similar. - + + A response from the server is not needed, therefore a very low timeout is used to + essentially "fire-and-forget" the HTTP request. Because the HTTP protocol expects + a response, the urllib will throw an URLError or (rarely) a TimeoutError, + which will be suppressed. """ + response = json.dumps(data).encode("utf-8") + req = Request(url, data=response) # noqa: S310 + req.add_header("Content-Type", "application/json; charset=utf-8") with contextlib.suppress(URLError, TimeoutError): - response = json.dumps(data).encode("utf-8") - req = Request(url, data=response) # noqa: S310 - req.add_header("Content-Type", "application/json; charset=utf-8") urlopen(req, timeout=timeout) # noqa: S310 - + def validate_and_return_port(port: str) -> int: - """Validate the port number.""" + """Validate the port number. + + The value of the environment variable is used as a direct input for the url, + that the logging info is sent to. To avoid security concerns the value is + checked to contain a valid port number and not an arbitrary string that could + modify the url. + """ try: port = int(port) except ValueError as e: - # TODO(@max): - # (1) Add comment to docstring, explaining why we do this - # (2) Raise ValueError with "good" error message - msg = f"Invalid port number: {port}, must be an integer." + msg = ( + "The value provided in the environment variable " + f"PYTASK_VSCODE must be an integer, got {port} instead." + ) raise ValueError(msg) from e return port @@ -67,7 +74,6 @@ def pytask_collect_log( os.environ.get("PYTASK_VSCODE") is not None and session.config["command"] == "collect" ): - port = validate_and_return_port(os.environ["PYTASK_VSCODE"]) exitcode = "OK" @@ -98,7 +104,6 @@ def pytask_execute_task_log_end( ) -> None: """Start threads to send logging information for executed tasks.""" if os.environ.get("PYTASK_VSCODE") is not None: - port = validate_and_return_port(os.environ["PYTASK_VSCODE"]) result = { diff --git a/tests/test_vscode.py b/tests/test_vscode.py index c9e1df41..23b9f097 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -4,20 +4,35 @@ import textwrap import pytest -from _pytask.vscode import send_logging_info, validate_and_return_port +from _pytask.vscode import send_logging_info +from _pytask.vscode import validate_and_return_port from pytask import ExitCode from pytask import cli +@pytest.mark.unit() def test_validate_and_return_port_valid_port(): assert validate_and_return_port("6000") == 6000 +@pytest.mark.unit() def test_validate_and_return_port_invalid_port(): - with pytest.raises(ValueError): + with pytest.raises( + ValueError, + match="The value provided in the environment variable " + "PYTASK_VSCODE must be an integer, got not_an_integer instead.", + ): validate_and_return_port("not_an_integer") +@pytest.mark.unit() +def test_send_logging_info(): + url = "http://localhost:6000/pytask/run" + data = {"test": "test"} + timeout = 0.00001 + send_logging_info(url, data, timeout) + + @pytest.mark.end_to_end() def test_vscode_collect_failed(runner, tmp_path): source = """ @@ -68,15 +83,7 @@ def task_example(): tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) - assert result.exit_code == ExitCode.OK + assert result.exit_code == ExitCode.FAILED result = runner.invoke(cli, [tmp_path.as_posix()]) - assert result.exit_code == ExitCode.OK - - -@pytest.mark.unit() -def test_send_logging_info(): - url = "http://localhost:6000/pytask/run" - data = {"test": "test"} - timeout = 0.00001 - send_logging_info(url, data, timeout) + assert result.exit_code == ExitCode.FAILED From a79c101b587ac0a487ea5e785d5d3250e8475207 Mon Sep 17 00:00:00 2001 From: mj023 Date: Wed, 14 Aug 2024 12:24:20 +0200 Subject: [PATCH 42/43] Add Mocking to Tests --- src/_pytask/vscode.py | 7 ++----- tests/test_vscode.py | 39 +++++++++++++++++++++------------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index 5c33938e..ca5ece15 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -9,7 +9,6 @@ from typing import TYPE_CHECKING from typing import Any from urllib.error import URLError -from urllib.request import Request from urllib.request import urlopen from _pytask.config import hookimpl @@ -39,11 +38,9 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: a response, the urllib will throw an URLError or (rarely) a TimeoutError, which will be suppressed. """ - response = json.dumps(data).encode("utf-8") - req = Request(url, data=response) # noqa: S310 - req.add_header("Content-Type", "application/json; charset=utf-8") + response = json.dumps(data).encode() with contextlib.suppress(URLError, TimeoutError): - urlopen(req, timeout=timeout) # noqa: S310 + urlopen(url=url, data=response, timeout=timeout) # noqa: S310 def validate_and_return_port(port: str) -> int: diff --git a/tests/test_vscode.py b/tests/test_vscode.py index 23b9f097..1f2e5dec 100644 --- a/tests/test_vscode.py +++ b/tests/test_vscode.py @@ -1,7 +1,9 @@ from __future__ import annotations +import json import os import textwrap +from unittest.mock import MagicMock import pytest from _pytask.vscode import send_logging_info @@ -26,15 +28,23 @@ def test_validate_and_return_port_invalid_port(): @pytest.mark.unit() -def test_send_logging_info(): +def test_send_logging_info(monkeypatch): + mock_urlopen = MagicMock() + monkeypatch.setattr("_pytask.vscode.urlopen", mock_urlopen) + url = "http://localhost:6000/pytask/run" data = {"test": "test"} timeout = 0.00001 + response = json.dumps(data).encode() + send_logging_info(url, data, timeout) + mock_urlopen.assert_called_with(url=url, data=response, timeout=timeout) @pytest.mark.end_to_end() -def test_vscode_collect_failed(runner, tmp_path): +def test_vscode_collect_failed(runner, tmp_path, monkeypatch): + mock_urlopen = MagicMock() + monkeypatch.setattr("_pytask.vscode.urlopen", mock_urlopen) source = """ raise Exception """ @@ -43,6 +53,11 @@ def test_vscode_collect_failed(runner, tmp_path): result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) assert result.exit_code == ExitCode.COLLECTION_FAILED + mock_urlopen.assert_called_with( + url="http://localhost:6000/pytask/collect", + data=b'{"exitcode": "COLLECTION_FAILED", "tasks": []}', + timeout=0.00001, + ) @pytest.mark.end_to_end() @@ -59,7 +74,9 @@ def task_example(): @pytest.mark.end_to_end() -def test_vscode_build(runner, tmp_path): +def test_vscode_build(runner, tmp_path, monkeypatch): + mock_urlopen = MagicMock() + monkeypatch.setattr("_pytask.vscode.urlopen", mock_urlopen) source = """ def task_example(): return @@ -70,20 +87,6 @@ def task_raises(): tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) result = runner.invoke(cli, [tmp_path.as_posix()]) - assert result.exit_code == ExitCode.FAILED - -@pytest.mark.end_to_end() -def test_vscode_env_variable(runner, tmp_path): - source = """ - def task_example(): - return - """ - os.environ["PYTASK_VSCODE"] = "TEST" - tmp_path.joinpath("task_module.py").write_text(textwrap.dedent(source)) - - result = runner.invoke(cli, ["collect", tmp_path.as_posix()]) - assert result.exit_code == ExitCode.FAILED - - result = runner.invoke(cli, [tmp_path.as_posix()]) assert result.exit_code == ExitCode.FAILED + assert mock_urlopen.call_count == 2 From 450ab7e12c477523414123598ffacc9b566a234d Mon Sep 17 00:00:00 2001 From: Tim Mensinger Date: Wed, 14 Aug 2024 14:57:06 +0200 Subject: [PATCH 43/43] Fix mypy error --- src/_pytask/vscode.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/_pytask/vscode.py b/src/_pytask/vscode.py index ca5ece15..30552d69 100644 --- a/src/_pytask/vscode.py +++ b/src/_pytask/vscode.py @@ -34,9 +34,10 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: """Send logging information to the provided port. A response from the server is not needed, therefore a very low timeout is used to - essentially "fire-and-forget" the HTTP request. Because the HTTP protocol expects - a response, the urllib will throw an URLError or (rarely) a TimeoutError, - which will be suppressed. + essentially "fire-and-forget" the HTTP request. Because the HTTP protocol expects a + response, the urllib will throw an URLError or (rarely) a TimeoutError, which will + be suppressed. + """ response = json.dumps(data).encode() with contextlib.suppress(URLError, TimeoutError): @@ -44,22 +45,24 @@ def send_logging_info(url: str, data: dict[str, Any], timeout: float) -> None: def validate_and_return_port(port: str) -> int: - """Validate the port number. + """Validate the port number and return it as an integer. + + The value of the environment variable is used as a direct input for the url, that + the logging info is sent to. To avoid security concerns the value is checked to + contain a valid port number and not an arbitrary string that could modify the url. + + If the port cannot be converted to an integer, a ValueError is raised. - The value of the environment variable is used as a direct input for the url, - that the logging info is sent to. To avoid security concerns the value is - checked to contain a valid port number and not an arbitrary string that could - modify the url. """ try: - port = int(port) + out = int(port) except ValueError as e: msg = ( - "The value provided in the environment variable " - f"PYTASK_VSCODE must be an integer, got {port} instead." + "The value provided in the environment variable PYTASK_VSCODE must be an " + f"integer, got {port} instead." ) raise ValueError(msg) from e - return port + return out @hookimpl(tryfirst=True)