mirror of
https://github.com/arsenetar/dupeguru.git
synced 2025-03-10 05:34:36 +00:00
Updated hscommon
This commit is contained in:
parent
33d9569427
commit
096e2bb78a
@ -14,6 +14,7 @@ from queue import Queue, Empty
|
|||||||
|
|
||||||
from . import io
|
from . import io
|
||||||
from .path import Path
|
from .path import Path
|
||||||
|
from .util import iterdaterange
|
||||||
|
|
||||||
class Currency:
|
class Currency:
|
||||||
all = []
|
all = []
|
||||||
@ -270,6 +271,9 @@ EUR = Currency(code='EUR')
|
|||||||
class CurrencyNotSupportedException(Exception):
|
class CurrencyNotSupportedException(Exception):
|
||||||
"""The current exchange rate provider doesn't support the requested currency."""
|
"""The current exchange rate provider doesn't support the requested currency."""
|
||||||
|
|
||||||
|
def date2str(date):
|
||||||
|
return '%d%02d%02d' % (date.year, date.month, date.day)
|
||||||
|
|
||||||
class RatesDB:
|
class RatesDB:
|
||||||
"""Stores exchange rates for currencies.
|
"""Stores exchange rates for currencies.
|
||||||
|
|
||||||
@ -329,12 +333,35 @@ class RatesDB:
|
|||||||
return row[0]
|
return row[0]
|
||||||
return seek('<=', 'desc') or seek('>=', '') or Currency(currency_code).latest_rate
|
return seek('<=', 'desc') or seek('>=', '') or Currency(currency_code).latest_rate
|
||||||
|
|
||||||
|
def _ensure_filled(self, date_start, date_end, currency_code):
|
||||||
|
"""Make sure that the cache contains *something* for each of the dates in the range.
|
||||||
|
|
||||||
|
Sometimes, our provider doesn't return us the range we sought. When it does, it usually
|
||||||
|
means that it never will and to avoid repeatedly querying those ranges forever, we have to
|
||||||
|
fill them. We use the closest rate for this.
|
||||||
|
"""
|
||||||
|
# We don't want to fill today, because we want to repeatedly fetch that one until the
|
||||||
|
# provider gives it to us.
|
||||||
|
if date_end >= date.today():
|
||||||
|
date_end = date.today() - timedelta(1)
|
||||||
|
sql = "select rate from rates where date = ? and currency = ?"
|
||||||
|
for curdate in iterdaterange(date_start, date_end):
|
||||||
|
cur = self._execute(sql, [date2str(curdate), currency_code])
|
||||||
|
if cur.fetchone() is None:
|
||||||
|
nearby_rate = self._seek_value_in_CAD(date2str(curdate), currency_code)
|
||||||
|
self.set_CAD_value(curdate, currency_code, nearby_rate)
|
||||||
|
logging.debug("Filled currency void for %s at %s (value: %2.2f)", currency_code, curdate, nearby_rate)
|
||||||
|
|
||||||
def _save_fetched_rates(self):
|
def _save_fetched_rates(self):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
rates, currency = self._fetched_values.get_nowait()
|
rates, currency, fetch_start, fetch_end = self._fetched_values.get_nowait()
|
||||||
|
logging.debug("Saving %d rates for the currency %s", len(rates), currency)
|
||||||
for rate_date, rate in rates:
|
for rate_date, rate in rates:
|
||||||
|
logging.debug("Saving rate %2.2f for %s", rate, rate_date)
|
||||||
self.set_CAD_value(rate_date, currency, rate)
|
self.set_CAD_value(rate_date, currency, rate)
|
||||||
|
self._ensure_filled(fetch_start, fetch_end, currency)
|
||||||
|
logging.debug("Finished saving rates for currency %s", currency)
|
||||||
except Empty:
|
except Empty:
|
||||||
break
|
break
|
||||||
|
|
||||||
@ -374,7 +401,7 @@ class RatesDB:
|
|||||||
else:
|
else:
|
||||||
value2 = self._cache.get((date, currency2_code))
|
value2 = self._cache.get((date, currency2_code))
|
||||||
if value1 is None or value2 is None:
|
if value1 is None or value2 is None:
|
||||||
str_date = '%d%02d%02d' % (date.year, date.month, date.day)
|
str_date = date2str(date)
|
||||||
if value1 is None:
|
if value1 is None:
|
||||||
value1 = self._seek_value_in_CAD(str_date, currency1_code)
|
value1 = self._seek_value_in_CAD(str_date, currency1_code)
|
||||||
self._cache[(date, currency1_code)] = value1
|
self._cache[(date, currency1_code)] = value1
|
||||||
@ -388,7 +415,7 @@ class RatesDB:
|
|||||||
# we must clear the whole cache because there might be other dates affected by this change
|
# we must clear the whole cache because there might be other dates affected by this change
|
||||||
# (dates when the currency server has no rates).
|
# (dates when the currency server has no rates).
|
||||||
self.clear_cache()
|
self.clear_cache()
|
||||||
str_date = '%d%02d%02d' % (date.year, date.month, date.day)
|
str_date = date2str(date)
|
||||||
sql = "replace into rates(date, currency, rate) values(?, ?, ?)"
|
sql = "replace into rates(date, currency, rate) values(?, ?, ?)"
|
||||||
self._execute(sql, [str_date, currency_code, value])
|
self._execute(sql, [str_date, currency_code, value])
|
||||||
self.con.commit()
|
self.con.commit()
|
||||||
@ -419,6 +446,7 @@ class RatesDB:
|
|||||||
"""
|
"""
|
||||||
def do():
|
def do():
|
||||||
for currency, fetch_start, fetch_end in currencies_and_range:
|
for currency, fetch_start, fetch_end in currencies_and_range:
|
||||||
|
logging.debug("Fetching rates for %s for date range %s to %s", currency, fetch_start, fetch_end)
|
||||||
for rate_provider in self._rate_providers:
|
for rate_provider in self._rate_providers:
|
||||||
try:
|
try:
|
||||||
values = rate_provider(currency, fetch_start, fetch_end)
|
values = rate_provider(currency, fetch_start, fetch_end)
|
||||||
@ -426,7 +454,11 @@ class RatesDB:
|
|||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
if values:
|
if values:
|
||||||
self._fetched_values.put((values, currency))
|
self._fetched_values.put((values, currency, fetch_start, fetch_end))
|
||||||
|
logging.debug("Fetching successful!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
logging.debug("Fetching failed!")
|
||||||
|
|
||||||
currencies_and_range = []
|
currencies_and_range = []
|
||||||
for currency in currencies:
|
for currency in currencies:
|
||||||
@ -437,7 +469,9 @@ class RatesDB:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
cached_range = self.date_range(currency)
|
cached_range = self.date_range(currency)
|
||||||
range_start = start_date
|
range_start = start_date
|
||||||
range_end = date.today()
|
# Don't try to fetch today's rate, it's never there and results in useless server
|
||||||
|
# hitting.
|
||||||
|
range_end = date.today() - timedelta(1)
|
||||||
if cached_range is not None:
|
if cached_range is not None:
|
||||||
cached_start, cached_end = cached_range
|
cached_start, cached_end = cached_range
|
||||||
if range_start >= cached_start:
|
if range_start >= cached_start:
|
||||||
@ -446,6 +480,10 @@ class RatesDB:
|
|||||||
else:
|
else:
|
||||||
# Make a backward fetch
|
# Make a backward fetch
|
||||||
range_end = cached_start - timedelta(days=1)
|
range_end = cached_start - timedelta(days=1)
|
||||||
|
# We don't want to fetch ranges that are too big. It can cause various problems, such
|
||||||
|
# as hangs. We prefer to take smaller bites.
|
||||||
|
if (range_end - range_start).days > 30:
|
||||||
|
range_start = range_end - timedelta(days=30)
|
||||||
if range_start <= range_end:
|
if range_start <= range_end:
|
||||||
currencies_and_range.append((currency, range_start, range_end))
|
currencies_and_range.append((currency, range_start, range_end))
|
||||||
self._fetched_ranges[currency] = (start_date, date.today())
|
self._fetched_ranges[currency] = (start_date, date.today())
|
||||||
|
@ -13,6 +13,7 @@ import re
|
|||||||
from math import ceil
|
from math import ceil
|
||||||
import glob
|
import glob
|
||||||
import shutil
|
import shutil
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from . import io
|
from . import io
|
||||||
from .path import Path
|
from .path import Path
|
||||||
@ -254,6 +255,16 @@ def multi_replace(s, replace_from, replace_to=''):
|
|||||||
s = s.replace(r_from, r_to)
|
s = s.replace(r_from, r_to)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
#--- Date related
|
||||||
|
|
||||||
|
def iterdaterange(start, end):
|
||||||
|
"""Yields every day between ``start`` and ``end``.
|
||||||
|
"""
|
||||||
|
date = start
|
||||||
|
while date <= end:
|
||||||
|
yield date
|
||||||
|
date += timedelta(1)
|
||||||
|
|
||||||
#--- Files related
|
#--- Files related
|
||||||
|
|
||||||
def modified_after(first_path, second_path):
|
def modified_after(first_path, second_path):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user