Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 67 additions & 66 deletions component_config/configSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,38 @@
"type": "object",
"title": "Configuration",
"required": [
"venv",
"user_properties",
"code",
"packages"
"source"
],
"properties": {
"venv": {
"enum": [
"3.14",
"3.13",
"3.12",
"base"
],
"type": "string",
"format": "radio",
"title": "Python Version & Environment Isolation",
"default": null,
"options": {
"tooltip": "- **Isolated environment** takes a couple of seconds to start, but gives you the opportuninty to pick one of the latest versions of Python. It's also a safer choice as it prevents package collisions.\n- Non-isolated environment (used to be the default choice) might start a bit faster, but can lead to issues mentioned above. It will also become a subject to deprecation in the future.\n- We recommmend you **update the code regularly** to make sure it runs with the latest versions of all packages. This will help you avoid issues with abandoned packages and **security vulnerabilities**.",
"enum_titles": [
"Python 3.14 beta – Isolated environment (just the packages of your choice)",
"Python 3.13 – Isolated environment (just the packages of your choice) – This is the recommended choice 🐙",
"Python 3.12 – Isolated environment (just the packages of your choice)",
"Python 3.10 – Shared environment (contains many pre-installed packages in legacy versions) – This used to be the default choice"
]
},
"propertyOrder": 10
},
"user_properties": {
"type": "object",
"title": "User Parameters",
"format": "editor",
"propertyOrder": 10,
"propertyOrder": 20,
"default": {
"debug": false
},
Expand All @@ -25,30 +47,9 @@
}
}
},
"venv": {
"enum": [
"base",
"3.12",
"3.13",
"3.14"
],
"type": "string",
"title": "Python Version & Environment Isolation",
"default": "3.13",
"options": {
"tooltip": "- Isolated environment takes a couple of seconds to start, but gives you the opportuninty to pick one of the latest versions of Python. It's also a safer choice as it prevents package collisions.\n- Non-isolated environment (used to be the default choice) might start a bit faster, but can lead to issues mentioned above.",
"enum_titles": [
"Python 3.10 – Shared environment (contains many pre-installed packages in legacy versions)",
"Python 3.12 – Isolated environment (just the packages of your choice)",
"Python 3.13 – Isolated environment (just the packages of your choice)",
"Python 3.14 beta – Isolated environment (just the packages of your choice)"
]
},
"required": false,
"propertyOrder": 30
},
"source": {
"type": "string",
"format": "radio",
"title": "Source Code & Dependencies",
"propertyOrder": 30,
"enum": [
Expand All @@ -62,8 +63,7 @@
"Get from Git repository"
]
},
"default": "code",
"required": false
"default": "code"
},
"packages": {
"type": "array",
Expand Down Expand Up @@ -110,51 +110,19 @@
},
"required": [
"url",
"branch",
"filename"
"auth"
],
"properties": {
"url": {
"type": "string",
"title": "Repository URL",
"propertyOrder": 70
},
"branch": {
"type": "string",
"enum": [],
"title": "Branch Name",
"propertyOrder": 80,
"options": {
"async": {
"label": "List Branches",
"action": "listBranches",
"autoload": [
"git.url"
],
"cache": false
}
}
},
"filename": {
"type": "string",
"enum": [],
"title": "Script Filename",
"propertyOrder": 90,
"options": {
"async": {
"label": "List Files",
"action": "listFiles",
"autoload": [
"git.branch"
],
"cache": false
}
}
},
"auth": {
"type": "string",
"format": "radio",
"title": "Repository Visibility & Authentication",
"propertyOrder": 100,
"propertyOrder": 80,
"enum": [
"none",
"pat",
Expand All @@ -167,13 +135,12 @@
"Private – SSH Key"
]
},
"default": "none",
"required": false
"default": "none"
},
"#token": {
"type": "string",
"title": "Personal Access Token",
"propertyOrder": 110,
"propertyOrder": 90,
"options": {
"dependencies": {
"auth": "pat"
Expand All @@ -183,13 +150,47 @@
"ssh_keys": {
"type": "object",
"format": "ssh-editor",
"propertyOrder": 120,
"propertyOrder": 100,
"options": {
"only_keys": true,
"dependencies": {
"auth": "ssh"
}
}
},
"branch": {
"type": "string",
"enum": [],
"title": "Branch Name",
"propertyOrder": 110,
"options": {
"tooltip": "If left empty, the default value `main` will be used.",
"async": {
"label": "List Branches",
"action": "listBranches",
"autoload": [
"git.url"
],
"cache": false
}
}
},
"filename": {
"type": "string",
"enum": [],
"title": "Script Filename",
"propertyOrder": 120,
"options": {
"tooltip": "If left empty, the default value `main.py` will be used.",
"async": {
"label": "List Files",
"action": "listFiles",
"autoload": [
"git.branch"
],
"cache": false
}
}
}
}
}
Expand Down
37 changes: 28 additions & 9 deletions src/subprocess_runner.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
import subprocess
import threading

from keboola.component.exceptions import UserException

Expand All @@ -16,18 +17,36 @@ def run(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=False,
text=True,
)

stdout, stderr = process.communicate()
if stdout:
logging.info("Command output:\n%s", stdout.decode())
stderr_output = []

process.poll()
if process.poll() != 0:
stderr_str = stderr.decode() if stderr else "Unknown error."
def read_stderr():
if process.stderr:
for line in iter(process.stderr.readline, ""):
stderr_output.append(line.strip())
logging.info("Command stderr: %s", line.strip())
process.stderr.close()

# Start stderr reader thread
stderr_thread = threading.Thread(target=read_stderr)
stderr_thread.start()

# Read stdout in main thread
stdout_lines = []
if process.stdout:
for line in iter(process.stdout.readline, ""):
stdout_lines.append(line.strip())
logging.info("Command output: %s", line.strip())
process.stdout.close()
stderr_thread.join()

process.wait()
stderr_str = "\n".join(stderr_output) if stderr_output else "Unknown error."
if process.returncode != 0:
raise UserException(f"{err_message} Log in event detail.", stderr_str)
elif stderr:
logging.info("%s Full log in detail.", ok_message, extra={"full_message": stderr.decode()})
elif stderr_str:
logging.info("%s Full log in detail.", ok_message, extra={"full_message": stderr_str})
else:
logging.info(ok_message)