Ejemplo n.º 1
0
def insertOrUpdate(db: str,
                   tableName: str,
                   dataFile: str,
                   conReplaceRules=None,
                   writeToNewFormat: bool = True):
    """
    inserta o actualiza en contenido del fichero json dataFile en tableName de
        la base de datos db
    args:
        ...
        conReplaceRules: connexión a una base de datos sqlite3

    dataFile es el fichero json que se descarga de aemet. Cada registro de
        dataFile puede tener un contenido variable de columnas (campos), dentro
        de las definidas en el fichero de metadatos; no haycampos nulos
    Algún campo puede tener valores que no coinciden con la definición dada por
        aemet -por ej. el campo prec se declara como real, pero puede tener
        valores Ip-; en este caso se sustituye el valor incorrecto por otro
        definido en FILEPARAM. Estas reglas de sustitución se pasan en el
        arg. conReplaceRules
    writeToNewFormat. si True, comprueba e inserta los datos en dataFile; si
        False sólo comprueba que se leen bien los datos
    """
    import json
    from os.path import split
    import sqlite3
    columnsInTable = namesTypesSqliteTable(db, tableName)
    stm1 = f'REPLACE INTO {tableName} '

    con = sqlite3.connect(db)
    cur = con.cursor()

    ierr = 0
    with open(dataFile) as fi:
        pathName = split(dataFile)
        data = json.load(fi)
        iline = 0
        for row in data:
            iline += 1
            columns = ','.join(row.keys())
            try:
                if conReplaceRules is None:
                    values = valuesInRow0(row, columnsInTable)
                else:
                    values = valuesInRow(row, columnsInTable, conReplaceRules)
                stm3 = stm1 + f'({columns}) VALUES {values}'
                if writeToNewFormat:
                    cur.execute(stm3)
            except ValueError as err:
                ierr += 1
                logging.append(f'File {pathName[1]}, line {iline:d}, '+\
                               f'error {err}')

    con.commit()
    con.close()
    print(f'{pathName[1]}, {ierr:d} errores en {iline:d} lineas')
Ejemplo n.º 2
0
    def __check_fks(self):
        """
        tests if foreign key columns values if file are in foregn keys
        """
        fk_errors = 0
        tcols = self.__table_column_get()
        names_table = [col1 for col1 in tcols]
        names_df = [col1 for col1 in self.data.columns]
        efks = self.table.findall('fk')
        for element in efks:
            # query column names
            q_cols = element.find('col').text.split(',')
            q_cols = [col1.strip() for col1 in q_cols]
            # check if q_cols are in names_df
            n = 0
            for col1 in q_cols:
                if col1 in names_df:
                    n += 1
            if len(names_df) != n:
                continue

            # foreign table column names
            fk_cols = element.find('fk_col').text.split(',')
            fk_cols = [col1.strip() for col1 in fk_cols]

            table = element.find('fk_table').text
            cols_in_select = ','.join(fk_cols)
            cols_in_where = [f'{col1}=%s' for col1 in fk_cols]
            cols_in_where = ','.join(cols_in_where)
            s1 = f'select {cols_in_select} from {table} where {cols_in_where}'
            if len(q_cols) == 1:
                values = set(df1['a'].values)
            else:
                values = []
                for i in range(len(self.data.index)):
                    r = tuple([self.data[col1].values[i] for col1 in q_cols])
                    values.append(r)
                values = tuple(set(values))
            not_found = 0
            for row in values:
                self.cur.execute(s1, row)
                r = self.cur.fetchone()
                if not r:
                    not_found += 1
                    logging.append(f'{row} not in {table}', False)
            tname = self.table.get('name')
            print(f'tabla {tname}: {not_found:n}/{len(values):n} not found')
            if not_found > 0:
                fk_errors + = 1
        if fk_errors > 0:
            raise ValueError(f'Errores de foreign keys in {fk_errors} ' \
                             'relaciones')
Ejemplo n.º 3
0
    def _fill_with_median(self, fidi, date_nodata, con, cur, insert):
        """
        fill not interpolated values using idw in dates date_nodata
        using medians
        """

        select1 = \
        """select value
        from {IDW.table_name_interpolated_values}
        where fid=?
        order by value"""

        select2 = \
        """select value
        from {IDW.table_name_interpolated_values}
        order by value
        """

        if len(date_nodata) == 0:
            return []

        med = np.empty((fidi.size, 12), np.float32)
        med[:] = np.NAN
        missed = []

        for date1 in date_nodata:
            imonth = int(date1[5:7]) - 1
            for i, fidi1 in enumerate(fidi):
                if np.isnan(med[i, imonth]):
                    IDW._median_set(cur, select1, imonth, i, med, fidi1)
                    if np.isnan(med[i, imonth]):
                        IDW._median_set(cur, select2, imonth, i, med)
                        if np.isnan(med[i, imonth]):
                            logging.append(f'{date1} no median available ' +\
                                           f'for point {fidi1}', False)

                if not np.isnan(med[i, imonth]):
                    cur.execute(insert, (fidi1, date1, float(med[i, imonth])))
                    a = f'point {fidi1}, fecha {date1} interpolated with ' +\
                    'median'
                    logging.append(f'{a}', False)
                else:
                    missed.append(f'point {fidi1}, fecha {date1}')
        con.commit()
        return missed
Ejemplo n.º 4
0
def taskGet(path: str,
            nameTask: str,
            estaciones: list = None,
            dateRange: list = None):
    """
    comprueba si existe una tarea previa y devuelve la tarea adecuada para la
        ejecución; tanto si se quiere ejecutar una tarea ya finalizada como
        si se quiere ejecutar una tarea donde ya hay otra diferente devuelve
        None
    """
    from datetime import date
    from os.path import isfile
    from aemetOpenDataTask import Task
    from aemetOD_constants import MSGCONTINUE

    if estaciones == None:
        estaciones = [
            'todas',
        ]
    if dateRange is None:
        D1 = date(1900, 1, 1)
        D2 = date(1900, 1, 2)
        dateRange = [D1, D2]
    task = Task(path,
                dateRange,
                estaciones,
                downloadType='estaciones',
                name=nameTask)
    if isfile(Task.nameFileTaskGet(path)):
        previousTask = Task.readFile(path)
        if previousTask.hasFinished():
            logging.append(f'El directorio {path} contiene una tarea '+\
                           'ya finalizada.\nInténtalo en un nuevo directorio')
            _ = input(MSGCONTINUE)
            return None
        if task != previousTask:
            logging.append('Estás tratando de utilizar el directorio' +
                           'de otra tarea')
            _ = input(MSGCONTINUE)
            return None
        return previousTask
    return task
Ejemplo n.º 5
0
    def z_get(self, xy):
        """
        returns the z value given a list of x, y coordinates
        Parameters
        ----------
        xy : List([int-str, float, float)
            list of coordinates as [gid1, x1, y1], [gid2, x2, y2]...
        Returns
        z : List(List)), each element: gid, x1, y1, z1
        """
        z = []
        tiny = 0.1
        for ii, xy1 in enumerate(xy):
            gid = xy1[0]
            x1 = xy1[1]
            y1 = xy1[2]

            if not self.point_in_grid(x1, y1):
                msg = f'{gid} {x1} {y1} NO está en {self.filename}'
                logging.append(msg, False)
                continue

            if x1 >= self.xmax:
                x1 = self.xmax - tiny
            if y1 >= self.ymax:
                y1 = self.ymax - tiny
            if x1 <= self.xmin:
                x1 = self.xmin
            if y1 <= self.ymin:
                y1 = self.ymin

            xi = ((y1 - self.ymin) * self.keys['nrows']) / (self.ymax -
                                                            self.ymin)
            xj = ((x1 - self.xmin) * self.keys['ncols']) / (self.xmax -
                                                            self.xmin)

            i = self.keys['nrows'] - int(xi) - 1
            j = int(xj)

            z.append([gid, self.Z[i, j]])
        return z
Ejemplo n.º 6
0
    def to_str(col: str,
               file: str,
               line: int,
               col_name: str,
               exception: bool,
               cols_with_null_values: list,
               required: bool = True):

        if col.lower() == 'null':
            if col_name not in cols_with_null_values.keys():
                cols_with_null_values[col_name] = 1
            else:
                cols_with_null_values[col_name] += 1

            msg = f'file {file}, line {i:n} {col_name} is null'
            logging.append(msg, toScreen=False)
            if required and exception:
                raise ValueError(msg)
            return ''
        else:
            return col
Ejemplo n.º 7
0
def get_z_drv(filepoints, dtypes, dir_asc_files, filenames, output_file):
    """
    driver to assign its z value to a set of points in filepoints
    Parameters
    ----------
    filepoints : str
        csv file with the following structure
        "gid","x","y"
        gid1 (int or str), x1 (float), y1 (float)
        ...
        gidn, xn, yn
    dtypes : Dictionary with 3 elements,
        {'gid': type, 'x': type, 'y': type}, examples:
        dtypes = {'gid': 'int32', 'x': 'float32', 'y': 'float32'}
        dtypes = {'gid': 'str', 'x': 'float32', 'y': 'float32'}
        dtypes = {'gid': 'int32', 'x': 'float64', 'y': 'float64'}
    dir_asc_files : str
        directory where filenames are found
    filenames : List(str)
        list in wich each element is the name of a standar asc file
    output_file : Path to a csv fil with the results of computations
    Returns
    -------
    dfp : pandas dataframe
        dateframe with data and z values
    """
    dfp = pd.read_csv(filepoints, dtype=dtypes)
    dfp['z'] = np.nan
    dfp['file'] = ''
    xys = [[row.gid, row.x, row.y] for _, row in dfp.iterrows()]

    for fn in filenames:
        grd = MDT_asc(dir_asc_files, fn)
        zs = grd.z_get(xys)
        for z1 in zs:
            dfp.loc[dfp['gid'] == z1[0], 'z'] = z1[-1]
            dfp.loc[dfp['gid'] == z1[0], 'file'] = fn
        dfp2 = dfp.loc[dfp.z.isnull()]
        xys = [[row.gid, row.x, row.y] for _, row in dfp2.iterrows()]
    if len(dfp2.index) > 0:
        msg = f'there are {len(dfp2.index)} points without assigned z'
        logging.append(msg)
        msg = dfp2.to_string()
        print(msg)
    else:
        msg = 'All points have been assigned'
        logging.append(msg)
    name = basename(output_file)
    path = dirname(filepoints)
    dfp.to_csv(join(path, name), sep=',', encoding='utf-8', index=False)
    msg = f'output file {join(path, name)}'
    logging.append(msg)
    return dfp
Ejemplo n.º 8
0
# points = ((688892-4, 4208042-4),)

if __name__ == "__main__":

    try:
        startTime = time()

        grd = mdt.MDT_asc(dir_input, filenames[0])
        z = grd.z_get(points)
        for z1 in z:
            print(z1)

        # grd.asc2csv()

        #axy.asc2xy(filename, fileout)


    except ValueError:
        msg = traceback.format_exc()
        logging.append(msg)
    except ImportError:
        msg = traceback.format_exc()
        logging.append(msg)
    except Exception:
        msg = traceback.format_exc()
        logging.append(msg)
    finally:
        logging.dump()
        xtime = time() - startTime
        print(f'El script tardó {xtime:0.1f} s')
Ejemplo n.º 9
0
def insert(csvfiles: list,
           csvpath: str,
           db: str,
           sep: str = ';',
           update_puntos: bool = True,
           exception: bool = True,
           insert_update: bool = True) -> None:
    """

    Parameters
    ----------
    csvfiles : list
        lista de ficheros csv o txt
    csvpath : str
        directorio de los ficheros csvfile
    db : str
        nombre y dirección de la db sqlite; si no existe la crea
    sep : text
        separador de columnas en los ficheros txt
    update_puntos : bool
        si True actualiza las filas de las tablas
    exception:
        si True lanza un raise si encuentra una tabla con un campo requerido
        con contenido null
    insert_update:
        si True realiza un insert/update de las tablas a partir de csvfiles
    Returns
        None
    """

    select_puntos = """
    select *
    from puntos
    where fid = ?
    """

    insert_puntos = """
    insert into puntos(fid, xetrs89, yetrs89, id_mas, tm, prov,
        id_uh, acu, prof)
    values (?, ?, ?, ?, ?, ?, ?, ?, ?)
    """

    select_masub = """
    select *
    from masub
    where fid = ?
    """

    insert_masub = """
    insert into masub(fid, name)
    values (?, ?)
    """

    select_param = """
    select *
    from param
    where fid = ?
    """

    insert_param = """
    insert into param(fid, name)
    values (?, ?)
    """

    select_uh = """
    select *
    from uh
    where fid = ?
    """

    insert_uh = """
    insert into uh(fid, name)
    values (?, ?)
    """

    select_analisis = """
    select *
    from analisis
    where fid = ? and fecha = ? and param = ?
    """

    insert_analisis = """
    insert into analisis(fid, fecha, param, valor, uds)
    values (?, ?, ?, ?, ?)
    """

    def to_float(col: str,
                 file: str,
                 line: int,
                 col_name: str,
                 exception: bool,
                 cols_with_null_values: list,
                 required: bool = True):

        if col.lower() == 'null':
            if col_name not in cols_with_null_values.keys():
                cols_with_null_values[col_name] = 1
            else:
                cols_with_null_values[col_name] += 1

            msg = f'file {file}, line {i:n} {col_name} is null'
            logging.append(msg, toScreen=False)
            if required and exception:
                raise ValueError(msg)
            return ''
        else:
            return float(col.replace(',', '.'))

    def to_str(col: str,
               file: str,
               line: int,
               col_name: str,
               exception: bool,
               cols_with_null_values: list,
               required: bool = True):

        if col.lower() == 'null':
            if col_name not in cols_with_null_values.keys():
                cols_with_null_values[col_name] = 1
            else:
                cols_with_null_values[col_name] += 1

            msg = f'file {file}, line {i:n} {col_name} is null'
            logging.append(msg, toScreen=False)
            if required and exception:
                raise ValueError(msg)
            return ''
        else:
            return col

    cols_with_null_values = {}

    try:
        connected = False
        con = sqlite3.connect(db)
        connected = True
        cur = con.cursor()
        for file in csvfiles:
            print(file)
            with open(join(csvpath, file), 'r', encoding='utf-8') as fi:
                csv_reader = csv.reader(fi, delimiter=sep)
                for i, row in enumerate(csv_reader):
                    if i == 0:
                        continue
                    col = row
                    for j in range(len(col)):
                        if j == 0:
                            col[j] = to_str(col[j], file, i, 'fid analisis',
                                            exception, cols_with_null_values)
                        elif j == 1:
                            col[j] = to_str(col[j], file, i, 'fecha',
                                            exception, cols_with_null_values)
                        elif j == 2:
                            col[j] = to_str(col[j], file, i, 'fid param',
                                            exception, cols_with_null_values)
                        elif j == 3:
                            col[j] = to_str(col[j], file, i, 'param',
                                            exception, cols_with_null_values)
                        elif j == 4:
                            col[j] = to_str(col[j], file, i, 'uds', exception,
                                            cols_with_null_values, False)
                        elif j == 5:
                            col[j] = to_float(col[j], file, i, 'valor',
                                              exception, cols_with_null_values)
                        elif j == 6:
                            col[j] = to_float(col[j], file, i, 'xetrs89',
                                              exception, cols_with_null_values)
                        elif j == 7:
                            col[j] = to_float(col[j], file, i, 'yetrs89',
                                              exception, cols_with_null_values)
                        elif j == 8:
                            col[j] = to_str(col[j], file, i, 'id_mas',
                                            exception, cols_with_null_values)
                        elif j == 9:
                            col[j] = to_str(col[j], file, i, 'mas name',
                                            exception, cols_with_null_values,
                                            False)
                        elif j == 10:
                            col[j] = to_str(col[j], file, i, 'tm', exception,
                                            cols_with_null_values, False)
                        elif j == 11:
                            col[j] = to_str(col[j], file, i, 'prov', exception,
                                            cols_with_null_values, False)
                        elif j == 12:
                            col[j] = to_str(col[j], file, i, 'id_uh',
                                            exception, cols_with_null_values)
                        elif j == 13:
                            col[j] = to_str(col[j], file, i, 'uh name',
                                            exception, cols_with_null_values,
                                            False)
                        elif j == 14:
                            col[j] = to_str(col[j], file, i, 'acu', exception,
                                            cols_with_null_values, False)
                        elif j == 15:
                            col[j] = to_float(col[j], file, i, 'prof',
                                              exception, cols_with_null_values,
                                              False)

                    if not insert_update:
                        continue

                    cur.execute(select_puntos, (col[0], ))
                    if cur.fetchone() is None:
                        cur.execute(insert_puntos,
                                    (col[0], col[6], col[7], col[8], col[10],
                                     col[11], col[12], col[14], col[15]))

                    cur.execute(select_masub, (col[8], ))
                    if cur.fetchone() is None:
                        cur.execute(insert_masub, (col[8], col[9]))

                    cur.execute(select_param, (col[2], ))
                    if cur.fetchone() is None:
                        cur.execute(insert_param, (col[2], col[3]))

                    cur.execute(select_uh, (col[12], ))
                    if cur.fetchone() is None:
                        cur.execute(insert_uh, (col[12], col[13]))

                    cur.execute(select_analisis, (col[0], col[1], col[2]))
                    if cur.fetchone() is None:
                        cur.execute(insert_analisis,
                                    (col[0], col[1], col[2], col[5], col[4]))

        print('\ncols with null values')
        print('column, null values number')
        for key, value in cols_with_null_values.items():
            print(f'{key}, {value}')

    except Error:
        raise ValueError(Error)
    except ValueError:
        msg = traceback.format_exc()
        logging.append(f'ValueError exception\n{msg}')
    finally:
        if connected:
            con.commit()
            con.close()
Ejemplo n.º 10
0
def meteoroMesGet(path: str, year1: int, year2: int, estaciones: list,
                  name: str):
    """
    devuelve los datos meteorológicos mensuales de las estaciones en un rango
        de años. En cada llamada aemet solo permite descargar una estación por
        año
    Se hace una primera petición get en la función request_to_aemet con el
        argumento meteoro=False; esta función devuelve un fichero json con 4
        parámetros (estado, descripcion, datos y metadatos). Estado es un
        estándar de respuestas del servidor; descripción es la idem de estado;
        datos es la url para descargar los datos solicitados; y metadatos es
        la url con los metadatos. Si la respuesta tieneéxito se hace una
        segunda petición con request_to_aemet con el argumento meteoro=True
        y utilizando las url devueltas en la primera petición; si tiene éxito
        se graban los datos
    Esta función tiene la misma estructura que meteoroDiaGet; si haces algún
        cambio aquí quizás lo tengas que trasladar a meteoroDiaGet
    args:
        path. carpeta donde se grabarán los resultados
        year1, year2. Años inicial y final de la petición de datos mensuales
        estaciones. lista de strings con los códigos de estaciones cuyos datos
            se desean descargar
        name. nombre de la tarea
    """
    from os.path import isfile, join
    from aemetOpenDataTaskMonth import TaskMonth
    from aemetOD_constants import MSGCONTINUE, URLBASE, meteoro_mes_url, \
    FMETADATA_METEORO_MES, STOP_REQUESTS, ANOTHER_REQUEST, SUCCESS_REQUEST, \
    MAXREQUEST

    try:
        task = TaskMonth.getTask(path, [year1, year2], estaciones, name,
                                 'meteoros mensuales')
    except ValueError as err:
        logging.append(err)
        _ = input(MSGCONTINUE)
        return

    NYEARSTEP = 1  # aemet no admite otro valor
    url_template = URLBASE + meteoro_mes_url
    file_metadatos = join(path, FMETADATA_METEORO_MES)
    wstations = [
        estacion for estacion in estaciones
        if estacion not in task.downloadedStations
    ]
    nestaciones = len(wstations)
    if nestaciones == 0:
        logging.append('Las estaciones ya se han descargado previamente')
        return

    start_time = time()

    for i, estacion in enumerate(wstations):
        if estacion in task.downloadedStations:
            continue
        year = year1
        nerrors, ndatos, ntry = 0, 0, 0
        ne = i + 1
        print(f'{estacion} {ne:d}/{nestaciones:d}')
        while year <= year2:
            nameFile = f'{estacion}_{year:d}_m.json'
            if isfile(join(path, nameFile)):
                year = year + NYEARSTEP
                continue

            url1 = url_template.format(f'{year:d}', f'{year:d}', estacion)
            code, r = request_to_aemet(url1, f'{estacion} {year:d}', False)
            if code == STOP_REQUESTS:
                nerrors += 1
                break
            elif code == ANOTHER_REQUEST:
                year = year + NYEARSTEP
                continue

            try:
                url2 = r.json()['datos']
            except ValueError as er:
                ntry += 1
                if ntry <= MAXREQUEST:
                    continue
                else:
                    logging.append(f'{er}', toScreen=False)
                    year = year + NYEARSTEP
                    continue

            code, r2 = request_to_aemet(url2, f'{estacion} {year:d}', True)
            if code == STOP_REQUESTS:
                nerrors += 1
                break
            elif code == ANOTHER_REQUEST:
                year = year + NYEARSTEP
                continue

            dst = join(path, nameFile)
            try:
                with open(dst, 'wb') as f:
                    for chunk in r2.iter_content(chunk_size=128):
                        f.write(chunk)
                ndatos += 1
            except Exception as er:
                logging.append(f'{er}', toScreen=False)
                nerrors += 1
                year = year + NYEARSTEP
                continue

            if not isfile(file_metadatos):
                url2 = r.json()['metadatos']
                code, r3 = request_to_aemet(url2, 'metadatos mensuales', True)
                if code == SUCCESS_REQUEST:
                    try:
                        with open(file_metadatos, 'wb') as f:
                            for chunk in r3.iter_content(chunk_size=128):
                                f.write(chunk)
                    except Exception as er:
                        logging.append(f'{er}', toScreen=False)

            year = year + NYEARSTEP

        ellapsed_time(start_time, nestaciones, ne, ndatos)
        logging.dump()
        if nerrors == 0:
            task.appendDownloadedStation(estacion)
            task.write()

    task.statusGet()
    logging.append('Descarga meteoros mensuales finalizada')
    _ = input(MSGCONTINUE)
Ejemplo n.º 11
0
    def upsert(self, update: bool = True, check: bool = True) -> None:
        """
        args:
            update: si ==True hace un update cuando la fila ya existe
            check: si True chekea los datos antes de insert-update
        inserta fila a fila
            si existe ya la fila con la clave primaria que se desea insertar
            actualiza sus contenidos en el caso de que update == True, en caso
            contrario no hace nada
        la operación se hace fila a fila y se contabiliza el número de
            insertados y el de actualizados, por lo que no se utiliza la
            sentencia upsert de postgres
        """
        s0 = "select fid from met.interpolation_points where fid = %s"
        s1 = \
        """
        select fid
        from met.interpolated_tseries
        where fid=%s and variable=%s and fecha=%s"""
        insert = \
        """
        insert into met.interpolated_tseries
            (fid, variable, fecha, value, metodo)
        values (%s, %s, %s, %s, %s);
        """
        update = \
        """
        update met.interpolated_tseries
        set value=%s, metodo=%s
        where fid=%s and variable=%s and fecha=%s
        """

        if check and not self.checked_data_in_tables:
            ok = self.check_data_in_tables()
            if not ok:
                return

        cur = self.con.cursor()
        nrows = self.data.shape[0] - 1
        not_found = inserted = updated = 0
        for index, row in self.data.iterrows():
            print(f'{index}/{nrows}')
            cur.execute(s0, (row[self.fid], ))
            row1 = cur.fetchone()
            if row1 is None:
                logging.append(f"{index} {row[self.fid]} not found")
                not_found += 1
                continue
            cur.execute(s1,
                        (row[self.fid], row[self.variable], row[self.fecha]))
            row1 = cur.fetchone()

            msg_key_columns = f"{index:n} {row[self.fid]} " \
            f"{row[self.variable]} {row[self.value]}"
            if row1 is None:
                try:
                    cur.execute(
                        insert,
                        (row[self.fid], row[self.variable], row[self.fecha],
                         row[self.value], row[self.metodo]))
                    logging.append(f"{msg_key_columns} inserted", False)
                    inserted += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{msg_key_columns} error inserting " \
                                   f'\n{msg}')
                    return
            else:
                if not update:
                    logging.append(f"{msg_key_columns} not updated", False)
                    continue
                try:
                    cur.execute(
                        update,
                        (row[self.value], row[self.metodo], row[self.fid],
                         row[self.variable], row[self.fecha]))
                    logging.append(f"{msg_key_columns} updated", False)
                    updated += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{msg_key_columns} error updating " \
                                   f'\n{msg}')
                    return
        self.con.commit()
        print(f'cod not found: {not_found:n}')
        print(f'inserted: {inserted:n}')
        print(f'updated: {updated}')
Ejemplo n.º 12
0
    def upsert(self, update: bool = True, check: bool = True) -> None:
        """
        args:
            update: si ==True hace un update cuando la fila ya existe
            check: si True chekea los datos antes de insert-update
        inserta fila a fila
            si existe ya la fila con la clave primaria que se desea insertar
            actualiza sus contenidos en el caso de que update == True, en caso
            contrario no hace nada
        la operación se hace fila a fila y se contabiliza el número de
            insertados y el de actualizados, por lo que no se utiliza la
            sentencia upsert de postgres
        """
        s0 = "select indic from met.pexistencias where indic = %s"
        s1 = 'select indic from met.pmes where indic=%s and fecha=%s'
        insert = \
        """
        insert into met.pmes (indic, fecha, prec)
        values (%s, %s, %s);
        """
        update = \
        """
        update met.pmes
        set prec=%s
        where indic=%s and fecha=%s
        """

        if check and not self.checked_data_in_tables:
            ok = self.check_data_in_tables()
            if not ok:
                return

        cur = self.con.cursor()
        nrows = self.data.shape[0] - 1
        not_found = inserted = updated = 0
        for index, row in self.data.iterrows():
            print(f'{index}/{nrows}')
            cur.execute(s0, (row[self.indic], ))
            row1 = cur.fetchone()
            if row1 is None:
                logging.append(f"{index} {row[self.indic]} not found")
                not_found += 1
                continue
            fecha1 = self.last_date_of_the_month(row[self.year],
                                                 row[self.month])
            cur.execute(s1, (row[self.indic], fecha1))
            row1 = cur.fetchone()

            if row1 is None:
                try:
                    cur.execute(insert,
                                (row[self.indic], fecha1, row[self.prec]))
                    logging.append(f"{index:n} {row[self.indic]} " \
                                   f"{fecha1} inserted", False)
                    inserted += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{index:n} {row[self.indic]} " \
                                   f"{fecha1} error " +\
                                   f'inserting\n{msg}')
                    return
            else:
                if not update:
                    logging.append(f"{index:n} {row[self.indic]} " \
                                   f"{fecha1} not updated", False)
                    continue
                try:
                    cur.execute(update,
                                (row[self.prec], row[self.indic], fecha1))
                    logging.append(f"{index:n} {row[self.indic]} " \
                                   f"{fecha1} updated", False)
                    updated += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{index:n} {row[self.indic]} " \
                                   f"{fecha1} error " +\
                                   f'updating\n{msg}')
                    return
        self.con.commit()
        print(f'cod not found: {not_found:n}')
        print(f'inserted: {inserted:n}')
        print(f'updated: {updated}')
Ejemplo n.º 13
0
def request_to_aemet(url: str, identifier: str, meteoro: bool):
    """
    Hace una petición al servidor de aemet open data
    args
        url. url
        identifier. texto con los args de petición, se utiliza sólo como
            un texto aclaratorio para los loggings
        meteoro. Si False es la llamada al servirdor donde responde con los
            descriptores de aemet 'estado','descripcion','datos' y 'metadatos'
            Si True devuelve una lista en que cada elemento es un diccionario
            de datos
    returns 2 objetos
        un integer de valor STOP_REQUESTS, ANOTHER_REQUEST, SUCCESS_REQUEST
        un objeto request o None
    El integer que devuelve depende de lo que quiero hacer con la respuesta
    La respuesta de request la examina de 2 maneras
        Primero compruebo las excepciones
        Si no hay excepciones y meteoro==True devuelve SUCCESS_REQUEST y la
            respuesta
        Si no hay excepciones y meteoro==False, entonces examina el fichero
            json que devuelve aemet con 4 valores
            - estado: request.status_code
            - descripcion: de estado
            - datos: una url con los de datos meteorológicos solicitados en la
              petición
            - metadatos: una url con los metatadatos de datos
        En este caso (no hay excepciones y meteoro==False) puede ocurrir que
        no tenga excepcion HTTPError y la clave "estado" no devuelve
        RESPONSEOK. Debe haber una coherencia entre las acciones que programas
        ante la misma respuesta del servidor cuando analizas la excepción y
        cuando analizas la clave "estado"
        SI MODIFICAS LA ACCIÓN A REALIZAR hazlo en los 2 sitios.
    """
    import requests
    from requests.exceptions import HTTPError
    from time import sleep
    from aemetOD_constants import headers, querystring, REQUEST_TIMEOUT, \
    UNAUTHORIZED, NOTFOUND, TOOMANYREQUESTS, MAXREQUEST, RESPONSEOK, \
    SLEEPSECONDS, STOP_REQUESTS, ANOTHER_REQUEST, SUCCESS_REQUEST

    nrequest = 0
    while True:
        try:
            r = requests.get(url,
                             headers=headers,
                             params=querystring,
                             timeout=REQUEST_TIMEOUT)
            r.raise_for_status()
        except HTTPError as er:
            logging.append(f'{er}', toScreen=False)
            if er.response.status_code == UNAUTHORIZED:
                return STOP_REQUESTS, None
            elif er.response.status_code == NOTFOUND:
                return ANOTHER_REQUEST, None
            elif er.response.status_code == TOOMANYREQUESTS:
                nrequest += 1
                if nrequest <= MAXREQUEST:
                    sleep(SLEEPSECONDS)
                    continue
                else:
                    return ANOTHER_REQUEST, None
            else:
                nrequest += 1
                if nrequest <= MAXREQUEST:
                    sleep(SLEEPSECONDS)
                    continue
                else:
                    return STOP_REQUESTS, None
        except Exception as er:
            logging.append(f'{er}', toScreen=False)
            return STOP_REQUESTS, None

        r.encoding = r.apparent_encoding
        try:
            rjson = r.json()
        except ValueError as er:
            nrequest += 1
            if nrequest <= MAXREQUEST:
                continue
            else:
                logging.append(f'{er}', toScreen=False)
                return ANOTHER_REQUEST, None

        if meteoro:
            return SUCCESS_REQUEST, r

        if rjson['estado'] == RESPONSEOK:
            return SUCCESS_REQUEST, r

        logging.append(f'{identifier}, estado {rjson["descripcion"]}',
                       toScreen=False)
        if rjson['estado'] == UNAUTHORIZED:
            return STOP_REQUESTS, None
        elif rjson['estado'] == NOTFOUND:
            return ANOTHER_REQUEST, None
        elif rjson['estado'] == TOOMANYREQUESTS:
            nrequest += 1
            if nrequest <= MAXREQUEST:
                sleep(SLEEPSECONDS)
                continue
            else:
                return ANOTHER_REQUEST, None
        else:
            nrequest += 1
            if nrequest <= MAXREQUEST:
                sleep(SLEEPSECONDS)
                continue
            else:
                return STOP_REQUESTS, None
Ejemplo n.º 14
0
    def upsert(self, update: bool=True, check: bool=True) ->None:
        """
        args:
            update: si ==True hace un update cuando la fila ya existe
            check: si True chekea los datos antes de insert-update
        inserta fila a fila
            si existe ya la fila con la clave primaria que se desea insertar
            actualiza sus contenidos en el caso de que update == True, en caso
            contrario no hace nada
        la operación se hace fila a fila y se contabiliza el número de
            insertados y el de actualizados, por lo que no se utiliza la
            sentencia upsert de postgres
        """
        s0 = "select cod from ipas.ipa1 where cod = %s"
        s1 = 'select cod from ipas.ipa2_h where cod=%s and fecha=%s'
        insert = \
        """
        insert into ipas.ipa2_h (cod, fecha, situacion, h, proyecto, medidor)
        values (%s, %s, %s, %s, %s, %s);
        """
        update = \
        """
        update ipas.ipa2_h
        set situacion=%s, h=%s, proyecto=%s, medidor=%s
        where cod=%s and fecha=%s
        """

        if check and not self.checked_data_in_tables:
            ok = self.check_data_in_tables()
            if not ok:
                return

        cur = self.con.cursor()
        nrows = self.data.shape[0] - 1
        not_found = inserted = updated = 0
        for index, row in self.data.iterrows():
            print(f'{index}/{nrows}')
            cur.execute(s0, (row[self.cod],))
            row1 = cur.fetchone()
            if row1 is None:
                logging.append(f"{index} {row[self.cod]} not found", False)
                not_found += 1
                continue
            cur.execute(s1, (row[self.cod], row[self.fecha]))
            row1 = cur.fetchone()

            if row1 is None:
                try:
                    cur.execute(insert,
                                (row[self.cod], row[self.fecha],
                                 row[self.situacion], row[self.h],
                                 row[self.proyecto], row[self.medidor]))
                    logging.append(f"{index:n} {row[self.cod]} " \
                                   f"{row[self.fecha]} inserted", False)
                    inserted += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{index:n} {row[self.cod]} " \
                                   f"{row[self.fecha]} error " +\
                                   f'inserting\n{msg}')
                    return
            else:
                if not update:
                    logging.append(f"{index:n} {row[self.cod]} " \
                                   f"{row[self.fecha]} not updated", False)
                    continue
                try:
                    cur.execute(update,
                                (row[self.situacion], row[self.h],
                                 row[self.proyecto], row[self.medidor],
                                 row[self.cod], row[self.fecha]))
                    logging.append(f"{index:n} {row[self.cod]} " \
                                   f"{row[self.fecha]} updated", False)
                    updated += 1
                except:
                    msg = traceback.format_exc()
                    logging.append(f"{index:n} {row[self.cod]} " \
                                   f"{row[self.fecha]} error " +\
                                   f'updating\n{msg}')
                    return
        self.con.commit()
        print(f'cod not found: {not_found:n}')
        print(f'inserted: {inserted:n}')
        print(f'updated: {updated}')
Ejemplo n.º 15
0
    def idw_ts(self, xygraph: bool):
        """
        Interpolación de una serie temporal en una serie de puntos sin datos
        xygraph: True si se graba un gráficos con cada punto interpolado
        """
        import sqlite3
        from os.path import join
        from time import time
        from scipy import spatial
        from db_connection import con_get
        import idw

        create_table1 = \
        f"""
        create table if not exists {IDW.table_name_interpolated_values} (
        fid TEXT,
        fecha TEXT,
        value REAL,
        PRIMARY KEY (fid, fecha))"""

        insert1 = \
        f"""
        insert into {IDW.table_name_interpolated_values}
        (fid, fecha, value)
        values(?, ?, ?)"""

        start_time = time()

        # datos donde hay que interpolar, devuelve numpy array of objects
        rows = IDW.__read_file_points(join(self.pathin, self.fpoints),
                                      self.skip_lines)
        # array con los id de los puntos donde se quiere interpolar
        fidi = rows[:, 0]
        # array con las coord. de los puntos
        xi = np.array(rows[:, [1, 2]], np.float32)
        # array para los valores interpolados en xi en cada fecha
        zi = np.empty((len(xi)), np.float32)

        # cursor a los datos para hacer las interpolaciones
        con = con_get(self.dbtype, self.db)
        cur = con.cursor()

        # cursor para los valores interpolados
        con1 = sqlite3.connect(':memory:')
        cur1 = con1.cursor()
        cur1.execute(create_table1)

        t0 = IDW.PRINT_SECS
        if self.tstep_type == 2:
            datei = IDW.__month_lastday(self.datei)
        else:
            datei = self.datei

        # los puntos con datos cambian de una fecha a otra por lo que hay que
        # hacer una select para cada fecha; esto hace que el proceso sea
        # sea largo para series temporales largas
        date_nodata = []
        while datei <= self.datefin:
            date_str = datei.strftime(self.date_format)
            if time() - t0 > IDW.PRINT_SECS:
                t0 = time()
                print(date_str)

            # datos en la fecha datei
            cur.execute(self.select, (datei, ))
            data = np.array([row for row in cur], np.float32)
            # puede haber fechas sin datos
            if data.size == 0:
                date_nodata.append(date_str)
                logging.append(f'{date_str} no data', False)
                datei = self.__next_date(datei)
                continue

            # builds kdtree tree and set distances
            xydata = data[:, [0, 1]]
            tree = spatial.cKDTree(xydata)
            dist, ii = tree.query(xi, k=min(self.kidw, xydata.shape[0]))

            # sort data by distance
            values0 = data[:, 2]
            values = np.empty((dist.shape), np.float32)
            idw.sortn(values0, ii, values)

            # idw interpolation
            idw.idwn(self.poweridw, dist, values, self.epsidw, zi)

            # insert interpolated values in sqlite
            for i in range(len(fidi)):
                cur1.execute(insert1, (fidi[i], date_str, float(zi[i])))

            datei = self.__next_date(datei)

        con.close()
        elapsed_time = time() - start_time
        print(f'La interpolación idw tardó {elapsed_time:0.1f} s')

        con1.commit()

        # las fechas sin datos se tratan de interpolar con medianas
        missed = self._fill_with_median(fidi, date_nodata, con1, cur1, insert1)

        # graba interpolación en ficheros de texto
        self.__write_interpolated_values(cur1)

        # graba fichero con los metadatos de la interpolación
        self.__write_idw_metadata(fidi.size, elapsed_time, missed)

        # graba el fichero de puntos donde se realizó la interpolación
        self.__write_interpolated_points(fidi, xi)

        # graba los gráficos
        if xygraph:
            self.__xy(cur1)
Ejemplo n.º 16
0
        now = datetime.now()

        startTime = time()

        b = BHIMES(project, et_proc)
        b.aquifer_upsert_from_file()  # controlled in xml
        b.outcrop_upsert_from_file()
        b.met_upsert_from_file01()
        b.swb01()

        if annual_graphs:
            b.save_annual_graphs()  # xy recharge, runoff & ret
            b.save_annual_data_graphs()  # xy p, tmax, tmin, tavg
            b.save_annual_eth_graphs()  # xy pet (hargreaves)

        xtime = time() - startTime
        print(f'El script tardó {xtime:0.1f} s')

    except ValueError:
        msg = traceback.format_exc()
        logging.append(f'ValueError exception\n{msg}')
    except ImportError:
        msg = traceback.format_exc()
        logging.append(f'ImportError exception\n{msg}')
    except Exception:
        msg = traceback.format_exc()
        logging.append(f'Exception\n{msg}')
    finally:
        logging.dump()
        print('\nFin')
Ejemplo n.º 17
0
def meteoroDiaGet(path: str, fecha1: date, fecha2: date, estaciones: list,
                  name: str):
    """
    devuelve los datos meteorológicos diarios de las estaciones en un rango
        de fechas. En cada llamada aemet solo permite descargar hasta 5 años
        por estación
    Esta función tiene la misma estructura que meteoroMesGet; si haces algún
        cambio aquí quizás lo tengas que trasladar a meteoroMesGet
    args:
        path. carpeta donde se grabarán los resultados
        fecha1, fecha2. Fechas inicial y final de la descarga
        estaciones. lista de strings con los códigos de estaciones cuyos datos
            se desean descargar
        name. nombre de la tarea
    """
    from dateutil.relativedelta import relativedelta
    from os.path import isfile, join
    from aemetOpenDataTask import Task
    from aemetOD_constants import MSGCONTINUE, URLBASE, meteoro_dia_url, \
    FMETADATA_METEORO_DIA, STOP_REQUESTS, ANOTHER_REQUEST, SUCCESS_REQUEST, \
    MAXREQUEST

    try:
        task = Task.getTask(path, [fecha1, fecha2], estaciones, name,
                            'meteoros diarios')
    except ValueError as err:
        logging.append(err)
        _ = input(MSGCONTINUE)
        return

    DAYSTEP = relativedelta(days=1)
    NYEARSTEP = 4  # aemet permite hasta 5 años por petición
    url_template = URLBASE + meteoro_dia_url
    file_metadatos = join(path, FMETADATA_METEORO_DIA)
    wstations = [
        estacion for estacion in estaciones
        if estacion not in task.downloadedStations
    ]
    nestaciones = len(wstations)
    if nestaciones == 0:
        logging.append('Las estaciones ya se han descargado previamente')
        return

    start_time = time()

    for i, estacion in enumerate(wstations):
        if estacion in task.downloadedStations:
            continue
        fecha = fecha1
        nerrors, ndatos, ntry = 0, 0, 0
        ne = i + 1
        print(f'{estacion} {ne:d}/{nestaciones:d}')
        while fecha <= fecha2:
            fecha1_request = fecha.strftime("%Y-%m-%d")
            fecha_last = fecha + relativedelta(years=NYEARSTEP)
            fecha2_request = fecha_last.strftime("%Y-%m-%d")
            nameFile = f'{estacion}_{fecha1_request}_{fecha2_request}_d.json'
            if isfile(join(path, nameFile)):
                fecha = fecha_last + DAYSTEP
                continue

            url1 = url_template.format(f'{fecha1_request}T00:00:00UTC',
                                       f'{fecha2_request}T00:00:00UTC',
                                       f'{estacion}')
            code, r = request_to_aemet(url1,
                                       f'{estacion} {fecha1_request} ' +\
                                       f'{fecha2_request}', False)
            if code == STOP_REQUESTS:
                nerrors += 1
                break
            elif code == ANOTHER_REQUEST:
                fecha = fecha_last + DAYSTEP
                continue

            try:
                url2 = r.json()['datos']
            except ValueError as er:
                ntry += 1
                if ntry <= MAXREQUEST:
                    continue
                else:
                    logging.append(f'{er}', toScreen=False)
                    fecha = fecha_last + DAYSTEP
                    continue

            code, r2 = request_to_aemet(url2, f'{estacion} {fecha1_request}' +\
                                        f'{fecha2_request}', True)
            if code == STOP_REQUESTS:
                nerrors += 1
                break
            elif code == ANOTHER_REQUEST:
                fecha = fecha_last + DAYSTEP
                continue

            dst = join(path, nameFile)
            try:
                with open(dst, 'wb') as f:
                    for chunk in r2.iter_content(chunk_size=128):
                        f.write(chunk)
                ndatos += 1
            except Exception as er:
                logging.append(f'{er}', toScreen=False)
                nerrors += 1
                fecha = fecha_last + DAYSTEP
                continue

            if not isfile(file_metadatos):
                url2 = r.json()['metadatos']
                code, r3 = request_to_aemet(url2, 'metadatos diarios', True)
                if code == SUCCESS_REQUEST:
                    try:
                        with open(file_metadatos, 'wb') as f:
                            for chunk in r3.iter_content(chunk_size=128):
                                f.write(chunk)
                    except Exception as er:
                        logging.append(f'{er}', toScreen=False)

            fecha = fecha_last + DAYSTEP

        ellapsed_time(start_time, nestaciones, ne, ndatos)
        logging.dump()
        if nerrors == 0:
            task.appendDownloadedStation(estacion)
            task.write()

    task.statusGet()
    logging.append('Descarga meteoros diarios finalizada')
    _ = input(MSGCONTINUE)