display_tapis_app_schema()

display_tapis_app_schema()#

display_tapis_app_schema(thisAppSchema)

Pretty-prints a Tapis App schema (or any nested TapisResult/dict/list) in a clean, JSON-like format. Keys are grouped for readability—scalars first, then lists, then nested dicts—and TapisResult objects are seamlessly expanded via their internal attributes.

What it does#

  • Accepts a Tapis App schema returned by tapipy (or a plain dict/list).

  • Unwraps TapisResult values into dictionaries automatically.

  • Prints arrays inline if they contain simple values, or expands them if they contain objects.

  • Displays a neat header with appID and version when available.

Signature#

display_tapis_app_schema(thisAppSchema)

Parameters#

  • thisAppSchema (TapisResult | dict | list) — The schema or nested object to display.

Returns#

  • None — The function prints to stdout.

Example#

# Suppose you fetched an app with tapipy:
app_schema = t.apps.getApp(appId="opensees-mp-s3", appVersion="latest")

# Print a readable schema view
display_tapis_app_schema(app_schema)

Sample output (excerpt):

########################################
########### TAPIS-APP SCHEMA ###########
########################################
######## appID: opensees-mp-s3
######## version: latest
########################################
root: {
  id: "opensees-mp-s3"
  version: "latest"
  name: "OpenSeesMP on Stampede3"
  inputs: [
    {
      id: "input_dir"
      required: true
      description: "Directory with input files"
    }
    ...
  ]
  ...
}
########################################

Files#

You can find these files in Community Data.

display_tapis_app_schema.py
def display_tapis_app_schema(thisAppSchema):
    """
    Pretty-print a Tapis App schema (or any nested TapisResult/dict/list) in a
    JSON-like format with readable grouping and indentation.

    Behavior
    --------
    - Accepts a TapisResult, dict, or list.
    - Groups and prints keys in the order: scalars → lists → nested dicts.
    - Handles TapisResult values by flattening their internal __dict__.
    - Prints arrays either inline (simple scalars) or expanded (objects).
    - Shows a header with app id and version (if present).

    Parameters
    ----------
    thisAppSchema : tapipy.tapis.TapisResult | dict | list
        The app schema or object to render.

    Returns
    -------
    None
        This function prints to stdout. It does not return a value.

    Example
    -------
    # Given a Tapis app schema returned by tapipy:
    display_tapis_app_schema(app_schema)

    Author
    ------
    Silvia Mazzoni, DesignSafe (silviamazzoni@yahoo.com)

    Date
    ----
    2025-08-14

    Version
    -------
    1.0
    """
    try:
        from tapipy.tapis import TapisResult
    except Exception:
        class TapisResult:  # sentinel so isinstance checks won’t crash if tapipy not available
            pass

    def _is_simple_scalar(x):
        return isinstance(x, (type(None), bool, int, float, str))

    def _quote_if_str(x):
        return f'"{x}"' if isinstance(x, str) else x

    def print_nested(key_prefix, obj, indent=1):
        sp = '  ' * indent

        # Unwrap TapisResult to dict
        if isinstance(obj, TapisResult):
            obj = obj.__dict__

        # Dict handling
        if isinstance(obj, dict):
            dict_keys, list_keys, scalar_keys = [], [], []
            for k, v in obj.items():
                v_unwrap = v.__dict__ if isinstance(v, TapisResult) else v
                if isinstance(v_unwrap, dict):
                    dict_keys.append(k)
                elif isinstance(v_unwrap, list):
                    list_keys.append(k)
                else:
                    scalar_keys.append(k)

            # print in order: scalars, lists, dicts
            ordered = [*scalar_keys, *list_keys, *dict_keys]
            for i, k in enumerate(ordered):
                v = obj[k]
                v_unwrap = v.__dict__ if isinstance(v, TapisResult) else v

                # Nested dict or object
                if isinstance(v_unwrap, dict):
                    # opening brace for top-level objects
                    if key_prefix:
                        print(f'{sp}{key_prefix}{k}: ' + '{')
                        next_prefix = ""
                    else:
                        print(f'{sp}{k}: ' + '{')
                        next_prefix = ""
                    print_nested(next_prefix, v_unwrap, indent + 1)
                    print(f'{sp}' + '}')
                    if i != len(ordered) - 1:
                        pass  # stylistically omit commas for readability

                # Lists
                elif isinstance(v_unwrap, list):
                    # Decide inline vs expanded
                    contains_objects = any(
                        (isinstance(it, (dict, TapisResult))) for it in v_unwrap
                    )
                    label = f'{sp}{key_prefix}{k}: ' if key_prefix else f'{sp}{k}: '
                    if not v_unwrap:
                        print(label + '[]')
                    elif contains_objects:
                        print(label + '[')
                        for j, it in enumerate(v_unwrap):
                            it_unwrap = it.__dict__ if isinstance(it, TapisResult) else it
                            if isinstance(it_unwrap, dict):
                                print('  ' * (indent + 1) + '{')
                                print_nested("", it_unwrap, indent + 2)
                                print('  ' * (indent + 1) + '}')
                            else:
                                val = _quote_if_str(it_unwrap)
                                print('  ' * (indent + 1) + f'{val}')
                            if j != len(v_unwrap) - 1:
                                pass  # omit commas for readability
                        print(sp + ']')
                    else:
                        # all simple values → inline
                        vals = [_quote_if_str(x) for x in v_unwrap]
                        print(label + f'[{", ".join(map(str, vals))}]')

                # Scalars
                else:
                    val = _quote_if_str(v_unwrap)
                    label = f'{sp}{key_prefix}{k}: ' if key_prefix else f'{sp}{k}: '
                    print(label + f'{val}')

        # List handling (rare for top-level)
        elif isinstance(obj, list):
            sp = '  ' * indent
            if not obj:
                print(sp + '[]')
                return
            contains_objects = any(isinstance(it, (dict, TapisResult)) for it in obj)
            if contains_objects:
                print(sp + '[')
                for it in obj:
                    it_unwrap = it.__dict__ if isinstance(it, TapisResult) else it
                    if isinstance(it_unwrap, dict):
                        print('  ' * (indent + 1) + '{')
                        print_nested("", it_unwrap, indent + 2)
                        print('  ' * (indent + 1) + '}')
                    else:
                        print('  ' * (indent + 1) + f'{_quote_if_str(it_unwrap)}')
                print(sp + ']')
            else:
                vals = [_quote_if_str(x) for x in obj]
                print(sp + f'[{", ".join(map(str, vals))}]')

        # Fallback scalar
        else:
            val = _quote_if_str(obj)
            print(sp + f'{val}')

    # Header
    print('########################################')
    print('########### TAPIS-APP SCHEMA ###########')
    print('########################################')
    # Best-effort id/version extraction
    app_id = getattr(thisAppSchema, 'id', None) or (thisAppSchema.get('id') if isinstance(thisAppSchema, dict) else None)
    version = getattr(thisAppSchema, 'version', None) or (thisAppSchema.get('version') if isinstance(thisAppSchema, dict) else None)
    if app_id is not None:
        print(f'######## appID: {app_id}')
    if version is not None:
        print(f'######## version: {version}')
    print('########################################')

    # Body (start with a label to indicate the root)
    print('{')
    print_nested("", thisAppSchema, indent=1)
    print('}')
    print('########################################')