Exemple #1
0
def update_database(chaptitles, subtitles, app):
    """
    When the build is completely finished output the information gathered about
    chapters and subchapters into the database.
    """
    if not engine:
        print("You need to install a DBAPI module - psycopg2 for Postgres")
        print("Or perhaps you have not set your DBURL environment variable")
        return

    course_id = app.env.config.html_context.get('course_id', "unknown")
    chapters = Table('chapters', meta, autoload=True, autoload_with=engine)
    sub_chapters = Table('sub_chapters',
                         meta,
                         autoload=True,
                         autoload_with=engine)
    questions = Table('questions', meta, autoload=True, autoload_with=engine)
    basecourse = app.config.html_context.get('basecourse', "unknown")
    print("Cleaning up old chapters info")
    engine.execute(chapters.delete().where(chapters.c.course_id == course_id))

    print("Populating the database with Chapter information")
    for chap in chaptitles:
        # insert row for chapter in the chapter table and get the id
        print(u"Adding chapter subchapter info for {}".format(chap))
        ins = chapters.insert().values(chapter_name=chaptitles.get(chap, chap),
                                       course_id=course_id,
                                       chapter_label=chap)
        res = engine.execute(ins)
        currentRowId = res.inserted_primary_key[0]
        for sub in subtitles[chap]:
            # insert row for subchapter
            q_name = u"{}/{}".format(chaptitles.get(chap, chap),
                                     subtitles[chap][sub])
            ins = sub_chapters.insert().values(
                sub_chapter_name=subtitles[chap][sub],
                chapter_id=str(currentRowId),
                sub_chapter_label=sub)
            engine.execute(ins)
            sel = select([questions]).where(
                and_(questions.c.chapter == chap,
                     questions.c.subchapter == sub,
                     questions.c.question_type == 'page',
                     questions.c.base_course == basecourse))
            res = engine.execute(sel).first()
            if res and res.name != q_name:
                # In this case the title has changed
                upd = questions.update().where(
                    questions.c.id == res['id']).values(name=q_name)
                engine.execute(upd)
            if not res:
                # this is a new subchapter
                ins = questions.insert().values(
                    chapter=chap,
                    subchapter=sub,
                    question_type='page',
                    name=q_name,
                    timestamp=datetime.datetime.now(),
                    base_course=basecourse)
                engine.execute(ins)
Exemple #2
0
def build_finished(app, ex):
    """
    When the build is completely finished output the information gathered about
    chapters and subchapters into the database.
    """
    if not engine:
        print("You need to install a DBAPI module - psycopg2 for Postgres")
        return
    print("Populating the database with Chapter information")
    course_id = app.env.config.html_context.get('course_id', "unknown")
    chapters = Table('chapters', meta, autoload=True, autoload_with=engine)
    sub_chapters = Table('sub_chapters',
                         meta,
                         autoload=True,
                         autoload_with=engine)
    print("Cleaning up old chapters info")
    engine.execute(chapters.delete().where(chapters.c.course_id == course_id))

    if 'Labs' in sub_ids_for_chapter:
        chap_order.append('Labs')
        subchap_order['Labs'] = sub_ids_for_chapter['Labs']
    for chap in chap_order:
        # insert row for chapter in the chapter table and get the id
        print("Adding chapter subchapter info for {}".format(chap))
        ins = chapters.insert().values(chapter_name=chaptitles.get(chap, chap),
                                       course_id=course_id,
                                       chapter_label=chap)
        res = engine.execute(ins)
        currentRowId = res.inserted_primary_key[0]
        for sub in subchap_order[chap]:
            # insert row for subchapter
            ins = sub_chapters.insert().values(
                sub_chapter_name=subtitles[chap][sub],
                chapter_id=str(currentRowId),
                sub_chapter_label=sub)
            engine.execute(ins)
def update_database(chaptitles, subtitles, skips, app):
    """
    When the build is completely finished output the information gathered about
    chapters and subchapters into the database.
    """
    if not engine:
        print("You need to install a DBAPI module - psycopg2 for Postgres")
        print("Or perhaps you have not set your DBURL environment variable")
        return

    course_id = app.env.config.html_context.get('course_id', "unknown")
    chapters = Table('chapters', meta, autoload=True, autoload_with=engine)
    sub_chapters = Table('sub_chapters', meta, autoload=True, autoload_with=engine)
    questions = Table('questions', meta, autoload=True, autoload_with=engine)
    basecourse = app.config.html_context.get('basecourse',"unknown")
    print("Cleaning up old chapters info")
    engine.execute(chapters.delete().where(chapters.c.course_id == course_id))

    print("Populating the database with Chapter information")

    for chap in chaptitles:
        # insert row for chapter in the chapter table and get the id
        print(u"Adding chapter subchapter info for {}".format(chap))
        ins = chapters.insert().values(chapter_name=chaptitles.get(chap, chap),
                                       course_id=course_id, chapter_label=chap)
        res = engine.execute(ins)
        currentRowId = res.inserted_primary_key[0]
        for sub in subtitles[chap]:
            if (chap,sub) in skips:
                skipreading = 'T'
            else:
                skipreading = 'F'
            # insert row for subchapter
            # todo: check if this chapter/subchapter is in the non-reading list
            q_name = u"{}/{}".format(chaptitles.get(chap,chap), subtitles[chap][sub])
            ins = sub_chapters.insert().values(sub_chapter_name=subtitles[chap][sub],
                                               chapter_id=str(currentRowId),
                                               sub_chapter_label=sub,
                                               skipreading=skipreading)
            engine.execute(ins)
            # Three possibilities:
            # 1) The chapter and subchapter labels match existing, but the q_name doesn't match; because you changed
            # heading in a file.
            # 2) The chapter and subchapter labels don't match (new file name), but there is an existing q_name match,
            # because you renamed the file
            # 3) Neither match, so insert a new question
            sel = select([questions]).where(or_(and_(questions.c.chapter == chap,
                                                     questions.c.subchapter == sub,
                                                     questions.c.question_type == 'page',
                                                     questions.c.base_course == basecourse),
                                                and_(questions.c.name == q_name,
                                                     questions.c.question_type == 'page',
                                                     questions.c.base_course == basecourse))
                                            )
            res = engine.execute(sel).first()
            if res and ((res.name != q_name) or (res.chapter != chap) or (res.subchapter !=sub)):
                # Something changed
                upd = questions.update().where(questions.c.id == res['id']).values(name=q_name,
                                                                                   chapter = chap,
                                                                                   subchapter = sub)
                engine.execute(upd)
            if not res:
                # this is a new subchapter
                ins = questions.insert().values(chapter=chap, subchapter=sub,
                                            question_type='page',
                                            name=q_name,
                                            timestamp=datetime.datetime.now(),
                                            base_course=basecourse)
                engine.execute(ins)
    def run(self):
        """
            process the multiplechoice directive and generate html for output.
            :param self:
            :return:
            .. datafile:: identifier
                :edit: Option that makes the datafile editable
                :cols: If editable, number of columns--default is 20
                :rows: If editable, number of rows--default is 40
                :hide: Flag that sets a non-editable datafile to be hidden
                :fromfile: path to file that contains the data
        """
        super(DataFile, self).run()
        env = self.state.document.settings.env

        if not hasattr(env,'datafilecounter'):
            env.datafilecounter = 0
        env.datafilecounter += 1
        import os
        if 'fromfile' in self.options:
            ffpath = os.path.dirname(self.srcpath)
            print(self.srcpath, os.getcwd())
            filename = os.path.join(env.srcdir, ffpath, self.options['fromfile'])
            with open(filename, 'rb') as f:
                self.content = [x[:-1].decode('utf8') for x in f.readlines()]

        if 'cols' in self.options:
            self.options['cols'] = self.options['cols']
        else:
            self.options['cols'] = min(65,max([len(x) for x in self.content]))
        if 'rows' in self.options:
            self.options['rows'] = self.options['rows']
        else:
            self.options['rows'] = 20

        if self.content:
            source = "\n".join(self.content)+"\n"
        else:
            source = '\n'
        self.options['filecontent'] = source

        if 'hide' in self.options:
            self.options['hidden'] = 'data-hidden'
        else:
            self.options['hidden'] = ''

        if 'edit' in self.options:
            self.options['edit'] = "true"
        else:
            self.options['edit'] = "false"

        if engine:
            Source_code = Table('source_code', meta, autoload=True, autoload_with=engine)
            course_name = env.config.html_context['course_id']
            divid = self.options['divid']

            engine.execute(Source_code.delete().where(Source_code.c.acid == divid).where(Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid = divid,
                course_id = course_name,
                main_code= source,
            ))
        else:
            print("Unable to save to source_code table in datafile__init__.py. Possible problems:")
            print("  1. dburl or course_id are not set in conf.py for your book")
            print("  2. unable to connect to the database using dburl")
            print()
            print("This should only affect the grading interface. Everything else should be fine.")


        data_file_node = DataFileNode(self.options, rawsource=self.block_text)
        data_file_node.source, data_file_node.line = self.state_machine.get_source_and_line(self.lineno)
        return [data_file_node]
Exemple #5
0
    def run(self):

        addQuestionToDB(self)

        env = self.state.document.settings.env
        # keep track of how many activecodes we have....
        # could be used to automatically make a unique id for them.
        if not hasattr(env, 'activecodecounter'):
            env.activecodecounter = 0
        env.activecodecounter += 1
        self.options['name'] = self.arguments[0].strip()
        self.options['divid'] = self.arguments[0]

        if not self.options['divid']:
            raise Exception(
                "No divid for ..activecode or ..actex in activecode.py")

        explain_text = None
        if self.content:
            if '~~~~' in self.content:
                idx = self.content.index('~~~~')
                explain_text = self.content[:idx]
                self.content = self.content[idx + 1:]
            source = "\n".join(self.content)
        else:
            source = '\n'

        self.options['initialcode'] = source
        str = source.replace("\n", "*nline*")
        str0 = str.replace("\"", "*doubleq*")
        str1 = str0.replace("(", "*open*")
        str2 = str1.replace(")", "*close*")
        str3 = str2.replace("'", "*singleq*")
        self.options['argu'] = str3

        complete = ""
        no_of_buttons = 0
        okeys = list(self.options.keys())
        for k in okeys:
            if '_' in k:
                x, label = k.split('_')
                no_of_buttons = no_of_buttons + 1
                complete = complete + self.options[k] + "*atype*"

        newcomplete = complete.replace("\"", "*doubleq*")
        self.options['ctext'] = newcomplete
        self.options['no_of_buttons'] = no_of_buttons

        if 'caption' not in self.options:
            self.options['caption'] = ''
        else:
            self.options[
                'caption'] = "data-caption='%s'" % self.options['caption']

        if 'include' not in self.options:
            self.options['include'] = ''
        else:
            lst = self.options['include'].split(',')
            lst = [x.strip() for x in lst]
            self.options['include'] = 'data-include="' + " ".join(lst) + '"'

        if 'hidecode' in self.options:
            self.options['hidecode'] = 'data-hidecode="true"'
        else:
            self.options['hidecode'] = ''

        if 'language' not in self.options:
            self.options['language'] = 'python'

        if self.options['language'] == 'html':
            self.options['language'] = 'htmlmixed'
            self.options['initialcode'] = escape(self.options['initialcode'])

        if 'nocodelens' in self.options or self.options['language'] != 'python':
            self.options['codelens'] = ''
        else:
            self.options['codelens'] = 'data-codelens="true"'

        if 'timelimit' not in self.options:
            self.options['timelimit'] = 'data-timelimit=25000'
        else:
            self.options[
                'timelimit'] = 'data-timelimit=%s' % self.options['timelimit']

        if 'autorun' not in self.options:
            self.options['autorun'] = ''
        else:
            self.options['autorun'] = 'data-autorun="true"'

        if 'coach' in self.options:
            self.options['coach'] = 'data-coach="true"'
        else:
            self.options['coach'] = ''

        # livecode options
        if 'stdin' in self.options:
            self.options['stdin'] = "data-stdin='%s'" % self.options['stdin']
        else:
            self.options['stdin'] = ""

        if 'datafile' not in self.options:
            self.options['datafile'] = ""
        else:
            self.options[
                'datafile'] = "data-datafile='%s'" % self.options['datafile']

        if 'sourcefile' not in self.options:
            self.options['sourcefile'] = ""
        else:
            self.options['sourcefile'] = "data-sourcefile='%s'" % self.options[
                'sourcefile']

        if 'gradebutton' not in self.options:
            self.options['gradebutton'] = ''
        else:
            self.options['gradebutton'] = "data-gradebutton=true"

        if self.content:
            if '====' in self.content:
                idx = self.content.index('====')
                source = "\n".join(self.content[:idx])
                suffix = "\n".join(self.content[idx + 1:])
            else:
                source = "\n".join(self.content)
                suffix = "\n"
        else:
            source = '\n'
            suffix = '\n'

        course_name = env.config.html_context['course_id']
        divid = self.options['divid']

        if engine:
            engine.execute(
                Source_code.delete().where(Source_code.c.acid == divid).where(
                    Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid=divid,
                course_id=course_name,
                main_code=source,
                suffix_code=suffix,
                includes=self.options['include'],
                available_files=self.options.get('available_files', "")))
        else:
            print(
                "Unable to save to source_code table in activecode.py. Possible problems:"
            )
            print(
                "  1. dburl or course_id are not set in conf.py for your book")
            print("  2. unable to connect to the database using dburl")
            print("")
            print(
                "This should only affect the grading interface. Everything else should be fine."
            )

        acnode = ActivcodeNode(self.options, rawsource=self.block_text)
        acnode.source, acnode.line = self.state_machine.get_source_and_line(
            self.lineno)
        self.add_name(
            acnode)  # make this divid available as a target for :ref:

        if explain_text:
            self.state.nested_parse(explain_text, self.content_offset, acnode)

        return [acnode]
def update_database(chaptitles, subtitles, skips, app):
    """
    When the build is completely finished output the information gathered about
    chapters and subchapters into the database.
    """
    if not engine:
        logger.warning("You need to install a DBAPI module - psycopg2 for Postgres")
        logger.warning("Or perhaps you have not set your DBURL environment variable")
        return

    course_id = app.env.config.html_context.get('course_id', "unknown")
    chapters = Table('chapters', meta, autoload=True, autoload_with=engine)
    sub_chapters = Table('sub_chapters', meta, autoload=True, autoload_with=engine)
    questions = Table('questions', meta, autoload=True, autoload_with=engine)
    basecourse = app.config.html_context.get('basecourse',"unknown")
    logger.info("Cleaning up old chapters info")
    engine.execute(chapters.delete().where(chapters.c.course_id == course_id))

    logger.info("Populating the database with Chapter information")

    for chap in chaptitles:
        # insert row for chapter in the chapter table and get the id
        logger.info(u"Adding chapter subchapter info for {}".format(chap))
        ins = chapters.insert().values(chapter_name=chaptitles.get(chap, chap),
                                       course_id=course_id, chapter_label=chap)
        res = engine.execute(ins)
        currentRowId = res.inserted_primary_key[0]
        for sub in subtitles[chap]:
            if (chap,sub) in skips:
                skipreading = 'T'
            else:
                skipreading = 'F'
            # insert row for subchapter
            # todo: check if this chapter/subchapter is in the non-reading list
            q_name = u"{}/{}".format(chaptitles.get(chap,chap), subtitles[chap][sub])
            ins = sub_chapters.insert().values(sub_chapter_name=subtitles[chap][sub],
                                               chapter_id=str(currentRowId),
                                               sub_chapter_label=sub,
                                               skipreading=skipreading)
            engine.execute(ins)
            # Three possibilities:
            # 1) The chapter and subchapter labels match existing, but the q_name doesn't match; because you changed
            # heading in a file.
            # 2) The chapter and subchapter labels don't match (new file name), but there is an existing q_name match,
            # because you renamed the file
            # 3) Neither match, so insert a new question
            sel = select([questions]).where(or_(and_(questions.c.chapter == chap,
                                                     questions.c.subchapter == sub,
                                                     questions.c.question_type == 'page',
                                                     questions.c.base_course == basecourse),
                                                and_(questions.c.name == q_name,
                                                     questions.c.question_type == 'page',
                                                     questions.c.base_course == basecourse))
                                            )
            res = engine.execute(sel).first()
            if res and ((res.name != q_name) or (res.chapter != chap) or (res.subchapter !=sub)):
                # Something changed
                upd = questions.update().where(questions.c.id == res['id']).values(name=q_name,
                                                                                   chapter = chap,
                                                                                   subchapter = sub)
                engine.execute(upd)
            if not res:
                # this is a new subchapter
                ins = questions.insert().values(chapter=chap, subchapter=sub,
                                            question_type='page',
                                            name=q_name,
                                            timestamp=datetime.datetime.now(),
                                            base_course=basecourse)
                engine.execute(ins)
    def run(self):
        super(ActiveCode, self).run()

        addQuestionToDB(self)

        env = self.state.document.settings.env
        # keep track of how many activecodes we have....
        # could be used to automatically make a unique id for them.
        if not hasattr(env, "activecodecounter"):
            env.activecodecounter = 0
        env.activecodecounter += 1
        self.options["name"] = self.arguments[0].strip()

        explain_text = None
        if self.content:
            if "~~~~" in self.content:
                idx = self.content.index("~~~~")
                explain_text = self.content[:idx]
                self.content = self.content[idx + 1:]
            source = "\n".join(self.content)
        else:
            source = "\n"

        self.options["initialcode"] = source
        str = source.replace("\n", "*nline*")
        str0 = str.replace('"', "*doubleq*")
        str1 = str0.replace("(", "*open*")
        str2 = str1.replace(")", "*close*")
        str3 = str2.replace("'", "*singleq*")
        self.options["argu"] = str3

        # TODO: This is BAD -- using '_' as a key for audio tour stuff is wrong.
        complete = ""
        no_of_buttons = 0
        okeys = list(self.options.keys())
        for k in okeys:
            if "tour_" in k:
                x, label = k.split("_")
                no_of_buttons = no_of_buttons + 1
                complete = complete + self.options[k] + "*atype*"

        newcomplete = complete.replace('"', "*doubleq*")
        self.options["ctext"] = newcomplete
        self.options["no_of_buttons"] = no_of_buttons

        if "caption" not in self.options:
            self.options["caption"] = ""
        else:
            self.options[
                "caption"] = "data-caption='%s'" % self.options["caption"]

        if "include" not in self.options:
            self.options["include"] = ""
        else:
            lst = self.options["include"].split(",")
            lst = [x.strip() for x in lst]
            self.options["include"] = 'data-include="' + " ".join(lst) + '"'

        if "hidecode" in self.options:
            self.options["hidecode"] = 'data-hidecode="true"'
        else:
            self.options["hidecode"] = ""

        if "enabledownload" in self.options:
            self.options["enabledownload"] = 'data-enabledownload="true"'
        else:
            self.options["enabledownload"] = ""

        if "chatcodes" in self.options:
            self.options["chatcodes"] = 'data-chatcodes="true"'
        else:
            self.options["chatcodes"] = ""

        if "language" not in self.options:
            self.options["language"] = "python"

        if self.options["language"] == "html":
            self.options["language"] = "htmlmixed"
            self.options["initialcode"] = escape(self.options["initialcode"])

        if "nocodelens" in self.options or self.options["language"] != "python":
            self.options["codelens"] = ""
        else:
            self.options["codelens"] = 'data-codelens="true"'

        if "nopair" in self.options:
            self.options["nopair"] = 'data-nopair="true"'
        else:
            self.options["nopair"] = ""

        if "timelimit" not in self.options:
            self.options["timelimit"] = "data-timelimit=25000"
        else:
            self.options[
                "timelimit"] = "data-timelimit=%s" % self.options["timelimit"]

        if "autorun" not in self.options:
            self.options["autorun"] = ""
        else:
            self.options["autorun"] = 'data-autorun="true"'

        if "coach" in self.options:
            self.options["coach"] = 'data-coach="true"'
        else:
            self.options["coach"] = ""

        # livecode options
        if "stdin" in self.options:
            self.options["stdin"] = "data-stdin='%s'" % self.options["stdin"]
        else:
            self.options["stdin"] = ""

        if "datafile" not in self.options:
            self.options["datafile"] = ""
        else:
            self.options[
                "datafile"] = "data-datafile='%s'" % self.options["datafile"]

        if "sourcefile" not in self.options:
            self.options["sourcefile"] = ""
        else:
            self.options["sourcefile"] = ("data-sourcefile='%s'" %
                                          self.options["sourcefile"])

        if "tie" in self.options:
            self.options["tie"] = "data-tie='{}'".format(self.options["tie"])
        else:
            self.options["tie"] = ""

        if "dburl" in self.options:
            self.options["dburl"] = "data-dburl='{}'".format(
                self.options["dburl"])
        else:
            self.options["dburl"] = ""

        for opt, tp in [
            ("compileargs", "cargs"),
            ("linkargs", "largs"),
            ("runargs", "rargs"),
            ("interpreterargs", "iargs"),
        ]:
            if opt in self.options:
                self.options[tp] = 'data-{}="{}"'.format(
                    opt, escape(self.options[opt]))
            else:
                self.options[tp] = ""

        if "gradebutton" not in self.options:
            self.options["gradebutton"] = ""
        else:
            self.options["gradebutton"] = "data-gradebutton=true"

        self.options["divclass"] = env.config.activecode_div_class
        if env.config.activecode_hide_load_history:
            self.options["hidehistory"] = "data-hidehistory=true"
        else:
            self.options["hidehistory"] = ""

        if env.config.wasm_uri:
            self.options["wasmuri"] = f"data-wasm={env.config.wasm_uri}"
        else:
            self.options["wasmuri"] = ""

        if self.content:
            if "====" in self.content:
                idx = self.content.index("====")
                source = "\n".join(self.content[:idx])
                suffix = "\n".join(self.content[idx + 1:])
            else:
                source = "\n".join(self.content)
                suffix = "\n"
        else:
            source = "\n"
            suffix = "\n"

        course_name = env.config.html_context["course_id"]
        divid = self.options["divid"]

        if engine:
            engine.execute(
                Source_code.delete().where(Source_code.c.acid == divid).where(
                    Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid=divid,
                course_id=course_name,
                main_code=source,
                suffix_code=suffix,
                includes=self.options["include"],
                available_files=self.options.get("available_files", ""),
            ))
        else:
            if (not hasattr(env, "dberr_activecode_reported")
                    or not env.dberr_activecode_reported):
                env.dberr_activecode_reported = True
                print(
                    "Unable to save to source_code table in activecode.py. Possible problems:"
                )
                print(
                    "  1. dburl or course_id are not set in conf.py for your book"
                )
                print("  2. unable to connect to the database using dburl")
                print("")
                print(
                    "This should only affect the grading interface. Everything else should be fine."
                )

        acnode = ActivcodeNode(self.options, rawsource=self.block_text)
        acnode.source, acnode.line = self.state_machine.get_source_and_line(
            self.lineno)
        self.add_name(
            acnode)  # make this divid available as a target for :ref:

        if explain_text:
            self.state.nested_parse(explain_text, self.content_offset, acnode)

        return [acnode]
Exemple #8
0
    def run(self):
        super(ActiveCode, self).run()

        addQuestionToDB(self)

        env = self.state.document.settings.env
        # keep track of how many activecodes we have....
        # could be used to automatically make a unique id for them.
        if not hasattr(env, 'activecodecounter'):
            env.activecodecounter = 0
        env.activecodecounter += 1
        self.options['name'] = self.arguments[0].strip()

        explain_text = None
        if self.content:
            if '~~~~' in self.content:
                idx = self.content.index('~~~~')
                explain_text = self.content[:idx]
                self.content = self.content[idx + 1:]
            source = "\n".join(self.content)
        else:
            source = '\n'

        self.options['initialcode'] = source
        str = source.replace("\n", "*nline*")
        str0 = str.replace("\"", "*doubleq*")
        str1 = str0.replace("(", "*open*")
        str2 = str1.replace(")", "*close*")
        str3 = str2.replace("'", "*singleq*")
        self.options['argu'] = str3

        complete = ""
        no_of_buttons = 0
        okeys = list(self.options.keys())
        for k in okeys:
            if '_' in k:
                x, label = k.split('_')
                no_of_buttons = no_of_buttons + 1
                complete = complete + self.options[k] + "*atype*"

        newcomplete = complete.replace("\"", "*doubleq*")
        self.options['ctext'] = newcomplete
        self.options['no_of_buttons'] = no_of_buttons

        if 'caption' not in self.options:
            self.options['caption'] = ''
        else:
            self.options[
                'caption'] = "data-caption='%s'" % self.options['caption']

        if 'include' not in self.options:
            self.options['include'] = ''
        else:
            lst = self.options['include'].split(',')
            lst = [x.strip() for x in lst]
            self.options['include'] = 'data-include="' + " ".join(lst) + '"'

        if 'hidecode' in self.options:
            self.options['hidecode'] = 'data-hidecode="true"'
        else:
            self.options['hidecode'] = ''

        if 'enabledownload' in self.options:
            self.options['enabledownload'] = 'data-enabledownload="true"'
        else:
            self.options['enabledownload'] = ''

        if 'chatcodes' in self.options:
            self.options['chatcodes'] = 'data-chatcodes="true"'
        else:
            self.options['chatcodes'] = ''

        if 'language' not in self.options:
            self.options['language'] = 'python'

        if self.options['language'] == 'html':
            self.options['language'] = 'htmlmixed'
            self.options['initialcode'] = escape(self.options['initialcode'])

        if 'nocodelens' in self.options or self.options['language'] != 'python':
            self.options['codelens'] = ''
        else:
            self.options['codelens'] = 'data-codelens="true"'

        if 'timelimit' not in self.options:
            self.options['timelimit'] = 'data-timelimit=25000'
        else:
            self.options[
                'timelimit'] = 'data-timelimit=%s' % self.options['timelimit']

        if 'autorun' not in self.options:
            self.options['autorun'] = ''
        else:
            self.options['autorun'] = 'data-autorun="true"'

        if 'runortest' not in self.options:
            self.options['runortest'] = ''
        else:
            lst = self.options['runortest'].split(',')
            lst = [x.strip() for x in lst]
            self.options['runortest'] = 'data-runortest="' + " ".join(
                lst) + '"'

        if 'playtask' not in self.options:
            self.options['playtask'] = ''
        elif self.options['runortest']:
            raise self.error(
                'There must not be interference between runortest and playtask options'
            )
        else:
            self.options['playtask'] = 'data-playtask="true"'

        if 'help' not in self.options:
            self.options['help'] = ''
        else:
            self.options['help'] = 'data-help="true"'

        if 'passivecode' not in self.options:
            self.options['passivecode'] = ''
        else:
            self.options[
                'passivecode'] = 'data-passivecode="%s"' % self.options[
                    'passivecode']

        if 'modaloutput' not in self.options:
            self.options['modaloutput'] = ''
        else:
            self.options['modaloutput'] = 'data-modaloutput="true"'

        if 'enablecopy' not in self.options:
            self.options['enablecopy'] = ''
        else:
            self.options['enablecopy'] = 'data-enablecopy="true"'

        if 'coach' in self.options:
            self.options['coach'] = 'data-coach="true"'
        else:
            self.options['coach'] = ''

        # livecode options
        if 'stdin' in self.options:
            self.options['stdin'] = "data-stdin='%s'" % self.options['stdin']
        else:
            self.options['stdin'] = ""

        if 'datafile' not in self.options:
            self.options['datafile'] = ""
        else:
            self.options[
                'datafile'] = "data-datafile='%s'" % self.options['datafile']

        if 'sourcefile' not in self.options:
            self.options['sourcefile'] = ""
        else:
            self.options['sourcefile'] = "data-sourcefile='%s'" % self.options[
                'sourcefile']

        for opt, tp in [('compileargs', 'cargs'), ('linkargs', 'largs'),
                        ('runargs', 'rargs'), ('interpreterargs', 'iargs')]:
            if opt in self.options:
                self.options[tp] = 'data-{}="{}"'.format(
                    opt, escape(self.options[opt]))
            else:
                self.options[tp] = ""

        if 'gradebutton' not in self.options:
            self.options['gradebutton'] = ''
        else:
            self.options['gradebutton'] = "data-gradebutton=true"

        self.options['divclass'] = env.config.activecode_div_class
        if env.config.activecode_hide_load_history:
            self.options['hidehistory'] = 'data-hidehistory=true'
        else:
            self.options['hidehistory'] = ''

        if 'includesrc' in self.options:
            fname = self.options['includesrc'].replace('\\', '/')
            cwd = os.path.abspath(os.getcwd())
            path = os.path.join(cwd, fname)
            with open(path, encoding='utf-8') as f:
                self.options[
                    'includesrc'] = 'data-includesrc="%s"' % html_escape(
                        f.read())
        else:
            self.options['includesrc'] = ""

        if 'includehsrc' in self.options:
            fname = self.options['includehsrc'].replace('\\', '/')
            cwd = os.path.abspath(os.getcwd())
            path = os.path.join(cwd, fname)
            with open(path, encoding='utf-8') as f:
                self.options[
                    'includehsrc'] = 'data-includehsrc="%s"' % html_escape(
                        f.read())
        else:
            self.options['includehsrc'] = ""

        if 'includexsrc' in self.options:
            fname = self.options['includexsrc'].replace('\\', '/')
            cwd = os.path.abspath(os.getcwd())
            path = os.path.join(cwd, fname)
            with open(path, encoding='utf-8') as f:
                self.options[
                    'includexsrc'] = 'data-includexsrc="%s"' % html_escape(
                        f.read())
        else:
            self.options['includexsrc'] = ""

        if self.content:
            if '====' in self.content:
                idx = self.content.index('====')
                source = "\n".join(self.content[:idx])
                suffix = "\n".join(self.content[idx + 1:])
            else:
                source = "\n".join(self.content)
                suffix = "\n"
        else:
            source = '\n'
            suffix = '\n'

        course_name = env.config.html_context['course_id']
        divid = self.options['divid']

        if engine:
            engine.execute(
                Source_code.delete().where(Source_code.c.acid == divid).where(
                    Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid=divid,
                course_id=course_name,
                main_code=source,
                suffix_code=suffix,
                includes=self.options['include'],
                available_files=self.options.get('available_files', "")))
        else:
            if not hasattr(env, 'dberr_activecode_reported'
                           ) or not env.dberr_activecode_reported:
                env.dberr_activecode_reported = True
                print(
                    "Unable to save to source_code table in activecode.py. Possible problems:"
                )
                print(
                    "  1. dburl or course_id are not set in conf.py for your book"
                )
                print("  2. unable to connect to the database using dburl")
                print("")
                print(
                    "This should only affect the grading interface. Everything else should be fine."
                )

        acnode = ActivcodeNode(self.options, rawsource=self.block_text)
        acnode.source, acnode.line = self.state_machine.get_source_and_line(
            self.lineno)
        self.add_name(
            acnode)  # make this divid available as a target for :ref:

        if explain_text:
            self.state.nested_parse(explain_text, self.content_offset, acnode)

        return [acnode]
    def run(self):
        super(ActiveCode, self).run()

        addQuestionToDB(self)

        env = self.state.document.settings.env
        # keep track of how many activecodes we have....
        # could be used to automatically make a unique id for them.
        if not hasattr(env, 'activecodecounter'):
            env.activecodecounter = 0
        env.activecodecounter += 1
        self.options['name'] = self.arguments[0].strip()

        explain_text = None
        if self.content:
            if '~~~~' in self.content:
                idx = self.content.index('~~~~')
                explain_text = self.content[:idx]
                self.content = self.content[idx+1:]
            source = "\n".join(self.content)
        else:
            source = '\n'

        self.options['initialcode'] = source
        str = source.replace("\n", "*nline*")
        str0 = str.replace("\"", "*doubleq*")
        str1 = str0.replace("(", "*open*")
        str2 = str1.replace(")", "*close*")
        str3 = str2.replace("'", "*singleq*")
        self.options['argu'] = str3

        complete = ""
        no_of_buttons = 0
        okeys = list(self.options.keys())
        for k in okeys:
            if '_' in k:
                x, label = k.split('_')
                no_of_buttons = no_of_buttons + 1
                complete = complete + self.options[k] + "*atype*"

        newcomplete = complete.replace("\"", "*doubleq*")
        self.options['ctext'] = newcomplete
        self.options['no_of_buttons'] = no_of_buttons

        if 'caption' not in self.options:
            self.options['caption'] = ''
        else:
            self.options['caption'] = "data-caption='%s'" % self.options['caption']

        if 'include' not in self.options:
            self.options['include'] = ''
        else:
            lst = self.options['include'].split(',')
            lst = [x.strip() for x in lst]
            self.options['include'] = 'data-include="' + " ".join(lst) + '"'

        if 'hidecode' in self.options:
            self.options['hidecode'] = 'data-hidecode="true"'
        else:
            self.options['hidecode'] = ''

        if 'enabledownload' in self.options:
            self.options['enabledownload'] = 'data-enabledownload="true"'
        else:
            self.options['enabledownload'] = ''

        if 'chatcodes' in self.options:
            self.options['chatcodes'] = 'data-chatcodes="true"'
        else:
            self.options['chatcodes'] = ''

        if 'language' not in self.options:
            self.options['language'] = 'python'

        if self.options['language'] == 'html':
            self.options['language'] = 'htmlmixed'
            self.options['initialcode'] = escape(self.options['initialcode'])

        if 'nocodelens' in self.options or self.options['language'] != 'python':
            self.options['codelens'] = ''
        else:
            self.options['codelens'] = 'data-codelens="true"'

        if 'timelimit' not in self.options:
            self.options['timelimit'] = 'data-timelimit=25000'
        else:
            self.options['timelimit'] = 'data-timelimit=%s' % self.options['timelimit']

        if 'autorun' not in self.options:
            self.options['autorun'] = ''
        else:
            self.options['autorun'] = 'data-autorun="true"'

        if 'coach' in self.options:
            self.options['coach'] = 'data-coach="true"'
        else:
            self.options['coach'] = ''

        # livecode options
        if 'stdin' in self.options:
            self.options['stdin'] = "data-stdin='%s'" % self.options['stdin']
        else:
            self.options['stdin'] = ""

        if 'datafile' not in self.options:
            self.options['datafile'] = ""
        else:
            self.options['datafile'] = "data-datafile='%s'" % self.options['datafile']

        if 'sourcefile' not in self.options:
            self.options['sourcefile'] = ""
        else:
            self.options['sourcefile'] = "data-sourcefile='%s'" % self.options['sourcefile']

        for opt,tp in [('compileargs','cargs'),('linkargs','largs'),('runargs','rargs'),('interpreterargs','iargs')]:
            if opt in self.options:
                self.options[tp] = 'data-{}="{}"'.format(opt, escape(self.options[opt]))
            else:
                self.options[tp] = ""

        if 'gradebutton' not in self.options:
            self.options['gradebutton'] = ''
        else:
            self.options['gradebutton'] = "data-gradebutton=true"

        self.options['divclass'] = env.config.activecode_div_class
        if env.config.activecode_hide_load_history:
            self.options['hidehistory'] = 'data-hidehistory=true'
        else:
            self.options['hidehistory'] = ''

        if self.content:
            if '====' in self.content:
                idx = self.content.index('====')
                source = "\n".join(self.content[:idx])
                suffix = "\n".join(self.content[idx+1:])
            else:
                source = "\n".join(self.content)
                suffix = "\n"
        else:
            source = '\n'
            suffix = '\n'


        course_name = env.config.html_context['course_id']
        divid = self.options['divid']

        if engine:
            engine.execute(Source_code.delete().where(Source_code.c.acid == divid).where(Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid = divid,
                course_id = course_name,
                main_code= source,
                suffix_code = suffix,
                includes = self.options['include'],
                available_files = self.options.get('available_files', "")
            ))
        else:
            if not hasattr(env, 'dberr_activecode_reported') or not env.dberr_activecode_reported:
                env.dberr_activecode_reported = True
                print("Unable to save to source_code table in activecode.py. Possible problems:")
                print("  1. dburl or course_id are not set in conf.py for your book")
                print("  2. unable to connect to the database using dburl")
                print("")
                print("This should only affect the grading interface. Everything else should be fine.")


        acnode = ActivcodeNode(self.options, rawsource=self.block_text)
        acnode.source, acnode.line = self.state_machine.get_source_and_line(self.lineno)
        self.add_name(acnode)    # make this divid available as a target for :ref:

        if explain_text:
            self.state.nested_parse(explain_text, self.content_offset, acnode)

        return [acnode]
    def run(self):
        """
            process the multiplechoice directive and generate html for output.
            :param self:
            :return:
            .. datafile:: identifier
                :edit: Option that makes the datafile editable
                :cols: If editable, number of columns--default is 20
                :rows: If editable, number of rows--default is 40
                :hide: Flag that sets a non-editable datafile to be hidden
        """
        super(DataFile, self).run()
        env = self.state.document.settings.env

        if not hasattr(env,'datafilecounter'):
            env.datafilecounter = 0
        env.datafilecounter += 1

        #if 'cols' not in self.options:
        #    self.options['cols'] = min(65,max([len(x) for x in self.content]))
        #if 'rows'not in self.options:
        #    self.options['rows'] = 20

        if 'cols' in self.options:
            self.options['cols'] = self.options['cols']
        else:
            self.options['cols'] = min(65,max([len(x) for x in self.content]))
        if 'rows' in self.options:
            self.options['rows'] = self.options['rows']
        else:
            self.options['rows'] = 20

        if self.content:
            source = "\n".join(self.content)+"\n"
        else:
            source = '\n'
        self.options['filecontent'] = source

        if 'hide' in self.options:
            self.options['hidden'] = 'data-hidden'
        else:
            self.options['hidden'] = ''

        if 'edit' in self.options:
            self.options['edit'] = "true"
        else:
            self.options['edit'] = "false"

        if engine:
            Source_code = Table('source_code', meta, autoload=True, autoload_with=engine)
            course_name = env.config.html_context['course_id']
            divid = self.options['divid']

            engine.execute(Source_code.delete().where(Source_code.c.acid == divid).where(Source_code.c.course_id == course_name))
            engine.execute(Source_code.insert().values(
                acid = divid,
                course_id = course_name,
                main_code= source,
            ))
        else:
            print("Unable to save to source_code table in datafile__init__.py. Possible problems:")
            print("  1. dburl or course_id are not set in conf.py for your book")
            print("  2. unable to connect to the database using dburl")
            print()
            print("This should only affect the grading interface. Everything else should be fine.")


        data_file_node = DataFileNode(self.options, rawsource=self.block_text)
        data_file_node.source, data_file_node.line = self.state_machine.get_source_and_line(self.lineno)
        return [data_file_node]