<reponame>websauna/pyramid_notebook
"""Helpers to set up Notebook startup imports and contexts."""
# Standard Library
import os


#: The splash text displayed at the notebook top. TODO: WSGI application description in Pyramid docs is bad, find better one.
PYRAMID_GREETING = """
* **app** - The [WSGI application](http://docs.pylonsproject.org/docs/pyramid/en/latest/api/paster.html?highlight=wsgi%20application#pyramid.paster.get_app) object generated by bootstrapping.
* **request** - A [pyramid.request.Request](http://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request) object implying the current request state for your script.
* **root** - The resource [root](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root) of your Pyramid application. This is an object generated by the [root factory](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root-factory) configured in your application.
* **registry** - The application [registry](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-application-registry) of your Pyramid application.
"""

#: startup.py bootstrap Python snippet to initialize the Pyramid application and get Pyramid specific variables into the shell
PYRAMID_BOOSTRAP = """
import os
from pyramid.paster import bootstrap
from pyramid_notebook.utils import change_directory

# Our development.ini, production.ini, etc.
config_file = '{config_uri}'
project_root_path = '{cwd}' or os.path.dirname(config_file)

# Most of Pyramid projects expect you run pserve et. al. in the project folder itself, thus config is hardwired to have project root relative paths
with change_directory(project_root_path):
    env = bootstrap(config_file)
    globals().update(env)

"""


def get_dotted_path(klass):
    return klass.__module__ + "." + klass.__name__


def get_import_statement(klass):
    mod = klass.__module__
    print(mod)
    return "from {} import {}".format(klass.__module__, klass.__name__)


def make_startup(notebook_context, config_file, bootstrap_py=PYRAMID_BOOSTRAP, bootstrap_greeting=PYRAMID_GREETING, cwd=""):
    """Populate notebook context with startup.py initialization file skeleton and greeting.

    This will set up context ``startup`` and ``greeting`` for their default values.

    :param notebook_context: Dictionary of notebook context info to be to passed to NotebookManager

    :param config_file: The current .ini file used to start up the Pyramid. This is used to pass it around to ``pyramid.paster.boostrap()`` to initialize dummy request object and such.

    :param bootstrap_py: startup.py script header which sets up environment creation

    :parma bootstrap_greeting: Markdown snippet which sets up start of greeting text

    :param cwd: Optional forced working directory. If not set use the directory of a config file.
    """

    # Set up some default imports and variables

    nc = notebook_context

    add_greeting(nc, "\nAvailable variables and functions:")

    # http://docs.pylonsproject.org/projects/pyramid/en/1.1-branch/narr/commandline.html#writing-a-script

    if config_file is not None:
        assert type(config_file) == str, "Got bad config_file {}".format(config_file)
        config_file = os.path.abspath(config_file)
        assert os.path.exists(config_file), "Passed in bad config file: {}".format(config_file)
        add_script(nc, bootstrap_py.format(config_uri=config_file, cwd=cwd))
        add_greeting(nc, bootstrap_greeting)

    add_script(nc, "import datetime")
    add_greeting(nc, "* **datetime** - Python [datetime module](https://docs.python.org/3.5/library/datetime.html)")

    add_script(nc, "import time")
    add_greeting(nc, "* **time** - Python [time module](https://docs.python.org/3.5/library/time.html)")

    try:
        # Commonly used with Pyramid applications
        import transaction  # noQA
        add_script(nc, "import transaction\n")
        add_greeting(nc, "* **transaction** - Zope [transaction manager](http://zodb.readthedocs.org/en/latest/transactions.html), e.g. `transaction.commit()`")
    except ImportError:
        pass


def include_sqlalchemy_models(nc, Base):
    """Include all SQLAlchemy models in the script context.

    :param nc: notebook_context dictionary
    :param Base: SQLAlchemy model Base class from where the all models inherit.
    """

    from sqlalchemy.ext.declarative.clsregistry import _ModuleMarker

    # Include all SQLAlchemy models in the local namespace
    for name, klass in Base._decl_class_registry.items():
        print(name, klass)
        if isinstance(klass, _ModuleMarker):
            continue

        add_script(nc, get_import_statement(klass))
        add_greeting(nc, "* **{}** - {}".format(klass.__name__, get_dotted_path(klass)))


def add_script(nc, line):
    """Add one-liner script or several lines (newline separated)"""

    assert type(nc) == dict

    nc["startup"] = nc.get("startup") or ""

    if not nc["startup"].endswith("\n"):
        nc["startup"] += "\n"
    nc["startup"] += line + "\n"


def add_greeting(nc, line):
    """Add one-liner script or several lines (newline separated)"""

    assert type(nc) == dict

    nc["greeting"] = nc.get("greeting") or ""

    # Markdown hard line break is two new lines
    if not nc["greeting"].endswith("\n"):
        nc["greeting"] += "\n"
    nc["greeting"] += line + "\n"

"""Helpers to set up Notebook startup imports and contexts."""
# Standard Library
import os


#: The splash text displayed at the notebook top. TODO: WSGI application description in Pyramid docs is bad, find better one.
PYRAMID_GREETING = """
* **app** - The [WSGI application](http://docs.pylonsproject.org/docs/pyramid/en/latest/api/paster.html?highlight=wsgi%20application#pyramid.paster.get_app) object generated by bootstrapping.
* **request** - A [pyramid.request.Request](http://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request) object implying the current request state for your script.
* **root** - The resource [root](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root) of your Pyramid application. This is an object generated by the [root factory](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root-factory) configured in your application.
* **registry** - The application [registry](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-application-registry) of your Pyramid application.
"""

#: startup.py bootstrap Python snippet to initialize the Pyramid application and get Pyramid specific variables into the shell
PYRAMID_BOOSTRAP = """
import os
from pyramid.paster import bootstrap
from pyramid_notebook.utils import change_directory

# Our development.ini, production.ini, etc.
config_file = '{config_uri}'
project_root_path = '{cwd}' or os.path.dirname(config_file)

# Most of Pyramid projects expect you run pserve et. al. in the project folder itself, thus config is hardwired to have project root relative paths
with change_directory(project_root_path):
    env = bootstrap(config_file)
    globals().update(env)

"""


def get_dotted_path(klass):
    return klass.__module__ + "." + klass.__name__


def get_import_statement(klass):
    mod = klass.__module__
    print(mod)
    return "from {} import {}".format(klass.__module__, klass.__name__)


def make_startup(notebook_context, config_file, bootstrap_py=PYRAMID_BOOSTRAP, bootstrap_greeting=PYRAMID_GREETING, cwd=""):
    """Populate notebook context with startup.py initialization file skeleton and greeting.

    This will set up context ``startup`` and ``greeting`` for their default values.

    :param notebook_context: Dictionary of notebook context info to be to passed to NotebookManager

    :param config_file: The current .ini file used to start up the Pyramid. This is used to pass it around to ``pyramid.paster.boostrap()`` to initialize dummy request object and such.

    :param bootstrap_py: startup.py script header which sets up environment creation

    :parma bootstrap_greeting: Markdown snippet which sets up start of greeting text

    :param cwd: Optional forced working directory. If not set use the directory of a config file.
    """

    # Set up some default imports and variables

    nc = notebook_context

    add_greeting(nc, "\nAvailable variables and functions:")

    # http://docs.pylonsproject.org/projects/pyramid/en/1.1-branch/narr/commandline.html#writing-a-script

    if config_file is not None:
        assert type(config_file) == str, "Got bad config_file {}".format(config_file)
        config_file = os.path.abspath(config_file)
        assert os.path.exists(config_file), "Passed in bad config file: {}".format(config_file)
        add_script(nc, bootstrap_py.format(config_uri=config_file, cwd=cwd))
        add_greeting(nc, bootstrap_greeting)

    add_script(nc, "import datetime")
    add_greeting(nc, "* **datetime** - Python [datetime module](https://docs.python.org/3.5/library/datetime.html)")

    add_script(nc, "import time")
    add_greeting(nc, "* **time** - Python [time module](https://docs.python.org/3.5/library/time.html)")

    try:
        # Commonly used with Pyramid applications
        import transaction  # noQA
        add_script(nc, "import transaction\n")
        add_greeting(nc, "* **transaction** - Zope [transaction manager](http://zodb.readthedocs.org/en/latest/transactions.html), e.g. `transaction.commit()`")
    except ImportError:
        pass


def include_sqlalchemy_models(nc, Base):
    """Include all SQLAlchemy models in the script context.

    :param nc: notebook_context dictionary
    :param Base: SQLAlchemy model Base class from where the all models inherit.
    """

    from sqlalchemy.ext.declarative.clsregistry import _ModuleMarker

    # Include all SQLAlchemy models in the local namespace
    for name, klass in Base._decl_class_registry.items():
        print(name, klass)
        if isinstance(klass, _ModuleMarker):
            continue

        add_script(nc, get_import_statement(klass))
        add_greeting(nc, "* **{}** - {}".format(klass.__name__, get_dotted_path(klass)))


def add_script(nc, line):
    """Add one-liner script or several lines (newline separated)"""

    assert type(nc) == dict

    nc["startup"] = nc.get("startup") or ""

    if not nc["startup"].endswith("\n"):
        nc["startup"] += "\n"
    nc["startup"] += line + "\n"


def add_greeting(nc, line):
    """Add one-liner script or several lines (newline separated)"""

    assert type(nc) == dict

    nc["greeting"] = nc.get("greeting") or ""

    # Markdown hard line break is two new lines
    if not nc["greeting"].endswith("\n"):
        nc["greeting"] += "\n"
    nc["greeting"] += line + "\n"
Helpers to set up Notebook startup imports and contexts. # Standard Library #: The splash text displayed at the notebook top. TODO: WSGI application description in Pyramid docs is bad, find better one. * **app** - The [WSGI application](http://docs.pylonsproject.org/docs/pyramid/en/latest/api/paster.html?highlight=wsgi%20application#pyramid.paster.get_app) object generated by bootstrapping. * **request** - A [pyramid.request.Request](http://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request) object implying the current request state for your script. * **root** - The resource [root](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root) of your Pyramid application. This is an object generated by the [root factory](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-root-factory) configured in your application. * **registry** - The application [registry](http://docs.pylonsproject.org/docs/pyramid/en/latest/glossary.html#term-application-registry) of your Pyramid application. #: startup.py bootstrap Python snippet to initialize the Pyramid application and get Pyramid specific variables into the shell import os from pyramid.paster import bootstrap from pyramid_notebook.utils import change_directory  # Our development.ini, production.ini, etc. config_file = '{config_uri}' project_root_path = '{cwd}' or os.path.dirname(config_file)  # Most of Pyramid projects expect you run pserve et. al. in the project folder itself, thus config is hardwired to have project root relative paths with change_directory(project_root_path):     env = bootstrap(config_file)     globals().update(env) Populate notebook context with startup.py initialization file skeleton and greeting.      This will set up context ``startup`` and ``greeting`` for their default values.      :param notebook_context: Dictionary of notebook context info to be to passed to NotebookManager      :param config_file: The current .ini file used to start up the Pyramid. This is used to pass it around to ``pyramid.paster.boostrap()`` to initialize dummy request object and such.      :param bootstrap_py: startup.py script header which sets up environment creation      :parma bootstrap_greeting: Markdown snippet which sets up start of greeting text      :param cwd: Optional forced working directory. If not set use the directory of a config file. # Set up some default imports and variables # http://docs.pylonsproject.org/projects/pyramid/en/1.1-branch/narr/commandline.html#writing-a-script # Commonly used with Pyramid applications # noQA Include all SQLAlchemy models in the script context.      :param nc: notebook_context dictionary     :param Base: SQLAlchemy model Base class from where the all models inherit. # Include all SQLAlchemy models in the local namespace Add one-liner script or several lines (newline separated) Add one-liner script or several lines (newline separated) # Markdown hard line break is two new lines