Skip to content

Commit 2d0c159

Browse files
committed
Added familiars to auctions
- Updated changelog and version
1 parent c14d2b4 commit 2d0c159

File tree

5 files changed

+134
-1
lines changed

5 files changed

+134
-1
lines changed

CHANGELOG.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ Changelog
66
Due to this library relying on external content, older versions are not guaranteed to work.
77
Try to always use the latest version.
88

9+
.. v3.7.0:
10+
11+
3.7.0 (2021-02-09)
12+
==================
13+
14+
- Parse familiars from auctions
15+
- Updated the way tooltips in auctions are parsed, the format changed, resulting in the previous code not working anymore.
16+
- Results count in bazaar pages are now properly parsed when there are comma thousand separators.
17+
- Item amounts are now more accurate instead of being based from their indicator (which was grouping them in thousands)
18+
19+
920
.. v3.6.5:
1021
1122
3.6.5 (2021-01-27)

docs/api.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,12 @@ CharmsEntry
544544
:members:
545545
:inherited-members:
546546

547+
DisplayFamiliar
548+
~~~~~~~~~~~~~~~
549+
.. autoclass:: DisplayFamiliar
550+
:members:
551+
:inherited-members:
552+
547553
DisplayItem
548554
~~~~~~~~~~~
549555
.. autoclass:: DisplayItem
@@ -562,6 +568,12 @@ DisplayOutfit
562568
:members:
563569
:inherited-members:
564570

571+
Familiars
572+
~~~~~~~~~
573+
.. autoclass:: Familiars
574+
:members:
575+
:inherited-members:
576+
565577
ItemSummary
566578
~~~~~~~~~~~
567579
.. autoclass:: ItemSummary

tests/tests_bazaar.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,14 @@ def test_auction_details_from_content_finished(self):
222222
self.assertEqual('Retro Warrior', auction.store_outfits.get_by_id(962).name)
223223
self.assertEqual(2, len(auction.store_outfits.search('retro')))
224224

225+
self.assertIsNotNone(auction.familiars)
226+
self.assertEqual(1, len(auction.familiars.entries))
227+
self.assertEqual(1, auction.familiars.total_pages)
228+
self.assertEqual(1, auction.familiars.results)
229+
self.assertEqual(992, auction.familiars.get_by_name("emberwing").familiar_id)
230+
self.assertEqual('Emberwing', auction.familiars.get_by_id(992).name)
231+
self.assertEqual(1, len(auction.familiars.search('ember')))
232+
225233
self.assertEqual(9, len(auction.blessings))
226234
self.assertEqual(18, len(auction.imbuements))
227235
self.assertEqual(8, len(auction.charms))

tibiapy/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = '3.6.5'
1+
__version__ = '3.7.0'
22
__author__ = 'Allan Galarza'
33

44
import logging

tibiapy/bazaar.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@
3131
"DisplayItem",
3232
"DisplayMount",
3333
"DisplayOutfit",
34+
"DisplayFamiliar",
3435
"ItemSummary",
3536
"ListedAuction",
3637
"Outfits",
3738
"OutfitImage",
3839
"Mounts",
40+
"Familiars",
3941
"SalesArgument",
4042
"SkillEntry",
4143
)
@@ -599,6 +601,41 @@ def _parse_image_box(cls, item_box):
599601
return outfit
600602

601603

604+
class DisplayFamiliar(DisplayImage):
605+
"""Represents a familiar owned or unlocked by the character.
606+
607+
Attributes
608+
----------
609+
image_url: :class:`str`
610+
The URL to the image.
611+
name: :class:`str`
612+
The familiar's name.
613+
familiar_id: :class:`int`
614+
The internal ID of the familiar.
615+
"""
616+
def __init__(self, **kwargs):
617+
super().__init__(**kwargs)
618+
self.familiar_id: int = kwargs.get("familiar_id", 0)
619+
620+
__slots__ = (
621+
"familiar_id",
622+
)
623+
624+
def __repr__(self):
625+
return f"<{self.__class__.__name__} name={self.name!r} familiar_id={self.familiar_id} " \
626+
f"image_url={self.image_url!r}>"
627+
628+
@classmethod
629+
def _parse_image_box(cls, item_box):
630+
familiar = super()._parse_image_box(item_box)
631+
name = familiar.name.split("(")[0].strip()
632+
familiar.name = name
633+
m = id_regex.search(familiar.image_url)
634+
if m:
635+
familiar.familiar_id = int(m.group(1))
636+
return familiar
637+
638+
602639
class ListedAuction(BaseCharacter, abc.Serializable):
603640
"""Represents an auction in the list, containing the summary.
604641
@@ -863,6 +900,8 @@ class AuctionDetails(ListedAuction):
863900
The outfits the character has unlocked.
864901
store_outfits: :class:`Outfits`
865902
The outfits the character has purchased from the store.
903+
familiars: :class:`Familiars`
904+
The familiars the character has purchased or unlocked.
866905
blessings: :class:`list` of :class:`BlessingEntry`
867906
The blessings the character has.
868907
imbuements: :class:`list` of :class:`str`
@@ -953,6 +992,7 @@ def __init__(self, **kwargs):
953992
"store_mounts",
954993
"outfits",
955994
"store_outfits",
995+
"familiars",
956996
"blessings",
957997
"imbuements",
958998
"charms",
@@ -1032,6 +1072,8 @@ def from_content(cls, content, auction_id=0, skip_details=False):
10321072
auction.outfits = Outfits._parse_table(details_tables["Outfits"])
10331073
if "StoreOutfits" in details_tables:
10341074
auction.store_outfits = Outfits._parse_table(details_tables["StoreOutfits"])
1075+
if "Familiars" in details_tables:
1076+
auction.familiars = Familiars._parse_table(details_tables["Familiars"])
10351077
if "Blessings" in details_tables:
10361078
auction._parse_blessings_table(details_tables["Blessings"])
10371079
if "Imbuements" in details_tables:
@@ -1508,6 +1550,66 @@ def _parse_table(cls, table):
15081550
return summary
15091551

15101552

1553+
class Familiars(PaginatedSummary):
1554+
"""The familiars the character has unlocked or purchased.
1555+
1556+
Attributes
1557+
----------
1558+
page: :class:`int`
1559+
The current page being displayed.
1560+
total_pages: :class:`int`
1561+
The total number of pages.
1562+
results: :class:`int`
1563+
The total number of results.
1564+
entries: :class:`list` of :class:`DisplayFamiliar`
1565+
The familiars the character has unlocked or purchased.
1566+
fully_fetched: :class:`bool`
1567+
Whether the summary was fetched completely, including all other pages.
1568+
"""
1569+
entries: List[DisplayFamiliar]
1570+
entry_class = DisplayFamiliar
1571+
1572+
def __init__(self, **kwargs):
1573+
super().__init__(**kwargs)
1574+
1575+
def get_by_id(self, entry_id):
1576+
"""Gets an outfit by its familiar id.
1577+
1578+
Parameters
1579+
----------
1580+
entry_id: :class:`int`
1581+
The ID of the outfit.
1582+
1583+
Returns
1584+
-------
1585+
:class:`DisplayOutfit`
1586+
The outfit matching the id.
1587+
"""
1588+
return next((e for e in self.entries if e.familiar_id == entry_id), None)
1589+
1590+
@classmethod
1591+
def _parse_table(cls, table):
1592+
"""Parses the outfits table.
1593+
1594+
Parameters
1595+
----------
1596+
table: :class:`bs4.Tag`
1597+
The table containing the character outfits.
1598+
1599+
Returns
1600+
-------
1601+
:class:`Outfits`
1602+
The outfits contained in the table.
1603+
"""
1604+
summary = cls()
1605+
summary._parse_pagination(table)
1606+
item_boxes = table.find_all("div", attrs={"class": "CVIcon"})
1607+
for item_box in item_boxes:
1608+
item = DisplayFamiliar._parse_image_box(item_box)
1609+
if item:
1610+
summary.entries.append(item)
1611+
return summary
1612+
15111613
class Outfits(PaginatedSummary):
15121614
"""The outfits the character has unlocked or purchased.
15131615

0 commit comments

Comments
 (0)