Skip to main content

A drop-in schema-based configuration system for FastHTML applications with automatic UI generation, sidebar navigation, and persistent storage.

Project description

cjm-fasthtml-settings

Install

pip install cjm_fasthtml_settings

Project Structure

nbs/
├── components/ (3)
│   ├── dashboard.ipynb  # Settings dashboard layout components
│   ├── forms.ipynb      # Form generation components for settings interfaces
│   └── sidebar.ipynb    # Navigation menu components for settings sidebar
├── core/ (5)
│   ├── config.ipynb        # Configuration constants, directory management, and base application schema
│   ├── html_ids.ipynb      # Centralized HTML ID constants for settings components
│   ├── schema_group.ipynb  # Grouping related configuration schemas for better organization
│   ├── schemas.ipynb       # Schema registry and management for settings
│   └── utils.ipynb         # Configuration loading, saving, and conversion utilities
├── plugins.ipynb  # Optional plugin integration for extensible settings systems
└── routes.ipynb   # FastHTML route handlers for settings interface

Total: 10 notebooks across 2 directories

Module Dependencies

graph LR
    components_dashboard[components.dashboard<br/>Dashboard]
    components_forms[components.forms<br/>Forms]
    components_sidebar[components.sidebar<br/>Sidebar]
    core_config[core.config<br/>Config]
    core_html_ids[core.html_ids<br/>HTML IDs]
    core_schema_group[core.schema_group<br/>Schema Group]
    core_schemas[core.schemas<br/>Schemas]
    core_utils[core.utils<br/>Utils]
    plugins[plugins<br/>Plugins]
    routes[routes<br/>Routes]

    components_dashboard --> core_html_ids
    components_dashboard --> components_sidebar
    components_dashboard --> core_utils
    components_dashboard --> core_config
    components_dashboard --> components_forms
    components_forms --> core_html_ids
    components_forms --> core_config
    components_forms --> core_utils
    components_sidebar --> core_html_ids
    components_sidebar --> core_schemas
    components_sidebar --> core_config
    core_schemas --> core_schema_group
    core_schemas --> core_config
    core_schemas --> core_schemas
    core_utils --> core_config
    routes --> core_utils
    routes --> core_html_ids
    routes --> components_sidebar
    routes --> components_dashboard
    routes --> routes
    routes --> core_config
    routes --> core_schemas
    routes --> components_forms

23 cross-module dependencies detected

CLI Reference

No CLI commands found in this project.

Module Overview

Detailed documentation for each module in the project:

Config (config.ipynb)

Configuration constants, directory management, and base application schema

Import

from cjm_fasthtml_settings.core.config import (
    DEFAULT_CONFIG_DIR,
    get_app_config_schema
)

Functions

def get_app_config_schema(
    app_title: str = "FastHTML Application",  # Default application title
    config_dir: str = "configs",  # Default configuration directory
    server_port: int = 5000,  # Default server port
    themes_enum: Optional[List[str]] = None,  # Optional list of theme values
    themes_enum_names: Optional[List[str]] = None,  # Optional list of theme display names
    default_theme: Optional[str] = None,  # Default theme value
    include_theme: bool = True,  # Whether to include theme selection
    **extra_properties  # Additional custom properties to add to the schema
) -> Dict[str, Any]:  # JSON Schema for application configuration
    """
    Generate a customizable application configuration schema.
    
    This function creates a JSON Schema for application settings that can be customized
    with your own defaults and additional properties.
    
    Returns:
        A JSON Schema dictionary with application configuration structure
    """

Variables

DEFAULT_CONFIG_DIR

Dashboard (dashboard.ipynb)

Settings dashboard layout components

Import

from cjm_fasthtml_settings.components.dashboard import (
    create_form_skeleton,
    render_schema_settings_content,
    settings_content
)

Functions

def create_form_skeleton(
    schema_id: str,  # The schema ID for the settings
    hx_get_url: str  # URL to fetch the actual form content
) -> Div:  # Div element with loading trigger
    """
    Create a loading skeleton for the settings form that loads asynchronously.
    
    This provides a placeholder that triggers an HTMX request to load the actual form,
    improving perceived performance for complex forms.
    """
def render_schema_settings_content(
    schema: Dict,  # JSON schema for the settings
    config_dir: Optional[Path] = None  # Config directory path
) -> FT:  # Settings form container
    """
    Render settings content for a schema-based configuration.
    
    Args:
        schema: The JSON schema to render
        config_dir: Directory where configs are stored
    """
def settings_content(
    request,  # FastHTML request object
    schema: Dict,  # Schema to display
    schemas: Dict,  # All registered schemas for sidebar
    config_dir: Optional[Path] = None,  # Config directory
    menu_section_title: str = "Settings",  # Sidebar section title
    plugin_registry: Optional[Any] = None  # Optional plugin registry
) -> Div:  # Settings content layout
    """
    Return settings content with sidebar and form.
    
    Handles both full page loads and HTMX partial updates.
    
    Args:
        request: The request object (to check for HTMX)
        schema: The schema to display
        schemas: All available schemas for the sidebar
        config_dir: Config directory path
        menu_section_title: Title for the sidebar menu section
        plugin_registry: Optional plugin registry for showing plugins in sidebar
    """

Forms (forms.ipynb)

Form generation components for settings interfaces

Import

from cjm_fasthtml_settings.components.forms import (
    create_settings_form,
    create_settings_form_container
)

Functions

def create_settings_form(
    schema: Dict[str, Any],  # JSON schema for the form
    values: Dict[str, Any],  # Current values for the form fields
    post_url: str,  # URL for form submission
    reset_url: str  # URL for resetting form to defaults
) -> Form:  # Form element with settings and action buttons
    """
    Create a settings form with action buttons.
    
    Generates a form using cjm-fasthtml-jsonschema based on the provided schema,
    with Save and Reset buttons.
    """
def create_settings_form_container(
    schema: Dict[str, Any],  # JSON schema for the form
    values: Dict[str, Any],  # Current values for the form fields
    post_url: str,  # URL for form submission
    reset_url: str,  # URL for resetting form to defaults
    alert_message: Optional[Any] = None,  # Optional alert element to display
    use_alert_container: bool = False  # If True, add empty alert-container div
) -> Div:  # Div containing the alert (if any) and the settings form
    """
    Create a container with optional alert and settings form.
    
    This is useful for wrapping a settings form with an alert area that can
    display success/error messages.
    """

HTML IDs (html_ids.ipynb)

Centralized HTML ID constants for settings components

Import

from cjm_fasthtml_settings.core.html_ids import (
    SettingsHtmlIds
)

Classes

class SettingsHtmlIds(AppHtmlIds):
    """
    HTML ID constants for settings components.
    
    This class extends AppHtmlIds from cjm_fasthtml_app_core with settings-specific IDs.
    It inherits ALERT_CONTAINER and as_selector() from the parent class.
    
    Inherited from AppHtmlIds:
        - ALERT_CONTAINER: "alert-container"
        - MAIN_CONTENT: "main-content"
        - as_selector(id_str): Converts an ID to CSS selector format (with #)
    
    For IDE Support:
        IDEs like VS Code with Pylance will autocomplete these attributes and warn
        if you try to access non-existent attributes.
    
    Note:
        The typing.Final annotation indicates these are constants that shouldn't
        be reassigned at runtime.
    """
    
    def menu_item(name: str) -> str
        "Generate a menu item ID for a given settings name."

Plugins (plugins.ipynb)

Optional plugin integration for extensible settings systems

Import

from cjm_fasthtml_settings.plugins import (
    PluginRegistryProtocol,
    SimplePluginRegistry
)

Classes

@runtime_checkable
class PluginRegistryProtocol(Protocol):
    """
    Protocol that plugin registries should implement.
    
    This allows the settings library to work with any plugin system
    that implements these methods.
    """
    
    def get_plugin(self, unique_id: str) -> Optional[PluginMetadata]:
            """Get plugin metadata by unique ID."""
            ...
        
        def get_plugins_by_category(self, category: str) -> list[PluginMetadata]
        "Get plugin metadata by unique ID."
    
    def get_plugins_by_category(self, category: str) -> list[PluginMetadata]:
            """Get all plugins in a category."""
            ...
        
        def get_categories_with_plugins(self) -> list[str]
        "Get all plugins in a category."
    
    def get_categories_with_plugins(self) -> list[str]:
            """Get all categories that have registered plugins."""
            ...
        
        def load_plugin_config(self, unique_id: str) -> Dict[str, Any]
        "Get all categories that have registered plugins."
    
    def load_plugin_config(self, unique_id: str) -> Dict[str, Any]:
            """Load saved configuration for a plugin."""
            ...
        
        def save_plugin_config(self, unique_id: str, config: Dict[str, Any]) -> bool
        "Load saved configuration for a plugin."
    
    def save_plugin_config(self, unique_id: str, config: Dict[str, Any]) -> bool
        "Save configuration for a plugin."
class SimplePluginRegistry:
    def __init__(self, config_dir: Optional[Path] = None):
        self._plugins: Dict[str, PluginMetadata] = {}
    """
    Simple implementation of PluginRegistryProtocol.
    
    This provides a basic plugin registry that can be used with the settings
    library. Applications with more complex needs can implement their own
    registry that follows the PluginRegistryProtocol.
    
    Categories are arbitrary strings defined by the application.
    """
    
    def __init__(self, config_dir: Optional[Path] = None):
            self._plugins: Dict[str, PluginMetadata] = {}
    
    def register_plugin(self, metadata: PluginMetadata):
            """Register a plugin."""
            # Check if plugin is configured
            config_file = self._config_dir / f"{metadata.get_unique_id()}.json"
            metadata.is_configured = config_file.exists()
            
            self._plugins[metadata.get_unique_id()] = metadata
        
        def get_plugin(self, unique_id: str) -> Optional[PluginMetadata]
        "Register a plugin."
    
    def get_plugin(self, unique_id: str) -> Optional[PluginMetadata]:
            """Get plugin metadata by unique ID."""
            return self._plugins.get(unique_id)
        
        def get_plugins_by_category(self, category: str) -> list
        "Get plugin metadata by unique ID."
    
    def get_plugins_by_category(self, category: str) -> list:
            """Get all plugins in a category."""
            return [p for p in self._plugins.values() if p.category == category]
        
        def get_categories_with_plugins(self) -> list
        "Get all plugins in a category."
    
    def get_categories_with_plugins(self) -> list:
            """Get all categories that have registered plugins."""
            categories = set(p.category for p in self._plugins.values())
            return sorted(categories)
        
        def load_plugin_config(self, unique_id: str) -> Dict[str, Any]
        "Get all categories that have registered plugins."
    
    def load_plugin_config(self, unique_id: str) -> Dict[str, Any]:
            """Load saved configuration for a plugin."""
            import json
            config_file = self._config_dir / f"{unique_id}.json"
            if config_file.exists()
        "Load saved configuration for a plugin."
    
    def save_plugin_config(self, unique_id: str, config: Dict[str, Any]) -> bool:
            """Save configuration for a plugin."""
            import json
            try
        "Save configuration for a plugin."

Routes (routes.ipynb)

FastHTML route handlers for settings interface

Import

from cjm_fasthtml_settings.routes import (
    config,
    settings_ar,
    RoutesConfig,
    index,
    load_form,
    save,
    reset,
    plugin_reset,
    plugin_save,
    plugin
)

Functions

def _resolve_schema(id: str)
    """
    Resolve schema from ID using the registry.
    
    Handles both direct schemas and grouped schemas via registry.resolve_schema().
    
    Returns:
        tuple: (schema, error_message) - schema is None if error occurred
    """
def _handle_htmx_request(request, content_fn: Callable, *args, **kwargs):
    """Handle HTMX vs full page response pattern."""
    content = content_fn(*args, **kwargs)
    
    # Check if this is an HTMX request
    if request.headers.get('HX-Request')
    "Handle HTMX vs full page response pattern."
def _create_settings_response(
    schema: Dict[str, Any],
    values: Dict[str, Any],
    save_url: str,
    reset_url: str,
    alert_msg,
    sidebar_id: str
)
    "Create standardized settings form response with sidebar."
@settings_ar
def index(request, id: str = None):
    """Main settings page.
    
    Args:
        request: FastHTML request object
        id: Schema ID to display (defaults to config.default_schema)
    """
    if id is None
    """
    Main settings page.
    
    Args:
        request: FastHTML request object
        id: Schema ID to display (defaults to config.default_schema)
    """
@settings_ar
def load_form(id: str = None):
    """Async endpoint that loads the settings form.
    
    Args:
        id: Schema ID to load (defaults to config.default_schema)
    """
    from cjm_fasthtml_tailwind.utilities.flexbox_and_grid import flex
    from cjm_fasthtml_tailwind.utilities.sizing import min_h
    from cjm_fasthtml_tailwind.core.base import combine_classes
    
    if id is None
    """
    Async endpoint that loads the settings form.
    
    Args:
        id: Schema ID to load (defaults to config.default_schema)
    """
@settings_ar
async def save(request, id: str):
    """Save configuration handler.
    
    Args:
        request: FastHTML request object
        id: Schema ID to save
    """
    schema, error_msg = _resolve_schema(id)
    if error_msg
    """
    Save configuration handler.
    
    Args:
        request: FastHTML request object
        id: Schema ID to save
    """
@settings_ar
def reset(id: str):
    """Reset configuration to defaults handler.
    
    Args:
        id: Schema ID to reset
    """
    schema, error_msg = _resolve_schema(id)
    if error_msg
    """
    Reset configuration to defaults handler.
    
    Args:
        id: Schema ID to reset
    """
@settings_ar
def plugin_reset(id: str):
    """Reset plugin configuration to defaults handler.
    
    Args:
        id: Plugin unique ID
    """
    if not config.plugin_registry
    """
    Reset plugin configuration to defaults handler.
    
    Args:
        id: Plugin unique ID
    """
@settings_ar
async def plugin_save(request, id: str):
    """Save plugin configuration handler.
    
    Args:
        request: FastHTML request object
        id: Plugin unique ID
    """
    if not config.plugin_registry
    """
    Save plugin configuration handler.
    
    Args:
        request: FastHTML request object
        id: Plugin unique ID
    """
@settings_ar
def plugin(request, id: str):
    """Plugin settings page.
    
    Args:
        request: FastHTML request object
        id: Plugin unique ID
    """
    if not config.plugin_registry
    """
    Plugin settings page.
    
    Args:
        request: FastHTML request object
        id: Plugin unique ID
    """

Classes

class RoutesConfig:
    """
    Configuration for settings routes behavior.
    
    Users can modify these before importing the router:
    
    Example:
        ```python
        from cjm_fasthtml_settings.routes import config
        config.config_dir = Path("my_configs")
        config.default_schema = "database"
        config.wrap_with_layout = my_layout_function
        config.plugin_registry = my_plugin_registry
        
        # Now import the router
        from cjm_fasthtml_settings.routes import settings_ar
        ```
    """

Schema Group (schema_group.ipynb)

Grouping related configuration schemas for better organization

Import

from cjm_fasthtml_settings.core.schema_group import (
    SchemaGroup
)

Classes

@dataclass
class SchemaGroup:
    """
    A group of related configuration schemas.
    
    Use SchemaGroup to organize multiple related schemas under a single
    collapsible section in the settings sidebar. This is useful for
    applications with many configuration options.
    
    Example:
        ```python
        media_group = SchemaGroup(
            name="media",
            title="Media Settings",
            schemas={
                "scanner": MEDIA_SCAN_SCHEMA,
                "player": MEDIA_PLAYER_SCHEMA,
                "library": MEDIA_LIBRARY_SCHEMA
            },
            default_open=True,
            description="Configure media scanning, playback, and library"
        )
        ```
    
    Attributes:
        name: Internal identifier for the group (used in unique IDs)
        title: Display title shown in the sidebar
        schemas: Dictionary mapping schema keys to schema definitions
        icon: Optional icon/SVG element for the group
        default_open: Whether the group is expanded by default
        description: Optional description of the group
    """
    
    name: str
    title: str
    schemas: Dict[str, Dict[str, Any]]
    icon: Optional[Any]
    default_open: bool = True
    description: Optional[str]
    
    def get_schema(self, schema_name: str) -> Optional[Dict[str, Any]]:
            """Get a specific schema from the group by name."""
            return self.schemas.get(schema_name)
    
        def get_unique_id(self, schema_name: str) -> str
        "Get a specific schema from the group by name."
    
    def get_unique_id(self, schema_name: str) -> str:
            """Generate a unique ID for a schema within this group.
            
            Format: {group_name}_{schema_name}
            Example: "media_scanner"
            """
            return f"{self.name}_{schema_name}"
    
        def has_configured_schemas(
            self,
            config_dir: Path  # Directory where config files are stored
        ) -> bool:  # True if any schema in group has saved config
        "Generate a unique ID for a schema within this group.

Format: {group_name}_{schema_name}
Example: "media_scanner""
    
    def has_configured_schemas(
            self,
            config_dir: Path  # Directory where config files are stored
        ) -> bool:  # True if any schema in group has saved config
        "Check if any schemas in this group have saved configurations."
    
    def get_configured_schemas(
            self,
            config_dir: Path  # Directory where config files are stored
        ) -> list:  # List of schema names that have saved configs
        "Get list of configured schema names in this group."

Schemas (schemas.ipynb)

Schema registry and management for settings

Import

from cjm_fasthtml_settings.core.schemas import (
    registry,
    SettingsRegistry
)

Classes

class SettingsRegistry:
    def __init__(self):
        self._schemas: Dict[str, Union[Dict[str, Any], 'SchemaGroup']] = {}
    """
    Registry for managing settings schemas and schema groups.
    
    Provides a centralized place to register and access settings schemas.
    Supports both individual schemas and SchemaGroup objects for organizing
    related configurations.
    
    Example:
        ```python
        from cjm_fasthtml_settings.core.schemas import registry
        from cjm_fasthtml_settings.core.schema_group import SchemaGroup
        
        # Register a simple schema
        registry.register(my_schema)
        
        # Register a schema group
        registry.register(SchemaGroup(
            name="media",
            title="Media Settings",
            schemas={"scanner": SCAN_SCHEMA, "player": PLAYER_SCHEMA}
        ))
        ```
    """
    
    def __init__(self):
            self._schemas: Dict[str, Union[Dict[str, Any], 'SchemaGroup']] = {}
    
    def register(
            self,
            schema: Union[Dict[str, Any], 'SchemaGroup'],  # Schema or SchemaGroup to register
            name: Optional[str] = None  # Optional name override
        )
        "Register a settings schema or schema group.

For schemas: must have a 'name' field or provide name parameter
For SchemaGroups: uses the group's name attribute"
    
    def get(
            self,
            name: str  # Name of the schema/group to retrieve
        ) -> Optional[Union[Dict[str, Any], 'SchemaGroup']]:  # The schema/group, or None if not found
        "Get a registered schema or group by name."
    
    def list_schemas(self) -> list:  # List of registered schema/group names
            """List all registered schema and group names."""
            return list(self._schemas.keys())
        
        def get_all(self) -> Dict[str, Union[Dict[str, Any], 'SchemaGroup']]:  # All schemas and groups
        "List all registered schema and group names."
    
    def get_all(self) -> Dict[str, Union[Dict[str, Any], 'SchemaGroup']]:  # All schemas and groups
            """Get all registered schemas and groups."""
            return self._schemas.copy()
        
        def resolve_schema(
            self,
            id: str  # Schema ID (can be 'name' or 'group_schema' format)
        ) -> tuple:  # (schema_dict, error_message)
        "Get all registered schemas and groups."
    
    def resolve_schema(
            self,
            id: str  # Schema ID (can be 'name' or 'group_schema' format)
        ) -> tuple:  # (schema_dict, error_message)
        "Resolve a schema ID to a schema dictionary.

Handles both direct schemas and grouped schemas:
- Direct: 'general' -> returns the general schema
- Grouped: 'media_scanner' -> returns scanner schema from media group

Args:
    id: Schema identifier
    
Returns:
    Tuple of (schema_dict, error_message). If successful, error_message is None.
    If failed, schema_dict is None and error_message explains the issue."

Sidebar (sidebar.ipynb)

Navigation menu components for settings sidebar

Import

from cjm_fasthtml_settings.components.sidebar import (
    create_sidebar_menu,
    create_oob_sidebar_menu
)

Functions

def create_sidebar_menu(
    schemas: Dict[str, Any],  # Dictionary of schemas/groups to display in sidebar
    active_schema: Optional[str] = None,  # The currently active schema name
    config_dir: Optional[Path] = None,  # Directory where config files are stored
    include_wrapper: bool = True,  # Whether to include the outer wrapper div
    menu_section_title: str = "Settings",  # Title for the settings section
    plugin_registry: Optional[Any] = None  # Optional plugin registry
) -> Union[Div, Ul]:  # Div or Ul element containing the sidebar menu
    """
    Create the sidebar navigation menu with support for schema groups and plugins.
    
    Renders schemas, SchemaGroup objects, and plugins (if registry provided).
    
    Args:
        schemas: Dictionary mapping names to schemas or SchemaGroup objects
        active_schema: Name of the currently active schema (can be 'group_schema' format)
        config_dir: Path to config directory (uses DEFAULT_CONFIG_DIR if None)
        include_wrapper: If False, returns just the Ul for OOB swaps
        menu_section_title: Title to display for the menu section
        plugin_registry: Optional plugin registry implementing PluginRegistryProtocol
    
    Returns:
        Sidebar menu component
    """
def create_oob_sidebar_menu(
    schemas: Dict[str, Dict[str, Any]],  # Dictionary of schemas
    active_schema: str,  # Active schema name
    config_dir: Optional[Path] = None,  # Config directory
    menu_section_title: str = "Settings",  # Menu section title
    plugin_registry: Optional[Any] = None  # Optional plugin registry
)
    """
    Create sidebar menu with OOB swap attribute for HTMX.
    
    This is useful for updating the sidebar menu without a full page reload.
    """

Utils (utils.ipynb)

Configuration loading, saving, and conversion utilities

Import

from cjm_fasthtml_settings.core.utils import (
    load_config,
    save_config,
    get_default_values_from_schema,
    get_config_with_defaults,
    convert_form_data_to_config
)

Functions

def load_config(
    schema_name: str,  # Name of the schema/configuration to load
    config_dir: Optional[Path] = None  # Directory where config files are stored
) -> Dict[str, Any]:  # Loaded configuration dictionary (empty dict if file doesn't exist)
    """
    Load saved configuration for a schema.
    
    Loads a JSON configuration file from the config directory.
    If the file doesn't exist, returns an empty dictionary.
    """
def save_config(
    schema_name: str,  # Name of the schema/configuration to save
    config: Dict[str, Any],  # Configuration dictionary to save
    config_dir: Optional[Path] = None  # Directory where config files are stored
) -> bool:  # True if save succeeded, False otherwise
    """
    Save configuration for a schema.
    
    Saves a configuration dictionary as a JSON file in the config directory.
    Creates the config directory if it doesn't exist.
    """
def get_default_values_from_schema(
    schema: Dict[str, Any]  # JSON Schema dictionary
) -> Dict[str, Any]:  # Dictionary of default values extracted from schema
    """
    Extract default values from a JSON schema.
    
    Iterates through the schema's properties and extracts any 'default' values.
    """
def get_config_with_defaults(
    schema_name: str,  # Name of the schema (or unique_id for grouped schemas)
    schema: Dict[str, Any],  # JSON Schema dictionary
    config_dir: Optional[Path] = None  # Directory where config files are stored
) -> Dict[str, Any]:  # Merged configuration with defaults and saved values
    """
    Get configuration with defaults merged with saved values.
    
    Loads saved configuration and merges it with schema defaults.
    Saved values take precedence over defaults.
    
    For grouped schemas, uses the 'unique_id' field if present.
    """
def convert_form_data_to_config(
    form_data: dict,  # Raw form data from request
    schema: Dict[str, Any]  # JSON Schema for type conversion
) -> dict:  # Converted configuration dictionary
    """
    Convert form data to configuration dict based on schema.
    
    Handles type conversions for:
    - Boolean fields (checkboxes)
    - Integer and number fields
    - Array fields (comma-separated or Python list format)
    """

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cjm_fasthtml_settings-0.0.2.tar.gz (33.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cjm_fasthtml_settings-0.0.2-py3-none-any.whl (32.7 kB view details)

Uploaded Python 3

File details

Details for the file cjm_fasthtml_settings-0.0.2.tar.gz.

File metadata

  • Download URL: cjm_fasthtml_settings-0.0.2.tar.gz
  • Upload date:
  • Size: 33.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.14

File hashes

Hashes for cjm_fasthtml_settings-0.0.2.tar.gz
Algorithm Hash digest
SHA256 37105ae90a9ca746f826247437f9ab796084301fa32c9f89c19e33319ad6be21
MD5 7541acfbcbadb4472cf5d162c647b697
BLAKE2b-256 2a5914cd0db5b0974ab3166f4b5cbd5ce3bc284a1c7ed16d73fb024b76d67b98

See more details on using hashes here.

File details

Details for the file cjm_fasthtml_settings-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for cjm_fasthtml_settings-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 f2a9a87b8487835967b889025c8939566b2b93a50e50d8bb3f98bae030866729
MD5 ae0cc0096da593810b8d1a1f148a6ba8
BLAKE2b-256 0f04be70537ad21c59d452441983e5416ae5b4169da1f4f0bbde64f6892870dd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page