Пример #1
0
def _formatter_callback_factory():  # pragma: no cover
    """Returns a list of includes to be given to `cnxepub.collation.collate`.

    """
    includes = []
    settings = get_current_registry().settings
    exercise_url_template = settings.get(
        'embeddables.exercise.url_template',
        None)
    exercise_match = settings.get('embeddables.exercise.match', None)
    exercise_token = settings.get('embeddables.exercise.token', None)
    mathml_url = settings.get('mathmlcloud.url', None)
    memcache_servers = settings.get('memcache_servers')
    if memcache_servers:
        memcache_servers = memcache_servers.split()
    else:
        memcache_servers = None

    if exercise_url_template and exercise_match:
        mc_client = None
        if memcache_servers:
            mc_client = memcache.Client(memcache_servers, debug=0)
        includes.append(exercise_callback_factory(exercise_match,
                                                  exercise_url_template,
                                                  mc_client,
                                                  exercise_token,
                                                  mathml_url))
    return includes
Пример #2
0
def _formatter_callback_factory():  # pragma: no cover
    """Returns a list of includes to be given to `cnxepub.collation.collate`.

    """
    includes = []
    exercise_url_template = '{baseUrl}/api/exercises?q={field}:"{{itemCode}}"'
    settings = get_current_registry().settings
    exercise_base_url = settings.get('embeddables.exercise.base_url', None)
    exercise_matches = [match.split(',', 1) for match in aslist(
        settings.get('embeddables.exercise.match', ''), flatten=False)]
    exercise_token = settings.get('embeddables.exercise.token', None)
    mathml_url = settings.get('mathmlcloud.url', None)
    memcache_servers = settings.get('memcache_servers')
    if memcache_servers:
        memcache_servers = memcache_servers.split()
    else:
        memcache_servers = None

    if exercise_base_url and exercise_matches:
        mc_client = None
        if memcache_servers:
            mc_client = memcache.Client(memcache_servers, debug=0)
        for (exercise_match, exercise_field) in exercise_matches:
            template = exercise_url_template.format(
                baseUrl=exercise_base_url, field=exercise_field)
            includes.append(exercise_callback_factory(exercise_match,
                                                      template,
                                                      mc_client,
                                                      exercise_token,
                                                      mathml_url))
    return includes
Пример #3
0
def assemble(ctx, input_dir, output_dir, exercise_token, exercise_host):
    """Assembles litezip structure data into a single-page-html file.

    This also stores the intermediary results alongside the resulting
    assembled single-page-html.

    """
    input_dir = Path(input_dir)
    output_dir = Path(output_dir)
    collection_assembled_xhtml = (output_dir / ASSEMBLED_FILENAME)

    if collection_assembled_xhtml.exists():
        confirm_msg = (
            "File '{}' already exists. Would you like to replace it?".format(
                collection_assembled_xhtml))
        click.confirm(confirm_msg, abort=True, err=True)
        collection_assembled_xhtml.unlink()
    if not output_dir.exists():
        output_dir.mkdir()

    collection_xml = input_dir / 'collection.xml'
    binder = Binder.from_collection_xml(collection_xml)

    # Write the collection.xml symlink to the output directory
    output_collection_xml = (output_dir / 'collection.xml')
    if output_collection_xml.exists():
        output_collection_xml.unlink()
    output_collection_xml.symlink_to(relative_path(collection_xml, output_dir))

    # Fetch exercises as part of producing the collection xhtml
    exercise_match_urls = (
        ('#ost/api/ex/',
         'https://{}/api/exercises?q=tag:{{itemCode}}'.format(exercise_host)),
        ('#exercise/',
         'https://{}/api/exercises?q=nickname:{{itemCode}}'.format(
             exercise_host)),
    )
    includes = [
        exercise_callback_factory(exercise_match,
                                  exercise_url,
                                  token=exercise_token)
        for exercise_match, exercise_url in exercise_match_urls
    ]

    # Write the binder out as a single-page-html
    collection_xhtml = produce_collection_xhtml(binder, output_dir, includes)
    logger.debug('Wrote: {}'.format(str(collection_xhtml.resolve())))

    # Write the symbolic links for modules to the output directory
    provide_supporting_files(input_dir, output_dir, binder)

    return 0
Пример #4
0
def main(argv=sys.argv):
    if len(argv) < 2:
        usage(argv)

    config_uri = argv[1]
    bootstrap(config_uri)
    settings = get_current_registry().settings
    connection_string = settings[CONNECTION_STRING]

    exercise_url_template = settings.get('embeddables.exercise.url_template',
                                         None)
    exercise_match = settings.get('embeddables.exercise.match', None)
    exercise_token = settings.get('embeddables.exercise.token', None)
    mathml_url = settings.get('mathmlcloud.url', None)

    includes = None
    if exercise_url_template and exercise_match:
        includes = [
            exercise_callback_factory(exercise_match, exercise_url_template,
                                      exercise_token, mathml_url)
        ]
    # Code adapted from
    # http://initd.org/psycopg/docs/advanced.html#asynchronous-notifications
    with psycopg2.connect(connection_string) as conn:
        conn.set_isolation_level(
            psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)

        with conn.cursor() as cursor:
            cursor.execute('LISTEN {}'.format(CHANNEL))

        logger.debug(
            'Waiting for notifications on channel "{}"'.format(CHANNEL))
        rlist = [conn]  # wait until ready for reading
        wlist = []  # wait until ready for writing
        xlist = []  # wait for an "exceptional condition"
        timeout = 5

        while True:
            if select.select(rlist, wlist, xlist, timeout) != ([], [], []):
                conn.poll()
                while conn.notifies:
                    notify = conn.notifies.pop(0)
                    logger.debug(
                        'Got NOTIFY: pid={} channel={} payload={}'.format(
                            notify.pid, notify.channel, notify.payload))
                    post_publication(conn, includes)
Пример #5
0
def main(argv=sys.argv):
    if len(argv) < 2:
        usage(argv)

    config_uri = argv[1]
    bootstrap(config_uri)
    settings = get_current_registry().settings
    connection_string = settings[CONNECTION_STRING]

    exercise_url_template = settings.get('embeddables.exercise.url_template',
                                         None)
    exercise_match = settings.get('embeddables.exercise.match', None)
    exercise_token = settings.get('embeddables.exercise.token', None)
    mathml_url = settings.get('mathmlcloud.url', None)

    includes = None
    if exercise_url_template and exercise_match:
        includes = [exercise_callback_factory(exercise_match,
                                              exercise_url_template,
                                              exercise_token,
                                              mathml_url)]
    # Code adapted from
    # http://initd.org/psycopg/docs/advanced.html#asynchronous-notifications
    with psycopg2.connect(connection_string) as conn:
        conn.set_isolation_level(
            psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)

        with conn.cursor() as cursor:
            cursor.execute('LISTEN {}'.format(CHANNEL))

        logger.debug('Waiting for notifications on channel "{}"'
                     .format(CHANNEL))
        rlist = [conn]  # wait until ready for reading
        wlist = []  # wait until ready for writing
        xlist = []  # wait for an "exceptional condition"
        timeout = 5

        while True:
            if select.select(rlist, wlist, xlist, timeout) != ([], [], []):
                conn.poll()
                while conn.notifies:
                    notify = conn.notifies.pop(0)
                    logger.debug('Got NOTIFY: pid={} channel={} payload={}'
                                 .format(notify.pid, notify.channel,
                                         notify.payload))
                    post_publication(conn, includes)
Пример #6
0
def main(argv=None):
    parser = argparse.ArgumentParser(description="Assemble complete book "
                                                 "as single HTML file")
    parser.add_argument('epub_file_path',
                        help='Path to the epub file containing the book')
    parser.add_argument("html_out", nargs="?",
                        type=argparse.FileType('w'),
                        help="assembled HTML file output (default stdout)",
                        default=sys.stdout)
    parser.add_argument('-m', "--mathjax_version", const=DEFAULT_MATHJAX_VER,
                        metavar="mathjax_version", nargs="?",
                        help="Add script tag to use MathJax of given version")
    parser.add_argument('-n', "--no-network", action='store_true',
                        help="Do not use network access "
                        "- no exercise or math conversion")
    parser.add_argument('-x', "--exercise_host",
                        const=DEFAULT_EXERCISES_HOST,
                        metavar="exercise_host", nargs="?",
                        help="Download included exercises from this host")
    parser.add_argument('-t', "--exercise_token",
                        metavar="exercise_token", nargs="?",
                        help="Token for including answers in exercises")
    parser.add_argument('-M', "--mathmlcloud_url",
                        metavar="mathmlcloud_url", nargs="?",
                        help="Convert TeX equations using "
                             "this mathmlcloud API url",
                        const=DEFAULT_MATHMLCLOUD_URL)
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='Send debugging info to stderr')
    parser.add_argument('-s', '--subset-chapters', dest='numchapters',
                        type=int, const=2, nargs='?', metavar='num_chapters',
                        help="Create subset of complete book "
                        "(default 2 chapters plus extras)")

    args = parser.parse_args(argv)

    handler = logging.StreamHandler(sys.stderr)
    if args.verbose:
        logger.setLevel(logging.DEBUG)
    logger.addHandler(handler)

    mathjax_version = args.mathjax_version
    if mathjax_version:
        if not mathjax_version.endswith('latest'):
            mathjax_version += '-latest'

    exercise_host = args.exercise_host or DEFAULT_EXERCISES_HOST
    exercise_token = args.exercise_token
    mml_url = args.mathmlcloud_url or DEFAULT_MATHMLCLOUD_URL
    if not args.no_network:
        exercise_url = \
                'https://%s/api/exercises?q=tag:{itemCode}' % (exercise_host)
        exercise_match = '#ost/api/ex/'
        includes = [exercise_callback_factory(exercise_match,
                                              exercise_url,
                                              exercise_token,
                                              mml_url)]
    else:
        includes = None

    single_html(args.epub_file_path, args.html_out, mathjax_version,
                args.numchapters, includes)