2. DSLite: Does my package work?
After completing the first exercise, we have a brand new DataSHIELD package ready. However, how do we know it works?
To assess that, we have in our hands a great tool named DSLite
. This tool will create a virtual environment that simulates a server on our own computer (!). This will allow us to run our DataSHILED functions, and moreoever it will bring us easy access to the values on the server R session, so we will be able to check if our assign function has worked, it if has assigned what we expected, etc.
We will now setup a script to setup DSLite
with our new packages and test that they work as we expect.
library(dsBase)
library(dsBaseClient)
library(dsClient)
library(dsServer)
<- DSI::newDSLoginBuilder()
builder <- DSLite::newDSLiteServer(
dslite.server config = DSLite::defaultDSConfiguration(
include=c("dsBase", "dsServer")
)
)$append(
builderserver = "server1",
url = "dslite.server",
driver = "DSLiteDriver"
)<- builder$build()
logindata.dslite <- DSI::datashield.login(logindata.dslite) conns
Now we have created a DSLite
virtual server and we have the connection object to talk to it. Note that it has the dsServer
and dsBase
packages inside of it, so we can use functions from those two packages.
Let’s now run our client function
::ds.assign.string(
dsClientobject = "myObject",
string = "myString"
)
If our packages are fine, we have now created a variable named myObject
that contains the string "myString"
. How can we check this? Let’s take a look
::getDSLiteData(
DSLiteconns = conns,
symbol = "myObject"
)
Sending data to my virtual server
This simple example we have just seen is pretty nice. However, one might be thinking hey typically I want my server functions to analyze tabular data, which is loaded by the user on the server session and will be used by my functions. We can also simulate this on DSLite
to test our packages. Let’s see an example where we will load iris
data on the virtual server.
library(dsBase)
library(dsBaseClient)
data("iris")
<- iris
myTable <- DSI::newDSLoginBuilder()
builder <- DSLite::newDSLiteServer(
dslite.server tables=list(myTable = myTable),
config = DSLite::defaultDSConfiguration(
include=c("dsBase")
)
)$append(
builderserver = "server1",
url = "dslite.server",
table = "myTable",
driver = "DSLiteDriver"
)<- builder$build()
logindata.dslite <- DSI::datashield.login(
conns logins = logindata.dslite,
assign=T,
symbol = "myTable_table"
)
This will assign the iris
dataset to a variable on the server named "myTable_table"
. As before, we can check it
::getDSLiteData(
DSLiteconns = conns,
symbol = "myTable_table"
)
When developing code, it is useful to be able to place debug points. This means being able to stop the execution on a certain point and look the environment, run code at that stop point etc. In R, a way of doing that is including browser()
statements on the code (more on this here).
DSLite
offers us the possibility of adding them on the server functions, and when we run them the execution will be stopped so we can take debug server functions.
Exercise 2
As out second exercise of the workshop, we will work on top of Exercise 1 developments.
Create a new aggregate function (named
getColnamesDS
) on thedsServer
package. This function will take as input argument a data table (that will be loaded on the server). It will return to the user the column names on the table.Create the correspondent function on
dsClient
(namedds.getColnames
) that calls the server function. This function will take as input argument the name of the server table that we want to get the number of columns.Test the new function using
DSLite
.