Raising specific error when datetime cannot be parsed.

This commit is contained in:
Roland 2023-10-29 22:15:57 -06:00
parent 38cddeff98
commit 9ea2dadde5
No known key found for this signature in database
GPG key ID: 9D6DBD3ACF11AB93
4 changed files with 17 additions and 20 deletions

View file

@ -18,7 +18,7 @@ from wrolpi.common import get_media_directory, logger, extract_domain, escape_fi
format_html_string, split_lines_by_length, get_html_soup
from wrolpi.dates import now, Seconds
from wrolpi.db import get_db_session, get_db_curs, optional_session
from wrolpi.errors import UnknownArchive, InvalidOrderBy
from wrolpi.errors import UnknownArchive, InvalidOrderBy, InvalidDatetime
from wrolpi.tags import tag_names_to_file_group_sub_select
from wrolpi.vars import PYTEST
@ -274,7 +274,6 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
# <meta content="2023-10-18T04:52:23+00:00" property="article:published_time"/>
if meta_published_time := get_meta_by_property('article:published_time'):
metadata.published_datetime = dates.strpdate(meta_published_time.attrs['content'])
logger.debug(f'Found meta published_time: {meta_published_time}')
# <meta name="article.published" content="2023-04-04T21:52:00.000Z">
if meta_article_published := soup.find('meta', attrs={'name': 'article.published'}):
metadata.published_datetime = metadata.published_datetime or dates.strpdate(
@ -286,7 +285,6 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
# <time itemprop="datePublished" datetime="2023-08-25">
if time := soup.find('time', attrs={'itemprop': 'datePublished'}):
metadata.published_datetime = metadata.published_datetime or dates.strpdate(time.attrs['datetime'])
logger.debug(f'Found time published_time: {time}')
# <abbr class="published" itemprop="datePublished" title="2022-03-17T03:00:00-07:00">March 17, 2022</abbr>
if abbr := soup.find('abbr', attrs={'itemprop': 'datePublished'}):
metadata.published_datetime = metadata.published_datetime or dates.strpdate(abbr.attrs['title'])
@ -294,7 +292,6 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
# <meta content="2023-10-19T05:53:24+00:00" property="article:modified_time"/>
if meta_modified_time := get_meta_by_property('article:modified_time'):
metadata.modified_datetime = dates.strpdate(meta_modified_time.attrs['content'])
logger.debug(f'Found meta modified_time: {meta_modified_time}')
# <meta name="article.updated" content="2023-04-04T21:52:00.000Z">
if meta_article_updated := soup.find('meta', attrs={'name': 'article.updated'}):
metadata.modified_datetime = metadata.modified_datetime or dates.strpdate(meta_article_updated.attrs['content'])
@ -302,19 +299,16 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
# <meta content="The Title" property="og:title"/>
if meta_title := get_meta_by_property('og:title'):
metadata.title = meta_title.attrs['content']
logger.debug(f'Found meta title: {meta_title}')
# <meta name="author" content="Author Name"/>
if meta_author := soup.find('meta', attrs={'name': 'author'}):
metadata.author = meta_author.attrs['content']
logger.debug(f'Found meta author: {meta_author}')
# <meta content="Billy" property="article:author"/>
if meta_property_author := get_meta_by_property('article:author'):
metadata.author = metadata.author or meta_property_author.attrs['content']
# <a href="https://example.com" rel="author">
if link_author := soup.find('a', attrs={'rel': 'author'}):
metadata.author = metadata.author or link_author.text.strip()
logger.debug(f'Found link author: {link_author}')
# <script class="sf-hidden" type="application/ld+json">
if (ld_script := soup.find('script', attrs={'type': 'application/ld+json'})) and ld_script.contents:
@ -327,12 +321,10 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
# Found https://schema.org/
if headline := schema.get('headline'):
metadata.title = metadata.title or schema.get('headline')
logger.debug(f'Found schema headline: {headline}')
if datePublished := schema.get('datePublished'):
try:
metadata.published_datetime = metadata.published_datetime or dates.strpdate(datePublished)
logger.debug(f'Found schema published_datetime: {datePublished}')
except RuntimeError as e:
except InvalidDatetime as e:
# Invalid date, ignore.
logger.error('Invalid datetime', exc_info=e)
if PYTEST:
@ -340,15 +332,13 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
if dateModified := schema.get('dateModified'):
try:
metadata.modified_datetime = metadata.modified_datetime or dates.strpdate(dateModified)
logger.debug(f'Found schema modified_datetime: {dateModified}')
except RuntimeError as e:
except InvalidDatetime as e:
# Invalid date, ignore.
logger.error('Invalid datetime', exc_info=e)
if PYTEST:
raise
if description := schema.get('description'):
metadata.description = description
logger.debug(f'Found schema description: {description}')
if author := schema.get('author'):
if isinstance(author, list) and len(author) >= 1:
# Use the first Author.
@ -359,7 +349,6 @@ def parse_article_html_metadata(html: Union[bytes, str], assume_utc: bool = True
if isinstance(author, str):
metadata.author = author
logger.debug(f'Found schema author: {author}')
else:
logger.warning(f'Unable to parse author schema: {author}')

View file

@ -7,6 +7,7 @@ import dateutil.parser
import pytz
from sqlalchemy import types
from wrolpi.errors import InvalidDatetime
from wrolpi.vars import DATETIME_FORMAT_MS
logger = logging.getLogger(__name__)
@ -119,7 +120,7 @@ def strpdate(dt: str) -> datetime:
# Last, try third-party module to parse ISO 8601 datetime.
return dateutil.parser.isoparse(dt)
except Exception as e:
raise RuntimeError(f'Unable to parse datetime string: {dt}') from e
raise InvalidDatetime(f'Unable to parse datetime string: {dt}') from e
def strftime_ms(dt: datetime) -> str:

View file

@ -143,3 +143,9 @@ class NoPrimaryFile(APIError):
code = 'NO_PRIMARY_FILE'
summary = 'Could not find a primary file in the provided group'
status = HTTPStatus.INTERNAL_SERVER_ERROR
class InvalidDatetime(APIError):
code = 'INVALID_DATETIME'
summary = 'Unable to parse a datetime string'
status = HTTPStatus.INTERNAL_SERVER_ERROR

View file

@ -9,6 +9,7 @@ from wrolpi import dates
from wrolpi.common import Base
from wrolpi.dates import TZDateTime, timedelta_to_timestamp, seconds_to_timestamp
from wrolpi.db import get_db_session, get_db_curs
from wrolpi.errors import InvalidDatetime
class TestTable(Base):
@ -126,15 +127,15 @@ def test_strpdate(dt, expected):
def test_invalid_strpdate():
with pytest.raises(RuntimeError):
with pytest.raises(InvalidDatetime):
dates.strpdate('1')
with pytest.raises(RuntimeError):
with pytest.raises(InvalidDatetime):
dates.strpdate('asdf')
with pytest.raises(RuntimeError):
with pytest.raises(InvalidDatetime):
dates.strpdate('13/1/2008')
# Not a real date.
with pytest.raises(RuntimeError):
with pytest.raises(InvalidDatetime):
dates.strpdate('2001-2-31')
with pytest.raises(RuntimeError):
with pytest.raises(InvalidDatetime):
dates.strpdate('2001-2-30')