File system permissions and paths in iOS

Although Juno makes coding on iPad a breeze, there are still some tricks you need to know — one of them is working with the file system and handling paths. For example, when your code is supposed to read file’s contents or write data to a file, how do you specify file’s location in iOS?

Manipulating file system paths in iOS and iPadOS (we will refer to both as iOS from now on) is actually fairly straightforward and similar to how it’s done, say, on a Mac — with only few peculiarities. Generally, you can assume that all the usual rules apply, with two key differences:

  • Access permissions. iOS is more strict in terms of what a third-party app like Juno can do in your device’s file system, and which locations it can access.
  • Absolute paths. Don’t rely on absolute paths too much — for example, when you are coding in Juno and would like to specify location of the file to read from, use a relative path instead.

Access permissions

By default, apps can only access their own virtual space in device’s file system, commonly referred to as app’s sandbox directory, or sandbox; you can find it in Files Files app icon as a folder with the app’s name and icon in your on-device storage (technically, this is only the user-accessible part of the app’s sandbox, but let’s ignore this for now). This is the part of the device’s file system that the app “owns” and has full read and write access to; this is also where Juno puts its introductory notebook and creates /site-packages directory for your own Python modules and packages. The main reason those files are where they are is because Juno can be sure it will be able to access this location no matter what.

However, iOS also lets third-party apps access files and directories in other locations (e.g. iCloud, or even other apps’ sandboxes), as long as you, as a user, explicitly grant access to them in the app. For example, when you open a Jupyter notebook in Files with Juno, system automatically grants Juno access to this file, and any changes you make will be saved to the notebook’s original location — just like on desktop. Same thing happens when you open a notebook using Juno’s file browser, which is, effectively, a system file selection dialogue provided by Juno’s integration with the Files app.

It’s all well and good if you are only interested in the document contents, but what if you also want to access the folder where the document is located? This is a very common scenario in Juno: when you run code in a notebook, you usually want to be able to access the notebook’s directory, too — for example, to read a .csv file, or save a plot image. But, unless your notebook is in Juno’s sandbox, system will not grant Juno access to the file’s directory automatically.

When Juno detects that it doesn’t have access to the directory of the notebook it is running, it will display a Locked folder button in the top bar, next to kernel’s name:

No directory access icon

If you tap this button, a system folder selection dialogue will appear, letting you explicitly grant Juno access to the notebook directory. Select the folder where the notebook is located (should be pre-selected by default) and tap Done:

System dialogue to grant access to a folder

That’s it — system will now grant Juno access to the selected directory, and Juno will automatically set it as notebook’s current working directory (CWD).

Please, mind that it may not work if your notebook is located in a cloud storage — for example, granting access to directories will work with iCloud, but not with Dropbox or OneDrive. This is because some cloud storage apps don’t fully integrate with Files Files app icon on iOS, and file system functionality that will work in Juno goes only as far as their developers chose to integrate with the Apple’s APIs. Hopefully, those cloud storage services will finalise their Files integration eventually; but we are looking into workarounds, where we could potentially integrate with some of them bypassing Files app.

Absolute paths

Although you will find that absolute paths on iOS look similar to paths on a desktop OS, such as macOS, you shouldn’t rely on them too much — because they are not permanent, and occasionally get updated by the system under the hood, even if you haven’t moved the file. Here is an example of an absolute path of a file in iOS:

/private/var/mobile/Containers/Data/Application/76FB0F63-CCC1-4754-8047-B79F5E45FA97/Documents/MNIST/data.csv

This file is located in the sandbox of an app, and the identifier in the middle of the path (76FB...FA97) specifies this particular app’s version. However, this identifier is not linked to the app in general, and may change at some point — for example, when the app is updated.

Don’t worry about this too much — as long as you use relative paths in your code, you should be fine. Juno sets CWD to notebook’s directory by default, so simply remember to reference all locations relative to where your notebook is (or to its CWD, to be precise). Take this line from our introductory notebook, for example:

df = pd.read_csv('welcome-data/iris.csv')

The notebook sits alongside /welcome-data directory, i.e. they are both located in the same folder — so instead of using directory’s absolute path, you can simply refer to the .csv file inside it with 'welcome-data/iris.csv'.

CWD

The concept of current working directory (or CWD) is important in the context of using relative vs absolute paths in Juno. You can think of CWD as a directory where the Python interpreter associated with your notebook’s kernel is running in. So, when you want to specify a particular file system location in your Python code — say, a file to read from, or write to — you can do so with respect to your working directory, and Python interpreter will be able to locate it without further clues. If your notebook’s CWD is set to your notebook’s directory, you can simply refer to files located alongside your notebook by their name, e.g. ‘data.csv’ — similar to the read_csv(...) example above.

When you open a notebook for the first time, Juno will attempt to set its CWD to the notebook’s directory. If Juno can’t access it, it will set notebook’s working directory to a temporary folder and prompt you to grant access by showing the Locked folder button in the top bar. When access is granted, Juno will set CWD to the selected directory automatically.

You can also change your notebook’s working directory manually at any time — perhaps, you would like to access a file in a completely different location rather than where your notebook is. Tap notebook’s name in the top bar and select “Change Directory…”, you will see the same system dialogue letting you grant Juno access to any directory on your device. Granting access will also change notebook’s working directory — so in just few taps you can switch your notebook’s CWD to any location on your device and read from (or write to) a file in it using a short relative path.

Finally, Juno will remember the working directory for each of your notebooks and will retain access permissions, which means you will only need to grant access to the notebook’s directory once, and Juno will take care of the rest from that point on. This will work even if you change your working directory to some other location, say, to another app’s sandbox: the next time you open this notebook, Juno will restore access to that directory automatically and set it as notebook’s CWD.

You can always check your current working directory by either tapping notebook name in the top bar (CWD is displayed at the bottom of the popover menu), or by running this:

import os
os.getcwd()

Juno will print the absolute path to this notebook’s current working directory in the cell output below.