PageRenderTime 254ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/osc2/util/xpath.py

https://github.com/openSUSE/osc2
Python | 876 lines | 873 code | 0 blank | 3 comment | 0 complexity | 611682b2953bf6e7cca5f827cabe175f MD5 | raw file
  1. """This module provides classes to build a XPath.
  2. The XPathBuilder class can be used to build an xpath expression
  3. in a "natural" and "pythonic" way.
  4. This module is mainly inspired by https://github.com/jnicklas/xpath
  5. (especially the syntax of the DSL).
  6. """
  7. def children(minimum, maximum):
  8. """Decorator which checks the number of an expression's children.
  9. It raises a XPathSyntaxError if it has less than minimum or
  10. more than maximum children.
  11. """
  12. def decorate(f):
  13. def checker(self, *args, **kwargs):
  14. len_children = len(self._children)
  15. if len_children < minimum:
  16. msg = "At least '%d' children required." % minimum
  17. raise XPathSyntaxError(msg)
  18. if len_children > maximum:
  19. msg = "At most '%d' children allowed." % maximum
  20. raise XPathSyntaxError(msg)
  21. return f(self, *args, **kwargs)
  22. checker.func_name = f.func_name
  23. return checker
  24. return decorate
  25. def no_dummy(f):
  26. """Decorator which checks that expr is no DummyExpression.
  27. If it is a DummyExpression the method is not executed
  28. and self is returned.
  29. """
  30. def checker(self, expr, *args, **kwargs):
  31. if isinstance(expr, DummyExpression):
  32. return self
  33. return f(self, expr, *args, **kwargs)
  34. checker.func_name = f.func_name
  35. return checker
  36. class XPathSyntaxError(SyntaxError):
  37. """Raised if the expression tree is (syntactically) invalid."""
  38. pass
  39. class XPathBuilder(object):
  40. """Provides methods to build a xpath expression in a pythonic way.
  41. It is the interface between the user and the internal classes.
  42. """
  43. def __init__(self, factory=None, context_item=False, is_relative=False):
  44. """Constructs a new XPathBuilder object.
  45. Keyword arguments:
  46. factory -- the factory which is used for creating the xpath
  47. expressions (default: XPathFactory)
  48. context_item -- if True a newly build path expression is preceded
  49. by a context item expression (default: False)
  50. is_relative -- if True a newly build path expression is a relative
  51. path expression (default: False)
  52. """
  53. super(XPathBuilder, self).__init__()
  54. self._factory = factory or XPathFactory()
  55. self.context_item = context_item
  56. self.is_relative = is_relative
  57. def context(self, context_item):
  58. """Returns a new XPathBuilder object.
  59. If context_item is True a path expression (which is
  60. constructed with the new XPathBuilder object) is preceded
  61. by a context item expression.
  62. """
  63. return XPathBuilder(self._factory, context_item=context_item)
  64. def relative(self, is_relative):
  65. """Returns a new XPathBuilder object.
  66. If is_relative is True a path expression (which is constructed
  67. with the new XPathBuilder object) is a relative path
  68. expression.
  69. """
  70. return XPathBuilder(self._factory, is_relative=is_relative)
  71. def attr(self, *args, **kwargs):
  72. """Returns a new AttributeExpression object.
  73. *args and **kwargs are additional arguments for the
  74. AttributeExpression's __init__ method.
  75. """
  76. kwargs.setdefault('in_pred', True)
  77. return self._factory.create_AttributeExpression(*args, **kwargs)
  78. def dummy(self):
  79. """Returns a new DummyExpression object.
  80. *args and **kwargs are additional arguments for the
  81. DummyExpression's __init__ method.
  82. """
  83. return self._factory.create_DummyExpression()
  84. def __getattr__(self, name):
  85. """Delegetates the call to a new PathExpression object.
  86. name is the name of the requested attribute.
  87. """
  88. ci = self.context_item
  89. rel = self.is_relative
  90. dummy = self._factory.create_PathExpression('', init=True,
  91. context_item=ci,
  92. is_relative=rel)
  93. expr = getattr(dummy, name)
  94. return expr
  95. class XPathFactory(object):
  96. """Factory to create the expression objects.
  97. This way it's possible replace the existing expression
  98. classes with its own implementation.
  99. """
  100. def create_PathExpression(self, *args, **kwargs):
  101. """Constructs a new PathExpression Object.
  102. *args and **kwargs are additional arguments for the
  103. PathExpression's __init__ method.
  104. """
  105. kwargs.setdefault('factory', self)
  106. return PathExpression(*args, **kwargs)
  107. def create_FunctionExpression(self, *args, **kwargs):
  108. """Constructs a new FunctionExpression Object.
  109. *args and **kwargs are additional arguments for the
  110. FunctionExpression's __init__ method.
  111. """
  112. kwargs.setdefault('factory', self)
  113. return FunctionExpression(*args, **kwargs)
  114. def create_BinaryExpression(self, *args, **kwargs):
  115. """Constructs a new BinaryExpression Object.
  116. *args and **kwargs are additional arguments for the
  117. BinaryExpression's __init__ method.
  118. """
  119. kwargs.setdefault('factory', self)
  120. return BinaryExpression(*args, **kwargs)
  121. def create_AttributeExpression(self, *args, **kwargs):
  122. """Constructs a new AttributeExpression Object.
  123. *args and **kwargs are additional arguments for the
  124. AttributeExpression's __init__ method.
  125. """
  126. kwargs.setdefault('factory', self)
  127. return AttributeExpression(*args, **kwargs)
  128. def create_PredicateExpression(self, *args, **kwargs):
  129. """Constructs a new PredicateExpression Object.
  130. *args and **kwargs are additional arguments for the
  131. PredicateExpression's __init__ method.
  132. """
  133. kwargs.setdefault('factory', self)
  134. return PredicateExpression(*args, **kwargs)
  135. def create_ParenthesizedExpression(self, *args, **kwargs):
  136. """Constructs a new ParenthesizedExpression Object.
  137. *args and **kwargs are additional arguments for the
  138. ParenthesizedExpression's __init__ method.
  139. """
  140. kwargs.setdefault('factory', self)
  141. return ParenthesizedExpression(*args, **kwargs)
  142. def create_LiteralExpression(self, *args, **kwargs):
  143. """Constructs a new LiteralExpression object.
  144. *args and **kwargs are additional arguments for the
  145. LiteralExpression's __init__ method.
  146. """
  147. kwargs.setdefault('factory', self)
  148. return LiteralExpression(*args, **kwargs)
  149. def create_GeneratorPathDelegate(self, *args, **kwargs):
  150. """Constructs a new GeneratorPathDelegate object.
  151. *args and **kwargs are additional arguments for the
  152. GeneratorPathDelegate's __init__ method.
  153. """
  154. kwargs.setdefault('factory', self)
  155. return GeneratorPathDelegate(*args, **kwargs)
  156. def create_GeneratorDelegate(self, delegate, *args, **kwargs):
  157. """Constructs a new GeneratorDelegate object.
  158. *args and **kwargs are additional arguments for the
  159. GeneratorDelegate's __init__ method.
  160. """
  161. base_cls = delegate.__class__
  162. class GeneratorDelegate(base_cls):
  163. """Used to generate expressions from a common base expression.
  164. Its main purpose is to wrap the base expression object so that
  165. all tree operations are executed on this object instead of the
  166. delegate.
  167. No children are added and just reparent operations are executed. In
  168. fact we could avoid this class if we wouldn't remove the child from
  169. the "old" parent if a reparent operation is executed.
  170. """
  171. def __init__(self, delegate, *args, **kwargs):
  172. """Constructs a new GeneratorDelegate object.
  173. delegate is the expression object which should be wrapped.
  174. *args, **kwargs are additional arguments for the base class'
  175. __init__ method.
  176. """
  177. super(self.__class__, self).__init__(*args, **kwargs)
  178. self._delegate = delegate
  179. def __call__(self):
  180. return self._factory.create_GeneratorDelegate(self._delegate)
  181. def tostring(self):
  182. return self._delegate.tostring()
  183. kwargs.setdefault('factory', self)
  184. # build dummy __init__ arguments
  185. dummy_args = []
  186. if delegate.__class__.__name__ != 'ParenthesizedExpression':
  187. # only a ParenthesizedExpression needs no dummy arg
  188. # (a PredicateExpression does not have to be considered because
  189. # it should never be passed to this method (use
  190. # createGeneratorPathDelegate instead))
  191. dummy_args.append('')
  192. return GeneratorDelegate(delegate, *dummy_args, **kwargs)
  193. def create_DummyExpression(self, *args, **kwargs):
  194. """Creates a new DummyExpression object.
  195. *args and **kwargs are additional arguments for the
  196. DummyExpression's __init__ method.
  197. """
  198. return DummyExpression(*args, **kwargs)
  199. class Tree(object):
  200. """Represents a simple tree.
  201. A tree node might have an arbitrary number of children but
  202. only one parent or None (if it has no parent it is the root
  203. node).
  204. It is required that a Tree (or subclass) object can be used
  205. in list context that is something like "tree in list" evaluates
  206. to True if and only if the tree object is in the list.
  207. As there might be cases where a Tree subclass implements a
  208. __eq__ method (for example) so that the requirement from above
  209. is NOT satisfied a special "tree mode" is introduced.
  210. If an object is in the "tree mode" its customized __eq__
  211. method should NOT be executed (for instance it should return
  212. "NotImplemented").
  213. In the tree mode it is guaranteed that only the methods and
  214. attributes which are defined in this class will be invoked
  215. (except if a subclass modified these methods).
  216. """
  217. def tree_op():
  218. """Decorator which is used to decorate all tree methods.
  219. For each object which participates in the method call
  220. (self, the argument and our children) the tree_mode is
  221. enabled.
  222. """
  223. def decorator(f):
  224. def operation(self, tree):
  225. self.tree_mode(True, self)
  226. if tree is not None:
  227. tree.tree_mode(True, self)
  228. for c in self._children:
  229. c.tree_mode(True, self)
  230. f(self, tree)
  231. self.tree_mode(False, self)
  232. if tree is not None:
  233. tree.tree_mode(False, self)
  234. for c in self._children:
  235. c.tree_mode(False, self)
  236. operation.func_name = f.func_name
  237. return operation
  238. return decorator
  239. def __init__(self, children=None):
  240. """Constructs a new Tree object.
  241. Keyword arguments:
  242. children -- the children objects (default: None)
  243. """
  244. super(Tree, self).__init__()
  245. self._children = children or []
  246. self._parent = None
  247. self._tree_mode = None
  248. for c in self._children:
  249. c.reparent(self)
  250. @tree_op()
  251. def reparent(self, parent):
  252. """Sets a new parent object.
  253. parent is the new parent.
  254. """
  255. old_parent = self._parent
  256. self._parent = parent
  257. if old_parent is not None:
  258. old_parent.remove_child(self)
  259. @tree_op()
  260. def append_child(self, child):
  261. """Appends a child object.
  262. child is the newly appended child.
  263. """
  264. self._children.append(child)
  265. child.reparent(self)
  266. @tree_op()
  267. def remove_child(self, child):
  268. """Removes a child object.
  269. child is the child which should be removed.
  270. """
  271. if child in self._children:
  272. self._children.remove(child)
  273. child.reparent(None)
  274. def tree_mode(self, on, obj):
  275. """Enables or disables the tree mode for this (self) object.
  276. on specifies whether the tree mode is enabled or
  277. disabled (True means enabled, False means disabled).
  278. obj is the object which want to the change the tree mode.
  279. A tree mode can only be disabled by the object which
  280. enabled it.
  281. """
  282. if self._tree_mode is None and on:
  283. self._tree_mode = obj
  284. elif not on and self._tree_mode is obj:
  285. self._tree_mode = None
  286. def is_tree_mode(self):
  287. """Returns True if the tree mode is enabled otherwise False."""
  288. return self._tree_mode is not None
  289. class Expression(Tree):
  290. """Abstract base class for all xpath expressions."""
  291. # Expressions are not hashable because __eq__ etc. are implemented
  292. # in an incompatible way
  293. __hash__ = None
  294. def disable_in_tree_mode():
  295. """Decorator which "disables" a method if the object is in tree mode.
  296. "Disabling" a method means in this context that it
  297. simply returns NotImplemented.
  298. """
  299. def decorator(f):
  300. def disable(self, *args, **kwargs):
  301. if self.is_tree_mode():
  302. return NotImplemented
  303. return f(self, *args, **kwargs)
  304. disable.func_name = f.func_name
  305. return disable
  306. return decorator
  307. def __init__(self, factory, children=None):
  308. """Constructs a new Expression object.
  309. factory is the factory which is used for creating new
  310. expression objects.
  311. Keyword arguments:
  312. children -- the expression's children (default: None)
  313. """
  314. super(Expression, self).__init__(children)
  315. self._factory = factory
  316. @no_dummy
  317. def log_and(self, expr):
  318. """Connects self and expr via "and".
  319. expr is the right expression.
  320. """
  321. children = [self, expr]
  322. return self._factory.create_BinaryExpression('and', children=children)
  323. @no_dummy
  324. def log_or(self, expr):
  325. """Connects self and expr via "or".
  326. expr is the right expression.
  327. """
  328. children = [self, expr]
  329. return self._factory.create_BinaryExpression('or', children=children)
  330. def log_not(self):
  331. """Negate self."""
  332. # technically not is an xpath function and not a
  333. # logical expression so the method name is a bit misleading
  334. # this object is NOT a children just a parameter
  335. return self._factory.create_FunctionExpression('not', self,
  336. in_pred=True,
  337. children=[])
  338. def equals(self, literal):
  339. """Compares
  340. literal is a str literal.
  341. """
  342. lit_expr = self._expression_or_literal(literal)
  343. children = [self, lit_expr]
  344. return self._factory.create_BinaryExpression('=', children=children)
  345. def not_equals(self, literal):
  346. """Returns a BinaryExpression Object.
  347. literal is a str literal.
  348. """
  349. lit_expr = self._expression_or_literal(literal)
  350. children = [self, lit_expr]
  351. return self._factory.create_BinaryExpression('!=', children=children)
  352. def parenthesize(self):
  353. """Parenthesize self."""
  354. return self._factory.create_ParenthesizedExpression(children=[self])
  355. def tostring(self):
  356. """String representation of the expression"""
  357. raise NotImplementedError()
  358. def _expression_or_literal(self, expr):
  359. """Returns an Expression (or subclass) object.
  360. If expr is an Expression object expr is returned otherwise
  361. a LiteralExpression is returned.
  362. """
  363. if not hasattr(expr, 'reparent'):
  364. # treat it as a literal (the above is sufficient - we don't
  365. # do strict type checks like issubclass etc.)
  366. expr = self._factory.create_LiteralExpression(expr)
  367. return expr
  368. def __enter__(self):
  369. return self._factory.create_GeneratorDelegate(self)
  370. def __exit__(self, exc_type, exc_value, traceback):
  371. pass
  372. @disable_in_tree_mode()
  373. def __and__(self, other):
  374. return self.log_and(other)
  375. @disable_in_tree_mode()
  376. def __or__(self, other):
  377. return self.log_or(other)
  378. @disable_in_tree_mode()
  379. def __eq__(self, other):
  380. return self.equals(other)
  381. @disable_in_tree_mode()
  382. def __ne__(self, other):
  383. return self.not_equals(other)
  384. class PathExpression(Expression):
  385. """Represents a xpath path expression"""
  386. def __init__(self, name, axis='', init=False,
  387. context_item=False, is_relative=False, **kwargs):
  388. """Constructs a new PathExpression object.
  389. name is the of the path component.
  390. **kwargs are the arguments for the superclass'
  391. __init__ method.
  392. Keyword arguments:
  393. axis -- the name of the axis (default: '' - child axis)
  394. init -- if True it indicates that this is the first expression
  395. in the expression tree (needs some special handling due
  396. to the way the XPathBuilder class works) (default: False)
  397. context_item -- if True the PathExpression is treated like a context
  398. item expression (it starts with an initial '.')
  399. (default: False)
  400. is_relative -- if True the PathExpression is a relative path
  401. expression (no leading '/') (default: False)
  402. """
  403. super(PathExpression, self).__init__(**kwargs)
  404. self._name = name
  405. self._axis = axis
  406. self._init = init
  407. self._context_item = context_item
  408. self._is_relative = is_relative
  409. def descendant(self, name):
  410. """Returns a PathExpression object for the descendant axis.
  411. name is the name of the path component.
  412. """
  413. return self._create_parent('Path', name, 'descendant')
  414. def preceding(self, name):
  415. """Returns a PathExpression object for the preceding axis.
  416. name is the name of the path component.
  417. """
  418. return self._create_parent('Path', name, 'preceding')
  419. def parent(self, name):
  420. """Returns a PathExpression object for the parent axis.
  421. name is the name of the path component.
  422. """
  423. return self._create_parent('Path', name, 'parent')
  424. def attr(self, name):
  425. """Returns an AttributeExpression object.
  426. name is the name of the attribute.
  427. """
  428. return self._create_parent('Attribute', name, in_pred=False)
  429. def where(self, expr):
  430. """Returns a PredicateExpression object.
  431. expr is the predicate expression or a (int) literal.
  432. """
  433. expr = self._expression_or_literal(expr)
  434. children = [self, expr]
  435. return self._factory.create_PredicateExpression(children=children)
  436. def join(self, expr):
  437. """Joins two (Path) Expressions and returns expr.
  438. expr is the (path) expression which is "appended".
  439. (Example: foo.bar.join(baz.foo) => /foo/bar/baz/foo)
  440. """
  441. leaf = expr
  442. # XXX: we should ensure that no infinite recursion is possible
  443. # ignore it for now
  444. while leaf._children:
  445. leaf = leaf._children[0]
  446. leaf.append_child(self)
  447. return expr
  448. def text(self):
  449. """Returns a FunctionExpression object.
  450. This FunctionExpression represents a text() kind test.
  451. """
  452. return self._factory.create_FunctionExpression('text', in_pred=False,
  453. children=[self])
  454. def _create_parent(self, kind, *args, **kwargs):
  455. """Returns a new Expression object which is the new parent"""
  456. if self._init:
  457. self._init = False
  458. kwargs.setdefault('context_item', self._context_item)
  459. kwargs.setdefault('is_relative', self._is_relative)
  460. else:
  461. kwargs.setdefault('children', [self])
  462. meth = getattr(self._factory, 'create_' + kind + 'Expression')
  463. expr = meth(*args, **kwargs)
  464. return expr
  465. def __getattr__(self, name):
  466. return self._create_parent('Path', name)
  467. def __getitem__(self, key):
  468. return self.where(key)
  469. def __enter__(self):
  470. return self._factory.create_GeneratorPathDelegate(self)
  471. @children(0, 1)
  472. def tostring(self):
  473. res = ''
  474. if self._children:
  475. res = self._children[0].tostring()
  476. if self._context_item:
  477. res += '.'
  478. if not self._is_relative:
  479. res += '/'
  480. if self._axis:
  481. return res + "%s::%s" % (self._axis, self._name)
  482. return res + "%s" % self._name
  483. class AttributeExpression(Expression):
  484. """Represents an attribute expression."""
  485. def __init__(self, name, in_pred=False, **kwargs):
  486. """Constructs a new AttributeExpression object.
  487. name is the name of the attribute.
  488. **kwargs are the arguments for the superclass'
  489. __init__ method.
  490. Keyword arguments:
  491. in_pred -- indicates if this attribute is used in a
  492. predicate or in a path (default: False)
  493. """
  494. super(AttributeExpression, self).__init__(**kwargs)
  495. self._name = name
  496. self._in_pred = in_pred
  497. def contains(self, literal):
  498. """Returns a FunctionExpression object.
  499. literal is a str literal.
  500. The FunctionExpression represents the "contains(attr, literal)"
  501. xpath function.
  502. """
  503. lit_expr = self._expression_or_literal(literal)
  504. return self._factory.create_FunctionExpression('contains', self,
  505. lit_expr,
  506. in_pred=self._in_pred,
  507. children=[])
  508. def tostring(self):
  509. if self._in_pred:
  510. return '@' + self._name
  511. if self._children:
  512. return self._children[0].tostring() + '/@' + self._name
  513. return '/@' + self._name
  514. class LiteralExpression(Expression):
  515. """Represents a literal."""
  516. def __init__(self, literal, **kwargs):
  517. """Constructs a new LiteralExpression object.
  518. literal is the literal which should be represented
  519. by this object. If the literal is a string (it is treated
  520. as a string if it has a "upper" attribute/method (this was
  521. arbitrarily chosen)) it sourrunded with "". Otherwise its
  522. str representation is returned.
  523. **kwargs are the arguments for the superclass'
  524. __init__ method.
  525. """
  526. super(LiteralExpression, self).__init__(**kwargs)
  527. self._literal = literal
  528. @children(0, 0)
  529. def tostring(self):
  530. if hasattr(self._literal, 'upper'):
  531. # treat it as a string
  532. return "\"%s\"" % str(self._literal)
  533. return str(self._literal)
  534. class PredicateExpression(PathExpression):
  535. """Represents a xpath predicate"""
  536. def __init__(self, **kwargs):
  537. """Constructs a new PredicateExpression object.
  538. **kwargs are the arguments for the superclass'
  539. __init__ method.
  540. """
  541. super(PredicateExpression, self).__init__('', **kwargs)
  542. @children(2, 2)
  543. def tostring(self):
  544. return "%s[%s]" % (self._children[0].tostring(),
  545. self._children[1].tostring())
  546. class BinaryExpression(Expression):
  547. """Represents a binary (operator) expression in infix notation."""
  548. def __init__(self, op, **kwargs):
  549. """Constructs a new BinaryExpression object.
  550. op is the binary operator which is used to connect children[0]
  551. and children[1]. children[0] is the left and children[1] the
  552. right expression.
  553. **kwargs are the arguments for the superclass'
  554. __init__ method.
  555. """
  556. super(BinaryExpression, self).__init__(**kwargs)
  557. self._op = op
  558. @children(2, 2)
  559. def tostring(self):
  560. return "%s %s %s" % (self._children[0].tostring(), self._op,
  561. self._children[1].tostring())
  562. class FunctionExpression(Expression):
  563. """Represents a xpath function in "prefix notation"."""
  564. def __init__(self, name, *params, **kwargs):
  565. """Constructs a new FunctionExpression object.
  566. name is the name of the function and params are
  567. the parameters.
  568. **kwargs are the arguments for the superclass'
  569. __init__ method.
  570. Keyword arguments:
  571. in_pred -- indicates if this function is used in a
  572. predicate or in a path (default: False)
  573. """
  574. in_pred = kwargs.pop('in_pred', False)
  575. super(FunctionExpression, self).__init__(**kwargs)
  576. self._name = name
  577. # hmm it might be better to treat the params as children
  578. self._params = []
  579. self._in_pred = in_pred
  580. for p in params:
  581. expr = self._expression_or_literal(p)
  582. self._params.append(expr)
  583. def tostring(self):
  584. res = ''
  585. if self._children:
  586. res = self._children[0].tostring()
  587. params = [p.tostring() for p in self._params]
  588. if not self._in_pred:
  589. res += '/'
  590. return res + "%s(%s)" % (self._name, ', '.join(params))
  591. class ParenthesizedExpression(Expression):
  592. """Represents a parenthesized expression."""
  593. def __init__(self, **kwargs):
  594. """Constructs a new ParenthesizedExpression object.
  595. parentheses.
  596. **kwargs are the arguments for the superclass'
  597. __init__ method.
  598. """
  599. super(ParenthesizedExpression, self).__init__(**kwargs)
  600. @children(1, 1)
  601. def tostring(self):
  602. return "(%s)" % self._children[0].tostring()
  603. class GeneratorPathDelegate(PathExpression):
  604. """Used to generate expressions from a common base PathExpression.
  605. Its main purpose is to wrap the base PathExpression (or subclass)
  606. object so that all tree operations are executed on this object
  607. instead of the delegate.
  608. """
  609. def __init__(self, delegate, **kwargs):
  610. """Constructs a new GeneratorPathDelegate object.
  611. delegate is the PathExpression (or subclass) object
  612. which should be wrapped.
  613. **kwargs are additional arguments for the Tree's
  614. __init__ method.
  615. """
  616. super(GeneratorPathDelegate, self).__init__('', **kwargs)
  617. self._delegate = delegate
  618. def __call__(self):
  619. return self._factory.create_GeneratorPathDelegate(self._delegate)
  620. @children(0, 1)
  621. def tostring(self):
  622. res = ''
  623. if self._children:
  624. res = self._children[0].tostring()
  625. return res + self._delegate.tostring()
  626. class DummyExpression(object):
  627. """This class represents a dummy expression.
  628. Its sole purpose is to make the xpath code
  629. easier to read (we can avoid "xp is None" tests
  630. in a loop).
  631. """
  632. def parenthesize(self):
  633. return self
  634. def log_not(self):
  635. return self
  636. def __and__(self, other):
  637. return other
  638. def __or__(self, other):
  639. return other
  640. def __eq__(self, other):
  641. return other
  642. def __ne__(self, other):
  643. return other
  644. def __nonzero__(self):
  645. return False