Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

style: address linting and typing issues #29

Merged
merged 11 commits into from
Oct 9, 2024
67 changes: 34 additions & 33 deletions .github/workflows/ci.yml
Karanjot786 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,44 @@ name: CI

on:
push:
branches: [ main ]
branches: '*'
pull_request:
branches: [ main ]
branches: '*'

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.11'

- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
poetry install

- name: Lint with Ruff
run: |
poetry run ruff check crategen/

- name: Type check with Mypy
run: |
poetry run mypy crategen/

- name: Run security checks with Bandit
run: |
poetry run bandit -r crategen/

- name: Install test dependencies
run: |
poetry add pytest pytest-cov pytest-mock

# - name: Run tests
# run: |
# poetry run pytest --cov=crategen
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'

- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
poetry install

- name: Lint with Ruff
run: |
poetry run ruff check crategen/
if: ${{ success() }}

- name: Type check with Mypy
run: |
poetry run mypy crategen/

- name: Run security checks with Bandit
run: |
poetry run bandit -r crategen/

- name: Install test dependencies
run: |
poetry add pytest pytest-cov pytest-mock

# - name: Run tests
# run: |
# poetry run pytest --cov=crategen
Karanjot786 marked this conversation as resolved.
Show resolved Hide resolved
36 changes: 22 additions & 14 deletions crategen/cli.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
import click
"""CLI module for converting TES and WES data to WRROC."""

import json

import click

from crategen.converter_manager import ConverterManager


@click.command()
@click.option('--input', prompt='Input file', help='Path to the input JSON file.')
@click.option('--output', prompt='Output file', help='Path to the output JSON file.')
@click.option('--conversion-type', prompt='Conversion type', type=click.Choice(['tes-to-wrroc', 'wes-to-wrroc']), help='Type of conversion to perform.')
def cli(input, output, conversion_type):
"""
Command Line Interface for converting TES/WES to WRROC.
"""
@click.option("--input", prompt="Input file", help="Path to the input JSON file.")
@click.option("--output", prompt="Output file", help="Path to the output JSON file.")
@click.option(
"--conversion-type",
prompt="Conversion type",
type=click.Choice(["tes-to-wrroc", "wes-to-wrroc"]),
help="Type of conversion to perform.",
)
def cli(input: str, output: str, conversion_type: str) -> None:
"""Command Line Interface for converting TES/WES to WRROC."""
manager = ConverterManager()
uniqueg marked this conversation as resolved.
Show resolved Hide resolved

# Load input data from JSON file
with open(input, 'r') as input_file:
with open(input) as input_file:
data = json.load(input_file)

# Perform the conversion based on the specified type
if conversion_type == 'tes-to-wrroc':
if conversion_type == "tes-to-wrroc":
result = manager.convert_tes_to_wrroc(data)
elif conversion_type == 'wes-to-wrroc':
elif conversion_type == "wes-to-wrroc":
result = manager.convert_wes_to_wrroc(data)

# Save the result to the output JSON file
with open(output, 'w') as output_file:
with open(output, "w") as output_file:
json.dump(result, output_file, indent=4)

if __name__ == '__main__':
if __name__ == "__main__":
cli()
16 changes: 13 additions & 3 deletions crategen/converter_manager.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
"""Manager for handling TES and WES to WRROC conversions."""

from typing import Any, Dict

from .converters.tes_converter import TESConverter
from .converters.wes_converter import WESConverter


class ConverterManager:
def __init__(self):
"""Manages conversion between TES/WES and WRROC formats."""

def __init__(self) -> None:
"""Initializes the converters for TES and WES."""
self.tes_converter = TESConverter()
self.wes_converter = WESConverter()

def convert_tes_to_wrroc(self, tes_data):
def convert_tes_to_wrroc(self, tes_data: Dict[str, Any]) -> Dict[str, Any]:
"""Converts TES data to WRROC format."""
return self.tes_converter.convert_to_wrroc(tes_data)

def convert_wes_to_wrroc(self, wes_data):
def convert_wes_to_wrroc(self, wes_data: Dict[str, Any]) -> Dict[str, Any]:
"""Converts WES data to WRROC format."""
return self.wes_converter.convert_to_wrroc(wes_data)
14 changes: 10 additions & 4 deletions crategen/converters/abstract_converter.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
"""Abstract base class for converters between TES/WES and WRROC formats."""

from abc import ABC, abstractmethod
from typing import Any, Dict


class AbstractConverter(ABC):
"""Abstract converter for TES/WES to WRROC and vice versa."""

@abstractmethod
def convert_to_wrroc(self, data):
"""Convert data to WRROC format"""
def convert_to_wrroc(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Convert data to WRROC format."""

@abstractmethod
def convert_from_wrroc(self, wrroc_data):
"""Convert WRROC data to the original format"""
def convert_from_wrroc(self, wrroc_data: Dict[str, Any]) -> Dict[str, Any]:
"""Convert WRROC data to the original format."""
34 changes: 26 additions & 8 deletions crategen/converters/tes_converter.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
"""Module for converting TES data to WRROC format and vice versa."""

from typing import Any, Dict

from .abstract_converter import AbstractConverter
from .utils import convert_to_iso8601


class TESConverter(AbstractConverter):
"""Converter for TES data to WRROC and vice versa."""

def convert_to_wrroc(self, tes_data: Dict[str, Any]) -> Dict[str, Any]:
Karanjot786 marked this conversation as resolved.
Show resolved Hide resolved
"""Convert TES data to WRROC format.
Karanjot786 marked this conversation as resolved.
Show resolved Hide resolved

def convert_to_wrroc(self, tes_data):
# Validate and extract data with defaults
Args:
tes_data (Dict[str, Any]): The TES data to be converted.

Returns:
Dict[str, Any]: The converted WRROC data.
"""
id = tes_data.get("id", "")
name = tes_data.get("name", "")
description = tes_data.get("description", "")
executors = tes_data.get("executors", [{}])
inputs = tes_data.get("inputs", [])
outputs = tes_data.get("outputs", [])
creation_time = tes_data.get("creation_time", "")
end_time = tes_data.get("logs", [{}])[0].get("end_time", "") # Corrected to fetch from logs
end_time = tes_data.get("logs", [{}])[0].get("end_time", "")

# Convert to WRROC
wrroc_data = {
"@id": id,
"name": name,
Expand All @@ -27,8 +39,15 @@ def convert_to_wrroc(self, tes_data):
}
return wrroc_data

def convert_from_wrroc(self, wrroc_data):
# Validate and extract data with defaults
def convert_from_wrroc(self, wrroc_data: Dict[str, Any]) -> Dict[str, Any]:
"""Convert WRROC data to TES format.
Karanjot786 marked this conversation as resolved.
Show resolved Hide resolved

Args:
wrroc_data (Dict[str, Any]): The WRROC data to be converted.

Returns:
Dict[str, Any]: The converted TES data.
"""
id = wrroc_data.get("@id", "")
name = wrroc_data.get("name", "")
description = wrroc_data.get("description", "")
Expand All @@ -38,7 +57,6 @@ def convert_from_wrroc(self, wrroc_data):
start_time = wrroc_data.get("startTime", "")
end_time = wrroc_data.get("endTime", "")

# Convert from WRROC to TES
tes_data = {
"id": id,
"name": name,
Expand All @@ -47,6 +65,6 @@ def convert_from_wrroc(self, wrroc_data):
"inputs": [{"url": obj.get("@id", ""), "path": obj.get("name", "")} for obj in object_data],
"outputs": [{"url": res.get("@id", ""), "path": res.get("name", "")} for res in result_data],
"creation_time": start_time,
"logs": [{"end_time": end_time}], # Added to logs
"logs": [{"end_time": end_time}],
}
return tes_data
24 changes: 13 additions & 11 deletions crategen/converters/utils.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
"""Utility functions for handling data conversion."""

import datetime
from typing import Optional


def convert_to_iso8601(timestamp: Optional[str]) -> Optional[str]:
"""Convert a given timestamp to ISO 8601 format.

def convert_to_iso8601(timestamp):
"""
Convert a given timestamp to ISO 8601 format.
Handles multiple formats including RFC 3339, ISO 8601 with and without fractional seconds.

Args:
timestamp (str): The timestamp to be converted.
timestamp (Optional[str]): The timestamp to be converted.

Returns:
str: The converted timestamp in ISO 8601 format, or None if the input format is incorrect.
Optional[str]: The converted timestamp in ISO 8601 format, or None if the input format is incorrect.
"""
if timestamp:
# List of supported formats
formats = [
"%Y-%m-%dT%H:%M:%S.%fZ", # RFC 3339 with fractional seconds
"%Y-%m-%dT%H:%M:%SZ", # RFC 3339 without fractional seconds
"%Y-%m-%dT%H:%M:%S%z", # ISO 8601 with timezone
"%Y-%m-%dT%H:%M:%S.%f%z", # ISO 8601 with fractional seconds and timezone
"%Y-%m-%dT%H:%M:%S.%fZ",
"%Y-%m-%dT%H:%M:%SZ",
"%Y-%m-%dT%H:%M:%S%z",
"%Y-%m-%dT%H:%M:%S.%f%z",
]
for fmt in formats:
try:
return datetime.datetime.strptime(timestamp, fmt).isoformat() + "Z"
except ValueError:
continue
# Handle incorrect format or other issues
return None
return None
32 changes: 25 additions & 7 deletions crategen/converters/wes_converter.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
"""Module for converting WES data to WRROC format and vice versa."""

from typing import Any, Dict

from .abstract_converter import AbstractConverter
from .utils import convert_to_iso8601


class WESConverter(AbstractConverter):
"""Converter for WES data to WRROC and vice versa."""

def convert_to_wrroc(self, wes_data: Dict[str, Any]) -> Dict[str, Any]:
"""Convert WES data to WRROC format.

def convert_to_wrroc(self, wes_data):
# Validate and extract data with defaults
Args:
wes_data (Dict[str, Any]): The WES data to be converted.

Returns:
Dict[str, Any]: The converted WRROC data.
"""
run_id = wes_data.get("run_id", "")
name = wes_data.get("run_log", {}).get("name", "")
state = wes_data.get("state", "")
start_time = wes_data.get("run_log", {}).get("start_time", "")
end_time = wes_data.get("run_log", {}).get("end_time", "")
outputs = wes_data.get("outputs", {})

# Convert to WRROC
wrroc_data = {
"@id": run_id,
"name": name,
Expand All @@ -23,16 +35,22 @@ def convert_to_wrroc(self, wes_data):
}
return wrroc_data

def convert_from_wrroc(self, wrroc_data):
# Validate and extract data with defaults
def convert_from_wrroc(self, wrroc_data: Dict[str, Any]) -> Dict[str, Any]:
"""Convert WRROC data to WES format.

Args:
wrroc_data (Dict[str, Any]): The WRROC data to be converted.

Returns:
Dict[str, Any]: The converted WES data.
"""
run_id = wrroc_data.get("@id", "")
name = wrroc_data.get("name", "")
start_time = wrroc_data.get("startTime", "")
end_time = wrroc_data.get("endTime", "")
state = wrroc_data.get("status", "")
result_data = wrroc_data.get("result", [])

# Convert from WRROC to WES

wes_data = {
"run_id": run_id,
"run_log": {
Expand Down
10 changes: 10 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pre-push:
commands:
ruff:
files: git diff --name-only --diff-filter=d $(git merge-base origin/main HEAD)..HEAD
run: poetry run ruff check {files}
glob: '*.py'
mypy:
files: git diff --name-only --diff-filter=d $(git merge-base origin/main HEAD)..HEAD
run: poetry run mypy {files}
glob: '*.py'
6 changes: 6 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,15 @@ select = [
"SIM", # flake8-simplify
"UP", # pyupgrade
]
ignore = ["E501"]
fixable = ["ALL"]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.typos.default.extend-words]
mke = 'mke'

[tool.mypy]
python_version = "3.11"
strict = true
Loading