def run(input_file, c, meta): p = HypatiaExoParser(input_file, meta['normalization']) if c: for star, elements, planets in p.next(): try: star.upsert(c) logger.info('Saved star, "%s"\n', star.columns['hip']) for catalogue, composition in elements: # Assumption 251024: Because of the way the records are updated, if a catalogue is updated say # from 'FeH 0.3 [Adamow et al. (2015)]' to 'FeH 0.3 [Adamow et al. (2016)]' a new catalogue is # added and the particular composition for that catalogue will still be present with # old catalogue in the composition table. For the above example the table composition will have # 2 entries, one with 2015 catalogue and one with 2016 # Fix: Delete the star completely and add it again. Deleting a star, also deletes the corresponding # composition elements, but catalogues are retained as other stars may still use it! cid = catalogue.upsert(c) composition.set('hip', star.columns['hip']) composition.set('cid', cid) composition.upsert(c) for planet in planets: planet.set('hip', star.columns['hip']) planet.upsert(c) except: logger.exception('Saving star failed: "%s"', star.columns['hip']) c.close()
def planet_props(): """ **** DEPRECATED: Use /planets/ instead **** Retrieve planet properties POST BODY: { properties: [optional] one or more of properties of a planet, e.g. [name, mass, hip, p, e, a] stars: [required] a list of hips whose planets' properties are returned } where, mass => planet mass if properties are ignored, all properties are returned :return: {hip1_planet1: {m_p: 867, p: 0.889}, hip2_planet2: {m_p: 773, p: 0.8772}} """ try: stars = map(lambda s: s.strip(), request.json['stars']) props = map(lambda s: s.strip(), request.json.get('properties', Planet.DEFAULTS.keys())) props_cols_map = {'name': 'name', 'mass': 'm_p as mass', 'p': 'p', 'e': 'e', 'a': 'a'} columns = [props_cols_map.get(p, p) for p in props] query = """SELECT CONCAT(s.hip, ' [', p.name, ']') as star_planet, {} FROM planet p INNER JOIN star s ON s.hip = p.hip WHERE s.hip IN (%s)""".format(', '.join(columns)) resp = tuples_as_dict(query, stars, 0) return jsonify({'planets': resp, "status": {"message": "Fetched info for %s planets" % len(resp)}}) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def stars(page, limit): """ Retrieve requested number of stars of a given page satisfying a condition :param page: page number :param limit: number of stars in this page :return: """ try: # TODO: Possible SQL injection due to WHERE clause query = "SELECT * FROM star WHERE {} ORDER BY `hip` LIMIT %s OFFSET %s".format( request.args.get("query") or "1 = 1") db_res = MySQL.execute(DATABASE, query, [limit, page * limit]) index_of_hip = db_res['columns'].index('hip') resp = { row[index_of_hip]: dict( zip(db_res['columns'], [str(t) if type(t) is bytearray else t for t in row])) for row in db_res['rows'] } return jsonify({ 'stars': resp, "status": { "message": "Fetched %s stars" % (len(resp), ) } }) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def composition_scatter(): """ Median composition of requested elements for the requested star considering common catalogs POST BODY: { normalization: [required] the type of solar normalization stars: [required] comma separated list of hips elements: [required] comma separated list of elements for which compositions are required catalogs: [optional] comma separated list of catalogs (author_year column) to exclude if provided, else all will be used } :return: {hip1: {FeH: {mdn: 0.5, avg: 0.56}, OH: {mdn: -0.07, avg: 0}, ...}, {hip2: {FeH: {mdn: 0.09, avg: 0.1}, ...}} """ try: solarnorm = request.json['normalization'] stars = map(lambda s: s.strip(), request.json['stars']) elements = map(lambda e: e.strip(), request.json['elements']) catalogs = map(lambda c: c.strip(), request.json.get('catalogs', [])) query = """SELECT t1.hip, t1.cid, t1.element, t1.value FROM composition t1, catalogue c, composition t2 WHERE t1.solarnorm = '%s' AND t2.solarnorm = '%s' AND t1.cid = t2.cid AND t1.element <> t2.element AND t1.hip = t2.hip AND t1.hip IN (%s) AND t1.element IN (%s) AND t2.element IN (%s) AND t1.cid = c.id %s;""" in_str_stars = ','.join(['%s'] * len(stars)) in_str_elems = ','.join(['%s'] * len(elements)) in_str_cats = ','.join(['%s'] * len(catalogs)) catalog_query = 'AND c.author_year NOT IN (%s)' % in_str_cats if len( catalogs) > 0 else '' db_res = MySQL.execute( DATABASE, query % (solarnorm, solarnorm, in_str_stars, in_str_elems, in_str_elems, catalog_query), stars + elements + elements + catalogs) resp = {} for row in db_res['rows']: upsert_dict_arr(resp, row[0], row[2], row[3]) for star in resp: for e in resp[star]: resp[star][e] = { 'mdn': median(resp[star][e]), 'avg': mean(resp[star][e]) } return jsonify({ 'stars': resp, "status": { "message": "Fetched %s stars" % len(resp) } }) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def elements_of_star(hip): """ Fetches the elements of a star :param hip: hip of the star :return: """ try: query = "SELECT DISTINCT element FROM composition WHERE hip = %s" res = map(lambda e: e[0], MySQL.execute(DATABASE, query, [hip])['rows']) return jsonify({'elements': res}) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def composition_scatter(): """ Median composition of requested elements for the requested star considering common catalogs POST BODY: { normalization: [required] the type of solar normalization stars: [required] comma separated list of hips elements: [required] comma separated list of elements for which compositions are required catalogs: [optional] comma separated list of catalogs (author_year column) to exclude if provided, else all will be used } :return: {hip1: {FeH: {mdn: 0.5, avg: 0.56}, OH: {mdn: -0.07, avg: 0}, ...}, {hip2: {FeH: {mdn: 0.09, avg: 0.1}, ...}} """ try: solarnorm = request.json['normalization'] stars = map(lambda s: s.strip(), request.json['stars']) elements = map(lambda e: e.strip(), request.json['elements']) catalogs = map(lambda c: c.strip(), request.json.get('catalogs', [])) query = """SELECT t1.hip, t1.cid, t1.element, t1.value FROM composition t1, catalogue c, composition t2 WHERE t1.solarnorm = '%s' AND t2.solarnorm = '%s' AND t1.cid = t2.cid AND t1.element <> t2.element AND t1.hip = t2.hip AND t1.hip IN (%s) AND t1.element IN (%s) AND t2.element IN (%s) AND t1.cid = c.id %s;""" in_str_stars = ','.join(['%s'] * len(stars)) in_str_elems = ','.join(['%s'] * len(elements)) in_str_cats = ','.join(['%s'] * len(catalogs)) catalog_query = 'AND c.author_year NOT IN (%s)' % in_str_cats if len(catalogs) > 0 else '' db_res = MySQL.execute(DATABASE, query % (solarnorm, solarnorm, in_str_stars, in_str_elems, in_str_elems, catalog_query), stars + elements + elements + catalogs) resp = {} for row in db_res['rows']: upsert_dict_arr(resp, row[0], row[2], row[3]) for star in resp: for e in resp[star]: resp[star][e] = {'mdn': median(resp[star][e]), 'avg': mean(resp[star][e])} return jsonify({'stars': resp, "status": {"message": "Fetched %s stars" % len(resp)}}) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def stars(page, limit): """ Retrieve requested number of stars of a given page satisfying a condition :param page: page number :param limit: number of stars in this page :return: """ try: # TODO: Possible SQL injection due to WHERE clause query = "SELECT * FROM star WHERE {} ORDER BY `hip` LIMIT %s OFFSET %s".format( request.args.get("query") or "1 = 1") db_res = MySQL.execute(DATABASE, query, [limit, page * limit]) index_of_hip = db_res['columns'].index('hip') resp = {row[index_of_hip]: dict(zip(db_res['columns'], [str(t) if type(t) is bytearray else t for t in row])) for row in db_res['rows']} return jsonify({'stars': resp, "status": {"message": "Fetched %s stars" % (len(resp),)}}) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def planet_props(): """ **** DEPRECATED: Use /planets/ instead **** Retrieve planet properties POST BODY: { properties: [optional] one or more of properties of a planet, e.g. [name, mass, hip, p, e, a] stars: [required] a list of hips whose planets' properties are returned } where, mass => planet mass if properties are ignored, all properties are returned :return: {hip1_planet1: {m_p: 867, p: 0.889}, hip2_planet2: {m_p: 773, p: 0.8772}} """ try: stars = map(lambda s: s.strip(), request.json['stars']) props = map(lambda s: s.strip(), request.json.get('properties', Planet.DEFAULTS.keys())) props_cols_map = { 'name': 'name', 'mass': 'm_p as mass', 'p': 'p', 'e': 'e', 'a': 'a' } columns = [props_cols_map.get(p, p) for p in props] query = """SELECT CONCAT(s.hip, ' [', p.name, ']') as star_planet, {} FROM planet p INNER JOIN star s ON s.hip = p.hip WHERE s.hip IN (%s)""".format(', '.join(columns)) resp = tuples_as_dict(query, stars, 0) return jsonify({ 'planets': resp, "status": { "message": "Fetched info for %s planets" % len(resp) } }) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def compositions_of_star(hip): """ Retrieves composition of a star If an element has multiple values from different catalogs, average value is returned :param hip: hip of the star :return: {FeH: 0.5, OH: -0.6} """ try: elements = request.args.getlist('elements') in_clause = ','.join(['%s'] * len(elements)) query = """SELECT element, AVG(value) FROM composition WHERE hip = %s AND element IN ({}) GROUP BY element;""".format(in_clause) res = {} for k, v in MySQL.execute(DATABASE, query, [hip] + elements)['rows']: res[k] = v return jsonify(res) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def stellar_props(): """ Retrieve stellar properties POST BODY: { properties: [optional] one or more of properties of a star, e.g. [u, w, dist, v, mass] stars: [required] a list of hips for whose the above properties are required } where, mass => stellar mass if properties are ignored, all properties are returned :return: {hip1: {mass: 867, dist: 0.889}, hip2: {mass: 773, dist: 0.8772}} """ try: stars = map(lambda s: s.strip(), request.json['stars']) props = map(lambda s: s.strip(), request.json.get('properties', Star.DEFAULTS.keys())) props_cols_map = { 'u': 'u', 'w': 'w', 'dist': 'dist', 'v': 'v', 'mass': 'mass' } columns = [props_cols_map.get(p, p) for p in props] query = "SELECT hip, {} FROM star WHERE hip IN (%s);".format( ', '.join(columns)) resp = tuples_as_dict(query, stars, 0) return jsonify({ 'stars': resp, "status": { "message": "Fetched info for %s stars" % len(resp) } }) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500
def stellar_props(): """ Retrieve stellar properties POST BODY: { properties: [optional] one or more of properties of a star, e.g. [u, w, dist, v, mass] stars: [required] a list of hips for whose the above properties are required } where, mass => stellar mass if properties are ignored, all properties are returned :return: {hip1: {mass: 867, dist: 0.889}, hip2: {mass: 773, dist: 0.8772}} """ try: stars = map(lambda s: s.strip(), request.json['stars']) props = map(lambda s: s.strip(), request.json.get('properties', Star.DEFAULTS.keys())) props_cols_map = {'u': 'u', 'w': 'w', 'dist': 'dist', 'v': 'v', 'mass': 'mass'} columns = [props_cols_map.get(p, p) for p in props] query = "SELECT hip, {} FROM star WHERE hip IN (%s);".format(', '.join(columns)) resp = tuples_as_dict(query, stars, 0) return jsonify({'stars': resp, "status": {"message": "Fetched info for %s stars" % len(resp)}}) except Exception as err: logger.exception(err) return jsonify({"status": {"message": "Something went wrong"}}), 500