Install & Compatibility
Where this runs
tested against v4.0.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.094s · 27.3MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 2.7s · import 0.090s · 29MB
27MB installed
● package 27MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
CourseKey
✓ from opaque_keys.edx.keys import CourseKey
✗ from opaque_keys.locators import CourseLocator
Old 'locators' module is deprecated; use 'edx.keys' for specific key types. While CourseLocator might still exist for compatibility in older versions, CourseKey is the preferred direct import for courses.
UsageKey
✓ from opaque_keys.edx.keys import UsageKey
✗ from opaque_keys.locators import BlockUsageLocator
Similar to CourseKey, BlockUsageLocator is an older concept. UsageKey is the direct opaque key for XBlock usages.
CollectionKey
✓ from opaque_keys.edx.keys import CollectionKey
✗ from opaque_keys.edx.keys import LibraryItemKey
In version 3.0.0 and later, LibraryItemKey was removed and replaced by CollectionKey and ContainerKey.
CourseKeyField
✓ from opaque_keys.edx.django.models import CourseKeyField
This provides a Django model field for storing CourseKey instances.
This quickstart demonstrates how to create `CourseKey` and `UsageKey` objects from string identifiers and how to extract their components. It also shows how to generate a `UsageKey` from a `CourseKey` and convert keys back to their string representations. A conceptual example for Django model fields is also included.
from opaque_keys.edx.keys import CourseKey, UsageKey
# Create a CourseKey from a string identifier
course_id_string = "course-v1:OrgX+DemoCourse+2023_T1"
course_key = CourseKey.from_string(course_id_string)
print(f"Parsed CourseKey: {course_key}")
print(f"Organization: {course_key.org}")
print(f"Course: {course_key.course}")
# Create a UsageKey (for an XBlock) associated with the course
usage_key = course_key.make_usage_key("video", "video_id_123")
print(f"Generated UsageKey: {usage_key}")
# Convert key back to string
key_string = str(usage_key)
print(f"UsageKey as string: {key_string}")
# Example with Django model field (conceptual, requires Django setup)
try:
from opaque_keys.edx.django.models import CourseKeyField
# Example of how it would be used in a Django model
# class MyModel(models.Model):
# course_id = CourseKeyField(max_length=255)
print("Django model fields available for integration.")
except ImportError:
print("Django is not installed or Django-specific features are not in use.")
Debug
Known issues
breakingThe `LibraryItemKey` class was removed in version 3.0.0 and replaced by `CollectionKey` and `ContainerKey`. Code using `LibraryItemKey` will break.fixMigrate usage of `LibraryItemKey` to `CollectionKey` or `ContainerKey` as appropriate for your data structure. Review the 3.0.0 changelog for details on the new classes.
affects: >=3.0.0
deprecatedSeveral methods and classes, particularly older `Locator` classes and utility methods like `to_deprecated_string()`, are marked as deprecated. They may still function but are subject to removal.fixAvoid using classes directly from `opaque_keys.locators` and instead prefer specific key types from `opaque_keys.edx.keys`. For string conversion, use `str(key)` or `unicode(key)` where appropriate instead of `to_deprecated_string()`.
affects: All versions (deprecation warnings may appear in logs)
gotchaOlder documentation and blog posts about 'Opaque Keys' can be misleading due to significant changes in the project's architecture and API over its 10+ year lifespan. Concepts like `CourseLocator` were once `CourseKey` and vice versa, leading to confusion.fixAlways refer to the official `edx-opaque-keys` GitHub repository and its docstrings for the most up-to-date and accurate API usage. Prioritize documentation generated from the current codebase.
affects: All versions, when consulting old resources
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'opaque_keys.locators'
Attempting to import deprecated `locators` module which might have been refactored or removed in recent versions.
fixUpdate your import statements to use the `opaque_keys.edx.keys` module for specific key types (e.g., `from opaque_keys.edx.keys import CourseKey`).
AttributeError: 'CourseKey' object has no attribute 'run' (or 'version_agnostic', etc.)
Attempting to access attributes or methods that were part of older `Locator` objects or have been refactored/removed from the current `OpaqueKey` subclasses. The internal structure of keys has evolved.
fixReview the API documentation for the specific `OpaqueKey` subclass (e.g., `CourseKey`) you are using to understand its current attributes and methods. Many key properties are accessible directly as attributes, but some older helper methods might be deprecated or removed.
django.core.exceptions.ValidationError: ['"invalid_key_string" is not a valid OpaqueKey.']
A string provided to `CourseKey.from_string()` or a `CourseKeyField` in Django is not in the correct opaque key format.
fixEnsure that the input string adheres to the expected opaque key format (e.g., `course-v1:Org+Course+Run`). Validate inputs before attempting to convert them to `OpaqueKey` objects.
Upgrade
Version history
4.0.0latest on PyPI · released Apr 2, 2026
Audit
Dependencies
pymongorequiredUsed for MongoDB interactions when dealing with persistent keys.
stevedorerequiredPlugin loading library, likely used for extensible key handling.
typing-extensionsrequiredProvides backported type hints for compatibility across Python versions.