Skip to content
Advertisement

How to wait until java compilation of PlantUML diagrams is completed, in Python?

Context

I’ve written a Python code that:

  1. First generates PlantUML .uml files.
  2. Then runs a Java command to locally compile those .uml files into .png diagrams.
  3. Exports those diagrams into a /images directory for latex compilation.
  4. Then compiles a latex document that integrates those generated PlantUML diagrams.

Code

The Python that compiles the .uml files into .png files is:

def compile_gantt(relative_plant_uml_java_filepath,relative_src_filepath,src_to_gantt_path):
    os.environ["PLANTUML_LIMIT_SIZE"] = "8192"
    run_bash_command(
        f"java -jar {relative_plant_uml_java_filepath} -verbose {relative_src_filepath}{src_to_gantt_path}"
    )

def run_bash_command(bashCommand):
    # Verbose call.
    subprocess.Popen(bashCommand, shell=True)
    # Silent call.
    #subprocess.Popen(bashCommand, shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)

And I have written a method that waits until all .png files are created:

def await_and_verify_compilation_results(self, dir, expected_diagram_filenames,compilation_timout):
        pause_per_iteration=4 #seconds
        
        count=0 # seconds
        while count<compilation_timout:
            all_found=True
            for diagram_filename in expected_diagram_filenames:
                if not os.path.isfile(f"{dir}/{diagram_filename}"):
                    all_found=False
                    print(f"Did not yet find:{dir}/{diagram_filename}")
            print(f"Awaiting compilation of Gantt charts: count={count}/{compilation_timout}.")
            
            # Break while condition.
            if all_found:
                count=compilation_timout+pause_per_iteration
            
            # Continue waiting.
            count=count+pause_per_iteration
            time.sleep(pause_per_iteration)
        
        if not all_found:
            raise Exception("Did not find all gantt diagrams in time!")
        time.sleep(30) # allow extra buffer for all images to be finalised.

Issue

The Python code proceeds before the images are completely generated by the Java process.

This means the images are created but it takes a while before they are actually filled with data. Even when they are filled with data it takes a while before they are completed. For example some_diagram.png may increase in file size from 0 kb, to 800 bytes to 1.2 kb over the timespan of a few seconds. So my “await_and_verify_compilation_results` does not wait until the generation of the pictures is completed.

Question

How can I make the Python code wait until the Java process/PlantUML generation of the .png files is completed?

Considerations

Since the .png files are generated automatically, I do not know what their final file size would be. I can set a manual pause of x seconds after each png to ensure they are completed on my device, but I would not want others with a faster device to have to wait on my buffer. Additionally such a hardcoded loiter may be unreliable, and inefficient compilation-timewise. So I think the most simple solution would be to modify the python function that calls the Java function. I have not yet found out how to make that wait, nor have I found how I can make the Java function signal that is is completed. (The PlantUML .jar file is downloaded automatically and I would prefer not to tamper with their file).

Advertisement

Answer

As Gonzalo Odiard already suggested in the comments, the solution could be found by using subprocess.call instead of subprocess.Popen. So a solution looked like:

def run_bash_command(bashCommand):
    # Verbose call.
    subprocess.call(bashCommand, shell=True)
    # Silent call.
    # subprocess.call(bashCommand, shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)

It was verified on Ubuntu 21.04 Using Python 3.6.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement