Skip to content

Commit

Permalink
[#505] REFACTOR: protected attrs over private in pom descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
yashaka committed Jul 22, 2024
1 parent 35e2d1e commit a8115bb
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ check vscode pylance, mypy, jetbrains qodana...

#### TODO: decide on lru_cache vs set attr on instance...

#### TODO: consider _pom.element over _pom.Element, and _pom.all_ over _pom.All

maybe as aliases...

### Deprecated conditions

- `be.present` in favor of `be.present_in_dom`
Expand Down
45 changes: 22 additions & 23 deletions selene/support/_pom.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,12 @@
# > The
class Element: # todo: consider implementing LocationContext interface
def __init__(self, selector: str | Tuple[str, str], _context=None):
# todo: consider refactoring to protected over private attributes
# at least for easier debugging
# and easier dynamic checks of attributes presence
self.__selector = selector
# TODO: should we set _name on init too?
# at least to None, if value was not provided...
self._selector = selector

# todo: should we wrap lambda below into lru_cache?
self.__context = lambda instance: (
self._context = lambda instance: (
(_context(instance) if callable(_context) else _context)
or getattr( # todo: refactor to one-liner via helper
instance,
Expand All @@ -79,17 +78,17 @@ def __init__(self, selector: str | Tuple[str, str], _context=None):

def _as_context(self, instance) -> selene.Element:
return (
context_of_self.element(self.__selector)
context_of_self.element(self._selector)
if isinstance(
context_of_self := self.__context(instance),
context_of_self := self._context(instance),
(selene.Browser, selene.Element),
)
# => self.__context is a descriptor:
else context_of_self._as_context(instance).element(self.__selector)
# => self._context is a descriptor:
else context_of_self._as_context(instance).element(self._selector)
)

def within(self, context, /):
return Element(self.__selector, _context=context)
return Element(self._selector, _context=context)

@property
def within_browser(self):
Expand Down Expand Up @@ -117,14 +116,14 @@ def element(self, selector: str | Tuple[str, str]) -> Element:
selector,
_context=lambda instance: ( # todo: should we lru_cache it?
(
getattr(instance, self.__name), # ← resolving descriptors chain –
getattr(instance, self._name), # ← resolving descriptors chain –
self, # – before returning the actual context :P
# otherwise any descriptor built on top of previously defined
# can be resolved improperly, because previous one
# might be not accessed yet, thus we have to simulate such assess
# on our own by forcing getattr
)[1]
if hasattr(self, f'_{self.__class__.__name__}__name')
if hasattr(self, '_name')
# => self if a "pass-through"-descriptor)
else self._as_context(instance)
),
Expand All @@ -135,18 +134,18 @@ def all(self, selector: str | Tuple[str, str]) -> All:
selector,
_context=lambda instance: (
(
getattr(instance, self.__name),
getattr(instance, self._name),
self,
)[1]
if hasattr(self, f'_{self.__class__.__name__}__name')
if hasattr(self, '_name')
else self._as_context(instance)
),
)

# --- Descriptor --- #

def __set_name__(self, owner, name):
self.__name = name # TODO: use it
self._name = name # TODO: use it

# TODO: should not we set attr on instance instead of lru_cache? :D
# set first time, then reuse :D
Expand All @@ -162,9 +161,9 @@ def __get__(self, instance, owner):

class All:
def __init__(self, selector: str | Tuple[str, str], _context=None):
self.__selector = selector
self._selector = selector

self.__context = lambda instance: (
self._context = lambda instance: (
(_context(instance) if callable(_context) else _context)
or getattr( # todo: refactor to one-liner via helper
instance,
Expand All @@ -187,17 +186,17 @@ def __init__(self, selector: str | Tuple[str, str], _context=None):

def _as_context(self, instance) -> selene.Collection:
return (
context_of_self.all(self.__selector)
context_of_self.all(self._selector)
if isinstance(
context_of_self := self.__context(instance),
context_of_self := self._context(instance),
(selene.Browser, selene.Element, selene.Collection),
)
# => self.__context is a descriptor:
else context_of_self._as_context(instance).all(self.__selector)
# => self._context is a descriptor:
else context_of_self._as_context(instance).all(self._selector)
)

def within(self, context, /):
return All(self.__selector, _context=context)
return All(self._selector, _context=context)

# todo: think on better name... within_page?
@property
Expand All @@ -224,7 +223,7 @@ def within_browser(self):
# --- Descriptor --- #

def __set_name__(self, owner, name):
self.__name = name # TODO: use it
self._name = name # TODO: use it

@lru_cache
def __get__(self, instance, owner):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest

import selene
from selene import browser, have, be, command, query
from selene.support._pom import Element, All

Expand Down Expand Up @@ -29,7 +30,7 @@ class DataGridMIT:
cells = content.all(_cells_selector)
editing_cell_input = content.element('.MuiDataGrid-cell--editing').element('input')

def __init__(self, context):
def __init__(self, context: selene.Element):
self.context = context

def cells_of_row(self, number, /):
Expand Down

0 comments on commit a8115bb

Please sign in to comment.