Coverage for amazonorders/entity/item.py: 98.48%
66 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-25 22:50 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-25 22:50 +0000
1import logging
2from datetime import datetime, date
3from typing import Optional
5from bs4 import Tag
7from amazonorders.entity.parsable import Parsable
8from amazonorders.entity.seller import Seller
9from amazonorders.session import BASE_URL
11__author__ = "Alex Laird"
12__copyright__ = "Copyright 2024, Alex Laird"
13__version__ = "1.0.5"
15logger = logging.getLogger(__name__)
18class Item(Parsable):
19 """
20 An Item in an Amazon `~amazonorders.entity.order.Order`.
21 """
23 def __init__(self,
24 parsed: Tag) -> None:
25 super().__init__(parsed)
27 #: The Item title.
28 self.title: str = self.safe_parse(self._parse_title)
29 #: The Item link.
30 self.link: str = self.safe_parse(self._parse_link)
31 #: The Item price.
32 self.price: Optional[float] = self.safe_parse(self._parse_price)
33 #: The Item Seller.
34 self.seller: Optional[Seller] = self.safe_parse(self._parse_seller)
35 #: The Item condition.
36 self.condition: Optional[str] = self.safe_parse(self._parse_condition)
37 #: The Item return eligible date.
38 self.return_eligible_date: Optional[date] = self.safe_parse(
39 self._parse_return_eligible_date)
40 #: The Item image URL.
41 self.image_link = self.safe_parse(self._parse_image_link)
42 #: The Item quantity.
43 self.quantity = self.safe_parse(self._parse_quantity)
45 def __repr__(self) -> str:
46 return "<Item: \"{}\">".format(self.title)
48 def __str__(self) -> str: # pragma: no cover
49 return "Item: {}".format(self.title)
51 def __lt__(self, other):
52 return self.title < other.title
54 def _parse_title(self) -> str:
55 tag = self.parsed.find("a")
56 return tag.text.strip()
58 def _parse_link(self) -> str:
59 tag = self.parsed.find("a")
60 return "{}{}".format(BASE_URL, tag.attrs["href"])
62 def _parse_price(self) -> Optional[float]:
63 for tag in self.parsed.find_all("div"):
64 if tag.text.strip().startswith("$"):
65 return float(tag.text.strip().replace("$", ""))
67 return None
69 def _parse_seller(self) -> Optional[Seller]:
70 for tag in self.parsed.find_all("div"):
71 if "Sold by:" in tag.text:
72 return Seller(tag)
74 return None
76 def _parse_condition(self) -> Optional[str]:
77 for tag in self.parsed.find_all("div"):
78 if "Condition:" in tag.text:
79 return tag.text.split("Condition:")[1].strip()
81 return None
83 def _parse_return_eligible_date(self) -> Optional[date]:
84 for tag in self.parsed.find_all("div"):
85 if "Return" in tag.text:
86 split_str = "through "
87 if "closed on " in tag.text:
88 split_str = "closed on "
89 clean_str = tag.text.strip()
90 if split_str in clean_str:
91 date_str = clean_str.split(split_str)[1]
92 return datetime.strptime(date_str, "%b %d, %Y").date()
94 return None
96 def _parse_image_link(self) -> Optional[str]:
97 img = self.parsed.find_previous_sibling().find("img")
98 if img:
99 return img.attrs["src"]
100 else:
101 return None
103 def _parse_quantity(self) -> Optional[int]:
104 tag = self.parsed.find_previous_sibling().find("span", {"class": "item-view-qty"})
105 if tag:
106 return int(tag.text.strip())
107 else:
108 return None