The Docker-based Open edX distribution designed for peace of mind
Core utilities for encryption, file operations, string processing, serialization, and output formatting. These utilities provide common functionality used throughout Tutor for security, data processing, and user interaction.
Password hashing and verification using bcrypt for secure credential storage.
def encrypt(text: str) -> str:
"""
Encrypt text using bcrypt hashing for secure password storage.
Args:
text (str): Plain text to encrypt
Returns:
str: Bcrypt hash of the input text
"""
def verify_encrypted(encrypted: str, text: str) -> bool:
"""
Verify that plain text matches the encrypted hash.
Args:
encrypted (str): Previously encrypted hash
text (str): Plain text to verify
Returns:
bool: True if text matches the encrypted hash
"""Utilities for managing directories and file paths.
def ensure_file_directory_exists(path: str) -> None:
"""
Create parent directory for a file path if it doesn't exist.
Args:
path (str): File path whose parent directory should be created
"""
def ensure_directory_exists(path: str) -> None:
"""
Create directory and any necessary parent directories.
Args:
path (str): Directory path to create
"""Utilities for generating random data and processing service configurations.
def random_string(length: int) -> str:
"""
Generate a random string of specified length using alphanumeric characters.
Args:
length (int): Length of random string to generate
Returns:
str: Random alphanumeric string
"""
def list_if(services: List[Tuple[str, bool]]) -> str:
"""
Generate JSON array string of service names where the boolean is True.
Args:
services (List[Tuple[str, bool]]): List of (service_name, enabled) tuples
Returns:
str: JSON array string of enabled service names
"""
def common_domain(d1: str, d2: str) -> str:
"""
Find the common domain suffix between two domain names.
Args:
d1 (str): First domain name
d2 (str): Second domain name
Returns:
str: Common domain suffix
"""
def reverse_host(domain: str) -> str:
"""
Reverse domain name in Java package style (com.example.subdomain).
Args:
domain (str): Domain name to reverse
Returns:
str: Reversed domain name
"""Utilities for checking system state and user permissions.
def is_root() -> bool:
"""
Check if the current process is running as root user.
Returns:
bool: True if running as root
"""YAML loading and saving with consistent formatting and multiple document support.
def load(stream: Union[str, IO[str]]) -> Any:
"""
Load YAML content from string or file stream.
Args:
stream (Union[str, IO[str]]): YAML content string or file stream
Returns:
Any: Parsed YAML data
"""
def load_all(stream: str) -> Iterator[Any]:
"""
Load multiple YAML documents from string.
Args:
stream (str): YAML content string with multiple documents
Returns:
Iterator[Any]: Iterator of parsed YAML documents
"""
def dump_all(documents: Sequence[Any], fileobj: TextIOWrapper) -> None:
"""
Write multiple YAML documents to a file.
Args:
documents (Sequence[Any]): Sequence of objects to serialize
fileobj (TextIOWrapper): File object to write to
"""
def dump(content: Any, fileobj: TextIOWrapper) -> None:
"""
Write single YAML document to a file.
Args:
content (Any): Object to serialize
fileobj (TextIOWrapper): File object to write to
"""
def dumps(content: Any) -> str:
"""
Serialize object to YAML string.
Args:
content (Any): Object to serialize
Returns:
str: YAML string representation
"""Special formatting for configuration values and output display.
def str_format(content: Any) -> str:
"""
Format values for string output with special handling for booleans and None.
Args:
content (Any): Value to format
Returns:
str: Formatted string (booleans as lowercase, None as empty string)
"""Console output styling with colors and semantic formatting for different message types.
def title(text: str) -> str:
"""
Format text as a title with green styling.
Args:
text (str): Text to format
Returns:
str: Styled title text
"""
def info(text: str) -> str:
"""
Format text as informational message in blue.
Args:
text (str): Text to format
Returns:
str: Styled info text
"""
def error(text: str) -> str:
"""
Format text as error message in red.
Args:
text (str): Text to format
Returns:
str: Styled error text
"""
def command(text: str) -> str:
"""
Format text as command in magenta.
Args:
text (str): Text to format
Returns:
str: Styled command text
"""
def question(text: str) -> str:
"""
Format text as question in yellow.
Args:
text (str): Text to format
Returns:
str: Styled question text
"""
def alert(text: str) -> str:
"""
Format text as alert with warning emoji.
Args:
text (str): Text to format
Returns:
str: Styled alert text with emoji
"""Functions for parsing and managing bind mounts between host and container directories.
def get_mounts(config: Config) -> list[str]:
"""
Get the list of bind mounts from configuration.
Args:
config (Config): Configuration dictionary
Returns:
list[str]: List of mount specifications
"""
def iter_mounts(user_mounts: list[str], *names: str) -> Iterable[str]:
"""
Iterate bind-mounts available to given compose services.
Args:
user_mounts (list[str]): List of user mount specifications
*names (str): Service names to filter mounts for
Yields:
str: Mount strings in "host_path:container_path" format
"""
def parse_mount(value: str) -> list[tuple[str, str, str]]:
"""
Parse mount argument into (service, host_path, container_path) tuples.
Supports explicit format: "service1,service2:/host/path:/container/path"
And implicit format: "/host/path" (uses COMPOSE_MOUNTS filter)
Args:
value (str): Mount specification string
Returns:
list[tuple[str, str, str]]: List of (service, host_path, container_path)
"""YAML parsing and serialization utilities using PyYAML SafeLoader.
def load(stream: Union[str, IO[str]]) -> Any:
"""
Load YAML from string or file stream.
Args:
stream (Union[str, IO[str]]): YAML content or file stream
Returns:
Any: Parsed YAML content
"""
def load_all(stream: str) -> Iterator[Any]:
"""
Load multiple YAML documents from string.
Args:
stream (str): YAML content with multiple documents
Yields:
Any: Each parsed YAML document
"""
def dump(content: Any, fileobj: TextIOWrapper) -> None:
"""
Write content as YAML to file stream.
Args:
content (Any): Content to serialize
fileobj (TextIOWrapper): File stream to write to
"""
def dumps(content: Any) -> str:
"""
Serialize content to YAML string.
Args:
content (Any): Content to serialize
Returns:
str: YAML string representation
"""
def parse_key_value(text: str) -> Optional[tuple[str, Any]]:
"""
Parse KEY=YAML_VALUE command line arguments.
Args:
text (str): Command line argument string
Returns:
Optional[tuple[str, Any]]: (key, parsed_value) or None if invalid
"""Console output functions that combine styling with printing.
def echo_info(text: str) -> None:
"""
Print informational message to stdout.
Args:
text (str): Message to print
"""
def echo_error(text: str) -> None:
"""
Print error message to stderr.
Args:
text (str): Error message to print
"""
def echo_alert(text: str) -> None:
"""
Print alert message to stderr.
Args:
text (str): Alert message to print
"""
def echo(text: str, err: bool = False) -> None:
"""
Print text to stdout or stderr.
Args:
text (str): Text to print
err (bool): Whether to print to stderr instead of stdout
"""Core type definitions for configuration management.
# Union type for all possible configuration values
ConfigValue = Union[str, float, None, bool, List[str], List[Any], Dict[str, Any], Dict[Any, Any]]
# Configuration dictionary type
Config = Dict[str, ConfigValue]
def cast_config(config: Any) -> Config:
"""
Validate and cast input to Config type.
Args:
config (Any): Input to validate as configuration
Returns:
Config: Validated configuration dictionary
Raises:
TutorError: If input is not a valid configuration
"""
def get_typed(config: dict, key: str, expected_type: type[T], default: Optional[T] = None) -> T:
"""
Get typed value from configuration dictionary with default fallback.
Args:
config (dict): Configuration dictionary
key (str): Configuration key to retrieve
expected_type (type[T]): Expected type of the value
default (Optional[T]): Default value if key is missing
Returns:
T: Typed configuration value
Raises:
TutorError: If value exists but is not of expected type
"""Base exception class for Tutor-specific errors.
class TutorError(Exception):
"""
Base exception class for all Tutor-specific errors.
Used for configuration errors, deployment failures, plugin issues, etc.
"""
passfrom tutor.utils import encrypt, verify_encrypted
# Encrypt a password
password = "my_secure_password"
encrypted = encrypt(password)
# Later verify the password
is_valid = verify_encrypted(encrypted, "my_secure_password") # True
is_invalid = verify_encrypted(encrypted, "wrong_password") # Falsefrom tutor.utils import ensure_file_directory_exists, ensure_directory_exists
# Ensure parent directory exists before creating file
file_path = "/path/to/deep/directory/config.yml"
ensure_file_directory_exists(file_path)
# Create directory structure
ensure_directory_exists("/path/to/new/directory")from tutor.utils import random_string, list_if, common_domain, reverse_host
# Generate random password
password = random_string(32)
# Process service list
services = [("lms", True), ("cms", True), ("forum", False)]
enabled_services = list_if(services) # '["lms", "cms"]'
# Domain processing
common = common_domain("learn.example.com", "studio.example.com") # "example.com"
reversed = reverse_host("learn.example.com") # "com.example.learn"from tutor.serialize import load, dumps, dump
from tutor.utils import ensure_file_directory_exists
# Load YAML configuration
with open("config.yml", "r") as f:
config = load(f)
# Serialize to string
yaml_str = dumps({"key": "value", "list": [1, 2, 3]})
# Save to file
ensure_file_directory_exists("output/config.yml")
with open("output/config.yml", "w") as f:
dump(config, f)from tutor.fmt import echo_info, echo_error, echo_alert, title, error
# Print styled messages
echo_info("Configuration loaded successfully")
echo_error("Failed to connect to database")
echo_alert("Running as root is not recommended")
# Create styled strings
header = title("Open edX Platform Status")
error_msg = error("Service unavailable")
print(header)
print(error_msg)from tutor.types import cast_config, get_typed, TutorError
# Validate configuration
try:
config = cast_config({"PLATFORM_NAME": "My Platform", "HTTP_PORT": 80})
except TutorError as e:
print(f"Invalid configuration: {e}")
# Get typed values with defaults
platform_name = get_typed(config, "PLATFORM_NAME", str, "Default Platform")
http_port = get_typed(config, "HTTP_PORT", int, 8000)
debug_mode = get_typed(config, "DEBUG", bool, False)from tutor.utils import list_if
# Define services with their enabled status
services = [
("lms", True),
("cms", True),
("forum", False),
("discovery", True),
("ecommerce", False)
]
# Generate JSON list of enabled services
enabled_json = list_if(services)
print(enabled_json) # ["lms", "cms", "discovery"]
# Use in templates or configuration
config_update = {
"ENABLED_SERVICES": enabled_json
}from tutor.bindmount import get_mounts, iter_mounts, parse_mount
from tutor.types import Config
# Get mounts from configuration
config: Config = {"MOUNTS": ["lms:/host/code:/openedx/edx-platform", "/host/themes"]}
mounts = get_mounts(config)
# Parse specific mount strings
explicit_mount = parse_mount("lms,cms:/host/code:/openedx/edx-platform")
# Returns: [("lms", "/host/code", "/openedx/edx-platform"), ("cms", "/host/code", "/openedx/edx-platform")]
implicit_mount = parse_mount("/host/themes")
# Uses COMPOSE_MOUNTS filter to determine container paths
# Get mounts for specific services
user_mounts = ["lms:/host/code:/openedx/edx-platform", "/host/themes"]
lms_mounts = list(iter_mounts(user_mounts, "lms"))from tutor.serialize import load, dumps, parse_key_value
import io
# Parse YAML string
yaml_content = """
platform:
name: "My Open edX"
debug: true
services:
- lms
- cms
"""
config = load(yaml_content)
# Parse command line arguments
key_value = parse_key_value("PLATFORM_NAME=My Custom Platform")
# Returns: ("PLATFORM_NAME", "My Custom Platform")
boolean_value = parse_key_value("DEBUG=true")
# Returns: ("DEBUG", True)
list_value = parse_key_value("SERVICES=[lms, cms, forum]")
# Returns: ("SERVICES", ["lms", "cms", "forum"])
# Serialize back to YAML
updated_config = {
"PLATFORM_NAME": "Updated Platform",
"HTTP_PORT": 8000,
"SERVICES": ["lms", "cms"]
}
yaml_string = dumps(updated_config)Install with Tessl CLI
npx tessl i tessl/pypi-tutor