Files
bricktracker
migrations
sql
views
__init__.py
app.py
config.py
configuration.py
configuration_list.py
exceptions.py
fields.py
instructions.py
instructions_list.py
login.py
metadata.py
metadata_list.py
minifigure.py
minifigure_list.py
navbar.py
parser.py
part.py
part_list.py
rebrickable.py
rebrickable_image.py
rebrickable_minifigure.py
rebrickable_part.py
rebrickable_set.py
rebrickable_set_list.py
record.py
record_list.py
reload.py
retired.py
retired_list.py
set.py
set_list.py
set_status.py
set_status_list.py
socket.py
socket_decorator.py
sql.py
sql_counter.py
sql_migration.py
sql_migration_list.py
sql_stats.py
theme.py
theme_list.py
version.py
wish.py
wish_list.py
docs
static
templates
.dockerignore
.env.sample
.gitignore
CHANGELOG.md
Dockerfile
LICENSE
README.md
__init__.py
app.py
compose.legacy.yml
compose.local.yaml
compose.yaml
entrypoint.sh
requirements.txt
test-server.sh
BrickTracker/bricktracker/retired_list.py

106 lines
3.2 KiB
Python

from datetime import datetime, timezone
import csv
import gzip
import logging
import os
from shutil import copyfileobj
from flask import current_app, g
import humanize
import requests
from .exceptions import ErrorException
from .retired import BrickRetired
logger = logging.getLogger(__name__)
# Lego retired sets
class BrickRetiredList(object):
retired: dict[str, BrickRetired]
mtime: datetime | None
size: int | None
exception: Exception | None
def __init__(self, /, *, force: bool = False):
# Load sets only if there is none already loaded
retired = getattr(self, 'retired', None)
if retired is None or force:
logger.info('Loading retired sets list')
BrickRetiredList.retired = {}
# Try to read the themes from a CSV file
try:
with open(current_app.config['RETIRED_SETS_PATH'], newline='') as themes_file: # noqa: E501
themes_reader = csv.reader(themes_file)
# Ignore the header
next(themes_reader, None)
for row in themes_reader:
retired = BrickRetired(*row)
BrickRetiredList.retired[retired.number] = retired
# File stats
stat = os.stat(current_app.config['RETIRED_SETS_PATH'])
BrickRetiredList.size = stat.st_size
BrickRetiredList.mtime = datetime.fromtimestamp(stat.st_mtime, tz=timezone.utc) # noqa: E501
BrickRetiredList.exception = None
# Ignore errors
except Exception as e:
BrickRetiredList.exception = e
BrickRetiredList.size = None
BrickRetiredList.mtime = None
# Get a retirement date for a set
def get(self, number: str, /) -> str:
if number in self.retired:
return self.retired[number].retirement_date
else:
number, _, _ = number.partition('-')
if number in self.retired:
return self.retired[number].retirement_date
else:
return ''
# Display the size in a human format
def human_size(self) -> str:
if self.size is not None:
return humanize.naturalsize(self.size)
else:
return ''
# Display the time in a human format
def human_time(self) -> str:
if self.mtime is not None:
return self.mtime.astimezone(g.timezone).strftime(
current_app.config['FILE_DATETIME_FORMAT']
)
else:
return ''
# Update the file
@staticmethod
def update() -> None:
response = requests.get(
current_app.config['RETIRED_SETS_FILE_URL'],
stream=True,
)
if not response.ok:
raise ErrorException('An error occured while downloading the retired sets file ({code})'.format( # noqa: E501
code=response.status_code
))
content = gzip.GzipFile(fileobj=response.raw)
with open(current_app.config['RETIRED_SETS_PATH'], 'wb') as f:
copyfileobj(content, f)
logger.info('Retired sets list updated')