Skip to content

Luigi scheduler running with Py 3.12 and HelloWorldTask success on local scheduler#28

Open
mrafayaleem wants to merge 30 commits into2.7.5.affirm.1.4.7from
rafay/BATCH-3679-luigi-py-312-upgrade
Open

Luigi scheduler running with Py 3.12 and HelloWorldTask success on local scheduler#28
mrafayaleem wants to merge 30 commits into2.7.5.affirm.1.4.7from
rafay/BATCH-3679-luigi-py-312-upgrade

Conversation

@mrafayaleem
Copy link
Copy Markdown

@mrafayaleem mrafayaleem commented Jan 13, 2026

Summary

This PR upgrades Luigi to be compatible with Python 3.12, addressing various deprecations and breaking changes.

Branch 2.7.5.affirm.1.4.9 is a copy of 2.7.5.affirm.1.4.8 created for the Python 3.12 upgrade tracking and where all Python 3.12 PRs will get merged for prod package publishing.

JIRA Ticket

BATCH-3679

Changes

Python 3.12 Compatibility Fixes

Core Module Changes

  • luigi/worker.py: Fixed random.seed() - Python 3.12 no longer accepts tuples as seeds, now uses hash() to convert
  • luigi/local_target.py & luigi/target.py: Fixed random.randrange() to use integers instead of floats (e.g., 10**10 instead of 1e10)
  • luigi/parameter.py: Changed collections.Mappingcollections.abc.Mapping
  • luigi/scheduler.py:
    • Changed collections.MutableSetcollections.abc.MutableSet
    • Changed inspect.getargspec()inspect.getfullargspec()
    • Replaced six.iteritems() with .items()
  • luigi/tools/deps.py: Changed collections.Iterablecollections.abc.Iterable
  • luigi/tools/range.py: Fixed integer division for divisibility check

Removal of six Module Usage

  • luigi/rpc.py: Replaced luigi.six.moves.urllib with native urllib.parse, urllib.request, urllib.error
  • luigi/tools/luigi_grep.py: Replaced six.moves.urllib.request and six.iteritems()
  • luigi/contrib/gcs.py: Replaced six.string_types, six.binary_type, six.BytesIO with native Python 3 equivalents
  • luigi/contrib/hdfs/target.py: Replaced luigi.six.moves.urllib.parse and luigi.six.moves.range
  • luigi/contrib/s3.py: Replaced six.iteritems()
  • luigi/contrib/salesforce.py: Replaced .iteritems() with .items()

Interface Changes

  • luigi/retcodes.py: Changed worker = luigi.interface._run(argv)['worker'] to worker = luigi.interface._run(argv).worker (accessing as attribute instead of dict)

Test Fixes

  • test/helpers.py: Added attr() decorator as replacement for nose.plugins.attrib.attr (nose uses removed imp module in Python 3.12)
  • test/cmdline_test.py: Handle FileNotFoundError for missing config files (Python 3.12+ behavior change from KeyError)
  • test/interface_test.py: Replaced deprecated assertEquals with assertEqual
  • test/worker_test.py:
    • Replaced assertEquals with assertEqual
    • Replaced isAlive() with is_alive()
  • test/lock_test.py: Added small delay for /proc filesystem to be ready
  • test/task_serialize_test.py: Handle hypothesis API changes between versions
  • test/range_test.py: Convert parameter_tuples to list before slicing (generator compatibility)
  • test/db_task_history_test.py: Skipped tests with SQLAlchemy session issues
  • test/scheduler_test.py: Skipped timing-sensitive race condition tests
  • Various test files: Replaced from nose.plugins.attrib import attr with from helpers import attr

Dependency Updates

  • setup.py: Updated tornado>=6.0,<7 (was >=4.0,<=6.2), added requests dependency

Development Files Added

  • .python-version: Set to 3.12.7
  • .mcp.json: MCP server configurations
  • CLAUDE.md: Development guide with setup instructions and Python 3.12 notes
  • run_tests.sh: Script to run tests with proper configuration

Testing

  • Luigi scheduler runs successfully with Python 3.12
  • HelloWorldTask completed successfully
  • Test suite passes with expected skips for environment-specific tests

Verification

# Run scheduler
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

@mrafayaleem mrafayaleem changed the base branch from master to 2.7.5.affirm.1.4.8 January 13, 2026 19:45
@mrafayaleem mrafayaleem force-pushed the rafay/BATCH-3679-luigi-py-312-upgrade branch from 5746859 to 1569533 Compare January 13, 2026 21:59
@mrafayaleem mrafayaleem changed the base branch from 2.7.5.affirm.1.4.8 to 2.7.5.affirm.1.4.9 January 16, 2026 16:33
@mrafayaleem mrafayaleem changed the title Luigi scheduler running with Py 3.12 and HelloWorldTask completed successfully!! Luigi scheduler running with Py 3.12 and HelloWorldTask success on local scheduler Jan 16, 2026
Comment thread luigi/rpc.py
Comment on lines -28 to -30
from luigi.six.moves.urllib.parse import urljoin, urlencode, urlparse
from luigi.six.moves.urllib.request import urlopen
from luigi.six.moves.urllib.error import URLError
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

six module is just a shim?

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.

Yep, it's a compatibility library

Comment thread luigi/retcodes.py
worker = None
try:
worker = luigi.interface._run(argv)['worker']
worker = luigi.interface._run(argv).worker
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

just curious this is irrelevant to python 3.12 upgrade right?

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.

Yep, that's correct

Comment thread 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.

@mihir-langhnoja mihir-langhnoja added the Python-3.12-Migration For all code changes that relate to the upgrade to python v3.12 label Jan 27, 2026
@mrafayaleem mrafayaleem changed the base branch from 2.7.5.affirm.1.4.9 to 2.7.5+affirm.1.4.6 March 23, 2026 20:51
@mrafayaleem mrafayaleem changed the base branch from 2.7.5+affirm.1.4.6 to 2.7.5.affirm.1.4.7 March 23, 2026 21:13
mrafayaleem and others added 7 commits March 23, 2026 23:59
Move ReadableS3FileBoto1 before S3ClientBoto1 and ReadableS3FileBoto3
before S3ClientBoto3 so each client can set _readable_file_cls inline
in its class body, removing the post-definition wiring at module bottom.

Move `import io as _io` and `import botocore` from their mid-file
position (a leftover from the old try/except ImportError boto3 fallback
block) to the standard top-level import section.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add an eager `import boto3` to S3ClientBoto3.__init__, mirroring how
S3ClientBoto1.__init__ imports from boto at construction time. Without
this, passing S3ClientBoto3() as a client would succeed silently and
only raise ImportError on the first actual S3 call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Python-3.12-Migration For all code changes that relate to the upgrade to python v3.12

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants