]
+ """
+ return self._filter_only(selector, self._prev_all(), reverse=True)
+
+ def siblings(self, selector=None):
+ """
+ >>> h = 'Hi
Bye
'
+ >>> d = PyQuery(h)
+ >>> d('.hello').siblings()
+ [, ]
+ >>> d('.hello').siblings('img')
+ [ ]
+
+ """
+ return self._filter_only(selector, self._prev_all() + self._next_all())
+
+ def parents(self, selector=None):
+ """
+ >>> d = PyQuery('Hi
Bye
')
+ >>> d('p').parents()
+ []
+ >>> d('.hello').parents('span')
+ []
+ >>> d('.hello').parents('p')
+ []
+ """
+ return self._filter_only(
+ selector,
+ [e for e in self._traverse_parent_topdown()],
+ unique=True
+ )
+
+ def children(self, selector=None):
+ """Filter elements that are direct children of self using optional
+ selector:
+
+ >>> d = PyQuery('Hi
Bye
')
+ >>> d
+ []
+ >>> d.children()
+ [, ]
+ >>> d.children('.hello')
+ [
]
+ """
+ elements = [child for tag in self for child in tag.getchildren()]
+ return self._filter_only(selector, elements)
+
+ def closest(self, selector=None):
+ """
+ >>> d = PyQuery(
+ ... '')
+ >>> d('strong').closest('div')
+ []
+ >>> d('strong').closest('.hello')
+ []
+ >>> d('strong').closest('form')
+ []
+ """
+ result = []
+ for current in self:
+ while (current is not None and
+ not self._copy(current).is_(selector)):
+ current = current.getparent()
+ if current is not None:
+ result.append(current)
+ return self._copy(result, parent=self)
+
+ def contents(self):
+ """
+ Return contents (with text nodes):
+
+ >>> d = PyQuery('hello bold ')
+ >>> d.contents() # doctest: +ELLIPSIS
+ ['hello ', ]
+ """
+ results = []
+ for elem in self:
+ results.extend(elem.xpath('child::text()|child::*', namespaces=self.namespaces))
+ return self._copy(results, parent=self)
+
+ def filter(self, selector):
+ """Filter elements in self using selector (string or function):
+
+ >>> d = PyQuery('Hi
Bye
')
+ >>> d('p')
+ [, ]
+ >>> d('p').filter('.hello')
+ [
]
+ >>> d('p').filter(lambda i: i == 1)
+ []
+ >>> d('p').filter(lambda i: PyQuery(this).text() == 'Hi')
+ [
]
+ >>> d('p').filter(lambda i, this: PyQuery(this).text() == 'Hi')
+ []
+ """
+ if not hasattr(selector, '__call__'):
+ return self._filter_only(selector, self)
+ else:
+ elements = []
+ args = inspect.getargspec(callback).args
+ try:
+ for i, this in enumerate(self):
+ if len(args) == 1:
+ func_globals(selector)['this'] = this
+ if callback(selector, i, this):
+ elements.append(this)
+ finally:
+ f_globals = func_globals(selector)
+ if 'this' in f_globals:
+ del f_globals['this']
+ return self._copy(elements, parent=self)
+
+ def not_(self, selector):
+ """Return elements that don't match the given selector:
+
+ >>> d = PyQuery('Hi
Bye
')
+ >>> d('p').not_('.hello')
+ []
+ """
+ exclude = set(self._copy(selector, self))
+ return self._copy([e for e in self if e not in exclude],
+ parent=self)
+
+ def is_(self, selector):
+ """Returns True if selector matches at least one current element, else
+ False:
+
+ >>> d = PyQuery('
Hi
Bye
')
+ >>> d('p').eq(0).is_('.hello')
+ True
+
+ >>> d('p').eq(0).is_('span')
+ False
+
+ >>> d('p').eq(1).is_('.hello')
+ False
+
+ ..
+ """
+ return bool(self._filter_only(selector, self))
+
+ def find(self, selector):
+ """Find elements using selector traversing down from self:
+
+ >>> m = 'Whoah!
there
'
+ >>> d = PyQuery(m)
+ >>> d('p').find('em')
+ [, ]
+ >>> d('p').eq(1).find('em')
+ []
+ """
+ xpath = self._css_to_xpath(selector)
+ results = [child.xpath(xpath, namespaces=self.namespaces) for tag in self
+ for child in tag.getchildren()]
+ # Flatten the results
+ elements = []
+ for r in results:
+ elements.extend(r)
+ return self._copy(elements, parent=self)
+
+ def eq(self, index):
+ """Return PyQuery of only the element with the provided index::
+
+ >>> d = PyQuery('Hi
Bye
')
+ >>> d('p').eq(0)
+ []
+ >>> d('p').eq(1)
+ []
+ >>> d('p').eq(2)
+ []
+
+ ..
+ """
+ # Slicing will return empty list when index=-1
+ # we should handle out of bound by ourselves
+ try:
+ items = self[index]
+ except IndexError:
+ items = []
+ return self._copy(items, parent=self)
+
+ def each(self, func):
+ """apply func on each nodes
+ """
+ try:
+ for i, element in enumerate(self):
+ func_globals(func)['this'] = element
+ if callback(func, i, element) is False:
+ break
+ finally:
+ f_globals = func_globals(func)
+ if 'this' in f_globals:
+ del f_globals['this']
+ return self
+
+ def map(self, func):
+ """Returns a new PyQuery after transforming current items with func.
+
+ func should take two arguments - 'index' and 'element'. Elements can
+ also be referred to as 'this' inside of func::
+
+ >>> d = PyQuery('
Hi there
Bye
')
+ >>> d('p').map(lambda i, e: PyQuery(e).text())
+ ['Hi there', 'Bye']
+
+ >>> d('p').map(lambda i, e: len(PyQuery(this).text()))
+ [8, 3]
+
+ >>> d('p').map(lambda i, e: PyQuery(this).text().split())
+ ['Hi', 'there', 'Bye']
+
+ """
+ items = []
+ try:
+ for i, element in enumerate(self):
+ func_globals(func)['this'] = element
+ result = callback(func, i, element)
+ if result is not None:
+ if not isinstance(result, list):
+ items.append(result)
+ else:
+ items.extend(result)
+ finally:
+ f_globals = func_globals(func)
+ if 'this' in f_globals:
+ del f_globals['this']
+ return self._copy(items, parent=self)
+
+ @property
+ def length(self):
+ return len(self)
+
+ def size(self):
+ return len(self)
+
+ def end(self):
+ """Break out of a level of traversal and return to the parent level.
+
+ >>> m = 'Whoah!
there
'
+ >>> d = PyQuery(m)
+ >>> d('p').eq(1).find('em').end().end()
+ [,
]
+ """
+ return self._parent
+
+ ##############
+ # Attributes #
+ ##############
+ def attr(self, *args, **kwargs):
+ """Attributes manipulation
+ """
+
+ mapping = {'class_': 'class', 'for_': 'for'}
+
+ attr = value = no_default
+ length = len(args)
+ if length == 1:
+ attr = args[0]
+ attr = mapping.get(attr, attr)
+ elif length == 2:
+ attr, value = args
+ attr = mapping.get(attr, attr)
+ elif kwargs:
+ attr = {}
+ for k, v in kwargs.items():
+ attr[mapping.get(k, k)] = v
+ else:
+ raise ValueError('Invalid arguments %s %s' % (args, kwargs))
+
+ if not self:
+ return None
+ elif isinstance(attr, dict):
+ for tag in self:
+ for key, value in attr.items():
+ tag.set(key, value)
+ elif value is no_default:
+ return self[0].get(attr)
+ elif value is None:
+ return self.remove_attr(attr)
+ else:
+ for tag in self:
+ tag.set(attr, value)
+ return self
+
+ @with_camel_case_alias
+ def remove_attr(self, name):
+ """Remove an attribute::
+
+ >>> d = PyQuery('
')
+ >>> d.remove_attr('id')
+ []
+ >>> d.removeAttr('id')
+ [
]
+
+ ..
+ """
+ for tag in self:
+ try:
+ del tag.attrib[name]
+ except KeyError:
+ pass
+ return self
+
+ attr = FlexibleElement(pget=attr, pdel=remove_attr)
+
+ #######
+ # CSS #
+ #######
+ def height(self, value=no_default):
+ """set/get height of element
+ """
+ return self.attr('height', value)
+
+ def width(self, value=no_default):
+ """set/get width of element
+ """
+ return self.attr('width', value)
+
+ @with_camel_case_alias
+ def has_class(self, name):
+ """Return True if element has class::
+
+ >>> d = PyQuery('
')
+ >>> d.has_class('myclass')
+ True
+ >>> d.hasClass('myclass')
+ True
+
+ ..
+ """
+ return self.is_('.%s' % name)
+
+ @with_camel_case_alias
+ def add_class(self, value):
+ """Add a css class to elements::
+
+ >>> d = PyQuery('
')
+ >>> d.add_class('myclass')
+ [
]
+ >>> d.addClass('myclass')
+ []
+
+ ..
+ """
+ for tag in self:
+ values = value.split(' ')
+ classes = (tag.get('class') or '').split()
+ classes += [v for v in values if v not in classes]
+ tag.set('class', ' '.join(classes))
+ return self
+
+ @with_camel_case_alias
+ def remove_class(self, value):
+ """Remove a css class to elements::
+
+ >>> d = PyQuery('
')
+ >>> d.remove_class('myclass')
+ []
+ >>> d.removeClass('myclass')
+ [
]
+
+ ..
+ """
+ for tag in self:
+ values = value.split(' ')
+ classes = set((tag.get('class') or '').split())
+ classes.difference_update(values)
+ classes.difference_update([''])
+ classes = ' '.join(classes)
+ if classes.strip():
+ tag.set('class', classes)
+ elif tag.get('class'):
+ tag.set('class', classes)
+ return self
+
+ @with_camel_case_alias
+ def toggle_class(self, value):
+ """Toggle a css class to elements
+
+ >>> d = PyQuery('
')
+ >>> d.toggle_class('myclass')
+ [
]
+ >>> d.toggleClass('myclass')
+ []
+
+ """
+ for tag in self:
+ values = value.split(' ')
+ classes = (tag.get('class') or '').split()
+ values_to_add = [v for v in values if v not in classes]
+ values_to_del = [v for v in values if v in classes]
+ classes = [v for v in classes if v not in values_to_del]
+ classes += values_to_add
+ tag.set('class', ' '.join(classes))
+ return self
+
+ def css(self, *args, **kwargs):
+ """css attributes manipulation
+ """
+
+ attr = value = no_default
+ length = len(args)
+ if length == 1:
+ attr = args[0]
+ elif length == 2:
+ attr, value = args
+ elif kwargs:
+ attr = kwargs
+ else:
+ raise ValueError('Invalid arguments %s %s' % (args, kwargs))
+
+ if isinstance(attr, dict):
+ for tag in self:
+ stripped_keys = [key.strip().replace('_', '-')
+ for key in attr.keys()]
+ current = [el.strip()
+ for el in (tag.get('style') or '').split(';')
+ if el.strip()
+ and not el.split(':')[0].strip() in stripped_keys]
+ for key, value in attr.items():
+ key = key.replace('_', '-')
+ current.append('%s: %s' % (key, value))
+ tag.set('style', '; '.join(current))
+ elif isinstance(value, basestring):
+ attr = attr.replace('_', '-')
+ for tag in self:
+ current = [
+ el.strip()
+ for el in (tag.get('style') or '').split(';')
+ if (el.strip() and
+ not el.split(':')[0].strip() == attr.strip())]
+ current.append('%s: %s' % (attr, value))
+ tag.set('style', '; '.join(current))
+ return self
+
+ css = FlexibleElement(pget=css, pset=css)
+
+ ###################
+ # CORE UI EFFECTS #
+ ###################
+ def hide(self):
+ """remove display:none to elements style
+
+ >>> print(PyQuery('
').hide())
+
+
+ """
+ return self.css('display', 'none')
+
+ def show(self):
+ """add display:block to elements style
+
+ >>> print(PyQuery('
').show())
+
+
+ """
+ return self.css('display', 'block')
+
+ ########
+ # HTML #
+ ########
+ def val(self, value=no_default):
+ """Set the attribute value::
+
+ >>> d = PyQuery('
')
+ >>> d.val('Youhou')
+ [
]
+
+ Get the attribute value::
+
+ >>> d.val()
+ 'Youhou'
+
+ """
+
+ def _get_value(tag):
+ #