Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
63b1727
update s3 contrib
mdragilev Jun 28, 2024
b852f88
remove b1
tempanyman Jul 16, 2024
0bdbfcf
Merge pull request #26 from Affirm/michaeld/s3-contrib-bump-boto
tempanyman Jul 16, 2024
149a0a0
Luigi scheduler running with Py 3.12 and HelloWorldTask completed suc…
mrafayaleem Jan 13, 2026
1569533
Rebase branch
mrafayaleem Jan 13, 2026
95510ea
Add more Python 3.12 compatibility fixes
mrafayaleem Jan 16, 2026
6b905e9
Test fixes
mrafayaleem Jan 16, 2026
0d4f01a
More fixes
mrafayaleem Jan 16, 2026
c81d487
More fixes
mrafayaleem Jan 16, 2026
2b8479c
Add more changes
mrafayaleem Jan 16, 2026
ac961da
Update claude.md
mrafayaleem Jan 16, 2026
daaf37c
Add removed tests
mrafayaleem Jan 16, 2026
af685eb
Rename
mrafayaleem Jan 16, 2026
811cea4
RC1
mrafayaleem Jan 26, 2026
9c66156
RC2
mrafayaleem Jan 26, 2026
72da954
RC2
mrafayaleem Jan 26, 2026
2aa26cc
Update requests
mrafayaleem Jan 27, 2026
4ea003c
Publish rc3
mrafayaleem Jan 27, 2026
bef79d4
More fixes
mrafayaleem Jan 27, 2026
424b5b9
RC4
mrafayaleem Jan 27, 2026
3be6fda
Update versioning to bypass uv pre-release verification
mrafayaleem Jan 30, 2026
1dcda89
Add Py39 compatibility
mrafayaleem Mar 23, 2026
be80135
Fix run_tests.sh script
mrafayaleem Mar 23, 2026
0006a90
Rebase s3 from 1.4.7
mrafayaleem Mar 23, 2026
0aadf9c
Update s3
mrafayaleem Mar 24, 2026
42b1d07
Update gitignore
mrafayaleem Mar 24, 2026
2aa8f2c
S3 compatibility
mrafayaleem Mar 24, 2026
05c7113
Reorder S3 classes and lift boto3 imports to top level
mrafayaleem Apr 13, 2026
9cf1c1a
Fail fast in S3ClientBoto3.__init__ if boto3 is not installed
mrafayaleem Apr 13, 2026
f2893bd
Bump the version
mrafayaleem Apr 13, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,4 @@ Icon
Network Trash Folder
Temporary Items
.apdisk
.venv
51 changes: 51 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"mcpServers": {
"microsoft/markitdown": {
"type": "stdio",
"command": "uvx",
"args": [
"markitdown-mcp==0.0.1a4"
],
"gallery": "https://api.mcp.github.com",
"version": "1.0.0"
},
"Context7": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@upstash/context7-mcp@latest"
]
},
"spark-history-server": {
"type": "http",
"url": "http://localhost:18888/mcp",
"env": {
"SHS_MCP_TRANSPORT": "stdio"
}
},
"memory-bank": {
"type": "stdio",
"command": "uvx",
"args": [
"--from",
"git+ssh://git@github.com/Affirm/ai-memory-bank-mcp",
"mcp_memory_bank_setup"
]
},
"notion": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://mcp.notion.com/mcp"
]
},
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/"
}
},
"inputs": []
}
1 change: 1 addition & 0 deletions .python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12.7
94 changes: 94 additions & 0 deletions CLAUDE.md
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nicely written instruction file here, did u use it along with the mcp set up json from above for this upgrade?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did yes. Heavily used both MCP and claude.md files. Also whenever I would discover a new command or process that was relevant, I would ask Claude to update this .md file.

Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Luigi Development Guide

## Overview
Luigi is a Python package for building complex pipelines of batch jobs. It handles dependency resolution, workflow management, visualization, and more.

## Development Setup

### Virtual Environment
```bash
source .venv/bin/activate
```

### Running Tests
```bash
# Run all tests and log results
./run_tests.sh

# Run specific test file
python -m pytest test/some_test.py -v

# Run specific test
python -m pytest test/some_test.py::TestClass::test_method -v

# Run with config (required for some tests)
LUIGI_CONFIG_PATH=test/testconfig/luigi.cfg python -m pytest test/some_test.py -v
```

## Project Structure
- `luigi/` - Main package source code
- `test/` - Test files
- `test/contrib/` - Tests for contrib modules (AWS, databases, etc.)
- `test/testconfig/` - Test configuration files

## Key Files
- `luigi/worker.py` - Task execution worker
- `luigi/scheduler.py` - Central scheduler
- `luigi/task.py` - Base Task class
- `luigi/parameter.py` - Parameter types
- `luigi/contrib/` - Integration modules (S3, ECS, Batch, etc.)

## Python 3.12 Compatibility Notes
- `random.seed()` no longer accepts tuples - use `hash()` to convert
- `pickle.dump()` requires binary mode (`"wb"`)
- `nose` module uses removed `imp` module - use pytest marks instead
- `logging.config.fileConfig()` raises `FileNotFoundError` for missing files (was `KeyError`)

## Running Luigi

### Quick Test with Local Scheduler (No Server)
For quick testing without starting a server, use `--local-scheduler` which runs an in-memory scheduler:
```bash
# Run the hello world example with in-memory scheduler (no web UI)
# Note: PYTHONPATH=. is needed to find the examples module from project root
PYTHONPATH=. luigi --module examples.hello_world examples.HelloWorldTask --local-scheduler
```

### Central Scheduler with Web UI (luigid)
The `luigid` daemon provides a central scheduler with web interface at http://localhost:8082

#### Run in Foreground
```bash
# Create log directory first
mkdir -p /tmp/luigi-logs

# Start the scheduler with web UI (http://localhost:8082)
luigid --logdir /tmp/luigi-logs

# Or with state persistence (survives restarts)
luigid --port 8082 --logdir /tmp/luigi-logs --state-path /tmp/luigi-state.pickle

# In another terminal, run a task against the central scheduler
PYTHONPATH=. luigi --module examples.hello_world examples.HelloWorldTask
```

#### Run in Background
```bash
mkdir -p /tmp/luigi-logs

# Start scheduler in background
luigid --background --logdir /tmp/luigi-logs --pidfile /tmp/luigi.pid

# Run a task
PYTHONPATH=. luigi --module examples.hello_world examples.HelloWorldTask

# Kill the scheduler
kill $(cat /tmp/luigi.pid)
# Or if pidfile not used
pkill -f luigid
```

## Common Test Issues
- boto3 tests require AWS region configuration or proper mocking
- SQLAlchemy tests need eager loading for relationships to avoid DetachedInstanceError
- Process-related tests may need small delays for `/proc` filesystem to be ready
11 changes: 5 additions & 6 deletions luigi/contrib/gcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@
except ImportError:
from urllib.parse import urlsplit

import io
from luigi.contrib import gcp
import luigi.target
from luigi import six
from luigi.six.moves import xrange

logger = logging.getLogger('luigi-interface')

Expand Down Expand Up @@ -70,7 +69,7 @@ def _wait_for_consistency(checker):
This is necessary for e.g. create/delete where the operation might return,
but won't be reflected for a bit.
"""
for _ in xrange(EVENTUAL_CONSISTENCY_MAX_SLEEPS):
for _ in range(EVENTUAL_CONSISTENCY_MAX_SLEEPS):
if checker():
return

Expand Down Expand Up @@ -255,10 +254,10 @@ def put(self, filename, dest_path, mimetype=None, chunksize=None):

def put_string(self, contents, dest_path, mimetype=None):
mimetype = mimetype or mimetypes.guess_type(dest_path)[0] or DEFAULT_MIMETYPE
assert isinstance(mimetype, six.string_types)
if not isinstance(contents, six.binary_type):
assert isinstance(mimetype, str)
if not isinstance(contents, bytes):
contents = contents.encode("utf-8")
media = http.MediaIoBaseUpload(six.BytesIO(contents), mimetype, resumable=bool(contents))
media = http.MediaIoBaseUpload(io.BytesIO(contents), mimetype, resumable=bool(contents))
self._do_put(media, dest_path)

def mkdir(self, path, parents=True, raise_if_exists=False):
Expand Down
3 changes: 1 addition & 2 deletions luigi/contrib/hdfs/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@
import luigi
import random
import warnings
from urllib import parse as urlparse
from luigi.target import FileSystemTarget
from luigi.contrib.hdfs.config import tmppath
from luigi.contrib.hdfs import format as hdfs_format
from luigi.contrib.hdfs import clients as hdfs_clients
from luigi.six.moves.urllib import parse as urlparse
from luigi.six.moves import range


class HdfsTarget(FileSystemTarget):
Expand Down
Loading