예제 #1
0
    def acquire_rates_data(self):
        """Request rates data from the site and processes them

        returns True on successful receiving and data processing
        """
        prinf('%s params: %s', self.base_url, self.my_params)
        g_start()
        try:
            self.response_data = requests.get(self.base_url, params=self.my_params, timeout=self.timeout)
        except OSError:
            prinw('%s host not available', self.name)
            return False
        g_end('request responded')

        if not self.response_data:
            return False
        else:
            status_code = self.response_data.status_code
            prinf(status_code )
            if status_code > 400 :
                prinw('%s currency converter site response not found. %s', self.nam, status_code)
                return False
            elif status_code == 200:
                prinf('%s response ok', self.name)

        self.update_rates_valid_data()
        self.in_ccode = self.response_data.json()[self.strs[jpn.key_in_ccode]]

        self.rates = self.response_data.json()[self.strs[jpn.key_output]]

        return True
    def internet_on():
        """Tries to reach google.com to find out if the connection to internet is established

        returns True on conected to internet False otherwise
        """
        try:
            # connect to the google.com -- tells us if the host is actually reachable
            g_start()
            socket.create_connection(("www.google.com", 80), timeout=1)
            g_end('connection to internet is available')
            return True
        except OSError:
            pass
        return False
    def save_to_sql(self, rates_df, rates_info_lines):
        """Saves rates database into sql file and database info file to disk"""
        self.create_engine()
        self.touch_db_file()
        with self.engine.connect() as conn, conn.begin():
            # rates sql database
            g_start()
            rates_df.to_sql(self.rates_table_name, conn, if_exists='replace')
            g_end('saved rates_df.to_sql')

            # database info file
            g_start()
            with open(self.rates_info_txt_file, 'w',
                      encoding=self.encoding) as f:
                f.writelines(rates_info_lines)
            g_end('saved rates_info_txt_file')
    def get_rates_from_sql(self, in_ccode=None, out_ccode=None):
        """Queries the sql database for input rates according to input arguments [in_ccode, out_ccode]

        - on no rates table or no sql database it returns None
        - when both arguments are None, returns the full database
        - when out_ccode is None, returns the [in_ccode] rates column
        - otherwise returns the exchange rate for the arguments
        """
        if self.db_file_exist():
            self.create_engine()
            rates_table_exist = self.engine.dialect.has_table(
                self.engine, self.rates_table_name)
            if rates_table_exist:
                if not (in_ccode or out_ccode):
                    g_start()
                    # load whole database to pandas (time consuming)
                    rates_df = pd.read_sql_table(self.rates_table_name,
                                                 self.engine)
                    g_end('loaded database')

                    rates_df.index = rates_df['index']
                    rate = rates_df[self.in_code].loc[self.out_code]
                    return rate

                elif in_ccode:
                    sql_query = 'SELECT "index", {} FROM {} ;'.format(
                        in_ccode, self.rates_table_name)
                    g_start()
                    in_col_df = pd.read_sql_query(sql_query, self.engine)
                    g_end('loaded query read_sql_query')
                    if out_ccode:
                        in_col_df.index = in_col_df['index']
                        rate = in_col_df[in_ccode].loc[out_ccode]
                        return rate
                    else:
                        rates = {
                            ccode: float(rate)
                            for ccode, rate in zip(in_col_df['index'],
                                                   in_col_df[in_ccode])
                        }
                        return rates
            else:
                return None
        else:
            return None
    def get_db_valid_from_via_txt(self):
        """Returns offline sql database valid_from utc time from txt file [rates_info_txt_file]"""
        rates_info_txt_exist = Path(self.rates_info_txt_file).is_file()
        if rates_info_txt_exist:
            g_start()
            with open(self.rates_info_txt_file, 'r',
                      encoding=self.encoding) as f:
                whole = f.readlines()
                if len(whole) < 2:
                    prinw(
                        'rates_info_txt_file does not contain lines with db_valid_to_str, db_valid_from_str!'
                    )
                    return None
                else:
                    db_valid_to_str, db_valid_from_str = whole[0:2]
                    db_valid_from = arrow.get(db_valid_from_str)

            g_end('loaded rates_info_txt_file')  # ~ 8 ms
            return db_valid_from
        else:
            prinw('rates_info_txt_file does not exist')
            return None
    def _init_redis_(self, use_redis):
        """Initialize redis variables and connections

        - even if use_redis is True, the first_contact_max_sec test is still used
        ::WINDOWS NOTE::
        the first access to redis has about 1 second time penalty on windows platform. idiocracy
        """
        self.use_redis = use_redis
        self.first_contact_max_sec = 2.5  # should be at most 300 ms to be better than hdd sql database
        self.redis_host = 'localhost'
        self.redis_port = 6379
        self.r = None
        if not self.use_redis:
            return

        g_start()
        redis_db = redis.StrictRedis(host="localhost", port=6379, db=0)
        g_end('redis strictRedis initialized')
        g_start()
        redis_db.set('redis', 'running')  # takes ~ 1000 ms on windows
        first_contact = g_end('first redis access')
        g_start()
        redis_running = redis_db.get(
            'redis') == 'running'  # takes ~ 0.1 ms on windows
        g_end('second redis access', 'd')
        redis_running = redis_db.info()['loading'] == 0

        if first_contact > self.first_contact_max_sec:
            # we don't want the redis to actually slow things down on Windows
            redis_running = False

        if redis_running:
            g_start()
            self.r = Root(host="localhost", port=6379, db=0)
            g_end('redisworks root initialized')
            prinf('Redis works root server running.')
 def create_engine(self):
     """Creates engine for sql database manipulation, if one does not exist yet"""
     g_start()
     if self.engine is None:
         self.engine = create_engine(self.db_engine_path)
     g_end('created engine')
    if platform.system() == 'Windows':
        truly_use_redis = use_redis_on_windows
        prinw(
            'Not using redis - Windows platform has 1 sec latency on first contact!'
        )
    return truly_use_redis


if __name__ == '__main__':
    """Converts amount of currency according to program arguments
    - Program arguments parsing
    - Redis usage decision
    - CurrencyConverter initializaton
    - Conversion according to parsed arguments
    """
    g_start('complete code')

    # parsing of arguments
    params = parse_arguments()

    # redis usage
    use_redis = setup_redis(use_redis=True, use_redis_on_windows=False)

    # main code
    cc = CurrencyConverter(use_redis=use_redis)
    cc.update_rates_data_if_needed()
    cc.convert(*params)

    g_end('complete program run', 'complete code')
    # ~ 44 ms on windows w/o redis