"""Commonly used Resource types."""
import json
import os
import stat
import zipfile
from typing import Any, Dict, List, Optional
from plynx.base import resource
from plynx.constants import NodeResources
from plynx.utils.common import zipdir
from plynx.utils.config import WebConfig, get_web_config
[docs]WEB_CONFIG: WebConfig = get_web_config()
[docs]class Raw(resource.BaseResource):
"""Raw Resource that will be stored in jsonable format in the Node."""
[docs] DISPLAY_RAW: bool = True
[docs]class RawInt(Raw):
"""Raw Resource that will store an integer in the Node."""
@staticmethod
[docs]class RawFloat(Raw):
"""Raw Resource that will store an integer in the Node."""
@staticmethod
[docs]class RawColor(Raw):
"""Raw Resource that will store an integer in the Node."""
@staticmethod
[docs]class File(resource.BaseResource):
"""Raw Resource that will be stored in the file format in the Node."""
[docs]class PDF(resource.BaseResource):
"""PDF file"""
@classmethod
[docs] def preview(cls, preview_object: resource.PreviewObject) -> str:
"""Generate preview html body"""
src_url = f"{WEB_CONFIG.endpoint}/resource/{preview_object.resource_id}"
return f'<iframe src="{src_url}" title="preview" type="application/pdf" width="100%"/>'
[docs]class Image(resource.BaseResource):
"""Image file"""
[docs] DISPLAY_THUMBNAIL: bool = True
@classmethod
[docs] def preview(cls, preview_object: resource.PreviewObject) -> str:
"""Generate preview html body"""
src_url = f"{WEB_CONFIG.endpoint}/resource/{preview_object.resource_id}"
return f'<img src="{src_url}" width="100%" alt="preview" />'
@classmethod
[docs] def thumbnail(cls, output: Any) -> Optional[str]:
if len(output.values) != 1:
return None
src_url = f"{WEB_CONFIG.endpoint}/resource/{output.values[0]}"
return f'<img src="{src_url}" width="100%" alt="preview" />'
[docs]class _BaseSeparated(resource.BaseResource):
"""Base Separated file, i.e. csv, tsv"""
[docs] SEPARATOR: Optional[str] = None
[docs] _ROW_CLASSES: List[str] = ['even', 'odd']
[docs] _NUM_ROW_CLASSES: int = len(_ROW_CLASSES)
@classmethod
[docs] def preview(cls, preview_object: resource.PreviewObject) -> str:
"""Generate preview html body"""
preview_object.fp.truncate(1024 ** 2)
formated_lines = []
for idx, line in enumerate(preview_object.fp.read().decode('utf-8').split('\n')):
even_or_odd = cls._ROW_CLASSES[idx % cls._NUM_ROW_CLASSES]
formated_cells = ''.join(map(lambda s: f'<td class="preview-table-col">{s}</td>', line.split(cls.SEPARATOR)))
formated_line = f'<tr class="preview-table-row-{even_or_odd}">{formated_cells}</tr>'
formated_lines.append(formated_line)
all_lines = '\n'.join(formated_lines)
return f'<table class="preview-table">{all_lines}</table>'
[docs]class CSV(_BaseSeparated):
"""CSV file"""
[docs]class TSV(_BaseSeparated):
"""TSV file"""
[docs]class Json(resource.BaseResource):
"""JSON file"""
@classmethod
[docs] def preview(cls, preview_object: resource.PreviewObject) -> str:
"""Generate preview html body"""
if preview_object.fp.getbuffer().nbytes > 1024 ** 2:
return super(Json, cls).preview(preview_object)
try:
readable_json = json.dumps(json.loads(preview_object.fp.read().decode('utf-8')), indent=2)
return f"<pre>{readable_json}</pre>"
except json.JSONDecodeError as e:
return f"Failed to parse json: {e}"
[docs]class Executable(resource.BaseResource):
"""Executable file, i.e. bash or python"""
@staticmethod
[docs]class Directory(resource.BaseResource):
"""Directory file, i.e. zipfile"""
@staticmethod
@staticmethod
[docs] def prepare_output(filename, preview: bool = False) -> Dict[str, str]:
"""Create output folder"""
if preview:
return {NodeResources.OUTPUT: filename}
os.mkdir(filename)
return {NodeResources.OUTPUT: filename}
@staticmethod
[docs] def postprocess_output(value: str) -> str:
"""Compress folder to a zip file"""
zip_filename = f"{value}.zip"
with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zf:
zipdir(value, zf)
return zip_filename
@classmethod
[docs] def preview(cls, preview_object: resource.PreviewObject) -> str:
"""Generate preview html body"""
with zipfile.ZipFile(preview_object.fp, 'r') as zf:
content_stream = '\n'.join(zf.namelist())
return f"<pre>{content_stream}</pre>"