File system permissions and paths in iOS

Although Juno makes coding on the 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 needs to read a file’s contents or write data to a file, how do you specify the 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 a 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 the 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 the device’s file system, commonly referred to as the 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 creates the /site-packages directory for your own Python modules and packages. The main reason those files are where they are is that Juno can be sure it will be able to access this location no matter what.

However, iOS also allows third-party apps to 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 Python script or a Jupyter notebook with Juno, the system automatically grants Juno access to this file, and any changes you make will be saved to the document’s original location — just like on desktop.

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 script or a notebook, you usually want to be able to access the file’s directory, too — for example, to read a .csv file, or save a plot image. But, unless the document you are working on is in Juno’s sandbox, the 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 document you are working on, it will give you an option to select a working directory, suggesting the location of the Python script or notebook file by default.

CWD browser with blurred content and action button to select working directory

Tap Select Working Directory, and a system folder selection dialogue will appear, letting you explicitly grant Juno access to the document’s directory (or any other location). Juno will automatically set the selected location as the workspace’s CWD and associate it with the file you are working on, so that you won’t need to repeat these steps next time you open it.

Please mind that this may not work if your script or notebook is located in 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 works in Juno goes only as far as their developers chose to integrate with Apple’s APIs. Hopefully, those cloud storage services will finalize their Files integration eventually; but we are looking into workarounds where we could potentially integrate with some of them, bypassing the 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. By default, Juno sets CWD to the directory of the Python script or notebook file, so simply remember to reference all locations relative to where your script or 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')

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

CWD

The concept of the 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 is running. 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 the Python interpreter will be able to locate it without further clues. If the CWD of your script or notebook is set to the source file’s directory, you can simply refer to files located alongside your script or notebook by their name, e.g., ‘data.csv’ — similar to the read_csv(...) example above.

When you open a document for the first time, Juno will attempt to set its CWD to the document’s directory. If Juno can’t access it, it will set the working directory to a temporary folder and will give you an option to choose a working directory in the working directory browser. When access is granted, Juno will set CWD to the selected location automatically.

You can also change the working directory manually at any time — perhaps, you would like to access a file in a completely different location rather than where your source file is. Select Change Directory in the Ellipsis circle icon overflow menu of the working directory browser, and you will see the same system dialogue letting you grant Juno access to any directory on your device. Granting access will also change the document’s working directory — so in just a few taps you can switch your source file’s CWD to any location on your device and read from (or write to) a file in it using a short relative path.

Juno will remember the working directory for each of your documents and will retain access permissions, which means you will only need to grant access to this 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 script or notebook, Juno will restore access to that directory automatically and set it as the CWD.

Working directory browser

File actions in the CWD browser

Juno strives to make interactions with the file system while coding as seamless as possible, whether you’re working on a Python script or a Jupyter notebook. It displays the contents of the working directory next to the source editor, letting you manage files and folders, quickly retrieve relative paths, preview documents, and edit any text-based files in a built-in text editor with syntax highlighting, all without ever leaving your coding environment. You can read more about the working directory browser here: Working Directory Browser.