Modules
In DolphinDB, you can save user-defined functions as reusable modules and organize the modules into hierarchical namespaces. Modules can be loaded during the system startup, or imported into a session when needed.
1. What are Modules
A module in DolphinDB is a script file that only contains function definitions. Modules have the following features:
- Module files are located in the [home]/modules directory by default.
- Module files have the extension .dos (short for "DolphinScript") or .dom (short for "DolphinModule").
- The first line of a module file must be the module declaration,
module [module_name]
. - Apart from the first line, a module file can only contain module import statements and function definitions.
2. Defining Modules
This section describes the steps to define modules.
2.1. Defining Directory for Module Files
Module files are located at [home]/modules by default.
- The [home] directory is specified by the configuration parameter
home, which you can check with
getHomeDir
. - The directory for the module files is specified by the configuration parameter moduleDir. The default value is the relative path "modules". The system searches "modules" in the following order: home directory of the node, the working directory of the node, and the directory with the DolphinDB executable. Please note that in the single node mode, these 3 directories are the same by default.
2.2. Creating a Module File
Create a file [moduleName].dos in the "modules" folder (e.g., fileLog.dos). The first line must be the module declaration:
module fileLog
In this example, "fileLog" is the module name, which must be the same as the name of the module file.
The rest of the file should only contain function definitions and, if necessary,
module import statements. Any code outside of function definitions, module
declarations, or import statements will be ignored. In this example, the
"fileLog" module contains only one function, appendLog
, which
writes log entries to a user-specified file.
module fileLog
def appendLog(filePath, logText){
f = file(filePath,"a+")
f.writeLine(string(now()) + " : " + logText)
f.close()
}
To organize modules, you can create subdirectories as namespaces under the "modules" directory. For details, see section 4.1. Declaring Namespace for Modules.
2.3. Serializing a Module File
Use saveModule to serialize a .dos module file to a binary file with the extension .dom. This enhances the security of the code. In this example, we serialize the module file from the previous section:
saveModule("fileLog")
The generated .dom file is saved to the same directory as the original .dos file.
- If the .dos file is changed, execute
saveModule
again to generate a new .dom file. Set the "overwrite" parameter to "true" to replace the old .domfile:saveModule(name="fileLog", overwrite=true)
- When a module references another module, the serialization process only includes the name of the referenced module, not its definition. As a result, when loading or moving a .dom file, ensure that you also load or move any referenced modules.
3. Importing Modules
This section describes two ways to import modules, importing with the
use
keyword, or loading modules as built-in functions.
3.1. Importing Modules with use
You can import a module with the use
keyword. If the imported
module uses other modules, these modules are also loaded automatically.
- The imported modules are only available in the current session.
- For version 2.00.11 and earlier, only module files with the .dos
extension can be imported with
use
.Starting from version 2.00.12,use
can be used to load .dos and .dom files. If files with the same name but different extensions (.dos and .dom) exist in the same location, the system will import the .dos file.
After importing the module, you can call the functions defined in the module in the following ways:
- Refer to the module
function:
use fileLog appendLog("mylog.txt", "test my log")
- Specify the namespace of the function (i.e., the full path of the function
under the
modules
directory)Use this option if there are functions with the same name in other imported modules.
use fileLog fileLog::appendLog("mylog.txt", "test my log")
3.2. Loading Module Functions as Built-in Functions
As mentioned in the preceding section, the use
keyword only
imports a module to the current session. To make the functions defined in a
module available to all sessions, we need to add them as system built-in
functions with the function loadModule
or the configuration
parameter preloadModules. This also makes the code more concise without
the use
statement, and more convenient for module function
references through API calls.
Note the following about module functions that are added as built-in functions:
- The functions cannot be overridden.
- When the function is referenced by
remoteRun
orrpc
, its definition will not be serialized and sent to the remote node. Therefore, make sure the relevant module has been loaded on the remote node before the remote call or an exception will be thrown. - The functions have only one copy in the memory and it is visible to all sessions. This saves not only the memory usage but also the time it takes for each session to import the module.
Both .dos files and .dom files can be used to load modules. If the "modules" directory contains a .dos file and a .dom file with the same name, the system will only load the latter. For a module function imported from a .dom file, its definition is not visible to the users.
3.2.1. Using the Function loadModule
loadModule
can only be used in the initialization script
(dolphindb.dos as the default file) of the system, and not in the
CLI or GUI. For example, to import the module file created in 2.2. Creating a Module File section,
append this line to the initialization script:
loadModule("fileLog")
When calling a function from the loaded module, specify the namespace of the
function (i.e., the full path of the function under the
modules
directory):
fileLog::appendLog("mylog.txt", "test my log")
3.2.2. Using the Configuration Parameter preloadModules
For standalone deployment, specify the modules to be loaded by configuring
the parameter preloadModules in the configuration file
dolphindb.cfg; for cluster deployment, configure
preloadModules
in both controller.cfg and
cluster.cfg as the module must be imported to both the controller
and the relevant data nodes.
For example:
preloadModules=fileLog
Use commas to separate multiple modules.
3.2.3. Functions Loaded from Modules vs. Function Views
Note the differences between the built-in functions loaded with
loadModule
or preloadModules and the DolphinDB
function views:
- The definition of a function view can be viewed by its creator, administrators and users with the required privileges. A module function loaded from a .dom file is more secure as no user can view its definition.
- Access control can be applied to function views but not loaded module functions.
- When the system serializes a module which references a function in another module, the referenced function is only serialized by its name and its definition is not serialized. A serialized function view, on the other hand, is self-contained with all the referenced objects serialized as well.
Function views and modules are designed for different scenarios. Function views are used in database queries whereas modules usually contain common algorithms or processing logic which can be referenced in different scripts. A function view may reference a function in a module but a module seldom references a function view.
4. Organizing Modules
This section describes how to organize modules using namespaces.
4.1. Declaring Namespace for Modules
To organize modules more efficiently, create subdirectories under the
modules
directory to create a hierarchy of namespaces for
the modules. For example:
- For a module at modules/system/file/fileUtil.dos, use the
declaration:
module system::file::fileUtil
- For a module at modules/system/temporal/dateUtil.dos, use the
declaration:
module system::temporal::dateUtil
4.2. Calling Modules with Namespaces
For a module located at the sub directories under modules
,
specify the full namespace of the module when:
- Calling the functions
saveModule
andloadModule
- Configuring the preloadModules parameter
- Importing it with the
use
statement
This example imports the "fileLog" module from the previous section:
use system::log::fileLog
After the module is imported, you can directly call the function in the module:
appendLog("mylog.txt", "test my log")
or call the module function with its full namespace:
system::log::fileLog::appendLog("mylog.txt", "test my log")
5. Debugging Modules Remotely in GUI and VS Code
When DolphinDB clients GUI or VS Code (through the DolphinDB extension) is connected
to a remote DolphinDB server, the module edited locally must be uploaded to the
[home]/modules directory on the remote server before it is called by the
use
statement.
5.1. DolphinDB GUI
To synchronize modules to a remote server in the DolphinDB GUI by following the steps below:
- Specify a remote server:
- Click Server → Add Server, and specify the Remote Directory.
- Alternatively, click Server → Edit Server to add the remote directory.
- Select the local "modules" directory to launch its menu. Click
Synchronize module to server to synchronize all files and sub
directories under the local "modules" directory to the previously specified
remote directory.
For example, the Remote Directory is specified as '[home]/modules', and the file to synchronize is C:/users/usr1/Project/scripts/test.dos. During the synchronization, the system will generate the directory and the file '[home]/modules/Project/scripts/test.dos' on the remote server.
Once the synchronization is complete, you can import modules with the
use
statement on the remote server. For more information
about setting modules directory, see 2.1.
Defining Directory for Module Files.
5.2. VS Code
The DolphinDB extension for Visual Studio Code provides a convenient way to upload modules to the server. Here's how to use this feature:
- Edit your module file in VS Code.
- Once you're ready to upload, right-click on the module file.
- From the context menu, select DolphinDB: Upload Module.
- A prompt will appear asking if you want to encrypt the module as a .dom file. Choose your preferred option.
6. Usage Rules
6.1. Calling Module Functions with the Same Name
Since different modules may contain functions with the same name, it is recommended to call a module function with its namespace.
For function calls that do not specify the function namespace, DolphinDB disambiguates functions with the same names according to the following rules:
- If one and only one imported module contains the function, it refers to the function defined in that module.
- If two or more imported modules contain the function, throw an
exception.
Modules [Module1] and [Module2] contain function [functionName]. Please use module name to qualify the function.
- If no imported module contains the function, search for system built-in functions; If there is no match, throw an exception.
- If a function in an imported module has the same name as a user-defined
function, use the function in the module. If you want to call the
user-defined function, specify its namespace.Note: The default namespace for all user-defined functions and built-in functions is the root directory, indicated by two colons
::
.
In this example,
- First, create a user-defined function
myfunc
:login("admin","123456") def myfunc(){ return 1 } addFunctionView(myfunc)
- Next, create a module "sys" that contains a function also named
myfunc
:module sys def myfunc(){ return 3 }
Now, if you want to call the function in the module "sys" in your current session,
- First, import the module with
use
:use sys
- Then call the function with its namespace:
sys::myfunc()
or simply:
myfunc()
To call the user-defined function, use:
::myfunc()
6.2. Reloading a Module
Each module is only imported once per session. If you want to repeatedly change a module to test interactively, there are two options:
- Execute the entire module after updating the module. This method is only effective for the current session.
- Call
clearCachedModules
after updating the module. Then when you import the module with theuse
statement again, the system reloads it from the module file instead of using the cached data, and there is no need to restart the node.Note: This option is available to administrators only.
6.3. Cross-module Calls
A module can be imported into another module. For example, you can import module A into module B, then import module B into module C.
However, circular imports are not supported. For example, if module A references functions defined in module B, then module B cannot reference the functions in module A.