require() not working correctly in interactive shell
Zirunis opened this issue · 5 comments
Minecraft Version
1.16.x
Version
1.101.3
Details
require(filePath)
doesn't work correctly with following setup:
- There is a folder in the home directory (in my case called "datatypes")
- It contains two lua files (in my case "Bidict.lua" and "Set.lua") with one importing the other (in my case the former importing the latter via
Set = require("Set")
- Starting the interactive lua shell from the home directory
- Importing the lua file which imports the other lua file (in my case:
Bidict = require("Bidict")
While it can find 'Bidict.lua', during its import it tries importing 'Set' inside of 'Bidict.lua' which fails. It can't find the module throwing a stack-trace with all the locations it looked for it. Unfortunately it is cut off so I can't paste it here. The logs also didn't have anything of interest.
Interestingly, starting the interactive shell from the folder containing the two files works fine. My programs in the home directory which import 'Bidict' just like I'm trying to in the shell also work fine.
I hope you can reproduce the bug. Please let me know if I can be of any further assistance!
Thanks for the report!
I'm afraid I'm getting a little stuck on following your reproduction steps (testing on CC 1.110.3, but I don't think this code has change much since).
Importing the lua file which imports the other lua file (in my case:
Bidict = require("Bidict")
I'm slightly surprised/confused by this step. I wouldn't expect this to work — if you're running from the root directory, require("Bidict")
will look for files at /Bidict.lua
, and so shouldn't find /datatypes/Bidict.lua
.
I'd also expect you to hit this problem with the programs in the root directory too. Just to check, you're not changing package.path
anywhere are you?
This is my current setup, with the following files:
datatypes/Set.lua
, just containingprint("Set")
.datatypes/Bidict.lua
, containingprint("Bidict"); require("Set")
Then opening the Lua REPL and running the following:
Am I missing/misunderstanding a step here?
Thanks for the fast reply!
I'd also expect you to hit this problem with the programs in the root directory too. Just to check, you're not changing package.path anywhere are you?
Nope
I'm slightly surprised/confused by this step. I wouldn't expect this to work — if you're running from the root directory, require("Bidict") will look for files at /Bidict.lua, and so shouldn't find /datatypes/Bidict.lua.
Yeah, I'm sorry, I messed up the description at that step. I'm actually calling require("datatypes/Bidict") which should work, right?
This is what I'm actually running:
This works even though the files are the same:
I have now noticed that my programs in the home directory calling require("datatypes/Bidict") in the same exact way actually don't work either. So it does not have to do with the interactive shell but require() in general.
Files are required from the currently running program, so if /startup.lua
requires datatypesDemo/Bidict
, then Bidict.lua
would need to require datatypesDemo/Set
.
Alternatively...
Updating package.path
In your root file, you will want to have some approximation of the following code:
package.path = package.path .. ";/datatypesDemo/?.lua;/datatypesDemo/?/init.lua"
What this does is tells require
that it should search in the datatypesDemo
folder for *
or */init.lua
, where *
is replaced by your require string.
Then, you can leave Bidict.lua
as is, to require("Set")
. As well, in your root file, you can just require("Bidict")
now, instead of needing to include the folder name.
Thank you for your answer but that makes no sense to me. How are dependencies then handled in the general case? I'd need to go through all dependencies and replace their require(relativePath)
which would work fine on its own with a require(absolutePath)
? That can't be right. Especially since there might even be naming conflicts. Who is to say that dependency A and dependency B don't both have a separate dependency like 'utils' that is contained in each of their directories? Now when my program imports these two dependencies it 1. Doesn't know where to look and 2. Might choose the wrong one if I use the package.path solution?
Nevermind. I looked it up and you're right. require()
seems to just suck.
However for people stumbling across this in the future: I found out that there is a better way. There is an argument passed to an api when it is require()'d which is the argument given to require() itself, which is either its absolute path or the relative path as seen from the importing program. So one can do something like this at the top of each file:
local pathToThisFile = (...):match("(.-)[^%.]+$") --turns "datatypes.Bidict" into "datatypes."
local Set = require(pathToThisFile .."Set")
In this case you'd always have to import files using dot-notation, but changing the pattern to also transform something like "datatypes/Bidict.lua" into "datatypes." shouldn't be too hard.