Skip to content

Commit

Permalink
Merge pull request #3 from RocketPy-Team/enh/logging-python
Browse files Browse the repository at this point in the history
ENH: change verbose prints to log in python.
  • Loading branch information
Gui-FernandesBR authored Feb 17, 2024
2 parents f242e84 + 6760bdd commit 6be0210
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 170 deletions.
103 changes: 63 additions & 40 deletions open_rocket_serializer/cli.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import json
import logging
import os
from pathlib import Path

import click
import orhelper
from bs4 import BeautifulSoup
from orhelper import OrLogLevel

from ._helpers import extract_ork_from_zip, parse_ork_file
from .ork_extractor import ork_extractor

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y.%b.%d %H:%M:%S",
filename="serializer.log",
filemode="w",
)
logger = logging.getLogger(__name__)

# define the logger handler for the console (useful for the command line interface)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
console.setFormatter(formatter)
logger.addHandler(console)


@click.group()
@click.version_option()
Expand Down Expand Up @@ -44,9 +63,11 @@ def cli():


@cli.command("ork2json")
@click.option("--filepath", type=str, required=True, help="The path to the .ork file.")
@click.option(
"--output", type=str, required=False, help="The path to the output folder."
"--filepath", type=click.Path(), required=True, help="The path to the .ork file."
)
@click.option(
"--output", type=click.Path(), required=False, help="The path to the output folder."
)
@click.option(
"--eng",
Expand All @@ -57,7 +78,7 @@ def cli():
)
@click.option(
"--ork_jar",
type=str,
type=click.Path(),
default=None,
required=False,
help="The path to the OpenRocket .jar file.",
Expand Down Expand Up @@ -95,37 +116,39 @@ def ork2json(filepath, output=None, eng=None, ork_jar=None, verbose=False):
--------
>>> serializer ork2json("rocket.ork", "rocket", "motor.eng")
"""
log_level = logging.DEBUG if verbose else logging.WARNING
logger.setLevel(log_level)

# first check if the file exists
if os.path.exists(filepath) is False:
raise ValueError(
"The .ork file does not exist.\n" + "Please specify a valid path."
)
filepath = Path(filepath)

try:
bs = BeautifulSoup(open(filepath, encoding="utf-8").read(), features="xml")
except UnicodeDecodeError:
raise ValueError(
"The .ork file is not in UTF-8.\n"
+ "Please open the .ork file in a text editor and save it as UTF-8."
+ "Also, you should check if your .ork file is really a xml file or "
+ "a zip file. If it is a zip file, you should unzip it first."
)
if not filepath.exists():
error = "[ork2json] The .ork file or zip archive does not exist. Please specify a valid path."
logger.error(error)
raise FileNotFoundError(error)

datapoints = bs.findAll("datapoint")
if filepath.suffix.lower() == ".ork":
extract_dir = filepath.parent
filepath = extract_ork_from_zip(filepath, extract_dir)
logger.info(f"[ork2json] Extracted .ork file to: '{filepath.as_posix()}'")

bs, datapoints = parse_ork_file(filepath)

if len(datapoints) == 0:
raise ValueError(
"The file must contain the simulation data.\n"
error_msg = (
"[ork2json] The file must contain the simulation data.\n"
+ "Open the .ork file and run the simulation first."
)
logger.error(error_msg)
raise ValueError(error_msg)

data_labels = bs.find("databranch").attrs["types"].split(",")
if "CG location" not in data_labels:
raise ValueError(
"The file must be in English.\n"
+ "Open the .ork file and change the language to English."
message = (
"[ork2json] The file must contain the simulation data.\n"
+ "Open the .ork file and run the simulation first."
)
logger.error(message)
raise ValueError(message)

if not ork_jar:
# get any .jar file in the current directory that starts with "OpenRocket"
Expand All @@ -134,49 +157,51 @@ def ork2json(filepath, output=None, eng=None, ork_jar=None, verbose=False):
]
if len(ork_jar) == 0:
raise ValueError(
"It was impossible to find the OpenRocket .jar file in the current directory.\n"
"[ork2json] It was impossible to find the OpenRocket .jar file in the current directory.\n"
+ "Please specify the path to the .jar file."
)
ork_jar = ork_jar[0]
# print to the user that the .jar file was found, and show the name of the file
if verbose:
print(f"[ork2json] Found OpenRocket .jar file: {ork_jar}")
logger.info(
f"[ork2json] Found OpenRocket .jar file: '{Path(ork_jar).as_posix()}'"
)

if not output:
# get the same folder as the .ork file
output = os.path.dirname(filepath)
if verbose:
print(f"[ork2json] Output folder not specified. Using {output} instead.")
logger.warning(
f"[ork2json] Output folder not specified. Using '{Path(output).as_posix()}' instead."
)

# orhelper options are: OFF, ERROR, WARN, INFO, DEBUG, TRACE and ALL
log_level = "OFF" if verbose else "OFF"
# log_level = "OFF" if verbose else "OFF"
# TODO: even if the log level is set to OFF, the orhelper still prints msgs

with orhelper.OpenRocketInstance(ork_jar, log_level=log_level) as instance:
with orhelper.OpenRocketInstance(ork_jar, log_level="OFF") as instance:
# create the output folder if it does not exist
if os.path.exists(output) is False:
os.mkdir(output)

orh = orhelper.Helper(instance)
ork = orh.load_doc(filepath)
ork = orh.load_doc(str(filepath))

settings = ork_extractor(
bs=bs,
filepath=filepath,
filepath=str(filepath),
output_folder=output,
ork=ork,
eng=eng,
verbose=verbose,
)

with open(os.path.join(output, "parameters.json"), "w") as convert_file:
convert_file.write(
json.dumps(settings, indent=4, sort_keys=True, ensure_ascii=False)
)
if verbose:
print(f"[ork2json] parameters.json file saved in {output}")

return None
logger.info(
f"[ork2json] The file 'parameters.json' was saved to: '{Path(output).as_posix()}'"
)
logger.info(
f"[ork2json] Operation completed successfully. You can now use the 'parameters.json' file to run a simulation."
)


@cli.command("ork2py")
Expand Down Expand Up @@ -209,7 +234,6 @@ def ork2py(
_description_
"""
get_dict = ork2json(filepath, output, eng, ork_jar)
return None


@cli.command("ork2ipynb")
Expand All @@ -219,4 +243,3 @@ def ork2py(
@click.option("--ork_jar", type=str, default=None, required=False)
def ork2ipynb(filepath, output, eng=None, ork_jar=None):
get_dict = ork2json(filepath, output, eng, ork_jar)
return None
18 changes: 11 additions & 7 deletions open_rocket_serializer/components/drag_curve.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import logging
import os
from pathlib import Path

import numpy as np

logger = logging.getLogger(__name__)

def save_drag_curve(datapoints, data_labels, output_folder, verbose=False):

def save_drag_curve(datapoints, data_labels, output_folder):
"""Extracts the drag curve from the data and saves it to a csv file.
Parameters
Expand All @@ -15,9 +19,6 @@ def save_drag_curve(datapoints, data_labels, output_folder, verbose=False):
path : str
Path to the folder where the drag curve should be saved. This needs to
be a folder that already exists.
verbose : bool, optional
Whether or not to print a message of successful execution, by default
False.
Returns
-------
Expand All @@ -29,8 +30,11 @@ def save_drag_curve(datapoints, data_labels, output_folder, verbose=False):
float(datapoint.text.split(",")[data_labels.index("Altitude")])
for datapoint in datapoints
]
logger.info(f"Collected altitude vector")

apogee_index = np.argmax(altitude_vector)
datapoints = datapoints[:apogee_index]
logger.info(f"Removed data after apogee")

# Extract the drag coefficient and Mach number
cd = [
Expand All @@ -41,6 +45,7 @@ def save_drag_curve(datapoints, data_labels, output_folder, verbose=False):
float(datapoint.text.split(",")[data_labels.index("Mach number")])
for datapoint in datapoints
]
logger.info(f"Collected drag coefficient and Mach number")

# Convert to numpy array
cd = np.array([mach, cd]).T
Expand All @@ -52,11 +57,10 @@ def save_drag_curve(datapoints, data_labels, output_folder, verbose=False):
cd = np.unique(cd, axis=0)
# Remove values when the drag is lower than 0
cd = cd[cd[:, 1] > 0, :]
logger.info(f"Successfully created the drag curve")

# Save to csv file
path = os.path.join(output_folder, "drag_curve.csv")
np.savetxt(path, cd, delimiter=",", fmt="%.6f")

if verbose:
print(f"[Drag Curve] Successfully extracted the drag curve: {path}")
logger.info(f"Successfully saved the drag curve file to: '{Path(path).as_posix()}'")
return path
40 changes: 31 additions & 9 deletions open_rocket_serializer/components/environment.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import logging

import yaml

from .._helpers import _dict_to_string

logger = logging.getLogger(__name__)

def search_environment(bs, verbose=False):

def search_environment(bs):
"""Searches the launch conditions in the bs object. Returns a dict with the
settings.
Parameters
----------
bs : BeautifulSoup
BeautifulSoup object of the .ork file.
verbose : bool, optional
Whether or not to print a message of successful execution, by default
False.
Returns
-------
Expand All @@ -28,13 +31,33 @@ def search_environment(bs, verbose=False):
wind_average = float(bs.find("windaverage").text)
wind_turbulence = float(bs.find("windturbulence").text)
geodetic_method = bs.find("geodeticmethod").text
logger.info(
"Collected first environment settings: latitude, "
+ "longitude, elevation, wind_average, wind_turbulence, geodetic_method"
)
try:
base_temperature = float(bs.find("basetemperature").text)
logger.info(
"The base temperature was found in the .ork file. "
+ f"It is {base_temperature} °C."
)
except AttributeError:
logger.warning(
"No base temperature was found in the .ork file. "
+ "The base temperature will be set to None."
)
base_temperature = None
try:
base_pressure = float(bs.find("basepressure").text)
logger.info(
"The base pressure was found in the .ork file. "
+ f"It is {base_pressure} Pa."
)
except AttributeError:
logger.warning(
"No base pressure was found in the .ork file. "
+ "The base pressure will be set to None."
)
base_pressure = None
date = None

Expand All @@ -49,9 +72,8 @@ def search_environment(bs, verbose=False):
"base_pressure": base_pressure,
"date": date,
}
if verbose:
print(
f"[Environment] The environment settings were extracted."
+ f" \n{yaml.dump(settings, default_flow_style=False)}"
)
logger.info(
"Successfully extracted all the environment settings.\n"
+ _dict_to_string(settings, indent=23)
)
return settings
Loading

0 comments on commit 6be0210

Please sign in to comment.