[General] Add API docs and pydantic for Data Dict
Fix schedule for latex
This commit is contained in:
parent
e474c140ee
commit
fb28c6c5c5
11 changed files with 186 additions and 57 deletions
0
src/nrsk/schedule/__init__.py
Normal file
0
src/nrsk/schedule/__init__.py
Normal file
|
|
@ -9,13 +9,11 @@ import logging
|
|||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
|
||||
import jpype
|
||||
import jpype.imports
|
||||
import matplotlib.dates as mdates
|
||||
import matplotlib.pyplot as plt
|
||||
import mpl_toolkits.axisartist as axisartist
|
||||
import pandas as pd
|
||||
import yaml
|
||||
from docutils import nodes
|
||||
|
|
@ -29,18 +27,12 @@ logger.setLevel(logging.DEBUG)
|
|||
# Start JVM with MPXJ jar
|
||||
jpype.startJVM(classpath=["/home/nick/repos/mpxj/mpxj-lib/*"])
|
||||
|
||||
from java.io import File
|
||||
from java.io import File # noqa: E402
|
||||
from java.time import LocalDateTime # noqa: E402
|
||||
from org.mpxj import ( # noqa: E402
|
||||
Availability,
|
||||
Duration,
|
||||
FieldType,
|
||||
ProjectFile,
|
||||
Relation,
|
||||
RelationType,
|
||||
Resource,
|
||||
TaskField,
|
||||
TaskType,
|
||||
TimeUnit,
|
||||
)
|
||||
from org.mpxj.cpm import MicrosoftScheduler, PrimaveraScheduler # noqa: E402
|
||||
|
|
@ -196,7 +188,7 @@ def _preprocess_plot(project):
|
|||
return df, df_deps
|
||||
|
||||
|
||||
def plot_schedule(
|
||||
def plot_schedule( # noqa: C901
|
||||
input_fname: str = "scheduled.xml", project=None, output_fname: str = "schedule.svg"
|
||||
):
|
||||
"""Generate plot of schedule."""
|
||||
|
|
@ -270,7 +262,7 @@ def plot_schedule(
|
|||
plt.title("AMS High-Level Schedule")
|
||||
# plt.tight_layout()
|
||||
plt.savefig(output_fname)
|
||||
plt.show()
|
||||
# plt.show()
|
||||
|
||||
|
||||
class ScheduleDirective(Directive):
|
||||
|
|
@ -281,65 +273,69 @@ class ScheduleDirective(Directive):
|
|||
|
||||
def run(self): # noqa: D102
|
||||
env = self.state.document.settings.env
|
||||
builder = env.app.builder
|
||||
schedule_data = self.arguments[0]
|
||||
|
||||
schedule_data_abs = os.path.join(env.srcdir, schedule_data)
|
||||
schedule_data_abs = Path(env.srcdir) / schedule_data
|
||||
|
||||
if not os.path.exists(schedule_data_abs):
|
||||
if not schedule_data_abs.exists():
|
||||
logger.error(f"Schedule file not found: {schedule_data_abs}")
|
||||
return []
|
||||
|
||||
# Image output directory
|
||||
gen_dir = os.path.join(env.app.srcdir, "generated_assets")
|
||||
# put image within _static so html builder knows to copy it over.
|
||||
gen_dir = Path(env.app.srcdir) / "_static" / "generated_assets"
|
||||
ensuredir(gen_dir)
|
||||
ensuredir(os.path.join(env.app.outdir, "_downloads"))
|
||||
|
||||
# Name of the generated file
|
||||
base = os.path.splitext(os.path.basename(schedule_data))[0]
|
||||
out_image = os.path.join(gen_dir, f"{base}.svg")
|
||||
out_image = gen_dir / f"{base}.svg"
|
||||
|
||||
start_date = datetime(2026, 1, 1)
|
||||
proj = load_from_yaml(fname=schedule_data)
|
||||
solve_schedule(proj, start_date)
|
||||
plot_schedule(project=proj, output_fname=out_image)
|
||||
writer = UniversalProjectWriter(FileFormat.MSPDI)
|
||||
writer.write(proj, os.path.join("_build", "_downloads", f"{base}_mspdi.xml"))
|
||||
writer.write(proj, gen_dir / f"{base}_mspdi.xml")
|
||||
|
||||
env.note_dependency(schedule_data_abs)
|
||||
rel = str(os.path.relpath(out_image, env.app.srcdir))
|
||||
# trying to mock /generated_assets/schedule.svg for the build folder
|
||||
# but it ends up in _images actually.
|
||||
# somewhat hacky but works in subfolders
|
||||
abs_rel = os.path.join("/", rel)
|
||||
image_node = nodes.image(uri=abs_rel)
|
||||
uri = builder.get_relative_uri(env.docname, "_images/" + f"{base}.svg")
|
||||
uri = uri.replace(".html", "")
|
||||
|
||||
ref_node = nodes.reference("", "", refuri=uri)
|
||||
ref_node += image_node
|
||||
ref_node["target"] = "_blank"
|
||||
ref_node["rel"] = "noopener"
|
||||
|
||||
uri_dl1 = builder.get_relative_uri(
|
||||
env.docname, "_downloads/" + f"{base}_mspdi.xml"
|
||||
)
|
||||
uri_dl1 = uri_dl1.replace(".html", "")
|
||||
download1 = nodes.reference(
|
||||
text="Download schedule in MS Project XML format",
|
||||
refuri=uri_dl1,
|
||||
classes=["download-link"],
|
||||
)
|
||||
|
||||
uri = f"/_static/generated_assets/{base}.svg"
|
||||
image_node = nodes.image(uri=uri)
|
||||
paragraph = nodes.paragraph()
|
||||
paragraph += ref_node
|
||||
paragraph += download1
|
||||
|
||||
# download link only makes sense in web env, not PDF
|
||||
builder_name = self.state.document.settings.env.app.builder.name
|
||||
if builder_name not in ("html", "singlehtml", "dirhtml"):
|
||||
paragraph += image_node
|
||||
else:
|
||||
# add hyperlink to image. Since this may be called from a subdir we need
|
||||
# relative paths that walk up appropriately.
|
||||
docname = env.docname # subdir/mydoc
|
||||
relative_root_path = "../" * docname.count(os.sep)
|
||||
hyperlink_uri = relative_root_path + uri[1:]
|
||||
|
||||
# Result when docname is 'subdir/mydoc':
|
||||
# hyperlink_uri will be: ../_static/generated_assets/my_diagram.svg
|
||||
ref_node = nodes.reference("", "", refuri=hyperlink_uri)
|
||||
ref_node += image_node
|
||||
ref_node["target"] = "_blank"
|
||||
ref_node["rel"] = "noopener"
|
||||
paragraph += ref_node
|
||||
|
||||
# and hyperlink to schedule data
|
||||
hyperlink_uri = (
|
||||
relative_root_path + f"_static/generated_assets/{base}_mspdi.xml"
|
||||
)
|
||||
download1 = nodes.reference(
|
||||
text="Download schedule in MS Project XML format",
|
||||
refuri=hyperlink_uri,
|
||||
classes=["download-link"],
|
||||
)
|
||||
paragraph += download1
|
||||
|
||||
return [paragraph]
|
||||
|
||||
|
||||
def setup(app):
|
||||
"""Setup for sphinx extension."""
|
||||
def setup(app): # noqa: D103
|
||||
app.add_directive("schedule", ScheduleDirective)
|
||||
|
||||
return {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue