Below is a ShowEnviron widget, which displays the contents of the wsgi environ dictionary. It is also available to your Python functions as attribute skicall.environ.

{'HTTP_ACCEPT': '*/*',
 'HTTP_ACCEPT_ENCODING': 'gzip, br, zstd, deflate',
 'HTTP_CONNECTION': 'close',
 'HTTP_HOST': 'localhost:8000',
 'HTTP_USER_AGENT': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; '
                    'compatible; ClaudeBot/1.0; +claudebot@anthropic.com)',
 'HTTP_X_FORWARDED_HOST': 'webparametrics.co.uk',
 'HTTP_X_FORWARDED_PORT': '80',
 'HTTP_X_REAL_IP': '52.15.74.16',
 'PATH_INFO': '/skiwidgets/debug_tools/ShowEnviron',
 'QUERY_STRING': '',
 'REMOTE_ADDR': '127.0.0.1',
 'REMOTE_HOST': '127.0.0.1',
 'REMOTE_PORT': '58768',
 'REQUEST_METHOD': 'GET',
 'REQUEST_URI': '/skiwidgets/debug_tools/ShowEnviron',
 'SCRIPT_NAME': '',
 'SERVER_NAME': 'waitress.invalid',
 'SERVER_PORT': '8000',
 'SERVER_PROTOCOL': 'HTTP/1.0',
 'SERVER_SOFTWARE': 'waitress',
 'waitress.client_disconnected': <bound method HTTPChannel.check_client_disconnected of <waitress.channel.HTTPChannel connected 127.0.0.1:58768 at 0x77e3f5b8d960>>,
 'wsgi.errors': <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>,
 'wsgi.file_wrapper': <class 'waitress.buffers.ReadOnlyFileBasedBuffer'>,
 'wsgi.input': <_io.BytesIO object at 0x77e3f592a610>,
 'wsgi.input_terminated': True,
 'wsgi.multiprocess': False,
 'wsgi.multithread': True,
 'wsgi.run_once': False,
 'wsgi.url_scheme': 'http',
 'wsgi.version': (1, 0)}

This table lists the Responders called to produce this page:

skiwidgets,7602SubmitDataSets up title and widget description
skiwidgets,7604This pagedebug_tools.ShowEnviron template

This is a ShowCallData widget, which displays the contents of the skicall.call_data dictionary.

{}

Below is the Python file which populates this page.

import os

from skipole import FailPage, GoTo, ValidateError, ServerError, ServeFile, PageData, SectionData


def index(skicall):
    "Called by a SubmitData responder, and sets up the page"

    # the title and widget decription is in section 'header' which contains a
    # HeadText widget with name 'title' and a TextBlockPara widget with name 'widgetdesc'
    # It also has a ButtonLink2 widget with name 'tomodule'
    headersection = SectionData('header')
    headersection['title', 'large_text'] = 'ShowEnviron'
    # A textblock contains the widget description
    ref = "widgets.debug_tools.ShowEnviron"
    headersection['widgetdesc','textblock_ref'] = ref
    headersection['widgetdesc','text_refnotfound'] = f'Textblock reference {ref} not found'
    # link to this widgets module page
    headersection['tomodule','button_text'] = "Module: debug_tools"
    headersection['tomodule','link_ident'] = skicall.makepath('debug_tools')
    skicall.update(headersection)

    # this code file contents is placed in section 'codefile' which contains a
    # PreText widget with name 'pretext'
    codesection = SectionData('codefile')
    code = os.path.realpath(__file__)
    with open(code) as f:
        codesection['pretext', 'pre_text'] = f.read()
    skicall.update(codesection)