Skip to content

Commit 7580fc8

Browse files
glenscJonnyWong16
andauthored
Use cached_property decorator (#1065)
* Use @cached_property in PlexSession.user * Use @cached_property in PlexServer.library * Use @cached_property in PlexServer.settings * Tests: Update clearing plex.settings cache * Use @cached_property in LibrarySection.totalSize * Add backports.cached-property==1.0.2; python_version<="3.7" dependency * Import cached_property from dist or backports * Add backports.cached-property to requirements_dev.txt * Remove version pin for backports.cached-property in requirements.txt Co-authored-by: JonnyWong16 <[email protected]> Co-authored-by: JonnyWong16 <[email protected]>
1 parent ac41fbf commit 7580fc8

File tree

7 files changed

+32
-37
lines changed

7 files changed

+32
-37
lines changed

plexapi/base.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from plexapi import log, utils
88
from plexapi.exceptions import BadRequest, NotFound, UnknownType, Unsupported
9+
from plexapi.utils import cached_property
910

1011
USER_DONT_RELOAD_FOR_KEYS = set()
1112
_DONT_RELOAD_FOR_KEYS = {'key'}
@@ -848,26 +849,23 @@ def _loadData(self, data):
848849
user = data.find('User')
849850
self._username = user.attrib.get('title')
850851
self._userId = utils.cast(int, user.attrib.get('id'))
851-
self._user = None # Cache for user object
852852

853853
# For backwards compatibility
854854
self.players = [self.player] if self.player else []
855855
self.sessions = [self.session] if self.session else []
856856
self.transcodeSessions = [self.transcodeSession] if self.transcodeSession else []
857857
self.usernames = [self._username] if self._username else []
858858

859-
@property
859+
@cached_property
860860
def user(self):
861861
""" Returns the :class:`~plexapi.myplex.MyPlexAccount` object (for admin)
862862
or :class:`~plexapi.myplex.MyPlexUser` object (for users) for this session.
863863
"""
864-
if self._user is None:
865-
myPlexAccount = self._server.myPlexAccount()
866-
if self._userId == 1:
867-
self._user = myPlexAccount
868-
else:
869-
self._user = myPlexAccount.user(self._username)
870-
return self._user
864+
myPlexAccount = self._server.myPlexAccount()
865+
if self._userId == 1:
866+
return myPlexAccount
867+
868+
return myPlexAccount.user(self._username)
871869

872870
def reload(self):
873871
""" Reload the data for the session.

plexapi/library.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from plexapi.base import OPERATORS, PlexObject
88
from plexapi.exceptions import BadRequest, NotFound
99
from plexapi.settings import Setting
10-
from plexapi.utils import deprecated
10+
from plexapi.utils import cached_property, deprecated
1111

1212

1313
class Library(PlexObject):
@@ -418,7 +418,6 @@ def _loadData(self, data):
418418
self._filterTypes = None
419419
self._fieldTypes = None
420420
self._totalViewSize = None
421-
self._totalSize = None
422421
self._totalDuration = None
423422
self._totalStorage = None
424423

@@ -456,12 +455,10 @@ def fetchItems(self, ekey, cls=None, container_start=None, container_size=None,
456455
item.librarySectionID = librarySectionID
457456
return items
458457

459-
@property
458+
@cached_property
460459
def totalSize(self):
461460
""" Returns the total number of items in the library for the default library type. """
462-
if self._totalSize is None:
463-
self._totalSize = self.totalViewSize(includeCollections=False)
464-
return self._totalSize
461+
return self.totalViewSize(includeCollections=False)
465462

466463
@property
467464
def totalDuration(self):

plexapi/server.py

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from plexapi.playlist import Playlist
1818
from plexapi.playqueue import PlayQueue
1919
from plexapi.settings import Settings
20-
from plexapi.utils import deprecated
20+
from plexapi.utils import cached_property, deprecated
2121
from requests.status_codes import _codes as codes
2222

2323
# Need these imports to populate utils.PLEXOBJECTS
@@ -109,8 +109,6 @@ def __init__(self, baseurl=None, token=None, session=None, timeout=None):
109109
self._showSecrets = CONFIG.get('log.show_secrets', '').lower() == 'true'
110110
self._session = session or requests.Session()
111111
self._timeout = timeout
112-
self._library = None # cached library
113-
self._settings = None # cached settings
114112
self._myPlexAccount = None # cached myPlexAccount
115113
self._systemAccounts = None # cached list of SystemAccount
116114
self._systemDevices = None # cached list of SystemDevice
@@ -173,27 +171,22 @@ def _headers(self, **kwargs):
173171
def _uriRoot(self):
174172
return f'server://{self.machineIdentifier}/com.plexapp.plugins.library'
175173

176-
@property
174+
@cached_property
177175
def library(self):
178176
""" Library to browse or search your media. """
179-
if not self._library:
180-
try:
181-
data = self.query(Library.key)
182-
self._library = Library(self, data)
183-
except BadRequest:
184-
data = self.query('/library/sections/')
185-
# Only the owner has access to /library
186-
# so just return the library without the data.
187-
return Library(self, data)
188-
return self._library
189-
190-
@property
177+
try:
178+
data = self.query(Library.key)
179+
except BadRequest:
180+
# Only the owner has access to /library
181+
# so just return the library without the data.
182+
data = self.query('/library/sections/')
183+
return Library(self, data)
184+
185+
@cached_property
191186
def settings(self):
192187
""" Returns a list of all server settings. """
193-
if not self._settings:
194-
data = self.query(Settings.key)
195-
self._settings = Settings(self, data)
196-
return self._settings
188+
data = self.query(Settings.key)
189+
return Settings(self, data)
197190

198191
def account(self):
199192
""" Returns the :class:`~plexapi.server.Account` object this server belongs to. """

plexapi/utils.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
except ImportError:
2525
tqdm = None
2626

27+
try:
28+
from functools import cached_property
29+
except ImportError:
30+
from backports.cached_property import cached_property # noqa: F401
31+
2732
log = logging.getLogger('plexapi')
2833

2934
# Search Types - Plex uses these to filter specific media types when searching.

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
# pip install -r requirements.txt
44
#---------------------------------------------------------
55
requests
6+
backports.cached-property; python_version<="3.7"

requirements_dev.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# PlexAPI requirements to run py.test.
33
# pip install -r requirements_dev.txt
44
#---------------------------------------------------------
5+
backports.cached-property==1.0.2; python_version<="3.7"
56
coveralls==3.3.1
67
flake8==5.0.4
78
pillow==9.3.0

tests/test_settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_settings_set(plex):
1313
new_value = not old_value
1414
cd.set(new_value)
1515
plex.settings.save()
16-
plex._settings = None
16+
del plex.__dict__['settings']
1717
assert plex.settings.get("autoEmptyTrash").value == new_value
1818

1919

@@ -22,5 +22,5 @@ def test_settings_set_str(plex):
2222
new_value = 99
2323
cd.set(new_value)
2424
plex.settings.save()
25-
plex._settings = None
25+
del plex.__dict__['settings']
2626
assert plex.settings.get("OnDeckWindow").value == 99

0 commit comments

Comments
 (0)