Example #1
0
def Creatediagram():
    desc = sadisplay.describe(globals().values())

    with codecs.open('schema.plantuml', 'w', encoding='utf-8') as f:
        f.write(sadisplay.plantuml(desc))

    with codecs.open('schema.dot', 'w', encoding='utf-8') as f:
        f.write(sadisplay.dot(desc))
def show_database_schema(
    schemastem: str,
    make_image: bool = False,
    java: str = None,
    plantuml: str = None,
    height_width_limit: int = 20000,
    java_memory_limit_mb: int = 2048,
) -> None:
    """
    Prints the database schema to a PNG picture.

    Args:
        schemastem:
            filename stem
        make_image:
            Make a PNG image? (May be impractically large!)
        java:
            (for ``make_image``) Java executable
        plantuml:
            (for ``make_image``) PlantUML Java ``.jar`` file
        height_width_limit:
            (for ``make_image``) maximum height and width for PNG; see
            https://plantuml.com/faq
        java_memory_limit_mb:
            (for ``make_image``) Java virtual machine memory limit, in Mb
    """
    # noinspection PyUnresolvedReferences
    import camcops_server.camcops_server_core as core  # delayed import; import side effects  # noqa
    import sadisplay  # delayed import
    import camcops_server.cc_modules.cc_all_models as models  # delayed import

    # ... a re-import to give it a name
    uml_filename = f"{schemastem}.plantuml"
    png_filename = f"{schemastem}.png"
    log.info(f"Making schema PlantUML: {uml_filename}")
    desc = sadisplay.describe([getattr(models, attr) for attr in dir(models)])
    # log.debug(desc)
    with open(uml_filename, "w") as f:
        f.write(sadisplay.plantuml(desc))
    if make_image:
        import shutil  # delayed import

        assert shutil.which(java), f"Can't find Java executable: {java}"
        assert os.path.isfile(
            plantuml
        ), f"Can't find PlantUML JAR file: {plantuml}"  # noqa
        log.info(f"Making schema PNG: {png_filename}")
        cmd = [
            java,
            f"-Xmx{java_memory_limit_mb}m",
            f"-DPLANTUML_LIMIT_SIZE={height_width_limit}",
            "-jar",
            plantuml,
            uml_filename,
        ]
        log.info("Arguments: {}", cmd)
        subprocess.check_call(cmd)
Example #3
0
def main():
    classes = [c for c in
            list(chain.from_iterable([[getattr(m, a) for a in dir(m)]
                for m in (terms, factset, network)]))
            if type(c) is DeclarativeMeta and issubclass(c, Base)]
    print(classes)

    desc = sadisplay.describe(classes, show_methods=False)
    open('schema.plantuml', 'w').write(sadisplay.plantuml(desc))
    open('schema.dot', 'w').write(sadisplay.dot(desc))
Example #4
0
def render(self, node):

    all_names = []

    for module_name in node['module']:
        __import__(module_name, globals(), locals(), [], -1)
        module = sys.modules[module_name]

        for attr in dir(module):
            try:
                m = getattr(module, attr)

                # !!!
                # Ugly hack
                repr(m) # without this statement - exception raises
                # any ideas?

                all_names.append(m)
            except:
                pass

    names = []

    if node['exclude']:
        for i in all_names:
            try:
                if i.__name__ not in node['exclude']:
                    names.append(i)
            except AttributeError:
                pass

    elif node['include']:
        for i in all_names:
            try:
                if i.__name__ in node['include']:
                    names.append(i)
            except AttributeError:
                pass

    else:
        names = all_names

    desc = sadisplay.describe(names)

    render = node['render'] or self.builder.config.sadisplay_default_render

    if render == 'plantuml':
        content = sadisplay.plantuml(desc)
        command = generate_plantuml_args(self)
    elif render == 'graphviz':
        content = sadisplay.dot(desc)
        command = generate_graphviz_args(self)

    return render_image(self, content, command)
Example #5
0
def render(self, node):

    all_names = []

    for module_name in node['module']:
        __import__(module_name, globals(), locals())
        module = sys.modules[module_name]

        for attr in dir(module):
            try:
                m = getattr(module, attr)

                # !!!
                # Ugly hack
                repr(m)  # without this statement - exception raises
                # any ideas?

                all_names.append(m)
            except:
                pass

    names = []

    if node['exclude']:
        for i in all_names:
            try:
                if i.__name__ not in node['exclude']:
                    names.append(i)
            except AttributeError:
                pass

    elif node['include']:
        for i in all_names:
            try:
                if i.__name__ in node['include']:
                    names.append(i)
            except AttributeError:
                pass

    else:
        names = all_names

    desc = sadisplay.describe(names)

    render = node['render'] or self.builder.config.sadisplay_default_render

    if render == 'plantuml':
        content = sadisplay.plantuml(desc)
        command = generate_plantuml_args(self)
    elif render == 'graphviz':
        content = sadisplay.dot(desc)
        command = generate_graphviz_args(self)

    return render_image(self, content, command)
Example #6
0
def get_ulm():
    desc = sadisplay.describe(
        [getattr(models, attr) for attr in dir(models)],
        show_methods=True,
        show_properties=True,
        show_indexes=True,
    )
    with codecs.open('doc/database/schema.plantuml', 'w',
                     encoding='utf-8') as f:
        f.write(sadisplay.plantuml(desc))
    with codecs.open('doc/database/schema.dot', 'w', encoding='utf-8') as f:
        f.write(sadisplay.dot(desc))
Example #7
0
def render(self, node):

    all_names = []

    for module_name in node['module']:
        __import__(module_name, globals(), locals(), [], -1)
        module = sys.modules[module_name]

        all_names += [getattr(module, attr) for attr in dir(module)]

    names = []

    if node['exclude']:
        for i in all_names:
            try:
                if i.__name__ not in node['exclude']:
                    names.append(i)
            except AttributeError:
                pass

    elif node['include']:
        for i in all_names:
            try:
                if i.__name__ in node['include']:
                    names.append(i)
            except AttributeError:
                pass

    else:
        names = all_names

    desc = sadisplay.describe(names)

    render = node['render'] or self.builder.config.sadisplay_default_render

    if render == 'plantuml':
        content = sadisplay.plantuml(desc)
        command = generate_plantuml_args(self)
    elif render == 'graphviz':
        content = sadisplay.dot(desc)
        command = generate_graphviz_args(self)

    return render_image(self, content, command)
Example #8
0
def render(self, node):

    all_names = []

    for module_name in node["module"]:
        __import__(module_name, globals(), locals(), [], -1)
        module = sys.modules[module_name]

        all_names += [getattr(module, attr) for attr in dir(module)]

    names = []

    if node["exclude"]:
        for i in all_names:
            try:
                if i.__name__ not in node["exclude"]:
                    names.append(i)
            except AttributeError:
                pass

    elif node["include"]:
        for i in all_names:
            try:
                if i.__name__ in node["include"]:
                    names.append(i)
            except AttributeError:
                pass

    else:
        names = all_names

    desc = sadisplay.describe(names)

    render = node["render"] or self.builder.config.sadisplay_default_render

    if render == "plantuml":
        content = sadisplay.plantuml(desc)
        command = generate_plantuml_args(self)
    elif render == "graphviz":
        content = sadisplay.dot(desc)
        command = generate_graphviz_args(self)

    return render_image(self, content, command)
Example #9
0
Index("ix_user_title", books.c.user_id, books.c.title)


class Book(object):
    pass


mapper(Book, books, {'user': relation(User, backref='books')})

# Not mapped table
notes = Table(
    'notes',
    BASE.metadata,
    Column('id', Integer, primary_key=True),
    Column('name', Unicode(200), nullable=False),
    Column('user_id', Integer, ForeignKey('user_table.id')),
)

if __name__ == '__main__':
    import codecs
    import sadisplay

    desc = sadisplay.describe(globals().values())

    with codecs.open('/tmp/schema.plantuml', 'w', encoding='utf-8') as f:
        f.write(sadisplay.plantuml(desc))

    with codecs.open('/tmp/schema.dot', 'w', encoding='utf-8') as f:
        f.write(sadisplay.dot(desc))
Example #10
0
)


class Book(object):
    pass


mapper(Book, books, {'user': relation(User, backref='books')})


# Not mapped table
notes = Table(
    'notes',
    BASE.metadata,
    Column('id', Integer, primary_key=True),
    Column('name', Unicode(200), nullable=False),
    Column('user_id', Integer, ForeignKey('user_table.id')),
)


if __name__ == '__main__':
    import sadisplay

    desc = sadisplay.describe(globals().values())

    with open('schema.plantuml', 'w') as f:
        f.write(sadisplay.plantuml(desc))

    with open('schema.dot', 'w') as f:
        f.write(sadisplay.dot(desc))
def main() -> int:
    """
    Command-line entry point.

    Returns:
        exit code
    """
    # -------------------------------------------------------------------------
    # Arguments
    # -------------------------------------------------------------------------
    parser = argparse.ArgumentParser(
        description="whisker_serial_order v{}. Serial order task for "
        "Whisker.".format(SERIAL_ORDER_VERSION))
    parser.add_argument("--logfile",
                        default=None,
                        help="Filename to append log to")
    parser.add_argument('--verbose',
                        '-v',
                        action='count',
                        default=0,
                        help="Be verbose. (Use twice for extra verbosity.)")
    parser.add_argument('--guilog',
                        action="store_true",
                        help="Show Python log in a GUI window")
    parser.add_argument('--upgrade-database',
                        action="store_true",
                        help="Upgrade database to current version.")
    # parser.add_argument('--debug-qt-signals', action="store_true",
    #                     help="Debug QT signals.")
    parser.add_argument(
        "--dburl",
        default=None,
        help="Database URL (if not specified, task will look in {} "
        "environment variable).".format(DB_URL_ENV_VAR))
    parser.add_argument('--dbecho',
                        action="store_true",
                        help="Echo SQL to log.")
    parser.add_argument(
        "--outdir",
        default=None,
        help="Directory for output file (if not specified, task will look in "
        "{} environment variable, or if none, working directory).".format(
            OUTPUT_DIR_ENV_VAR))
    parser.add_argument('--gui',
                        '-g',
                        action="store_true",
                        help="GUI mode only")
    parser.add_argument('--schema',
                        action="store_true",
                        help="Generate schema picture and stop")
    parser.add_argument(
        "--java",
        default='java',
        help="Java executable (for schema diagrams); default is 'java'")
    parser.add_argument(
        "--plantuml",
        default='plantuml.jar',
        help="PlantUML Java .jar file (for schema diagrams); default "
        "is 'plantuml.jar'")
    parser.add_argument(
        "--schemastem",
        default='schema',
        help="Stem for output filenames (for schema diagrams); default is "
        "'schema'; '.plantuml' and '.png' are appended")
    parser.add_argument(
        "--testtrialplan",
        action="store_true",
        help="Print a test trial plan of the specified sequence length "
        "+/- restrictions")
    parser.add_argument("--seqlen",
                        metavar='SEQUENCE_LEN',
                        type=int,
                        default=None,
                        help="Sequence length for --testtrialplan")
    parser.add_argument(
        "--choice_hole_restriction",
        metavar='CHOICE_HOLE_GROUPS',
        type=ChoiceHoleRestriction,
        help="Optional choice hole restrictions for --testtrialplan; use "
        "e.g. '--choice_hole_restriction \"1,2;3,4\"' to restrict the "
        "choice phase to holes 1 v 2 and 3 v 4")
    parser.add_argument(
        "--serial_pos_restriction",
        metavar='SERIAL_ORDER_POS_GROUPS',
        type=SerialPosRestriction,
        help="Optional choice serial order position restrictions for "
        "--testtrialplan; use e.g. '--serial_pos_restriction "
        "\"1,2;1,3\"' to restrict the choice phase to serial positions "
        "1 v 2 and 1 v 3")
    parser.add_argument(
        "--side_dwor_multiplier",
        metavar="SIDE_DWOR_MULTIPLIER",
        type=int,
        default=1,
        help="Draw-without-replacement (DWOR) multiplier for shuffling on the "
        "basis of whether the left or right side is correct; see docs.")

    # We could allow extra Qt arguments:
    # args, unparsed_args = parser.parse_known_args()
    # Or not:
    args = parser.parse_args()
    unparsed_args = []

    qt_args = sys.argv[:1] + unparsed_args

    # -------------------------------------------------------------------------
    # Modify settings if we're in a PyInstaller bundle
    # -------------------------------------------------------------------------
    in_bundle = getattr(sys, 'frozen', False)
    if in_bundle:
        args.gui = True
    if not args.gui:
        args.guilog = False

    # -------------------------------------------------------------------------
    # Create QApplication before we create any windows (or Qt will crash)
    # -------------------------------------------------------------------------
    qt_app = QApplication(qt_args)

    # -------------------------------------------------------------------------
    # Logging
    # -------------------------------------------------------------------------
    loglevel = logging.DEBUG if args.verbose >= 1 else logging.INFO
    main_only_quicksetup_rootlogger(loglevel)
    logging.getLogger('whisker').setLevel(
        logging.DEBUG if args.verbose >= 2 else logging.INFO)
    if args.logfile:
        copy_root_log_to_file(args.logfile)
    if args.guilog:
        rootlogger = logging.getLogger()
        log_window = LogWindow(level=loglevel,
                               window_title=WINDOW_TITLE + " Python log",
                               logger=rootlogger)
        log_window.show()

    # If any exceptions happen up to this point, we're a bit stuffed.
    # But from now on, we can trap anything and see it in the GUI log, if
    # enabled, even if we have no console.

    # noinspection PyBroadException,PyPep8
    try:

        # ---------------------------------------------------------------------
        # Info
        # ---------------------------------------------------------------------
        log.info("whisker_serial_order v{}: Serial order task for Whisker, "
                 "by Rudolf Cardinal ([email protected])".format(
                     SERIAL_ORDER_VERSION))
        log.debug("args: {}".format(args))
        log.debug("qt_args: {}".format(qt_args))
        log.debug("PyQt version: {}".format(PYQT_VERSION_STR))
        log.debug("QtCore version: {}".format(QT_VERSION_STR))
        log.debug("Whisker client version: {}".format(whisker.version.VERSION))
        if in_bundle:
            log.debug("Running inside a PyInstaller bundle")
        if args.gui:
            log.debug("Running in GUI-only mode")
        # if args.debug_qt_signals:
        #     enable_signal_debugging_simply()

        # ---------------------------------------------------------------------
        # Schema diagram generation only?
        # ---------------------------------------------------------------------
        if args.schema:
            umlfilename = args.schemastem + '.plantuml'
            log.info("Making schema PlantUML: {}".format(umlfilename))
            desc = sadisplay.describe(
                [getattr(models, attr) for attr in dir(models)])
            log.debug(desc)
            with open(umlfilename, 'w') as f:
                f.write(sadisplay.plantuml(desc))
            log.info("Making schema PNG: {}".format(args.schemastem + '.png'))
            cmd = [args.java, '-jar', args.plantuml, umlfilename]
            log.debug(cmd)
            subprocess.check_call(cmd)
            sys.exit(0)

        # ---------------------------------------------------------------------
        # Demo trial plan only?
        # ---------------------------------------------------------------------
        if args.testtrialplan:
            seqlen = args.seqlen
            if seqlen is None or seqlen < MIN_SEQUENCE_LENGTH:
                raise ValueError("--seqlen must be an integer >= {}".format(
                    MIN_SEQUENCE_LENGTH))
            tplist = SerialOrderTask.create_trial_plans(
                seqlen=seqlen,
                choice_hole_restriction=args.choice_hole_restriction,
                serial_pos_restriction=args.serial_pos_restriction,
                side_dwor_multiplier=args.side_dwor_multiplier)
            print("""
Explanation:
- there are 5 holes, numbered 1-5
- sequence: the sequence of hole numbers presented in the trial
    e.g. for a sequence length of 3, you might have sequence=(3, 1, 4),
    meaning that the subject will be shown hole 3, then hole 1, then hole 4,
    in the first phase
- hole_choice: the two holes presented during the choice phase
    e.g. hole_choice=[3,4]
- serial_order_choice: the serial order, in the first phase, of the two holes
    offered in the second (choice) phase -- in this example, you would get
    serial_order_choice=[1,3], because hole 3 was offered in the choice phase
    and was in position 1 in the sequence, and hole 4 was offered in the
    choice phase and was in position 3 in the sequence.
Hint: use grep to check the output.

Choice hole restrictions: {chr}
Serial position restrictions: {spr}
            """.format(
                chr=args.choice_hole_restriction,
                spr=args.serial_pos_restriction,
            ))
            for i, tp in enumerate(tplist, start=1):
                print("{}. {}".format(i, tp))
            sys.exit(0)

        # ---------------------------------------------------------------------
        # File output
        # ---------------------------------------------------------------------
        if args.outdir:
            set_output_directory(args.outdir)
        log.info("Using output directory: {}".format(get_output_directory()))
        if not os.access(get_output_directory(), os.W_OK):
            raise ValueError("Cannot write to output directory")

        # ---------------------------------------------------------------------
        # Database
        # ---------------------------------------------------------------------
        # Get URL, or complain
        if args.dburl:
            set_database_url(args.dburl)
        if args.dbecho:
            set_database_echo(args.dbecho)
        if not dbsettings['url']:
            if args.gui:
                win = NoDatabaseSpecifiedWindow()
                if args.guilog:
                    # noinspection PyUnboundLocalVariable
                    win.exit_kill_log.connect(log_window.exit)
                return run_gui(qt_app, win)
            raise ValueError(MSG_DB_ENV_VAR_NOT_SPECIFIED)
        log.debug("Using database URL: {}".format(dbsettings['url']))
        if database_is_sqlite(dbsettings):
            log.critical(
                "Avoid SQLite: not safe for concurrent use in this context")
            sys.exit(1)

        # Has the user requested a command-line database upgrade?
        if args.upgrade_database:
            sys.exit(
                upgrade_database(ALEMBIC_CONFIG_FILENAME, ALEMBIC_BASE_DIR))
        # Is the database at the correct version?
        (current_revision, head_revision) = get_current_and_head_revision(
            dbsettings['url'], ALEMBIC_CONFIG_FILENAME, ALEMBIC_BASE_DIR)
        if current_revision != head_revision:
            if args.gui:
                win = WrongDatabaseVersionWindow(current_revision,
                                                 head_revision)
                if args.guilog:
                    # noinspection PyUnboundLocalVariable
                    win.exit_kill_log.connect(log_window.exit)
                return run_gui(qt_app, win)
            raise ValueError(
                WRONG_DATABASE_VERSION_STUB.format(
                    head_revision=head_revision,
                    current_revision=current_revision))

        # ---------------------------------------------------------------------
        # Run app
        # ---------------------------------------------------------------------
        log.debug("Seeding random number generator")
        random.seed()
        win = MainWindow(dbsettings)
        if args.guilog:
            # noinspection PyUnboundLocalVariable
            win.exit_kill_log.connect(log_window.exit)
        return run_gui(qt_app, win)

    except:
        if args.guilog:
            log.critical(traceback.format_exc())
            log_window.set_may_close(True)
            return qt_app.exec_()
        else:
            raise