Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
{
"name": "ap-python",
"image": "adregistry.fnal.gov/dev-containers/ap-python:latest",
"features": {
"ghcr.io/devcontainers/features/desktop-lite:1": {
"password": "",
"webPort": 6080
}
},
"customizations": {
"vscode": {
"extensions": [
Expand All @@ -24,5 +30,5 @@
}
}
},
"postCreateCommand": "uv sync --dev --all-extras && uv run pre-commit install"
"postStartCommand": "uv sync --dev --all-extras && uv run pre-commit install"
}
25 changes: 5 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,15 @@ A Python-first project template with one installable application package that pr

1. **Do not** clone this repo! Instead, click "**Use this template**" at the top right of its GitHub page, then click "**Create a new repository**" and complete the form to create a new repo using this template.

2. Rename the template to make it your own project:
2. [Set up your development environment](docs/devpod.md)

```bash
python3 scripts/rename_project.py
```

3. Install dependencies:

```bash
uv sync
```

4. Run the app in CLI mode:
3. Rename the template to make it your own project:

```bash
uv run ap-python-starter-kit
python3 scripts/rename_project.py
```

5. Optionally install GUI support and run the integrated GUI through the main launcher:

```bash
uv sync --extra gui-pyqt
uv run ap-python-starter-kit --gui
```
4. Code away!

Detailed onboarding is in [`docs/quickstart.md`](docs/quickstart.md).

Expand All @@ -41,7 +26,7 @@ This repo includes a Dev Container descriptor file at [`.devcontainer/devcontain

Read more about DevPod [here](https://devpod.sh/docs/what-is-devpod)

Docs: [`docs/devpod.md`](docs/devpod.md).
Full instructions: [`docs/devpod.md`](docs/devpod.md).

## Application Modes

Expand Down
145 changes: 131 additions & 14 deletions docs/devpod.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,142 @@ The workspace uses the external image referenced there, which is expected to pro

## Use

1. On your local machine, [install DevPod](https://devpod.sh/docs/getting-started/install).
2. Open DevPod and enter the URL of your project's GitHub repository, or point it to the local directory if you've already cloned the repo.
3. After the workspace starts, run the default build command, or run it manually:
### Setup

```bash
uv sync
```
1. Ensure [VS Code is set up](#vs-code). This includes installing some necessary extensions, listed in the instructions.
2. Prepare your machine
- [Mac](#mac)
- [Windows](#windows)
3. On your local machine, [install DevPod](https://devpod.sh/docs/getting-started/install#install-devpod).
4. Open DevPod and enter the URL of your project's GitHub repository, or point it to the local directory if you've already cloned the repo.
5. Select Docker as the "Provider"
- If on Windows, edit the advanced options to specify the "Host" as `tcp://127.0.0.1:2375`
6. Select VS Code as your IDE
7. Click Create - the dev container will be pulled down and started for you, and VS Code should open
8. After the workspace starts, open a terminal in VS Code and run
```bash
uv sync --dev --all-extras
```
9. Run tests
```bash
uv run pytest
```
10. Run the CLI app
```bash
uv run ap-python-starter-kit
```
11. (Optional) Run the GUI
1. [Set up access to the container's desktop](#ui-development-after-setup-is-complete)
2. Run
```bash
uv run ap-python-starter-kit --gui
```

4. Run tests:
### Prerequisites

```bash
uv run pytest
```
#### VS Code

5. Run the CLI app:
1. [Install VS Code](https://code.visualstudio.com/download)
2. Open VS Code and navigate to the Extensions tab (icon looks like four squares, where the top-right square is rotated 45 degrees)
3. In the search bar at the top, type "Dev Containers" and install the extension from Microsoft
4. (Windows-only) Do the same as step 3, searching for and installing the "WSL" extension (also by Microsoft)

```bash
uv run ap-python-starter-kit
```
#### Mac

Mac users will require Docker to be installed. While Windows users can leverage Docker Engine to avoid licensing issues, Mac users will have to leverage an open-source alternative called [Colima](https://github.com/abiosoft/colima).

1. Install Colima using [one of the provided methods](https://github.com/abiosoft/colima/blob/main/docs/INSTALL.md)
2. Start Colima using
```bash
colima start
```
3. During DevPod setup, follow the instructions for using Docker as your provider. Colima will be substituted by DevPod automatically.

#### Windows

If your local machine is running Windows, you will need to have Windows Subsystem for Linux installed, with Docker or some other pod management system installed there. Here are the steps to accomplish this:

1. Run the following in a terminal with administrator rights (you may be asked to restart your machine)
```PowerShell
wsl --install
```
Ubuntu will be the default Linux distribution, and the remainder of this guide will target that.
2. Open the Start menu and type `wsl`. Run the WSL application.
3. You will be asked to set up a username and password in the Ubuntu instance. This has no bearing on your Windows environment. The user you set up will have administrator (sudo) permissions in the Ubuntu image.
4. Update the packages installed by running
```bash
sudo apt update && sudo apt upgrade
```
5. Install needed packages for Docker
```bash
sudo apt install ca-certificates curl gnupg lsb-release
```
6. Set up GPG for Docker authentication
```bash
sudo mkdir -p /etc/apt/keyrings
```
```bash
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
```
7. Configure GPG authentication
```bash
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
8. Install Docker Engine
```bash
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
9. Add your user to the `docker` group (prevents needing to use `sudo` for every Docker command)
```bash
sudo usermod -aG docker $USER
```
10. Start Docker
```bash
sudo systemctl enable --now docker
```
```bash
sudo systemctl enable containerd
```
Verify Docker is running
```bash
sudo systemctl status docker
```
11. Configure Docker to be accessible to DevPod
```bash
sudo systemctl edit --full docker.service
```
This should open an editor. Look for
```
...
[Service]
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
...
```
On the end of this line, add `-H tcp://127.0.0.1:2375`. The full entry should now read
```
...
[Service]
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://127.0.0.1:2375
...
```
Now run
```bash
sudo systemctl daemon-reload && sudo systemctl restart docker.service
```

### UI development (After setup is complete)

While building your app, you'll probably want to test out changes to the UI before deploying. In the container, this requires one preliminary step.

The development container comes with a minimal desktop overlay, in which your app will run when you kick it off. To see it, do the following:

1. In VS Code, go to the "Ports" tab of the bottom panel (toggle the panel with the appropriate button in the very top-right if it is not already visible)
2. Click the "Forward a Port" button
3. Type `6080` and hit Enter
4. If it doesn't open automatically, go to your web browser and navigate to `localhost:6080`
5. Click "Connect"

You're all set! Now when you run the app locally, it will come up in your web browser at `localhost:6080`.

## Notes

Expand Down
88 changes: 88 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Migrating an existing Python project

This guide will walk through the steps to take when pulling an existing Python project into the
AP Python ecosystem.

### Assumptions

This guide assumes your project uses `pip` as a package manager and `PyQt 5` as a GUI framework.
There will be sections dedicated to migrating from `pip` to `uv` and from `PyQt 5` to `PyQt 6`.
Feel free to skip these if you're already set up with `uv` and `PyQt 6`.

Included at the end of this guide are a few extra Quality-of-Life enhancements made to the original Auto Quad Centering application when testing out the migration process. They have to do with the application itself rather than the project configuration, so they may or may not have relevance in other applications.

## General migration steps

1. Construct a new repository for your migrated application from this template, using the "**Create a new repository**" button.
2. Ensure your AP Python development environment is set up. Follow [the guide](docs/devpod.md) for complete instructions.
3. Use the rename script (run `python3 scripts/rename_project.py` in the DevPod for your migrated project repository) to change the project package name.
Make it match the package name you use in your source project.

For example, for Auto Quad Centering, the project name became `auto-quad-centering` and the package name was likewise `auto_quad_centering`.
4. Replace the contents of `src/<your package name>` with your existing Python code to be migrated.
5. If your source project used `pip`, follow the [`pip` to `uv` migration steps](#pip-to-uv-migration).
6. If your source project used `PyQt 5`, follow the [`PyQt 5` to `PyQt 6` migration steps](#pyqt-5-to-pyqt-6).

## `pip` to `uv` migration

`uv` and its dependencies are already installed in your DevPod environment. To build with `uv`, you'll simply need to let it know what Python packages your project depends on and where the entrypoint for your code is. This is configured in the `pyproject.toml` file at the root of the repository. The exact version of the dependencies used by `uv` when building your code will be recorded in the `uv.lock` file.

Migration steps are as follows:

1. In the command line, run `uv add -r src/<your_package_name>/requirements.txt`
2. Rebuild the virtual environment by running `uv venv --clear` in the command line (this may take a minute to complete)
- Be sure to run `source .venv/bin/activate` once the virtual environment has been rebuilt
Comment thread
jacob-curley-fnal marked this conversation as resolved.
- Also run `uv run pre-commit install` to ensure the Git pre-commit hooks work correctly
3. (optional) You can delete your `requirements.txt`. All dependencies should now be handled via the `pyproject.toml` file. Use `uv add` and `uv remove` to update your dependencies from the command line, or edit the `dependencies` section of `pyproject.toml` directly.

`uv --help` has a complete list of the commands available with `uv`.

4. Update the project entrypoint in `pyproject.toml`

By now, your `pyproject.toml` should have a section that looks like
```toml
...
[project.scripts]
<kebab-case-project-name> = "<snake_case_package_name>.main:main"
...
```

Update this section so the `.main:main` portion reflects the name and main function of the entry file for your project. For example, Auto Quad Centering has this section as
```toml
...
[project.scripts]
auto-quad-centering = "auto_quad_centering.autocenter:main"
...
```
This reflects that the main file for the project is `auto_quad_centering/autocenter.py`, and the entrypoint for that file is a function called `main()`.

## `PyQt 5` to `PyQt 6`

While the bulk of upgrading from PyQt 5 to PyQt 6 is simply a matter of updating your import statements (i.e., `from PyQt5 import ...` becoming `from PyQt6 import ...`), there are a couple breaking changes to be aware of.

- PyQt 6 demands fully-qualified enums, e.g. `Qt.AlignCenter` must now be `Qt.AlignmentFlag.AlignCenter`
- Any uses of PyQt 5's `exec_()` function must now use the standard `exec()` function from Python 3
- Various classes have moved to different modules (e.g. `QAction` and `QShortcut` are now in `QtGui` rather than `QtWidgets`)
- Some methods/APIs have changed (e.g. `QMouseEvent` now uses `.position()` instead of `.x()` and `.y()`)

For a deeper breakdown and migration guide, see [this article](https://www.pythonguis.com/faq/pyqt5-vs-pyqt6/).

## Auto Quad Centering addons

The following are some enhancements made to the original Auto Quad Centering application so it plays a little nicer with the Xpra runtime.

1. Added scrolling behavior to all tabs

The Xpra runtime only exposes a certain amount of screen real estate. The original Auto Quad Centering app went off the screen by quite a bit, when first tested in the Xpra deployment. To resolve this, a `QScrollArea` was added to each of the tab widgets in the `ui` directory.

2. Added a Kerberos login dialog

Auto Quad Centering requires the user to have an active Kerberos ticket to make settings to the accelerator. The original application assumed such a ticket would already be available in the host runtime. With the move to the remote Xpra environment, this is no longer a valid assumption.

A small username/password dialog was added to `ui/dialogs.py` that would be activated when the user selects to generate a new ticket. This allows the migrated app to leverage the preexisting code to generate a ticket in Kerberos from `auth/kerberos_manager.py`.

3. Updated the file loading process to reflect the remote runtime

The original application expected to be able to load files from the user's system. With the deployment to a remote Xpra instance, this is no longer a straightforward process. Users must first upload files to the Xpra runtime, and only then can the application access those files. The same is true, but in reverse, for files generated by the app. It writes the file to the Xpra runtime, and users must initiate the process in Xpra to download a file from the remote filesystem.

To help clarify this, some modifications were made to the file upload section in `ui/setup_tab.py`. There is now descriptive text to call out the new process.