Here's what's happening
I look in the server machine where published tools are hosted and I see that not all of the scripts used by the tool are uploaded to the server. Comparing the two photos below, the photo with more stuff in it is my dev folder, while the one with less stuff is the folder on the server machine. As you can see, when I publish, not all the scripts make it on to the server.
As a workaround, if I manually copy over the scripts that didn't publish, then restart the web service, all works well, but this seems like an inconvenient workaround. Why aren't all scripts publishing? Do I need to tweak my code? Here is how I'm importing modules in the main script--highlighted lines are for modules that did not import*:
* I have an untested theory that if I specify from <module> import <thing> that it will result in the module not uploading. Is this the case? Do I instead need to write import <module> then in my code specify <module>.<thing>?
Your theory is likely correct, this has been noticed previously (see 2nd comment below this GIS-SE answer).
You can also use import <module>.<thing> as <thing>.
Progress but still no victory yet. Here's what happens:
Why am I not surprised...
I'm assuming since you can import utils.utils then it is a proper python package with a utils/__init__.py and then the other submodules like utils.py etc.
Possible dodgy workaround (I can't test publishing) - the docs only discuss importing modules not packages (other docs discuss how to install external 3rd party packages, but that's not relevant). But there is a section in there that talks about sys.path.append:
Another technique for referencing modules to import is to use the sys.path.append method. This allows you to set a path to a folder containing scripts that you need to import.
note that the sys.path.append method requires a folder as an argument. Since r'e:\Warehousing\Scripts' is a folder, the entire contents of the folder will be consolidated.
I paraphrased the quote slightly, but it makes me think you might be able to throw in sys.path.append("utils") and the utils package and all its submodules would get consolidated and published.
I don't think there would be any issue with the import utils.utils call after appending the utils dir to sys.path, I just tried in a simple python script on my local drive and it worked. But if there is, you could always sys.path.pop() or del sys.path[-1] directly after the append.
Thanks for the tip Luke. I was trying the sys.path.append("utils") approach and for some reason it was giving me a "module not found error". I then tried adding an __init__.py script to the utils folder, but that didn't fix it, but then commenting out the sys.path.append("utils") did seem to fix it. At the same time my Arc Pro has been inconsistent this morning--I'll try the .append() approach perhaps on a different day after restarting my machine.
Just too bad that the utils folder doesn't just import!