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)
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))
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)
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)
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))
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)
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)
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))
) 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