The more I look at this code, the more confused I get.  I'm looking BaseSite.__getattr__() on master.  It starts out:


    def __getattr__(self, attr):
        """Delegate undefined methods calls to the Family object."""
        if hasattr(self.__class__, attr):
            return getattr(self.__class__, attr)


how could that branch ever be taken?  __getattr__() is called when "when the default attribute access fails with an AttributeError".  Which means the hasattr() call will always return False.



On Dec 11, 2022, at 10:20 PM, info@gno.de wrote:


Hi,

It is not a reimplementation of class inheritance. The API method is delegated to the Family method for its site code only e.g. site.encodings() calls site.family.encodings(site.code).

Best
xqt

Am 12.12.2022 um 02:50 schrieb Roy Smith <roy@panix.com>:

I've been beating my head against the wall trying to figure out how to build a Mock of APISite.  If I do the obvious:

  site = mocker.MagicMock(spec=APISite)

I end up with:

AttributeError: Mock object has no attribute 'encodings'

Yet, if I hand-build a Site object, sure enough it does:

import pywikibot
site = pywikibot.Site("en", "wikipedia")
site.encodings()
('utf-8', 'iso-8859-1')


To make a long story short, eventually I found this bit of magic in _basesite.py:

  def __getattr__(self, attr):
      """Delegate undefined methods calls to the Family object."""
      if hasattr(self.__class__, attr):
          return getattr(self.__class__, attr)
      try:
          method = getattr(self.family, attr)
          if not callable(method):
              raise AttributeError
          f = functools.partial(method, self.code)
          if hasattr(method, '__doc__'):
              f.__doc__ = method.__doc__
          return f
      except AttributeError:
          raise AttributeError("{} instance has no attribute '{}'"
                               .format(self.__class__.__name__, attr))


WTF?  I mean, I see what it's doing, but why go to this level of obfuscation?  It's basically reimplementing class inheritance manually (and in a way which is totally beyond the ability of Mock to understand).
_______________________________________________
pywikibot mailing list -- pywikibot@lists.wikimedia.org
To unsubscribe send an email to pywikibot-leave@lists.wikimedia.org
_______________________________________________
pywikibot mailing list -- pywikibot@lists.wikimedia.org
To unsubscribe send an email to pywikibot-leave@lists.wikimedia.org