From c0b34cb5bafddbc476d05bb92d908541d01603d2 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson
Date: Mon, 5 Oct 2026 12:06:54 +0100
Subject: [PATCH 1/5] Add req.txt
---
.github/workflows/build.yml | 5 +++--
requirements.txt | 3 +++
2 files changed, 6 insertions(+), 2 deletions(-)
create mode 100644 requirements.txt
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4c395ab..89f4faa 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -27,9 +27,10 @@ jobs:
- name: Install dependencies
run: |
- sudo apt-get update
+ sudo apt-get update
sudo apt-get install ffmpeg -y
- pip install numpy matplotlib ruff
+
+ pip install -r requirements.txt
- name: Test WCONViewer
run: |
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..e0bbc91
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+numpy
+matplotlib
+ruff
\ No newline at end of file
From 832e2bd71ce783d0119a69d51ffae8686cf0ae6d Mon Sep 17 00:00:00 2001
From: Padraig Gleeson
Date: Mon, 5 Oct 2026 12:20:01 +0100
Subject: [PATCH 2/5] ignore dir
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 1410572..527efda 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/__pycache__
/.DS_Store
/examples/*.mp4
+/old
From 05160c49510c2aa5bce7d500a0294afe2389cca1 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson
Date: Mon, 5 Oct 2026 12:20:11 +0100
Subject: [PATCH 3/5] Ruff options
---
pyproject.toml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 pyproject.toml
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..5571f32
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,6 @@
+[tool.ruff]
+target-version = "py310"
+line-length = 88
+
+[tool.ruff.lint]
+select = ["E4", "E7", "E9", "F"]
From d70b0274e1a946a62943b74625daf9186b19186b Mon Sep 17 00:00:00 2001
From: Padraig Gleeson
Date: Mon, 5 Oct 2026 12:41:46 +0100
Subject: [PATCH 4/5] Make into pip installable package
---
.github/workflows/build.yml | 6 +++---
.gitignore | 2 ++
README.md | 16 ++++++++++++++++
app.py | 2 +-
pyproject.toml | 22 ++++++++++++++++++++++
test_all.sh | 14 ++++++++------
Player.py => wconviewer/Player.py | 0
SimpleWCON.py => wconviewer/SimpleWCON.py | 0
WormView.py => wconviewer/WormView.py | 6 +++---
wconviewer/__init__.py | 0
wconviewer/__main__.py | 5 +++++
11 files changed, 60 insertions(+), 13 deletions(-)
rename Player.py => wconviewer/Player.py (100%)
rename SimpleWCON.py => wconviewer/SimpleWCON.py (100%)
rename WormView.py => wconviewer/WormView.py (99%)
create mode 100644 wconviewer/__init__.py
create mode 100644 wconviewer/__main__.py
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 89f4faa..d43e143 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -29,14 +29,14 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install ffmpeg -y
-
- pip install -r requirements.txt
- name: Test WCONViewer
run: |
- ./test_all.sh
+
+ ./test_all.sh # also does pip install . and ruff check
- name: Print info on files
run: |
+ pip list
ls -alt
diff --git a/.gitignore b/.gitignore
index 527efda..2d24004 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,5 @@
/.DS_Store
/examples/*.mp4
/old
+/build
+/*.egg-info
diff --git a/README.md b/README.md
index 8785ead..0791e53 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,18 @@
# WCONViewer
Python based viewer for WCON files in 2D
+
+## Installation
+
+```
+pip install .
+```
+
+Saving animations with `-nogui` requires the `ffmpeg` binary to be installed on your system.
+
+## Usage
+
+```
+wconviewer -f examples/simdata.wcon
+```
+
+Run `wconviewer -h` for all options (e.g. `-nogui` to save an `.mp4` instead of showing a window).
diff --git a/app.py b/app.py
index f6ed73f..dbdba1d 100644
--- a/app.py
+++ b/app.py
@@ -3,7 +3,7 @@
import streamlit as st
-from WormView import WormView
+from wconviewer.WormView import WormView
DEFAULT_WCON = "examples/simdata.wcon"
FRAME_DELAY = 0.1 # seconds between frames while playing
diff --git a/pyproject.toml b/pyproject.toml
index 5571f32..b36d89a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,25 @@
+[build-system]
+requires = ["setuptools>=61"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "WCONViewer"
+version = "0.1.0"
+description = "Viewer for WCON (Worm tracker Commons Object Notation) files in 2D"
+readme = "README.md"
+license = { file = "LICENSE" }
+requires-python = ">=3.10"
+dependencies = ["numpy", "matplotlib"]
+
+[project.optional-dependencies]
+dev = ["ruff"]
+
+[project.scripts]
+wconviewer = "wconviewer.WormView:main"
+
+[tool.setuptools]
+packages = ["wconviewer"]
+
[tool.ruff]
target-version = "py310"
line-length = 88
diff --git a/test_all.sh b/test_all.sh
index 831f82f..751bef4 100755
--- a/test_all.sh
+++ b/test_all.sh
@@ -1,11 +1,13 @@
#!/bin/bash
set -ex
-ruff format *.py
-ruff check *.py
+ruff format wconviewer app.py
+ruff check wconviewer app.py
-python WormView.py -f examples/simdata.wcon -nogui -z # Test reloading WCON in Player
-python WormView.py -f examples/worm_motion_log.wcon -nogui -g
-python WormView.py -f examples/output_W2D.wcon -nogui -g -z
+pip install .
-#python WormView.py -f examples/N2\ on\ food\ L_2009_09_15__11_01_01___8___1.wcon.zip -nogui
+wconviewer -f examples/simdata.wcon -nogui -z # Test reloading WCON in Player
+wconviewer -f examples/worm_motion_log.wcon -nogui -g
+wconviewer -f examples/output_W2D.wcon -nogui -g -z
+
+#wconviewer -f examples/N2\ on\ food\ L_2009_09_15__11_01_01___8___1.wcon.zip -nogui
diff --git a/Player.py b/wconviewer/Player.py
similarity index 100%
rename from Player.py
rename to wconviewer/Player.py
diff --git a/SimpleWCON.py b/wconviewer/SimpleWCON.py
similarity index 100%
rename from SimpleWCON.py
rename to wconviewer/SimpleWCON.py
diff --git a/WormView.py b/wconviewer/WormView.py
similarity index 99%
rename from WormView.py
rename to wconviewer/WormView.py
index 3c67d37..641a0f5 100644
--- a/WormView.py
+++ b/wconviewer/WormView.py
@@ -5,8 +5,8 @@
import os
import argparse
import sys
-from Player import Player
-from SimpleWCON import SimpleWCON
+from .Player import Player
+from .SimpleWCON import SimpleWCON
class HalfIntegerLocator(MultipleLocator):
@@ -277,7 +277,7 @@ def parse_args():
"--wcon_file",
type=validate_file,
help="WCON file path",
- default="examples/simdata.wcon",
+ required=True,
)
parser.add_argument(
"-nogui", action="store_true", help="Just load file, don't show GUI"
diff --git a/wconviewer/__init__.py b/wconviewer/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/wconviewer/__main__.py b/wconviewer/__main__.py
new file mode 100644
index 0000000..c1179f5
--- /dev/null
+++ b/wconviewer/__main__.py
@@ -0,0 +1,5 @@
+import sys
+
+from .WormView import main
+
+sys.exit(main())
From e946f97ebbbc982cdf8f1cc529a374adc3b0ab39 Mon Sep 17 00:00:00 2001
From: Padraig Gleeson
Date: Mon, 5 Oct 2026 12:45:58 +0100
Subject: [PATCH 5/5] install ruff
---
.github/workflows/build.yml | 4 +++-
requirements.txt | 3 ---
2 files changed, 3 insertions(+), 4 deletions(-)
delete mode 100644 requirements.txt
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d43e143..393039f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -30,9 +30,11 @@ jobs:
sudo apt-get update
sudo apt-get install ffmpeg -y
+ pip install ruff
+
- name: Test WCONViewer
run: |
-
+
./test_all.sh # also does pip install . and ruff check
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index e0bbc91..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-numpy
-matplotlib
-ruff
\ No newline at end of file