ethoscopy 2.0.3__tar.gz → 2.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ethoscopy-2.0.5/.claude/settings.local.json +40 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/.pre-commit-config.yaml +2 -2
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/CLAUDE.md +35 -0
- ethoscopy-2.0.5/Docker/.env.dummy.example +25 -0
- ethoscopy-2.0.5/Docker/.env.github.example +39 -0
- ethoscopy-2.0.5/Docker/.env.google.example +41 -0
- ethoscopy-2.0.5/Docker/.env.keycloak.example +53 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/Docker/Dockerfile +8 -1
- ethoscopy-2.0.5/Docker/README.md +220 -0
- ethoscopy-2.0.5/Docker/README_AUTH.md +548 -0
- ethoscopy-2.0.5/Docker/config/jupyterhub_config.py +154 -0
- ethoscopy-2.0.5/Docker/config/users.py +47 -0
- ethoscopy-2.0.5/Docker/docker-compose.yml +57 -0
- {ethoscopy-2.0.3/Docker/config → ethoscopy-2.0.5/Docker/jupyterhub_data}/jupyterhub.sqlite +0 -0
- ethoscopy-2.0.5/Docker/jupyterhub_data/jupyterhub_cookie_secret +1 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/PKG-INFO +22 -1
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/README.md +21 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/pyproject.toml +8 -1
- ethoscopy-2.0.5/scripts/README.md +121 -0
- ethoscopy-2.0.5/scripts/convert_databases.sh +51 -0
- ethoscopy-2.0.5/scripts/convert_wal_to_delete.py +240 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/__init__.py +3 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/load.py +93 -11
- ethoscopy-2.0.5/src/ethoscopy/misc/__init__.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/get_HMM.py +8 -18
- ethoscopy-2.0.5/src/ethoscopy/misc/get_tutorials.py +220 -0
- ethoscopy-2.0.5/tasks/todo.md +90 -0
- ethoscopy-2.0.5/tests/test_get_tutorials.py +338 -0
- ethoscopy-2.0.5/tests/test_load_metadata_fixes.py +214 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/1_Overview_tutorial.ipynb +26 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/2_HMM_tutorial.ipynb +26 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/3_Circadian_tutorial.ipynb +28 -2
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/5_Ethoscopy_catch22_tutorial.ipynb +26 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/6_Ethoscopy_to_hctsa_tutorial.ipynb +26 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/notebook_paper.ipynb +26 -0
- ethoscopy-2.0.3/.claude/settings.local.json +0 -25
- ethoscopy-2.0.3/Docker/.claude/settings.local.json +0 -19
- ethoscopy-2.0.3/Docker/.env +0 -39
- ethoscopy-2.0.3/Docker/README.md +0 -85
- ethoscopy-2.0.3/Docker/config/jupyterhub_cookie_secret +0 -1
- ethoscopy-2.0.3/Docker/docker-compose.yml +0 -25
- ethoscopy-2.0.3/Docker/jupyterhub_data/jupyterhub-proxy.pid +0 -1
- ethoscopy-2.0.3/Docker/jupyterhub_data/jupyterhub.sqlite +0 -0
- ethoscopy-2.0.3/Docker/jupyterhub_data/jupyterhub_cookie_secret +0 -1
- ethoscopy-2.0.3/QWEN.md +0 -88
- ethoscopy-2.0.3/src/ethoscopy/misc/get_tutorials.py +0 -48
- ethoscopy-2.0.3/tests/test_get_tutorials.py +0 -136
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/.codecov.yml +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/.github/workflows/ci.yml +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/.github/workflows/release.yml +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/.gitignore +0 -0
- /ethoscopy-2.0.3/src/ethoscopy/misc/__init__.py → /ethoscopy-2.0.5/Docker/.env.gitlab.example +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/Docker/.env.keycloak +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/Docker/install_r_packages.r +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/Docker/jupyterhub_data/jupyterhub_config.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/LICENSE +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/TESTING.md +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/_config.yml +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/pytest.ini +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/run_tests.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/setup.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/analyse.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_HMM_class.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_class.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_core.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_draw.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_periodogram_class.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_plotly.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/behavpy_seaborn.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/metadata_db.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/circadian_bars.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/general_functions.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/hmm_functions.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/periodogram_functions.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/src/ethoscopy/misc/validate_datetime.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/__init__.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/conftest.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/data/README.md +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/data/test_ethoscope.db +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_analyse.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_baseline_enhancements.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_behavpy.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_behavpy_core_simple.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_compatibility_classes.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_general_functions.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_load.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_load_comprehensive.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tests/test_load_optimizations.py +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/4_Navigating_db_tutorial.ipynb +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/ethoscope_db.csv +0 -0
- {ethoscopy-2.0.3 → ethoscopy-2.0.5}/tutorial_notebook/jones_et_al_metadata.csv +0 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(wc:*)",
|
|
5
|
+
"Bash(paplay:*)",
|
|
6
|
+
"Bash(ETHOSCOPE_DATA_PATH=/mnt/ethoscope_data docker compose:*)",
|
|
7
|
+
"Bash(docker ps:*)",
|
|
8
|
+
"Bash(docker logs:*)",
|
|
9
|
+
"Bash(docker compose:*)",
|
|
10
|
+
"Bash(curl:*)",
|
|
11
|
+
"Bash(docker exec:*)",
|
|
12
|
+
"Bash(mkdir -p /tmp/ethoscopy_wheel_inspect)",
|
|
13
|
+
"Read(//tmp/**)",
|
|
14
|
+
"Bash(pip download *)",
|
|
15
|
+
"Bash(unzip -l ethoscopy-2.0.4-py3-none-any.whl)",
|
|
16
|
+
"Bash(git check-ignore *)",
|
|
17
|
+
"Bash(/home/gg/Code/ethoscope_project/ethoscopy/.venv/bin/pip install *)",
|
|
18
|
+
"Bash(.venv/bin/python -m pytest tests/test_get_tutorials.py -v)",
|
|
19
|
+
"Bash(.venv/bin/python *)",
|
|
20
|
+
"Bash(.venv/bin/pip install *)",
|
|
21
|
+
"Bash(gh auth *)",
|
|
22
|
+
"Bash(gh repo *)",
|
|
23
|
+
"Bash(docker info *)",
|
|
24
|
+
"mcp__bookstack__bookstack_search",
|
|
25
|
+
"Bash(.venv/bin/ruff check *)",
|
|
26
|
+
"Bash(.venv/bin/black --check src/ tests/)",
|
|
27
|
+
"Bash(.venv/bin/black src/ethoscopy/misc/get_tutorials.py tests/test_get_tutorials.py)",
|
|
28
|
+
"mcp__bookstack__bookstack_pages_read",
|
|
29
|
+
"mcp__bookstack__bookstack_pages_update",
|
|
30
|
+
"Bash(gh issue create --repo gilestrolab/ethoscopy --title 'Tutorial data pickles missing from PyPI wheel \\(2.0.0 – 2.0.4\\)' --body ' *)",
|
|
31
|
+
"Bash(git add *)",
|
|
32
|
+
"Bash(git commit *)",
|
|
33
|
+
"Bash(git push *)",
|
|
34
|
+
"Bash(git tag *)",
|
|
35
|
+
"Bash(gh release create v2.0.5 --repo gilestrolab/ethoscopy --title 'v2.0.5 — package tutorial data separately' --notes ' *)",
|
|
36
|
+
"Bash(gh run *)",
|
|
37
|
+
"Bash(gh issue *)"
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -51,7 +51,7 @@ repos:
|
|
|
51
51
|
language: system
|
|
52
52
|
pass_filenames: false
|
|
53
53
|
always_run: true
|
|
54
|
-
stages: [commit]
|
|
54
|
+
stages: [pre-commit]
|
|
55
55
|
|
|
56
56
|
- id: pytest-fast
|
|
57
57
|
name: pytest-fast
|
|
@@ -59,4 +59,4 @@ repos:
|
|
|
59
59
|
language: system
|
|
60
60
|
pass_filenames: false
|
|
61
61
|
always_run: true
|
|
62
|
-
stages: [push]
|
|
62
|
+
stages: [pre-push]
|
|
@@ -45,6 +45,41 @@ pip install -e ".[dev]"
|
|
|
45
45
|
- Build: `JUPYTER_HUB_TAG=5.3.0 ETHOSCOPE_LAB_TAG=1.0 docker compose build`
|
|
46
46
|
- Run: `docker compose up -d` (from Docker/ directory)
|
|
47
47
|
|
|
48
|
+
### Troubleshooting: Database "Malformed" Errors
|
|
49
|
+
|
|
50
|
+
**Problem**: Intermittent "database disk image is malformed" errors when loading ethoscope data in Docker
|
|
51
|
+
|
|
52
|
+
**Root Cause**: SQLite databases in WAL (Write-Ahead Logging) mode on read-only Docker mounts
|
|
53
|
+
|
|
54
|
+
**Solution Options**:
|
|
55
|
+
1. **Convert databases to DELETE mode** (recommended for immediate fix)
|
|
56
|
+
```bash
|
|
57
|
+
# Using the conversion script (from project root)
|
|
58
|
+
python3 scripts/convert_wal_to_delete.py /mnt/ethoscope_data/results --verbose
|
|
59
|
+
|
|
60
|
+
# Or using bash wrapper
|
|
61
|
+
./scripts/convert_databases.sh /mnt/ethoscope_data/results
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
2. **Improved connection handling** (v2.0.4+)
|
|
65
|
+
- The `_connect_db()` function in `load.py` now detects WAL mode automatically
|
|
66
|
+
- Uses `mode=ro&nolock=1` URI parameters for WAL databases on read-only mounts
|
|
67
|
+
- Includes retry logic in `read_single_roi_optimized()` for resilience
|
|
68
|
+
|
|
69
|
+
**Key Implementation Details** (load.py):
|
|
70
|
+
- Lines 18-70: `_connect_db()` - Smart connection with WAL detection and appropriate parameters
|
|
71
|
+
- Lines 943-979: Retry logic in `read_single_roi_optimized()` - Handles transient errors with fresh connections
|
|
72
|
+
|
|
73
|
+
**Testing After Changes**:
|
|
74
|
+
```python
|
|
75
|
+
import ethoscopy as etho
|
|
76
|
+
metadata = etho.link_meta_index('metadata.csv', '/mnt/ethoscope_results')
|
|
77
|
+
data = etho.load_ethoscope(metadata, reference_hour=9.0, FUN=etho.sleep_annotation)
|
|
78
|
+
# Should load all ROIs without "malformed" errors
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**See Also**: `Docker/README.md` for detailed database preparation instructions
|
|
82
|
+
|
|
48
83
|
## Architecture and Code Structure
|
|
49
84
|
|
|
50
85
|
### Core Architecture
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# DUMMY AUTHENTICATOR (Simple Shared Password)
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Default authentication method - all users share the same password
|
|
5
|
+
# Best for: Lab environments, small teams, trusted networks
|
|
6
|
+
|
|
7
|
+
# Authenticator type (must be 'dummy' for this configuration)
|
|
8
|
+
AUTHENTICATOR_CLASS=dummy
|
|
9
|
+
|
|
10
|
+
# Shared password for all users
|
|
11
|
+
DUMMY_PASSWORD=ethoscope
|
|
12
|
+
|
|
13
|
+
# Comma-separated list of allowed users
|
|
14
|
+
ALLOWED_USERS=amadabhushi,ggilestro,mjoyce,lguo,labguest1,labguest2,labguest3,labguest4,labguest5,labguest6,labguest7,labguest8,ethoscopelab
|
|
15
|
+
|
|
16
|
+
# Comma-separated list of admin users
|
|
17
|
+
ADMIN_USERS=ggilestro
|
|
18
|
+
|
|
19
|
+
# Docker user/group (optional, defaults to 1000:1000)
|
|
20
|
+
UID=1000
|
|
21
|
+
GID=1000
|
|
22
|
+
|
|
23
|
+
# JupyterHub and Ethoscope Lab versions
|
|
24
|
+
JUPYTER_HUB_TAG=5.3.0
|
|
25
|
+
ETHOSCOPE_LAB_TAG=1.1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# GITHUB OAUTH AUTHENTICATOR
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Authenticate users via their GitHub accounts
|
|
5
|
+
# Best for: Open source projects, teams already using GitHub
|
|
6
|
+
#
|
|
7
|
+
# Setup Instructions:
|
|
8
|
+
# 1. Go to GitHub Settings > Developer Settings > OAuth Apps
|
|
9
|
+
# 2. Create a new OAuth App
|
|
10
|
+
# 3. Set Homepage URL: http://your-server:8082
|
|
11
|
+
# 4. Set Authorization callback URL: http://your-server:8082/hub/oauth_callback
|
|
12
|
+
# 5. Copy the Client ID and generate a Client Secret
|
|
13
|
+
|
|
14
|
+
# Authenticator type
|
|
15
|
+
AUTHENTICATOR_CLASS=github
|
|
16
|
+
|
|
17
|
+
# OAuth credentials from GitHub OAuth App
|
|
18
|
+
OAUTH_CLIENT_ID=your_github_client_id_here
|
|
19
|
+
OAUTH_CLIENT_SECRET=your_github_client_secret_here
|
|
20
|
+
|
|
21
|
+
# Callback URL (must match what you set in GitHub OAuth App)
|
|
22
|
+
OAUTH_CALLBACK_URL=http://your-server:8082/hub/oauth_callback
|
|
23
|
+
|
|
24
|
+
# (Optional) Restrict to GitHub organization members
|
|
25
|
+
# GITHUB_ORG=your-organization-name
|
|
26
|
+
|
|
27
|
+
# Comma-separated list of allowed users (GitHub usernames)
|
|
28
|
+
ALLOWED_USERS=username1,username2,username3
|
|
29
|
+
|
|
30
|
+
# Comma-separated list of admin users (GitHub usernames)
|
|
31
|
+
ADMIN_USERS=your-github-username
|
|
32
|
+
|
|
33
|
+
# Docker user/group (optional, defaults to 1000:1000)
|
|
34
|
+
UID=1000
|
|
35
|
+
GID=1000
|
|
36
|
+
|
|
37
|
+
# JupyterHub and Ethoscope Lab versions
|
|
38
|
+
JUPYTER_HUB_TAG=5.3.0
|
|
39
|
+
ETHOSCOPE_LAB_TAG=1.1
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# GOOGLE OAUTH AUTHENTICATOR
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Authenticate users via their Google accounts
|
|
5
|
+
# Best for: Organizations using Google Workspace, universities with Google
|
|
6
|
+
#
|
|
7
|
+
# Setup Instructions:
|
|
8
|
+
# 1. Go to Google Cloud Console (console.cloud.google.com)
|
|
9
|
+
# 2. Create a new project or select existing
|
|
10
|
+
# 3. Enable Google+ API
|
|
11
|
+
# 4. Go to Credentials > Create Credentials > OAuth 2.0 Client ID
|
|
12
|
+
# 5. Set Application type: Web application
|
|
13
|
+
# 6. Add Authorized redirect URI: http://your-server:8082/hub/oauth_callback
|
|
14
|
+
# 7. Copy the Client ID and Client Secret
|
|
15
|
+
|
|
16
|
+
# Authenticator type
|
|
17
|
+
AUTHENTICATOR_CLASS=google
|
|
18
|
+
|
|
19
|
+
# OAuth credentials from Google Cloud Console
|
|
20
|
+
OAUTH_CLIENT_ID=your_google_client_id.apps.googleusercontent.com
|
|
21
|
+
OAUTH_CLIENT_SECRET=your_google_client_secret_here
|
|
22
|
+
|
|
23
|
+
# Callback URL (must match what you set in Google Cloud Console)
|
|
24
|
+
OAUTH_CALLBACK_URL=http://your-server:8082/hub/oauth_callback
|
|
25
|
+
|
|
26
|
+
# (Optional) Restrict to Google Workspace domain
|
|
27
|
+
# GOOGLE_HOSTED_DOMAIN=yourdomain.com
|
|
28
|
+
|
|
29
|
+
# Comma-separated list of allowed users (Gmail addresses without @gmail.com or @yourdomain.com)
|
|
30
|
+
ALLOWED_USERS=user1,user2,user3
|
|
31
|
+
|
|
32
|
+
# Comma-separated list of admin users
|
|
33
|
+
ADMIN_USERS=your-email-username
|
|
34
|
+
|
|
35
|
+
# Docker user/group (optional, defaults to 1000:1000)
|
|
36
|
+
UID=1000
|
|
37
|
+
GID=1000
|
|
38
|
+
|
|
39
|
+
# JupyterHub and Ethoscope Lab versions
|
|
40
|
+
JUPYTER_HUB_TAG=5.3.0
|
|
41
|
+
ETHOSCOPE_LAB_TAG=1.1
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# ============================================================================
|
|
2
|
+
# KEYCLOAK / GENERIC OIDC AUTHENTICATOR
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Authenticate users via Keycloak or any OIDC-compliant provider
|
|
5
|
+
# Best for: Organizations with existing SSO, enterprise environments
|
|
6
|
+
#
|
|
7
|
+
# Setup Instructions for Keycloak:
|
|
8
|
+
# 1. Log into your Keycloak Admin Console
|
|
9
|
+
# 2. Select your realm (e.g., 'gilestro-lab')
|
|
10
|
+
# 3. Go to Clients > Create Client
|
|
11
|
+
# 4. Set Client ID: jupyterhub
|
|
12
|
+
# 5. Set Client Protocol: openid-connect
|
|
13
|
+
# 6. Set Access Type: confidential
|
|
14
|
+
# 7. Set Valid Redirect URIs: http://your-server:8082/hub/oauth_callback
|
|
15
|
+
# 8. Save and go to Credentials tab to get the Client Secret
|
|
16
|
+
# 9. Create users in Keycloak matching your existing home directory names
|
|
17
|
+
|
|
18
|
+
# Authenticator type
|
|
19
|
+
AUTHENTICATOR_CLASS=generic
|
|
20
|
+
|
|
21
|
+
# OAuth credentials from Keycloak client
|
|
22
|
+
OAUTH_CLIENT_ID=jupyterhub
|
|
23
|
+
OAUTH_CLIENT_SECRET=your_keycloak_client_secret_here
|
|
24
|
+
|
|
25
|
+
# Callback URL
|
|
26
|
+
OAUTH_CALLBACK_URL=http://your-server:8082/hub/oauth_callback
|
|
27
|
+
|
|
28
|
+
# Keycloak OIDC endpoints (replace YOUR_KEYCLOAK_SERVER and YOUR_REALM)
|
|
29
|
+
# Example: http://keycloak.example.com/realms/gilestro-lab
|
|
30
|
+
OAUTH_AUTHORIZE_URL=http://YOUR_KEYCLOAK_SERVER/realms/YOUR_REALM/protocol/openid-connect/auth
|
|
31
|
+
OAUTH_TOKEN_URL=http://YOUR_KEYCLOAK_SERVER/realms/YOUR_REALM/protocol/openid-connect/token
|
|
32
|
+
OAUTH_USERDATA_URL=http://YOUR_KEYCLOAK_SERVER/realms/YOUR_REALM/protocol/openid-connect/userinfo
|
|
33
|
+
|
|
34
|
+
# Username claim (Keycloak uses 'preferred_username' by default)
|
|
35
|
+
OAUTH_USERNAME_CLAIM=preferred_username
|
|
36
|
+
|
|
37
|
+
# OAuth scopes (comma-separated, optional)
|
|
38
|
+
OAUTH_SCOPE=openid,profile,email
|
|
39
|
+
|
|
40
|
+
# CRITICAL: Keycloak usernames MUST match existing home directory names exactly
|
|
41
|
+
# Comma-separated list of allowed users
|
|
42
|
+
ALLOWED_USERS=amadabhushi,ggilestro,mjoyce,lguo,labguest1,labguest2,labguest3,labguest4,labguest5,labguest6,labguest7,labguest8,ethoscopelab
|
|
43
|
+
|
|
44
|
+
# Comma-separated list of admin users
|
|
45
|
+
ADMIN_USERS=ggilestro
|
|
46
|
+
|
|
47
|
+
# Docker user/group (optional, defaults to 1000:1000)
|
|
48
|
+
UID=1000
|
|
49
|
+
GID=1000
|
|
50
|
+
|
|
51
|
+
# JupyterHub and Ethoscope Lab versions
|
|
52
|
+
JUPYTER_HUB_TAG=5.3.0
|
|
53
|
+
ETHOSCOPE_LAB_TAG=1.1
|
|
@@ -70,16 +70,23 @@ RUN pip3 install jupyterlab-spreadsheet-editor
|
|
|
70
70
|
# ============================================================================
|
|
71
71
|
|
|
72
72
|
# Install Python data science packages
|
|
73
|
+
# Including oauthenticator for flexible authentication support
|
|
73
74
|
RUN pip3 install \
|
|
75
|
+
oauthenticator \
|
|
74
76
|
pandas \
|
|
75
77
|
seaborn \
|
|
76
78
|
bokeh \
|
|
77
79
|
lifelines \
|
|
78
80
|
opencv-python \
|
|
79
81
|
mysql-connector \
|
|
80
|
-
ethoscopy
|
|
82
|
+
ethoscopy
|
|
81
83
|
# pycatch22
|
|
82
84
|
|
|
85
|
+
# Pre-populate tutorial datasets inside the installed package so non-root
|
|
86
|
+
# JupyterHub users don't have to download them on first notebook run. The
|
|
87
|
+
# pickles (~36 MB total) live in the ethoscopy repo, not the PyPI wheel.
|
|
88
|
+
RUN python3 -c "from ethoscopy.misc.get_tutorials import download_tutorial_data, package_tutorial_data_dir; download_tutorial_data(dest_dir=package_tutorial_data_dir(), verbose=True)"
|
|
89
|
+
|
|
83
90
|
# Install Ethoscope from source
|
|
84
91
|
RUN git clone https://github.com/gilestrolab/ethoscope.git /opt/ethoscope && \
|
|
85
92
|
cd /opt/ethoscope/ && git checkout dev && \
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Ethoscopelab docker instance
|
|
2
|
+
|
|
3
|
+
Note: Most users will **not** need to recreate this image. These instructions are just provided as reference.
|
|
4
|
+
The ethoscopelab docker instance lives on dockerhub at the following address: [https://hub.docker.com/r/ggilestro/ethoscope-lab](https://hub.docker.com/r/ggilestro/ethoscope-lab) and this is what regular users should download and run. Follow instructions there and on the [ethoscopy manual](https://bookstack.lab.gilest.ro/books/ethoscopy/page/getting-started).
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Docker files that were used to create the ethoscope-lab docker instance
|
|
8
|
+
|
|
9
|
+
The files in this folder can be used to recreate the image as uploaded on dockerhub.
|
|
10
|
+
|
|
11
|
+
The command to use to recreate that image is `JUPYTER_HUB_TAG=5.3.0 ETHOSCOPE_LAB_TAG=1.0 docker compose build`. This creates the image with the specified tag. For Docker Hub deployment, push the image: `docker push ggilestro/ethoscope-lab:1.0`. To also create a latest tag: `docker tag ggilestro/ethoscope-lab:1.0 ggilestro/ethoscope-lab:latest && docker push ggilestro/ethoscope-lab:latest`. You can verify your local images with `docker images | grep ethoscope-lab`.
|
|
12
|
+
|
|
13
|
+
After creation, the image can be run using the enclosed `docker-compose.yml` file, replacing values as fit.
|
|
14
|
+
|
|
15
|
+
## Authentication and User Management
|
|
16
|
+
|
|
17
|
+
This JupyterHub instance supports multiple authentication methods including:
|
|
18
|
+
- **Keycloak OAuth** (current production setup at auth.gilest.ro)
|
|
19
|
+
- GitHub OAuth
|
|
20
|
+
- Google OAuth
|
|
21
|
+
- GitLab OAuth
|
|
22
|
+
- Dummy authenticator (shared password)
|
|
23
|
+
|
|
24
|
+
### Adding New Users
|
|
25
|
+
|
|
26
|
+
**⚠️ Important**: Adding a new user requires steps on BOTH the authentication provider AND the JupyterHub host.
|
|
27
|
+
|
|
28
|
+
For detailed instructions on adding users, making users admins, and switching authentication methods, see:
|
|
29
|
+
|
|
30
|
+
**📖 [README_AUTH.md](./README_AUTH.md) - Complete Authentication and User Management Guide**
|
|
31
|
+
|
|
32
|
+
### Quick Reference
|
|
33
|
+
|
|
34
|
+
**For Keycloak (current setup)**:
|
|
35
|
+
1. Add user to Keycloak at `auth.gilest.ro` in the `gilestro-lab` realm
|
|
36
|
+
2. Create home directory on host: `sudo mkdir -p /mnt/homes/username && sudo chown 1000:1000 /mnt/homes/username`
|
|
37
|
+
3. (Optional) Add to `config/users.py` if using whitelist enforcement
|
|
38
|
+
|
|
39
|
+
**For Dummy Auth**:
|
|
40
|
+
1. Add username to `config/users.py` or `.env` file
|
|
41
|
+
2. Create home directory on host
|
|
42
|
+
3. Restart container
|
|
43
|
+
|
|
44
|
+
See [README_AUTH.md](./README_AUTH.md) for complete step-by-step instructions.
|
|
45
|
+
|
|
46
|
+
## Mounting Home Directories as Volumes
|
|
47
|
+
|
|
48
|
+
To persist user data and notebooks across container restarts, you should mount user home directories as Docker volumes. This is done by modifying the `docker-compose.yml` file.
|
|
49
|
+
|
|
50
|
+
### Benefits of mounting home directories:
|
|
51
|
+
|
|
52
|
+
1. **Data Persistence**: User notebooks, data files, and configurations survive container restarts and updates
|
|
53
|
+
2. **Backup and Recovery**: Easy to backup user data by copying the mounted directories
|
|
54
|
+
3. **Performance**: Direct access to host filesystem, avoiding container storage overhead
|
|
55
|
+
4. **Sharing**: Users can access their files from the host system if needed
|
|
56
|
+
|
|
57
|
+
### Example volume configuration:
|
|
58
|
+
|
|
59
|
+
Add volumes to your `docker-compose.yml`:
|
|
60
|
+
|
|
61
|
+
```yaml
|
|
62
|
+
services:
|
|
63
|
+
jupyterhub:
|
|
64
|
+
volumes:
|
|
65
|
+
- ./user_data:/home # Maps host ./user_data to container /home
|
|
66
|
+
- ./jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Or for individual user directories:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
volumes:
|
|
73
|
+
- ./users/ggilestro:/home/ggilestro
|
|
74
|
+
- ./users/amadabhushi:/home/amadabhushi
|
|
75
|
+
- ./users/shared:/home/shared # Shared directory for all users
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This ensures all user work is preserved even when containers are recreated or updated.
|
|
79
|
+
|
|
80
|
+
## Database Preparation for Docker
|
|
81
|
+
|
|
82
|
+
When mounting ethoscope database files into Docker containers with read-only permissions (`:ro`), you may encounter "database disk image is malformed" errors. This occurs when SQLite databases are in WAL (Write-Ahead Logging) mode but mounted on read-only filesystems where WAL companion files (`.db-wal`, `.db-shm`) cannot be accessed.
|
|
83
|
+
|
|
84
|
+
### Understanding the Issue
|
|
85
|
+
|
|
86
|
+
**Why this happens:**
|
|
87
|
+
- Ethoscope databases may be created in **WAL mode** for better write performance
|
|
88
|
+
- WAL mode requires companion files (`.db-wal` and `.db-shm`) alongside the main `.db` file
|
|
89
|
+
- Docker read-only mounts (`:ro`) prevent SQLite from accessing these files properly
|
|
90
|
+
- This causes intermittent "database disk image is malformed" errors during data loading
|
|
91
|
+
|
|
92
|
+
**Symptoms:**
|
|
93
|
+
- Intermittent loading failures for specific ROIs
|
|
94
|
+
- Error message: "database disk image is malformed"
|
|
95
|
+
- Same ROI may succeed on some loads and fail on others
|
|
96
|
+
- More common with large databases (>1 GB)
|
|
97
|
+
|
|
98
|
+
### Solution: Convert Databases to DELETE Mode
|
|
99
|
+
|
|
100
|
+
Before mounting databases in Docker, convert them from WAL to DELETE mode:
|
|
101
|
+
|
|
102
|
+
#### Using the Python Script (Recommended)
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# From the ethoscopy project root
|
|
106
|
+
python3 scripts/convert_wal_to_delete.py /mnt/ethoscope_data/results --dry-run
|
|
107
|
+
|
|
108
|
+
# Convert all databases with detailed output
|
|
109
|
+
python3 scripts/convert_wal_to_delete.py /mnt/ethoscope_data/results --verbose
|
|
110
|
+
|
|
111
|
+
# Force conversion even for recently modified files (use with caution)
|
|
112
|
+
python3 scripts/convert_wal_to_delete.py /mnt/ethoscope_data/results --force
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Using the Bash Wrapper
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# From the ethoscopy project root
|
|
119
|
+
./scripts/convert_databases.sh /mnt/ethoscope_data/results
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Manual Conversion Using sqlite3
|
|
123
|
+
|
|
124
|
+
For individual databases:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
sqlite3 /path/to/database.db "PRAGMA wal_checkpoint(TRUNCATE); PRAGMA journal_mode=DELETE;"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For bulk conversion:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
find /mnt/ethoscope_data/results -name "*.db" -type f -exec sqlite3 {} "PRAGMA wal_checkpoint(TRUNCATE); PRAGMA journal_mode=DELETE;" \;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Verification
|
|
137
|
+
|
|
138
|
+
After conversion, verify the database is in DELETE mode:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
sqlite3 /path/to/database.db "PRAGMA journal_mode;"
|
|
142
|
+
# Should output: delete
|
|
143
|
+
|
|
144
|
+
sqlite3 /path/to/database.db "PRAGMA integrity_check;"
|
|
145
|
+
# Should output: ok
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Best Practices
|
|
149
|
+
|
|
150
|
+
1. **Run conversion BEFORE starting Docker containers**
|
|
151
|
+
```bash
|
|
152
|
+
# From the ethoscopy project root, convert databases first
|
|
153
|
+
./scripts/convert_databases.sh /mnt/ethoscope_data/results
|
|
154
|
+
|
|
155
|
+
# Then start containers
|
|
156
|
+
cd Docker && docker compose up -d
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
2. **Do NOT convert databases while ethoscopes are actively writing**
|
|
160
|
+
- The conversion script skips files modified in the last 24 hours by default
|
|
161
|
+
- Use `--force` to override this safety check if needed
|
|
162
|
+
|
|
163
|
+
3. **Test on a backup first**
|
|
164
|
+
```bash
|
|
165
|
+
# Create a test copy
|
|
166
|
+
cp /path/to/database.db /tmp/test.db
|
|
167
|
+
|
|
168
|
+
# Test conversion
|
|
169
|
+
sqlite3 /tmp/test.db "PRAGMA wal_checkpoint(TRUNCATE); PRAGMA journal_mode=DELETE;"
|
|
170
|
+
|
|
171
|
+
# Verify it works
|
|
172
|
+
sqlite3 /tmp/test.db "PRAGMA integrity_check;"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
4. **Consider converting at the ethoscope source** (upstream fix)
|
|
176
|
+
- Configure ethoscopes to use DELETE mode by default
|
|
177
|
+
- Prevents the need for post-processing
|
|
178
|
+
|
|
179
|
+
### Troubleshooting
|
|
180
|
+
|
|
181
|
+
**Q: I still get "malformed" errors after conversion**
|
|
182
|
+
|
|
183
|
+
A: The ethoscopy library now includes improved connection handling that should work with both WAL and DELETE mode databases. If you still encounter issues:
|
|
184
|
+
1. Verify the database was actually converted: `sqlite3 database.db "PRAGMA journal_mode;"`
|
|
185
|
+
2. Check database integrity: `sqlite3 database.db "PRAGMA integrity_check;"`
|
|
186
|
+
3. Ensure you're using ethoscopy version 2.0.4 or later
|
|
187
|
+
|
|
188
|
+
**Q: Can I convert databases while Docker is running?**
|
|
189
|
+
|
|
190
|
+
A: Yes, but you should restart the container after conversion:
|
|
191
|
+
```bash
|
|
192
|
+
# From the ethoscopy project root
|
|
193
|
+
./scripts/convert_databases.sh /mnt/ethoscope_data/results
|
|
194
|
+
cd Docker && docker compose restart ethoscope-lab
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Q: Will this affect data quality or analysis?**
|
|
198
|
+
|
|
199
|
+
A: No. The conversion only changes how SQLite manages the database internally. All data remains identical and analysis results are unaffected.
|
|
200
|
+
|
|
201
|
+
**Q: How do I check if a database is in WAL mode?**
|
|
202
|
+
|
|
203
|
+
A:
|
|
204
|
+
```bash
|
|
205
|
+
sqlite3 database.db "PRAGMA journal_mode;"
|
|
206
|
+
```
|
|
207
|
+
Output will be either `wal` or `delete` (or `truncate`, `persist`, `memory`).
|
|
208
|
+
|
|
209
|
+
### Emergency Quick Fix
|
|
210
|
+
|
|
211
|
+
If you need to work immediately and can't run the full conversion:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# SSH to host machine (not inside container)
|
|
215
|
+
# Convert just the failing database
|
|
216
|
+
sqlite3 /path/to/failing/database.db "PRAGMA wal_checkpoint(TRUNCATE); PRAGMA journal_mode=DELETE;"
|
|
217
|
+
|
|
218
|
+
# Restart container
|
|
219
|
+
docker compose restart ethoscope-lab
|
|
220
|
+
```
|