Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restore metaclass functionality on all python versions #106

Closed
jancespivo opened this issue Aug 21, 2018 · 7 comments
Closed

Restore metaclass functionality on all python versions #106

jancespivo opened this issue Aug 21, 2018 · 7 comments

Comments

@jancespivo
Copy link

Hi,
see

__metaclass__ = abc.ABCMeta

Unfortunately __metaclass__ has no effect in Python 3. The correct way in Python3 is: class StatsClientBase(metaclass=abc.ABCMeta):

The best way how to keep compatibility with the Python 2 is to use six or future.utils. For only this particular purpose I recommend the future.utils. See http://python-future.org/_modules/future/utils.html#with_metaclass

@jsocol
Copy link
Owner

jsocol commented Aug 21, 2018

Honestly, I'm not sure that the ABCMeta metaclass is doing very much. No tests fail on Python 3.x that pass on Python 2.x (there's an issue with test_ipv6_resolution_udp on Travis but that's true on all Python versions except Pypy).

The only thing we're doing with it is ensuring all the necessary abstract methods are implemented—but neither StatsClientBase nor PipelineBase are intended to be extended by userland code, they're purely internal. That means we can solve this multiple ways. I don't particularly want to add a dependency for this on either six or future. The fact that all the tests pass on 3.6 (at least when I run it locally) is kind of enough for me.

I'm going to pull out the metaclass and dependency on abc, and have the unimplemented methods raise NotImplementedError() instead. But in the meantime, I don't actually believe there's any externally-facing behavior that doesn't work on Py3 here. There are some internal guarantees that aren't being backstopped by the ABCMeta infrastructure—but they are being guaranteed by the test suite.

jsocol added a commit that referenced this issue Aug 21, 2018
StatsClientBase and PipelineBase are not intended to be public APIs, and
the syntax for metaclasses introduces some complexity between Python 2
and 3.

Since ABCMeta and abc.abstractmethod were only being used to guarantee
that internal subclasses implemented these methods correctly, and
there's no external behavioral issues on Python 3, where the metaclass
has been ignored for years, let's remove the metaclass and rely on
NotImplementedError() and the test suite as a backstop.

Fixes #106.
@jancespivo
Copy link
Author

I fully understand your attitude.

We've just implemented our custom statsd client compatible with StatsClient. We use the typechecking via mypy so we need to somewhat declare that our client has the same interface as a StatsClient. It can be simply done with StatstBase.register method provided by ABCMeta. The simple inheritance can cause a problems.

Best regards.

@jsocol
Copy link
Owner

jsocol commented Aug 21, 2018

I'm definitely open to re-adding the metaclass if there are other benefits to it—I'd still rather avoid a dependency here but I think we could vendor in (copy/paste) the with_metaclass helper from future.util.

I'm not entirely sure I'm following, though. Why does statsd.client.StatsClient need to implement register()? It seems like your implementation would be the one declaring itself a StatsClient? Is there a snippet or example code you could share?

@jancespivo
Copy link
Author

jancespivo commented Aug 22, 2018

+1 for idea of vendoring the code from future.util

ABCMeta provides the classmethod register (see https://docs.python.org/3/library/abc.html#abc.ABCMeta.register) so no implementation is needed. Actually I think it is only feature which ABCMeta provides at all.

@jsocol
Copy link
Owner

jsocol commented Sep 26, 2018

Sorry @jancespivo—I was on vacation for a little while. So is my understanding correct that:

class MyABC(metaclass=ABCMeta):
    pass

class X:
    pass

MyABC.register(X)

issubclass(X, MyABC)  # is True

Right? While that makes sense for built-in or other 3rd-party classes, I guess I don't understand the types of problems that directly subclassing StatsClient (or StatsClientBase—if you want to venture into private code) would cause?

@jancespivo
Copy link
Author

@jsocol Now it is not a problem, it is for the future. For example if the __setattr__ will be implemented in StatsClient or StatsClientBase for some unknown reason, it will influence all inherited classes. The ABCMeta separates the implementation and the interface.

@jsocol jsocol changed the title Incompatibility with Python 3 Restore metaclass functionality on all python versions Oct 2, 2018
@jsocol
Copy link
Owner

jsocol commented Oct 2, 2018

I’ve updated the title here to give a more accurate (and less alarming) description, but am going to leave closed for right now as there don’t actually appear to be any practical repercussions of the removal right now.

However, like I said, I’m definitely open to re-introducing the metaclass if there’s a demonstrable issue today, or if we introduce one in the future eg with __setattr__. If we do, I want to make sure we have some test of the metaclass functionality within this library’s test suite.

nshenkman added a commit to klaviyo/pystatsd that referenced this issue Feb 26, 2020
* Bug: Fix timer decorator with partial functions (jsocol#85)

* Update badges

* Drop support for old Python versions

Leave Python 2.6, 3.2, and 3.3 out. Let's focus on >=3.4 (and we'll
still support 2.7 because it's easy).

* Skip IPv6 resolution test

Since early June[1], IPv6 loopback address resolution has been flaky on
TravisCI. It seems that it should have been flaky even earlier, or
there's something strange going on. For now, skip the test. We can come
back to diagnosing once master is (otherwise) passing.

This failure first started on Python 2.6, but quickly spread to all
versions. It appears to pass occasionally, but not on any consistent
version. Lately it seems to fail more or less all the time, though on
the latest cron build, it did pass on Pypy[2].

[1]: https://travis-ci.org/jsocol/pystatsd/builds/387167216
[2]: https://travis-ci.org/jsocol/pystatsd/builds/417687774

* Remove dependency on ABCMeta.

StatsClientBase and PipelineBase are not intended to be public APIs, and
the syntax for metaclasses introduces some complexity between Python 2
and 3.

Since ABCMeta and abc.abstractmethod were only being used to guarantee
that internal subclasses implemented these methods correctly, and
there's no external behavioral issues on Python 3, where the metaclass
has been ignored for years, let's remove the metaclass and rely on
NotImplementedError() and the test suite as a backstop.

Fixes jsocol#106.

* Fix minor nits, spelling and unused imports

* Add a document about tagging metrics

Collecting thoughts that have been spread across several GitHub issues
and pull requests into one place, a reference to use from now on when
the discussion of tags comes up.

* Add timedelta support to Client.timing

Allow passing datetime.timedelta objects directly to
StatsClient.timing(), automatically converting to milliseconds.

* Simplify timer decorator

* Introduce UnixSocketStatsClient class.

New client for handling sending stats through Unix domains sockets.

* Update Sphinx directives in docs

Tweaks a lot of doc references to use better Sphinx tooling. Shouldn't
break any existing links, but may get to a point where we don't need
quite as many named references.

* Fix wrapping in reference docs

* Use Python-domain Sphinx references

* Remove redundant reference points

* Refactor client module into package

The client module just broke 300 lines and had a lot of functionality in
it. This breaks the single file up into a package and reduces a decent
amount of duplication. Makes a few related changes:

- Replaces old Python __future__ imports with new ones
- Removes __all__ in favor of fewer imports
- Refactors common stream code into StreamClientBase
- Renames TCPPipeline to StreamPipeline for consistency (this is not a
  public class name)

* Remove old version classifiers

* Version 3.3

- Drop support for Python 2.5, 2.6, 3.2, 3.3 (jsocol#108, jsocol#116).
- Add UnixSocketStatsClient (jsocol#76, jsocol#112).
- Add support for timedeltas in timing() (jsocol#104, jsocol#111).
- Fix timer decorator with partial functions (jsocol#85).
- Remove ABCMeta metaclass (incompatible with Py3) (jsocol#109).
- Refactor client module (jsocol#115).
- Various doc updates (jsocol#99, jsocol#102, jsocol#110, jsocol#113, jsocol#114).

Co-authored-by: Mathieu Leplatre <mathieu@leplat.re>
Co-authored-by: James Socol <me@jamessocol.com>
Co-authored-by: Jorge Maroto <patoroco@gmail.com>
Co-authored-by: Gijs van der Voort <vandervoort.gijs@gmail.com>
Co-authored-by: Michael <michael-k@users.noreply.github.com>
Co-authored-by: hintofbasil <CuteCondemnedPenguin@shadowmail.co.uk>
Co-authored-by: Jason Parker <jason.thomas.parker@gmail.com>
csestelo pushed a commit to Destygo/pystatsd that referenced this issue Jul 18, 2022
* Back to global variables

* Migration

* Update tests/api/namespace/test_variables.py

Co-authored-by: Vincent GENTY <Wellan89@users.noreply.github.com>

* Update tests/api/namespace/test_variables.py

Co-authored-by: Vincent GENTY <Wellan89@users.noreply.github.com>

* Review + upgrade requirements

* Upgrade precommits

Co-authored-by: Vincent GENTY <Wellan89@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants