The latter will be easier to debug, because you will have smaller functions to check, test, etc.
If not a GUI, perhaps tell them to edit an excel spreadsheet? To have them choose files, you can use NativeFileDialogue.jl.
Hmm, I thought I would be ok regardless of where they run the file from based on the documentation of
@__dir__: “Expand to a string with the absolute path to the directory of the file containing the macrocall.”
Yeah, most of the data files I am reading are already
.xlsx. I wasn’t sure that
.xlsx was a good medium for reading scalar inputs though. NativeFileDialog.jl seems really useful.
In any case, I can test out some different file types and helper packages (maybe
__init__ too). I just wanted to make sure I wasn’t overlooking some obvious workflow. It sounds like I should still be using a package (and thus a module) but that it would be better to put function calls inside
process rather than
include statements, even if that means I need to define containers for everything.
Give the name of the input file as argument?
julia script.jl arg1 arg2 (Getting Started · The Julia Language)
I think OP’s audience is on Windows and probably doesn’t know how to use the command line.
#!JLScript -iq --startup-file=no --project=@GlobalScripting_ASME using ASME_Materials #raw"": Allows paths with "\" without escaping (ex: "S:\\Material..."): data_root = raw"S:\Material Properties" options = ( input_file = joinpath(data_root, "Section II-D Tables.xlsx"), output_dir = joinpath(data_root, raw"Excel Material Data\AIP Q&T Steels"), ) result = ASME_Materials.RunTheScript(options) display(result) #Because: Why not? :DONE
…and execute it from with a right-click in Windows Explorer?
You could provide (copy) the basic “Scripting interface” from
- Creates a sample “shared” Julia environment (
GlobalScripting_ASMEenvironment is used by sample script
- Copies a powershell script (
launch_julia_script.ps1) to the active Julia directory.
- This might require Windows admin privileges.
- Adds RMB “Execute with Julia” action for
.jl_scriptfiles in Windows Explorer.
- Also requires Windows admin privileges.
That’s really cool, but admin privileges might be an issue.
If admin privileges are an issue:
You won’t need them to write the
.ps1 file… since it gets copied to your Julia install directory (which presumably was installed without admin privileges either)
You would only need them to execute/install the
.inffile to register the RMB action item in Windows Explorer.
But since the
.inf file is relatively simple/easy to decode, you can probably convince someone in IT to install it for you:
[version] signature="$CHICAGO$" [DefaultInstall] AddReg = Explore.AddReg [Strings] ACTION_TEXT = "Execute with Julia v1.7.2" ACTION_CMD = "powershell -WindowStyle hidden -ExecutionPolicy Bypass -Command "C:\APPS\Julia-1.7.2\bin\launch_julia_script.ps1" '%1'" [Explore.AddReg] HKCR,SystemFileAssociations\\.jl_script\\shell\\JLScript-v1.7.2,,,%ACTION_TEXT% HKCR,SystemFileAssociations\\.jl_script\\shell\\JLScript-v1.7.2\\command,,,%ACTION_CMD%
(It gets installed by double-clicking on this file if it has a
That’s because you shouldn’t run
include() from within a function (much in the same way you shouldn’t run
using from within a function).
Doing so appears to run
include() in the calling scope… and so you start getting strange behaviours. I am almost certain running
include() from within a function is bad practice, and I would personally avoid it.
include() isn’t exactly the same as
#include in C/C++.
What you should instead be doing is something more like:
include("ReadTables.jl") include("BuildTables.jl") include("WriteTables.jl") include("PlotTables.jl") function process(options) read_input_tables(options) # defined in ReadTables.jl build_more_tables(options) # defined in BuildTables.jl write_some_tables(options) # defined in WriteTables.jl plot_important_tables(options) # defined in PlotTables.jl return results #written somewhere in the module's global namespace, I suppose end
This coding shift requires encapsulating much of the code you wrote in the global namespace (of
*Tables.jl files) inside these
build_more_tables()/… functions. You can leave the code in their respective files - just wrap them inside one-or-more function call(s).
If you want to keep the data around inside the global namespace: just remember to declare/tag the variable as global:
function readtable(...) #This low-level function is fine as it is. No need to change it. function read_input_tables(options) #New encapsulating function #... global tableY = readtable(options.inputfilepath, "Table Y-1") #... end
One of the consequences of what @mkitti mentioned:
is that you shouldn’t write your
*Tables.jl files as conventional scripts with code running in the global namespace (ie: “global” = not “inside” functions).
That only works for executing files in the REPL. As soon as you wrap files into modules, your non-static, “execution-mode” code should all be written inside one (or-more) functions.
I don’t think this is explicitly stated anywhere (I’m sort of sad to make this realization just now)… but it is a natural consequence of what @mkitti just said.
Only “static” code that can effectively be pre-compiled is allowed to exist outside functions.
I have a few more relatively important suggestions for improving your code, but this particular issue seems to be your dominant problem - so I’ll refrain from giving you more confusing tips.
The JuilaScripting.jl sample I provided earlier shows a more Julian way to write your module (I modelled it closely after your
ASME_Materials.jl module to help you better understand the Matlab->Julia transition)
→ take another look!: GitHub - ma-laforge/JuliaScripting.jl
I also tried to add useful comments to the global namespace &
__init__() functions so you can get a better idea of what should go where.
Thank you so much! I am happy to hear all your suggestions. Give me a few days to try to update my package with the suggestions already provided (maybe longer to figure out the
.ps1 stuff ). Then I will reach back out to you privately.