예제 #1
0
    def pull_data(self,
                  my_conn: Optional[dict] = None,
                  t_log: Optional[TimeLogger] = None,
                  verbose: bool = False):
        """Method to pull data from database"""
        table = self.name

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        sql = "SELECT * FROM {tbl}"
        query = SQL(sql).format(tbl=Identifier(table))

        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']

        out_data = read_sql(query, con=conn, index_col='type_name')

        if verbose:
            t_log.new_event('Extracting records from Table: ' + table)

        return out_data
예제 #2
0
def available_templates(my_conn: Optional[dict] = None, t_log: Optional[TimeLogger] = None,
                        verbose: bool = False) -> TemplateIDs:
    """Function to pull available templates from ddtatbase"""

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']

    if verbose is True:
        print('Extracting available Templates')

    if verbose is True:
        t_log.new_event('Connecting to Templates on Database')

    cur = conn.cursor()
    try:
        cur.execute('SELECT id FROM template ORDER BY created_at')
    except DatabaseError as error:
        print("Couldn't retrieve templates", error)

    output = cur.fetchall()
    cur.close()

    template_ids = TemplateIDs([x[0] for x in output])

    if verbose is True:
        t_log.new_event('Finished Extracting Data')

    return template_ids
예제 #3
0
    def delete(self,
               id_tup: Tuple,
               my_conn: Optional[dict] = None,
               t_log: Optional[TimeLogger] = None,
               verbose: bool = False):
        """Method to Insert New Equation Records"""
        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']
        cur = conn.cursor()

        sql: str = 'DELETE FROM {table} WHERE id IN ({values});'
        query = SQL(sql).format(values=SQL(', ').join(map(Literal, id_tup)),
                                table=Identifier(self.name))

        self.pull_data()

        if verbose is True:
            t_log.new_event("execute_values() done")
        try:
            cur.execute(query, id_tup)
            conn.commit()
        except DatabaseError as error:
            print("Error: %s" % error)
            conn.rollback()
            cur.close()
    def update_insertion_order_for_selected(self,
                                            order: dict,
                                            my_conn: Optional[dict] = None,
                                            t_log: Optional[TimeLogger] = None,
                                            verbose: bool = False):
        """Populates insertion_order attribute"""
        self.pull_grouped_data()
        df = self.selected_data_df()

        join_table: str = self.table_name + '_' + self.parent_table_name

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.my_conn = my_conn
        conn = my_conn['conn']

        sql = 'UPDATE {table} SET insertion_order = %s WHERE ({c_table_id}, {p_table_id}) = (%s, %s)'

        query = SQL(sql).format(table=Identifier(join_table),
                                c_table_id=Identifier(self.id_name()),
                                p_table_id=Identifier(
                                    self.parent_table_id_name()))

        cur = conn.cursor(cursor_factory=NamedTupleCursor)

        if verbose is True:
            t_log.new_event('Updating Insertion order for: ' + join_table)
            print(query.as_string(conn))

        for eq_name, i in order.items():
            p_id = self.selected_parent_id
            c_id = int(df.name[df.name == eq_name].index[0])

            if verbose:
                print(cur.mogrify(query, (i, c_id, p_id)))
            try:
                cur.execute(query, (i, c_id, p_id))
            except OperationalError as error:
                print(error)

        conn.commit()

        self.pull_grouped_data()

        if verbose is True:
            t_log.new_event('Finished Updating Insertion Order: ' + join_table)
예제 #5
0
def generic_new_record_db(table_name: str = None, data_df: Optional[DataFrame] = None,
                          name: str = None, new_record=None, notes: str = None,
                          created_by: str = None,  my_conn: Optional[dict] = None,
                          t_log: Optional[TimeLogger] = None, verbose: bool = None) -> DataFrame:
    """Insert New Record Into math_object"""

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']
    db_params = my_conn['db_params']

    if new_record is None:
        new_record = {}

    next_id: int = generic_record_count(data_df) + 1

    if name is None:
        name = "{aTable} {ID:d}".format(ID=next_id, aTable=table_name)
    if created_by is None:
        created_by = db_params['user']

    new_record.update(name=name, notes=notes, created_by=created_by)

    query = SQL('INSERT INTO {table} ({fields}) VALUES ({values})'
                ).format(table=Identifier(table_name),
                         fields=SQL(', ').join(map(Identifier, new_record.keys())),
                         values=SQL(', ').join(map(Placeholder, new_record.keys())))

    if verbose:
        print(query.as_string(conn))

    cur = conn.cursor(cursor_factory=NamedTupleCursor)

    if verbose:
        t_log.new_event('Adding new record to Table: {aTable}'.format(aTable=table_name))

    try:
        cur.execute(query, new_record)
    except OperationalError as error:
        print(error)

    # new_records = cur.fetchall()
    conn.commit()
    cur.close()

    updated_df = \
        generic_pull_data(table_name=table_name, my_conn=my_conn, t_log=t_log, verbose=verbose)

    return updated_df
예제 #6
0
    def delete_types(self,
                     types,
                     my_conn: Optional[dict] = None,
                     t_log: Optional[TimeLogger] = None,
                     verbose: bool = False):
        """Method to Insert New Equation Records"""
        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']
        cur = conn.cursor()

        if verbose is True:
            t_log.new_event(type(types))
            if isinstance(types, str):
                print('you are here')
                types = tuple([types])

        sql: str = 'DELETE FROM {table} WHERE type_name IN ({values});'
        query = SQL(sql).format(values=SQL(', ').join(map(Literal, types)),
                                table=Identifier(self.name))

        if verbose is True:
            print(query.as_string(cur))
            t_log.new_event('Values' + str(types))
            t_log.new_event('Pulling Data for: ' + self.name)

        try:
            cur.execute(query, types)
            conn.commit()
        except DatabaseError as error:
            print("Error: %s" % error)
            conn.rollback()
            cur.close()

        self.reinitialize_types_df(my_conn=my_conn,
                                   t_log=t_log,
                                   verbose=verbose)

        if verbose is True:
            t_log.new_event("execute_values() done")

        cur.close()
def generic_disassociate_parent(parent_id: int = None,
                                child_id: int = None,
                                table_name: str = None,
                                parent_table_name: str = None,
                                my_conn: Optional[dict] = None,
                                t_log: Optional[TimeLogger] = None,
                                verbose: bool = False):
    """Associate the parent and child tables using parent id. Insertion_order and inserted_by are optional"""
    parent_key = parent_table_name + '_id'
    self_key = table_name + '_id'

    join_table = table_name + '_' + parent_table_name

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']

    sql = 'DELETE FROM {table} WHERE ({self_id}, {parent_id}) = (%s, %s)'

    query = SQL(sql).format(table=Identifier(join_table),
                            self_id=Identifier(self_key),
                            parent_id=Identifier(parent_key))

    cur = conn.cursor(cursor_factory=NamedTupleCursor)

    if verbose is True:
        print(query.as_string(conn))
        print(cur.mogrify(query, (child_id, parent_id)))
        t_log.new_event('Disassociating Tables: ' + join_table)

    try:
        cur.execute(query, (child_id, parent_id))
    except OperationalError as error:
        print(error)

    conn.commit()

    data_df = \
        generic_pull_grouped_data(table_name=table_name, parent_table_name=parent_table_name,
                                  my_conn=my_conn, t_log=t_log, verbose=verbose)

    if verbose is True:
        t_log.new_event('Finished disassociating: ' + join_table)

    return data_df
def generic_pull_grouped_data(table_name: str = None,
                              parent_table_name: str = None,
                              verbose: bool = False,
                              my_conn: Optional[dict] = None,
                              t_log: Optional[TimeLogger] = None) -> DataFrame:
    """Multi-index Extract DataFrame DB"""

    table_id_name: str = table_name + '_id'
    parent_id_name: str = parent_table_name + '_id'
    join_table: str = table_name + '_' + parent_table_name

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']

    sql = 'SELECT * FROM {join_table} RIGHT JOIN {table} USING({table_id})'

    query = SQL(sql).format(table=Identifier(table_name),
                            join_table=Identifier(join_table),
                            table_id=Identifier(table_id_name))

    if verbose is True:
        t_log.new_event('Loading Database: ' + table_name)

    data_df = read_sql(query,
                       con=conn,
                       index_col=[parent_id_name, table_id_name])
    # This was a good example of loading objects to file
    # data_df['latex'] = data_df['latex'].apply(loads)

    data_df['latex_obj'] = None

    for row in data_df.itertuples():
        data_df.loc[row.Index, 'latex_obj'] = \
            LatexData(my_conn=my_conn, latex=row.latex, template_id=row.template_id,
                      image=row.image, compiled_at=row.compiled_at)

    data_df.sort_values([parent_id_name, 'insertion_order', 'created_at'],
                        inplace=True)

    if verbose is True:
        t_log.new_event('Database Loaded: ' + table_name)

    return data_df
    def other_parents(self,
                      child_id: int = None,
                      my_conn: Optional[dict] = None,
                      t_log: Optional[TimeLogger] = None,
                      verbose: bool = None):
        """Pulls list of other parents"""
        gd = self.grouped_data
        gd_inds = gd.index.dropna()
        if len(gd_inds) > 0:
            parent_df = gd.loc[(slice(None),
                                child_id), :].droplevel(self.id_name())
            pids = tuple(parent_df.index.to_list())

            if verbose is True and t_log is None:
                t_log = TimeLogger()

            if my_conn is None:
                my_conn = self.my_conn
            else:
                self.my_conn = my_conn

            my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
            conn = my_conn['conn']

            sql = "SELECT * FROM {parent_table} WHERE {parent_id} IN %s;"

            query = SQL(sql).format(
                parent_table=Identifier(self.parent_table_name),
                parent_id=Identifier(self.parent_table_id_name()))

            if verbose is True:
                t_log.new_event('Loading Database: ' + self.parent_table_name)

            cur = conn.cursor(cursor_factory=NamedTupleCursor)

            cur.execute(query, (pids, ))
            records = cur.fetchall()
            if verbose is True:
                t_log.new_event('Database Loaded: ' + self.parent_table_name)
        else:
            if verbose is True:
                t_log.new_event('No Other Parents')
            records = []

        return records
예제 #10
0
    def new_record(self,
                   new_record: TemplateRecordInput,
                   my_conn: Optional[dict] = None,
                   t_log: Optional[TimeLogger] = None,
                   verbose: bool = False):
        """Method to Insert New Equation Records"""
        table_name = self.name

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']

        query = SQL('INSERT INTO {table} ({fields}) VALUES ({values})').format(
            table=Identifier(table_name),
            fields=SQL(', ').join(map(Identifier, new_record._fields)),
            values=SQL(', ').join(map(Placeholder, new_record._fields)))

        if verbose:
            t_log.new_event(query.as_string(conn))

        cur = conn.cursor(cursor_factory=NamedTupleCursor)

        if verbose:
            t_log.new_event('Adding new record to Table: {aTable}'.format(
                aTable=table_name))

        try:
            cur.execute(query, new_record._asdict())
        except DatabaseError as error:
            print(error)

        conn.commit()

        cur.close()

        self.pull_data()
예제 #11
0
    def insert(self,
               new_data,
               my_conn: Optional[dict] = None,
               t_log: Optional[TimeLogger] = None,
               verbose: bool = False):
        """Method to Insert New Equation Records"""

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']

        cur = conn.cursor()

        self.types_df = self.types_df.append(new_data)

        sql = 'INSERT INTO {table} (type_name) VALUES %s;'
        query = SQL(sql).format(table=Identifier(self.name))

        tuples = [tuple([x]) for x in new_data.index]

        if verbose is True:
            print(query.as_string(cur))
            print('Values', tuples)
            t_log.new_event('Loading: ' + self.name)

        try:
            execute_values(cur, query, tuples)
            conn.commit()
        except DatabaseError as error:
            print("Error: %s" % error)
            conn.rollback()
            cur.close()

        if verbose is True:
            t_log.new_event("execute_values() done")
        cur.close()
예제 #12
0
def template(my_conn: Optional[dict] = None, t_log: Optional[TimeLogger] = None,
             version: int = None, verbose: bool = False) -> NamedTupleCursor:
    """Function to pull the data for a specified template"""

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']

    cur = conn.cursor(cursor_factory=NamedTupleCursor)

    if version is None:
        if verbose:
            t_log.new_event('Extracting Latest Template from Database')

        cur.execute('SELECT * FROM template ORDER BY created_at DESC LIMIT 1')
    else:
        try:
            if verbose:
                t_log.new_event('Extracting Template with id: {} from Database'.format(version))

            cur.execute('SELECT * FROM template WHERE ID=%s', (version,))
        except DatabaseError as error:
            print("Couldn't retrieve that template.", error)
            print("Returning latest template.")
            cur.execute('SELECT * FROM template ORDER BY created_at DESC LIMIT 1')

    if verbose:
        t_log.new_event('Starting Template Extraction')

    the_template = cur.fetchone()
    cur.close()

    if verbose:
        t_log.new_event('Finished Template Extraction')

    return the_template
예제 #13
0
def generic_pull_data(table_name: str = None, my_conn: Optional[dict] = None,
                      t_log: Optional[TimeLogger] = None, verbose: bool = None) -> DataFrame:
    """Multi-index Extract DataFrame DB"""

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']

    table_id_name: str = table_name + '_id'

    query = SQL('SELECT * FROM {table}').format(table=Identifier(table_name))

    if verbose is True:
        t_log.new_event('Loading Equation Group Data')

    data_df = read_sql(query, con=conn, index_col=table_id_name)

    if verbose is True:
        t_log.new_event('Finished Equation Group Data')

    return data_df
예제 #14
0
    def update(self, an_id: id = None, where_key: str = None, name: str = None, data=None, notes: str = None,
               modified_by: str = None, created_by: str = None, my_conn: Optional[dict] = None,
               t_log: Optional[TimeLogger] = None, verbose: bool = None):
        """Insert New Record Into grouped_physics_object"""

        if my_conn is None:
            my_conn = self.my_conn
        else:
            self.my_conn = my_conn

        if verbose is True and t_log is None:
            t_log = TimeLogger()

        my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
        conn = my_conn['conn']
        db_params = my_conn['db_params']

        if where_key is None:
            where_key = self.id_name()

        if an_id is None:
            warn("No Record ID Specified", NoRecordIDError)
        else:
            if data is None:
                data = {}

            data.update(add_field('name', name))
            data.update(add_field('notes', notes))
            data.update(add_field('created_by', created_by))

            # If there is no data, then skip. Of course one could still change modified by:
            if len(data) > 0 or modified_by is not None:

                # Always require a modified by and because one can change data without specifying a modifer,
                # this is necessary. We don't check it before the previous if, because we don't want to create
                # a modified_by if not data was set and no modified_by was set.
                if modified_by is None:
                    modified_by = db_params['user']

                data.update(modified_by=modified_by)

                fields = data.keys()

                sql = "UPDATE {table} SET {fields} WHERE {pkey} = {a_value}"

                if verbose:
                    print('Data:\n', data)
                    print('\nFields:\n', fields)

                query = SQL(sql).format(
                    table=Identifier(self.table_name),
                    fields=SQL(', ').join(
                        Composed([Identifier(k), SQL(' = '), Placeholder(k)]) for k in fields
                    ),
                    pkey=Identifier(where_key),
                    a_value=Placeholder('where_key')
                )

                data.update(where_key=an_id)

                cur = conn.cursor(cursor_factory=NamedTupleCursor)

                if verbose:
                    print(query.as_string(conn))
                    print(cur.mogrify(query, data))

                try:
                    cur.execute(query, data)
                except OperationalError as error:
                    print(error)

                conn.commit()

                cur.close()

                self.pull_data()
def generic_associate_parent(parent_id: int = None,
                             child_id: int = None,
                             table_name: str = None,
                             parent_table_name: str = None,
                             insertion_order: int = None,
                             inserted_by: str = None,
                             new_record: dict = None,
                             verbose: bool = False,
                             my_conn: Optional[dict] = None,
                             t_log: Optional[TimeLogger] = None):
    """Associate the parent and child tables using parent id. Insertion_order and inserted_by are optional"""
    parent_key = parent_table_name + '_id'
    self_key = table_name + '_id'

    join_table = table_name + '_' + parent_table_name

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']
    db_params = my_conn['db_params']

    if new_record is None:
        new_record = {}

    if inserted_by is None:
        inserted_by = db_params['user']

    new_record.update({
        parent_key: parent_id,
        self_key: child_id
    },
                      insertion_order=insertion_order,
                      inserted_by=inserted_by)

    sql = 'INSERT INTO {table} ({fields}) VALUES ({values})'

    keys = new_record.keys()

    query = SQL(sql).format(table=Identifier(join_table),
                            fields=SQL(', ').join(map(Identifier, keys)),
                            values=SQL(', ').join(map(Placeholder, keys)))

    cur = conn.cursor(cursor_factory=NamedTupleCursor)

    if verbose is True:
        t_log.new_event('Associating Tables: ' + join_table)

    try:
        cur.execute(query, new_record)
    except OperationalError as error:
        print(error)

    conn.commit()
    cur.close()

    data_df = \
        generic_pull_grouped_data(table_name=table_name, parent_table_name=parent_table_name,
                                  my_conn=my_conn, t_log=t_log, verbose=verbose)

    if verbose is True:
        t_log.new_event('Finished Associating: ' + join_table)

    return data_df
def generic_new_record_db(parent_id: int = None,
                          table_name: str = None,
                          parent_table_name: str = None,
                          data_df: Optional[DataFrame] = None,
                          name: str = None,
                          new_record=None,
                          latex: LatexData = None,
                          notes: str = None,
                          dimensions: int = 1,
                          insertion_order: int = None,
                          created_by: str = None,
                          unit_id: int = 1,
                          verbose: bool = None,
                          my_conn: Optional[dict] = None,
                          t_log: Optional[TimeLogger] = None) -> DataFrame:
    """Insert New Record Into math_object"""

    if verbose is True and t_log is None:
        t_log = TimeLogger()

    if new_record is None:
        new_record = {}

    my_conn = my_connect(my_conn=my_conn, t_log=t_log, verbose=verbose)
    conn = my_conn['conn']
    db_params = my_conn['db_params']

    table_id = table_name + '_id'
    next_id: int = generic_last_equation_number(data_df) + 1

    if name is None:
        name = "{aTable} {ID:d}".format(ID=next_id, aTable=table_name)
    if created_by is None:
        created_by = db_params['user']

    if latex is None:
        latex = LatexData()

    new_record.update(name=name,
                      notes=notes,
                      dimensions=dimensions,
                      unit_id=unit_id,
                      type_name='Unassigned',
                      latex=latex.latex,
                      image=latex.image,
                      compiled_at=latex.compiled_at,
                      template_id=latex.template_id,
                      created_by=created_by)

    query = SQL(
        'INSERT INTO {table} ({fields}) VALUES ({values}) RETURNING *').format(
            table=Identifier(table_name),
            fields=SQL(', ').join(map(Identifier, new_record.keys())),
            values=SQL(', ').join(map(Placeholder, new_record.keys())))

    if verbose:
        print(query.as_string(conn))

    cur = conn.cursor(cursor_factory=NamedTupleCursor)

    if verbose:
        print('Adding new record to Table: {aTable}'.format(aTable=table_name))

    try:
        cur.execute(query, new_record)
    except OperationalError as error:
        print(error)

    new_records = cur.fetchall()
    conn.commit()
    cur.close()
    updated_df: Optional[DataFrame] = None

    if parent_id is not None:
        for record in new_records:
            updated_df = generic_associate_parent(
                my_conn=my_conn,
                t_log=t_log,
                parent_id=parent_id,
                child_id=getattr(record, table_id),
                insertion_order=insertion_order,
                table_name=table_name,
                parent_table_name=parent_table_name,
                inserted_by=created_by,
                verbose=verbose)
    else:
        updated_df = \
            generic_pull_grouped_data(table_name=table_name, parent_table_name=parent_table_name,
                                      my_conn=my_conn, t_log=t_log, verbose=verbose)

    return updated_df
예제 #17
0
def compile_pattern(pattern: str = 'm^3', keep: bool = True, temp_fname: str = "eq_db", version: int = None,
                    a_template: str = None, verbose: bool = False,
                    my_conn: Optional[dict] = None, t_log: Optional[TimeLogger] = None) -> bytes:
    """General Latex Compile Function"""

    if verbose:
        if t_log is None:
            t_log = TimeLogger()
        print('\tArguments:')
        pprint.PrettyPrinter(indent=12).pprint(locals())

    if a_template is None:
        a_template_record = template(version=version, my_conn=my_conn, t_log=t_log, verbose=verbose)
        a_template = a_template_record.data

    this_path = Path.cwd()
    if this_path.name == 'CustomWidgets':
        os.chdir('../LaTeX')
    elif this_path.name == 'equation_database':
        os.chdir('LaTeX')
    else:
        warn('Unrecognized Directory')

    # preprocess pattern to make sure it conforms to latex
    processed_pattern = pattern.strip()

    text_file = open(temp_fname+'.tex', "w")
    text_file.write(a_template.replace('%__REPLACEMENT__TEXT', processed_pattern))
    text_file.close()

    # try:
    if verbose:
        print("Operating System: ", os.name)
        t_log.new_event('Executing XeLaTeX:')

    shell = os.name == 'nt'

    try:
        p_1 = subprocess.run(['xelatex.exe', temp_fname + '.tex', '-interaction=batchmode'],
                             shell=shell, capture_output=True, text=True, check=True)

        if verbose:
            pprint.PrettyPrinter(indent=8).pprint(p_1)
    except subprocess.CalledProcessError as error:
        print(error.output)

    try:
        if verbose:
            t_log.new_event('Converting to png')

        p_2 = subprocess.run(['convert.exe', '-density', '300', '-depth', '8', '-quality', '85', temp_fname + '.pdf',
                             'png32:'+temp_fname+'.png'], shell=shell, capture_output=True, text=True, check=True)

        if verbose:
            t_log.new_event('Finished converting png')
            pprint.PrettyPrinter(indent=8).pprint(p_2)

    except subprocess.CalledProcessError as error:
        t_log.new_event('Failed to make png:')
        print(error.output)

    if verbose:
        t_log.new_event('Pulling png data into python')

    with open(temp_fname + '.png', 'rb') as file:
        png_data: bytes = file.read()

    os.chdir(this_path)

    if keep is False:
        clean_files(temp_fname)

    return png_data
    def __init__(self, *args, **kwargs):
        self.app = QApplication(sys.argv)
        super().__init__(*args, **kwargs)

        # Some good colors:
        # #afbcc6, #b9afc6, #afb0c6
        self.title = "Equation Database"
        self.left = WINDOW_LEFT_START
        # self.left = 0
        self.top = WINDOW_TOP_START
        self.height = WINDOW_HEIGHT
        self.width = int(self.height * golden_ratio)

        # region ToolBar
        self.toolbar = self.addToolBar('Save')
        self.toolbar.setIconSize(QSize(128, 128))

        save_action = QAction(QIcon('Icons/save_button_256x256.png'), '&Save', self)
        save_action.setShortcut('Ctrl+S')
        save_action.setStatusTip('Save Equation Group')

        analyze_action = QAction(QIcon('Icons/analyze_cog_512x512.png'), '&Analyze', self)
        analyze_action.setShortcut('Alt+A')
        analyze_action.setStatusTip('Analyze Equation Group')

        new_eqn_action = QAction(QIcon('Icons/sigma_icon_256x256.png'), '&New Equation', self)
        new_eqn_action.setShortcut('Ctrl+N')
        new_eqn_action.setStatusTip('New Equation')

        new_eqn_group_action = QAction(QIcon('Icons/new_eq_group_1000x1000.png'), '&New Equation Group', self)
        new_eqn_group_action.setShortcut('Alt+N')
        new_eqn_group_action.setStatusTip('New Equation Group')
        new_eqn_group_action.triggered.connect(self.new_equation_group)

        eqn_group_info_action = QAction(QIcon('Icons/info_icon256x256.png'), '&Equation Group Information', self)
        eqn_group_info_action.setShortcut('Alt+I')
        eqn_group_info_action.setStatusTip('Equation Group Information')

        self.toolbar.addAction(save_action)
        self.toolbar.addAction(new_eqn_action)
        empty1 = QWidget(self.toolbar)
        ew: int = 50  # pylint: disable=invalid-name
        empty1.setFixedWidth(ew)
        empty2 = QWidget(self.toolbar)
        empty2.setFixedWidth(ew)
        self.toolbar.addWidget(empty1)
        self.toolbar.addSeparator()
        self.toolbar.addWidget(empty2)
        self.toolbar.addAction(new_eqn_group_action)
        self.toolbar.addAction(analyze_action)
        self.toolbar.addAction(eqn_group_info_action)

        # endregion
        t_log = TimeLogger()

        verbose = True
        my_conn = my_connect(t_log=t_log, verbose=verbose)
        self.my_conn = my_conn

        t_log.new_event("Start Gui Build: ")

        # region Equation Group - Left Frame
        # -----------------------------------------------------------------------------------------------------------
        self.eq_group_gbox = QGroupBox("Equation Group")
        self.eq_group_gbox.setMinimumWidth(200)
        self.eq_group_v_layout = QVBoxLayout(self.eq_group_gbox)
        self.eq_group_v_layout.setSpacing(5)

        self.eq_group_cbox = QComboBox(self.eq_group_gbox)
        self.eq_group_cbox.activated.connect(self.populate_equation_listbox)

        self.eq_group_v_layout.addWidget(self.eq_group_cbox)

        self.analyze_frame = QFrame(self.eq_group_gbox)
        self.analyze_h_layout = QHBoxLayout(self.analyze_frame)
        self.analyze_h_layout.setContentsMargins(10, 0, 10, 15)
        size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.analyze_frame.setSizePolicy(size_policy)

        self.equation_filter_list = EDFilterListWidget(self.eq_group_gbox)
        self.equation_listbox = self.equation_filter_list.list
        # self.equation_listbox = QListWidget(self.eq_group_gbox)
        self.equation_listbox.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.equation_listbox.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.equation_listbox.selectionModel().selectionChanged.connect(self.select_one_equation)
        self.equation_filter_list.add.connect(self.add_equation)
        self.equation_filter_list.remove.connect(self.remove_equation)

        self.eq_group_v_layout.addWidget(self.equation_filter_list)
        # endregion

        # region Equation Details - Right Frame
        # -----------------------------------------------------------------------------------------------------------
        self.eq_details_gbox = QGroupBox("Equation Details")  # Entire encapsulating Gbox
        self.eq_details_v_layout = QVBoxLayout(self.eq_details_gbox)

        # region Equation Header added to Equation Details
        # **********************************************************
        self.eq_header_frame = QFrame()
        size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.eq_header_frame.setSizePolicy(size_policy)
        self.eq_header_g_layout = QGridLayout(self.eq_header_frame)
        self.eq_details_v_layout.addWidget(self.eq_header_frame)

        self.name_label = QLabel("Equation Name")
        self.name_l_edit = QLineEdit()
        self.eq_header_g_layout.addWidget(self.name_label, 0, 0)
        self.eq_header_g_layout.addWidget(self.name_l_edit, 0, 1)

        self.codefile_label = QLabel("Code File")
        self.codefile_l_edit = QLineEdit()
        self.eq_header_g_layout.addWidget(self.codefile_label, 1, 0)
        self.eq_header_g_layout.addWidget(self.codefile_l_edit, 1, 1)

        self.type_label = QLabel("Type")
        self.type_cbox = QComboBox()
        self.type_cbox.setMinimumWidth(700)
        self.eq_header_g_layout.addWidget(self.type_label, 0, 2)
        self.eq_header_g_layout.addWidget(self.type_cbox, 0, 3)

        self.associated_eq_groups_btn = EquationButton("Associated Eq Groups")
        self.eq_header_g_layout.addWidget(self.associated_eq_groups_btn, 1, 3)
        self.eq_header_g_layout.setAlignment(self.associated_eq_groups_btn, Qt.AlignLeft)
        self.details_btn = EquationButton("Other Details")
        self.eq_header_g_layout.addWidget(self.details_btn, 1, 3)
        self.eq_header_g_layout.setAlignment(self.details_btn, Qt.AlignRight)
        # endregion

        # region LaTeX added to Equation Details
        # **********************************************************

        self.latex_gbox = QGroupBox("LaTeX")
        size_policy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.latex_gbox.setSizePolicy(size_policy)
        self.latex_v_layout = QVBoxLayout(self.latex_gbox)

        # This would be great for when one wants to filter content based on what is being typed
        # self.latex_textbox.textChanged.connect(self.update_latex_image)

        self.latex_graphicbox = QGraphicsView(self.latex_gbox)
        self.scene = QGraphicsScene()
        self.latex_graphicbox.setScene(self.scene)
        # self.latex_graphicbox.setMinimumSize(QSize(907, 369))

        self.latex_textbox = LaTexTextEdit(my_conn=my_conn, parent=self.latex_gbox, t_log=t_log, scene=self.scene,
                                           graphics_view=self.latex_graphicbox, verbose=verbose)

        self.latex_splitter = Customsplitter(Qt.Vertical)  # Note Handle for a vert splitter is oriented Horizontally
        self.latex_splitter.addWidget(self.latex_textbox)
        self.latex_splitter.addWidget(self.latex_graphicbox)
        self.latex_v_layout.addWidget(self.latex_splitter)

        self.latex_btn_frame = QFrame()
        size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.latex_btn_frame.setSizePolicy(size_policy)
        self.latex_btn_h_layout = QHBoxLayout(self.latex_btn_frame)
        self.latex_btn_h_layout.setContentsMargins(0, 0, 1, 10)
        self.latex_template_btn = EquationButton("Template")
        self.latex_update_btn = EquationButton("Update")
        h_spacer = QSpacerItem(20, 40, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding)
        self.latex_btn_h_layout.addWidget(self.latex_template_btn)
        self.latex_btn_h_layout.addItem(h_spacer)
        self.latex_btn_h_layout.addWidget(self.latex_update_btn)
        self.latex_v_layout.addWidget(self.latex_btn_frame)

        # endregion

        # region Variables Notes
        self.var_notes_frame = QFrame(self.eq_details_gbox)
        self.var_notes_v_layout = QVBoxLayout(self.var_notes_frame)
        # self.var_notes_frame.setLayout(self.var_notes_v_layout)

        self.variables_gbox = QGroupBox("Variables")
        self.variables_v_layout = QVBoxLayout(self.variables_gbox)
        self.variables_v_layout.setSpacing(5)
        # self.variables_gbox.setLayout(self.var_notes_v_layout)
        self.variables_tbl = QTableWidget(self.variables_gbox)
        self.variables_v_layout.addWidget(self.variables_tbl)

        self.var_add_btn = QPushButton("+")
        self.var_add_btn.setObjectName("add_rm_btn")
        ar_w = 50
        self.var_add_btn.setFixedSize(QSize(ar_w, int(ar_w)))
        self.var_add_btn.clicked.connect(self.add_variable)

        self.var_rm_btn = QPushButton("-")
        self.var_rm_btn.setObjectName("add_rm_btn")
        self.var_rm_btn.clicked.connect(self.remove_variable)
        self.var_rm_btn.setFixedSize(QSize(ar_w, int(ar_w)))

        self.var_add_rm_frame = QFrame(self.variables_gbox)
        size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.var_add_rm_frame.setSizePolicy(size_policy)
        self.var_add_rm_h_layout = QHBoxLayout(self.var_add_rm_frame)
        self.var_add_rm_h_layout.setSpacing(2)
        h_spacer = QSpacerItem(20, 40, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding)
        self.var_add_rm_h_layout.addItem(h_spacer)
        self.var_add_rm_h_layout.addWidget(self.var_add_btn)
        self.var_add_rm_h_layout.addWidget(self.var_rm_btn)
        self.variables_v_layout.addWidget(self.var_add_rm_frame)

        self.notes_gbox = QGroupBox("Notes")
        self.notes_v_layout = QVBoxLayout(self.notes_gbox)
        # self.notes_gbox.setLayout(self.notes_v_layout)
        self.notes_textbox = QTextEdit(self.notes_gbox)
        self.notes_v_layout.addWidget(self.notes_textbox)

        self.notes_btn_frame = QFrame()
        size_policy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed)
        self.notes_btn_frame.setSizePolicy(size_policy)
        self.notes_btn_h_layout = QHBoxLayout(self.notes_btn_frame)
        self.notes_btn_h_layout.setContentsMargins(0, 0, 1, 10)
        self.notes_update_btn = EquationButton("Update")
        h_spacer = QSpacerItem(20, 40, QSizePolicy.MinimumExpanding, QSizePolicy.Expanding)
        self.notes_btn_h_layout.addItem(h_spacer)
        self.notes_btn_h_layout.addWidget(self.notes_update_btn)
        self.notes_v_layout.addWidget(self.notes_btn_frame)

        self.var_notes_vsplt = Customsplitter(Qt.Vertical)
        self.var_notes_vsplt.addWidget(self.variables_gbox)
        self.var_notes_vsplt.addWidget(self.notes_gbox)
        self.var_notes_v_layout.addWidget(self.var_notes_vsplt)

        # endregion

        self.detail_v_splitter = Customsplitter()
        self.detail_v_splitter.addWidget(self.latex_gbox)
        self.detail_v_splitter.addWidget(self.var_notes_frame)
        self.detail_v_splitter.setSizes([int(self.width * 0.7 * 0.5), int(self.width * 0.7 * 0.5)])
        self.eq_details_v_layout.addWidget(self.detail_v_splitter)

        # endregion

        # region Main Splitter splits the equation groups list view from the details view
        # -----------------------------------------------------------------------------------------------------------
        self.main_splitter = Customsplitter()
        self.main_splitter.addWidget(self.eq_group_gbox)
        self.main_splitter.addWidget(self.eq_details_gbox)
        self.main_splitter.setSizes([int(self.width * 0.3), int(self.width * 0.7)])
        # endregion

        # region Main Window Creation
        self.main_frame = QFrame()
        self.main_layout = QVBoxLayout(self.main_frame)
        self.main_layout.addWidget(self.main_splitter)

        self.setCentralWidget(self.main_frame)

        self.setGeometry(self.left, self.top, self.width, self.height)

        self.setWindowTitle(self.title)
        app_icon = QIcon("Icons/sigma_icon.png")
        self.setWindowIcon(app_icon)
        self.app.setStyle('Oxygen')
        # endregion

        # region Data members

        t_log.new_event("End GUI Build")

        self.state_data = dict()
        # t_log.new_event("Equation Group Load")
        self.eqn_grp = EquationGroup(my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.eq = GroupedEquations(my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.var = GroupedVariables(my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.unit = Unit(my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.eq_type = TypeTable(name='equation_type', my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.var_type = TypeTable(name='variable_type', my_conn=my_conn, t_log=t_log, verbose=verbose)
        self.unit_type = TypeTable(name='unit_type', my_conn=my_conn, t_log=t_log, verbose=verbose)

        t_log.new_event("Data Finished Loading")

        self.eq_grp_id: int = 1  # Can envision it pulling user specified state information someday
        self.eqn_records_for_eqn_group = None  # Gets Populated when equations are present
        self.eq_id: tuple = (1,)  # Same comment as eq_grp_id
        self.var_records_for_eqns = None  # Gets populated when eqn_group_gets selected
        self.selected_equation = None  # Stores the selected equation
        self.latex_textbox.db_ref = self.eq
        self.equation_taken: bool = False

        t_log.new_event("Populating Boxes")
        self.refresh_eqn_group_combo_box()
        self.populate_equation_listbox()
        t_log.new_event("Populating Boxes")
        self.app.setStyleSheet(open('equation_db.css').read())
        t_log.new_event("Finished Style Sheet")
        print()
        print('Total Time: ', t_log.total_time())
from equation_group_dialog import EquationGroupDialog
from equation_dialog import EquationDialog
from equations import GroupedEquations  # , EquationRecord
from variables import GroupedVariables, GroupedVariableRecord
from variable_dialog import VariableDialog
from CustomWidgets.filter_list_widget import EDFilterListWidget
from unit import Unit
from type_table import TypeTable
from time_logging import TimeLogger

WINDOW_LEFT_START = 300
WINDOW_TOP_START = 300
WINDOW_HEIGHT = 1500

if platform.system() == "Windows":
    outer_log = TimeLogger()
    outer_log.new_event('Starting Windows Stuff: ')

    displays = screeninfo.get_monitors()

    if len(displays) == 2:
        WINDOW_LEFT_START = 3200
        WINDOW_TOP_START = 25
        WINDOW_HEIGHT = 900
    elif len(displays) == 3:
        my_mon = displays[2]
        WINDOW_LEFT_START = my_mon.x + int(my_mon.width / 20)
        WINDOW_TOP_START = 300
        WINDOW_HEIGHT = 1500

    # for item in obj: