jaraco / skeleton

A generic project skeleton for Python projects.
http://blog.jaraco.com/skeleton/
MIT License
123 stars 36 forks source link

Expand type hints across projects #98

Open jaraco opened 1 year ago

jaraco commented 1 year ago

I received this inquiry in discord:

i want to put some effort into an initiative of filling jaraco.* and related projects with full-fledged type hints. would you mind helping me by providing a short list of the most important projects that i should focus on in the first place? thanks in advance! my intention is to make those projects play nicely with mypy, because i find them very useful, but i also value fully typed code.

jaraco commented 1 year ago

I'm happy to accept contributions! I tried to find a popularity ranking of all Python packages, but I didn't succeed. I did find snyk Advisor provides a quick and easy way to find packages by first letter (https://snyk.io/advisor/packages/python/j). You could go through the list of packages there and look at the popularity of each. It also sounds as if the pypi downloads tables are available to be queried (https://pypistats.org/api/#etiquette), so you could probably construct a query to do that. You might also search Github for projects with the skeleton badge - that's a pretty good indicator that it's following my best practices.

Tips

bswck commented 1 year ago

I am used to type checking my code with mypy in strict mode. While some may see the strict mode as too aggressive, I will have no problem adjusting a bigger codebase to pass strict type checking. This is what I had in mind during writing the message.

I'm not a fan of type hinting noise (e.g. -> None for two-line private methods with no return). Try to focus on adding type hints that add value - that communicate something additional and non-obvious. I won't reject a PR based on this condition, but it'll be more easily accepted if it's clearly adding value and not lint.

mypy disallows untyped definitions in the strict mode. A private function without the return statement is still assumed to return Any, which is untrue, since None is the desired return type:

class Foo:
    def _bar(self):  # seen by mypy as untyped
        pass

reveal_type(Foo()._bar())  # Revealed type is "Any"

class Spam:
    def _eggs(self, biz: int):  # seen as typed, return assumed to be Any
        pass

reveal_type(Spam()._eggs(5))  # Revealed type is "Any"

[!Note] The only exceptions from the behavior above are __init__ and __init_subclass__ methods where -> None can be omitted, provided the function has at least one type hint in the signature.

Relevant resources:

While no presence of the return statement in a method may be an obvious sign that the return type of that method does not matter, which is a logical reason not to leave a type hint there, even a return None statement with an unequivocal implication of the None return type is still seen as Any by mypy:

class Example:
    def _com(self, port: int):
        return None

reveal_type(Example()._com(43))  # Revealed type is "Any"

In places where the value of such a method is being used, the type hinting noise is then simply necessary to inform mypy about the actual return type that affects other scopes of the codebase.

I firmly believe that the best option would be being as explicit as possible when annotating types, because, as it seems, there are too few obvious cases at the end of the day.

The Zen of Python, by Tim Peters:

Beautiful is better than ugly. Explicit is better than implicit.

Note: The examples were tested on mypy 1.7.0.

bswck commented 1 year ago

I'm happy to accept contributions! I tried to find a popularity ranking of all Python packages, but I didn't succeed. I did find snyk Advisor provides a quick and easy way to find packages by first letter (snyk.io/advisor/packages/python/j). You could go through the list of packages there and look at the popularity of each. It also sounds as if the pypi downloads tables are available to be queried (pypistats.org/api/#etiquette), so you could probably construct a query to do that. You might also search Github for projects with the skeleton badge - that's a pretty good indicator that it's following my best practices.

Thank you for your time spent on the research. I will use these resources and compile a TO-DO list of the projects to work on in this issue. Every subsequent PR will reference this issue.

bswck commented 1 year ago

I firmly believe that the best option would be being as explicit as possible when annotating types, because, as it seems, there are too few obvious cases at the end of the day.

Of course if the new type hints would appear too intricate for the eye, which I can totally understand, there is always an option of creating stubs to isolate two worlds of the implementation and the type hints, like in https://github.com/jaraco/jaraco.functools/pull/22. What are your thoughts on this @jaraco?

bswck commented 1 year ago

The roadmap is ready! πŸŽ‰

I wrote a script that extracted all jaraco projects from PyPI and sorted them by the total of downloads in the last month. The last two projectsβ€”Distutils and backportsβ€”have 0 downloads only because checking pypi stats on them causes an HTTP 404 error. I don't think inspecting that issue is necessary.

[!Note] Skeleton badges come from the PyPI latest releases, not the projects' repositories. As a result, these badges are valid indicators of the years all the relevant latest PyPI releases took place.

The script produced the following table:

| | downloads last month | jaraco's role | uses skeleton? | |:------------------------------------------------------------------------------------------------------------|-----------------------:|:----------------|:----------------------------------------------------------------------| | [setuptools](https://pypi.org/project/setuptools) | 322655647 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [importlib-metadata](https://pypi.org/project/importlib-metadata) | 180078405 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [zipp](https://pypi.org/project/zipp) | 162258510 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [importlib-resources](https://pypi.org/project/importlib-resources) | 65910632 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [keyring](https://pypi.org/project/keyring) | 40286684 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.classes](https://pypi.org/project/jaraco.classes) | 37033262 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [setuptools-scm](https://pypi.org/project/setuptools-scm) | 25467595 | Owner | ❌ | | [pytest-runner](https://pypi.org/project/pytest-runner) | 16293153 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [configparser](https://pypi.org/project/configparser) | 10187739 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jsonpickle](https://pypi.org/project/jsonpickle) | 9339847 | Owner | ❌ | | [pep517](https://pypi.org/project/pep517) | 6590096 | Owner | ❌ | | [inflect](https://pypi.org/project/inflect) | 4843645 | Maintainer | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [twine](https://pypi.org/project/twine) | 3678588 | Owner | ❌ | | [backports.functools-lru-cache](https://pypi.org/project/backports.functools-lru-cache) | 2285253 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [singledispatch](https://pypi.org/project/singledispatch) | 2269372 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [comtypes](https://pypi.org/project/comtypes) | 1732642 | Owner | ❌ | | [cssutils](https://pypi.org/project/cssutils) | 1668764 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.functools](https://pypi.org/project/jaraco.functools) | 1623127 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [path](https://pypi.org/project/path) | 1583434 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [cheroot](https://pypi.org/project/cheroot) | 1482151 | Owner | ❌ | | [tempora](https://pypi.org/project/tempora) | 890592 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [portend](https://pypi.org/project/portend) | 829890 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.collections](https://pypi.org/project/jaraco.collections) | 795281 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [CherryPy](https://pypi.org/project/CherryPy) | 790657 | Owner | ❌ | | [distribute](https://pypi.org/project/distribute) | 741920 | Owner | ❌ | | [jaraco.text](https://pypi.org/project/jaraco.text) | 739296 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.context](https://pypi.org/project/jaraco.context) | 733410 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [keyrings.alt](https://pypi.org/project/keyrings.alt) | 614293 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [backports.entry-points-selectable](https://pypi.org/project/backports.entry-points-selectable) | 564770 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [path.py](https://pypi.org/project/path.py) | 333772 | Owner | ❌ | | [Tempita](https://pypi.org/project/Tempita) | 202581 | Maintainer | ❌ | | [Fuzzy](https://pypi.org/project/Fuzzy) | 120698 | Owner | ❌ | | [datadiff](https://pypi.org/project/datadiff) | 117694 | Owner | ❌ | | [wolframalpha](https://pypi.org/project/wolframalpha) | 51502 | Owner | ❌ | | [oathtool](https://pypi.org/project/oathtool) | 34623 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) | | [jaraco.logging](https://pypi.org/project/jaraco.logging) | 27595 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [irc](https://pypi.org/project/irc) | 22739 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [cherrypy-cors](https://pypi.org/project/cherrypy-cors) | 18930 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.stream](https://pypi.org/project/jaraco.stream) | 18120 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) | | [pytest-checkdocs](https://pypi.org/project/pytest-checkdocs) | 14617 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [pytest-enabler](https://pypi.org/project/pytest-enabler) | 14499 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [pip-run](https://pypi.org/project/pip-run) | 10838 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.env](https://pypi.org/project/jaraco.env) | 9083 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.itertools](https://pypi.org/project/jaraco.itertools) | 8260 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [hgtools](https://pypi.org/project/hgtools) | 7996 | Owner | ❌ | | [pytest-ignore-flaky](https://pypi.org/project/pytest-ignore-flaky) | 7441 | Maintainer | ❌ | | [jaraco.path](https://pypi.org/project/jaraco.path) | 7331 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.envs](https://pypi.org/project/jaraco.envs) | 6930 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [backports.datetime-timestamp](https://pypi.org/project/backports.datetime-timestamp) | 6897 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.versioning](https://pypi.org/project/jaraco.versioning) | 6230 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [mongo-connector](https://pypi.org/project/mongo-connector) | 5814 | Owner | ❌ | | [pytest-perf](https://pypi.org/project/pytest-perf) | 5729 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.ui](https://pypi.org/project/jaraco.ui) | 5272 | Owner | ❌ | | [jaraco.packaging](https://pypi.org/project/jaraco.packaging) | 4884 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.develop](https://pypi.org/project/jaraco.develop) | 4502 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.structures](https://pypi.org/project/jaraco.structures) | 4416 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [pytest-services](https://pypi.org/project/pytest-services) | 4205 | Maintainer | ❌ | | [rst.linker](https://pypi.org/project/rst.linker) | 3714 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.windows](https://pypi.org/project/jaraco.windows) | 3706 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.vcs](https://pypi.org/project/jaraco.vcs) | 3633 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [backports.unittest-mock](https://pypi.org/project/backports.unittest-mock) | 3263 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.docker](https://pypi.org/project/jaraco.docker) | 2477 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [suds-bis](https://pypi.org/project/suds-bis) | 2094 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) | | [jaraco.abode](https://pypi.org/project/jaraco.abode) | 1941 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.email](https://pypi.org/project/jaraco.email) | 1704 | Owner | ❌ | | [jaraco.net](https://pypi.org/project/jaraco.net) | 1697 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [MagicBus](https://pypi.org/project/MagicBus) | 1478 | Owner | ❌ | | [svg.charts](https://pypi.org/project/svg.charts) | 1416 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.mongodb](https://pypi.org/project/jaraco.mongodb) | 1336 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [calendra](https://pypi.org/project/calendra) | 1242 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.services](https://pypi.org/project/jaraco.services) | 768 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [pmxbot](https://pypi.org/project/pmxbot) | 740 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.tidelift](https://pypi.org/project/jaraco.tidelift) | 718 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [event](https://pypi.org/project/event) | 673 | Owner | ❌ | | [jaraco.clipboard](https://pypi.org/project/jaraco.clipboard) | 560 | Owner | ❌ | | [openpack](https://pypi.org/project/openpack) | 526 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [elastic2-doc-manager](https://pypi.org/project/elastic2-doc-manager) | 504 | Owner | ❌ | | [jaraco.test](https://pypi.org/project/jaraco.test) | 499 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [jaraco.pmxbot](https://pypi.org/project/jaraco.pmxbot) | 439 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [dynpool](https://pypi.org/project/dynpool) | 312 | Owner | ❌ | | [pytest-black-multipy](https://pypi.org/project/pytest-black-multipy) | 307 | Owner | ❌ | | [cherrypy-dynpool](https://pypi.org/project/cherrypy-dynpool) | 307 | Owner | ❌ | | [jaraco.modb](https://pypi.org/project/jaraco.modb) | 269 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [yg.lockfile](https://pypi.org/project/yg.lockfile) | 239 | Owner | ❌ | | [chucknorris](https://pypi.org/project/chucknorris) | 236 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [nspektr](https://pypi.org/project/nspektr) | 225 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [xlsxcessive](https://pypi.org/project/xlsxcessive) | 203 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [cmdix](https://pypi.org/project/cmdix) | 189 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [googlevoice](https://pypi.org/project/googlevoice) | 188 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.financial](https://pypi.org/project/jaraco.financial) | 175 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.timing](https://pypi.org/project/jaraco.timing) | 171 | Owner | ❌ | | [jaraco.postgres](https://pypi.org/project/jaraco.postgres) | 164 | Owner | ❌ | | [jaraco.compat](https://pypi.org/project/jaraco.compat) | 163 | Owner | ❌ | | [paradocx](https://pypi.org/project/paradocx) | 162 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [http-okapi](https://pypi.org/project/http-okapi) | 142 | Owner | ❌ | | [jaraco.geo](https://pypi.org/project/jaraco.geo) | 137 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [elastic-doc-manager](https://pypi.org/project/elastic-doc-manager) | 132 | Owner | ❌ | | [jaraco.util](https://pypi.org/project/jaraco.util) | 131 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) | | [compilers](https://pypi.org/project/compilers) | 129 | Owner | ❌ | | [jaraco.apt](https://pypi.org/project/jaraco.apt) | 122 | Owner | ❌ | | [setuptools-svn](https://pypi.org/project/setuptools-svn) | 103 | Owner | ❌ | | [jaraco.xonsh](https://pypi.org/project/jaraco.xonsh) | 98 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [vr.cli](https://pypi.org/project/vr.cli) | 96 | Owner | ❌ | | [vr.runners](https://pypi.org/project/vr.runners) | 96 | Owner | ❌ | | [lpaste](https://pypi.org/project/lpaste) | 92 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [rwt](https://pypi.org/project/rwt) | 92 | Owner | ❌ | | [jaraco.fabric](https://pypi.org/project/jaraco.fabric) | 83 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [NAT-PMP](https://pypi.org/project/NAT-PMP) | 83 | Owner | ❌ | | [vr.common](https://pypi.org/project/vr.common) | 81 | Owner | ❌ | | [pytest-home](https://pypi.org/project/pytest-home) | 74 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [fogbugz-bis](https://pypi.org/project/fogbugz-bis) | 68 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [backports.hook-compressed](https://pypi.org/project/backports.hook-compressed) | 66 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.nxt](https://pypi.org/project/jaraco.nxt) | 61 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [motivation](https://pypi.org/project/motivation) | 60 | Owner | ❌ | | [jaraco.video](https://pypi.org/project/jaraco.video) | 57 | Owner | ❌ | | [eggmonster](https://pypi.org/project/eggmonster) | 56 | Owner | ❌ | | [jaraco.site](https://pypi.org/project/jaraco.site) | 55 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [vr.server](https://pypi.org/project/vr.server) | 53 | Owner | ❌ | | [vr.imager](https://pypi.org/project/vr.imager) | 51 | Owner | ❌ | | [backports.print_function](https://pypi.org/project/backports.print_function) | 49 | Owner | ❌ | | [librarypaste](https://pypi.org/project/librarypaste) | 47 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [backports.method_request](https://pypi.org/project/backports.method_request) | 45 | Owner | ❌ | | [excuses](https://pypi.org/project/excuses) | 44 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.translate](https://pypi.org/project/jaraco.translate) | 43 | Owner | ❌ | | [backports.pdb](https://pypi.org/project/backports.pdb) | 43 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.media](https://pypi.org/project/jaraco.media) | 41 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [jaraco.crypto](https://pypi.org/project/jaraco.crypto) | 39 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [pmxbot.webhooks](https://pypi.org/project/pmxbot.webhooks) | 39 | Owner | ❌ | | [popquotes](https://pypi.org/project/popquotes) | 38 | Owner | ❌ | | [vr.builder](https://pypi.org/project/vr.builder) | 37 | Owner | ❌ | | [solr-doc-manager](https://pypi.org/project/solr-doc-manager) | 33 | Owner | ❌ | | [jaraco.input](https://pypi.org/project/jaraco.input) | 32 | Owner | ❌ | | [jaraco.home](https://pypi.org/project/jaraco.home) | 31 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.imaging](https://pypi.org/project/jaraco.imaging) | 30 | Owner | ❌ | | [vr.agent](https://pypi.org/project/vr.agent) | 29 | Owner | ❌ | | [jaraco.keyring](https://pypi.org/project/jaraco.keyring) | 28 | Owner | ❌ | | [vr.events](https://pypi.org/project/vr.events) | 28 | Owner | ❌ | | [pmxbot.rss](https://pypi.org/project/pmxbot.rss) | 28 | Owner | ❌ | | [jaraco.xkcd](https://pypi.org/project/jaraco.xkcd) | 27 | Owner | ❌ | | [jaraco.office](https://pypi.org/project/jaraco.office) | 26 | Owner | ❌ | | [freedompop](https://pypi.org/project/freedompop) | 26 | Owner | ❌ | | [treehouse](https://pypi.org/project/treehouse) | 26 | Owner | ❌ | | [dropbox-index](https://pypi.org/project/dropbox-index) | 26 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [jaraco.zstd](https://pypi.org/project/jaraco.zstd) | 24 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) | | [recapturedocs](https://pypi.org/project/recapturedocs) | 24 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) | | [setuptools-hacks.bypass-summary-newline](https://pypi.org/project/setuptools-hacks.bypass-summary-newline) | 21 | Owner | ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) | | [pmxbot.nsfw](https://pypi.org/project/pmxbot.nsfw) | 20 | Owner | ❌ | | [vr.launch](https://pypi.org/project/vr.launch) | 18 | Owner | ❌ | | [pmxbot.saysomething](https://pypi.org/project/pmxbot.saysomething) | 13 | Owner | ❌ | | [jaraco.parables](https://pypi.org/project/jaraco.parables) | 11 | Owner | ❌ | | [yg.thumpy](https://pypi.org/project/yg.thumpy) | 11 | Owner | ❌ | | [yg.eventful](https://pypi.org/project/yg.eventful) | 7 | Owner | ❌ | | [Distutils](https://pypi.org/project/Distutils) | 0 | Owner | ❌ | | [backports](https://pypi.org/project/backports) | 0 | Owner | ❌ |

In order to make tracking the progress significantly easier, I've generated the following checklist-form roadmap.

# Roadmap **TODO for every project linked below**: - ensure a `py.typed` marker is present, - modernize type hinting, - ensure that `mypy --strict` passes successfully. ---- - [ ] [setuptools](https://pypi.org/project/setuptools) [![downloads](https://static.pepy.tech/badge/setuptools/month)](https://pepy.tech/projects/setuptools) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [importlib-metadata](https://pypi.org/project/importlib-metadata) [![downloads](https://static.pepy.tech/badge/importlib-metadata/month)](https://pepy.tech/projects/importlib-metadata) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [zipp](https://pypi.org/project/zipp) [![downloads](https://static.pepy.tech/badge/zipp/month)](https://pepy.tech/projects/zipp) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [importlib-resources](https://pypi.org/project/importlib-resources) [![downloads](https://static.pepy.tech/badge/importlib-resources/month)](https://pepy.tech/projects/importlib-resources) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [keyring](https://pypi.org/project/keyring) [![downloads](https://static.pepy.tech/badge/keyring/month)](https://pepy.tech/projects/keyring) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.classes](https://pypi.org/project/jaraco.classes) [![downloads](https://static.pepy.tech/badge/jaraco.classes/month)](https://pepy.tech/projects/jaraco.classes) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [setuptools-scm](https://pypi.org/project/setuptools-scm) [![downloads](https://static.pepy.tech/badge/setuptools-scm/month)](https://pepy.tech/projects/setuptools-scm) - [ ] [pytest-runner](https://pypi.org/project/pytest-runner) [![downloads](https://static.pepy.tech/badge/pytest-runner/month)](https://pepy.tech/projects/pytest-runner) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [configparser](https://pypi.org/project/configparser) [![downloads](https://static.pepy.tech/badge/configparser/month)](https://pepy.tech/projects/configparser) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jsonpickle](https://pypi.org/project/jsonpickle) [![downloads](https://static.pepy.tech/badge/jsonpickle/month)](https://pepy.tech/projects/jsonpickle) - [ ] [pep517](https://pypi.org/project/pep517) [![downloads](https://static.pepy.tech/badge/pep517/month)](https://pepy.tech/projects/pep517) - [ ] [inflect](https://pypi.org/project/inflect) [![downloads](https://static.pepy.tech/badge/inflect/month)](https://pepy.tech/projects/inflect) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [twine](https://pypi.org/project/twine) [![downloads](https://static.pepy.tech/badge/twine/month)](https://pepy.tech/projects/twine) - [ ] [backports.functools-lru-cache](https://pypi.org/project/backports.functools-lru-cache) [![downloads](https://static.pepy.tech/badge/backports.functools-lru-cache/month)](https://pepy.tech/projects/backports.functools-lru-cache) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [singledispatch](https://pypi.org/project/singledispatch) [![downloads](https://static.pepy.tech/badge/singledispatch/month)](https://pepy.tech/projects/singledispatch) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [comtypes](https://pypi.org/project/comtypes) [![downloads](https://static.pepy.tech/badge/comtypes/month)](https://pepy.tech/projects/comtypes) - [ ] [cssutils](https://pypi.org/project/cssutils) [![downloads](https://static.pepy.tech/badge/cssutils/month)](https://pepy.tech/projects/cssutils) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [x] [jaraco.functools](https://pypi.org/project/jaraco.functools) [![downloads](https://static.pepy.tech/badge/jaraco.functools/month)](https://pepy.tech/projects/jaraco.functools) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [path](https://pypi.org/project/path) [![downloads](https://static.pepy.tech/badge/path/month)](https://pepy.tech/projects/path) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [cheroot](https://pypi.org/project/cheroot) [![downloads](https://static.pepy.tech/badge/cheroot/month)](https://pepy.tech/projects/cheroot) - [ ] [tempora](https://pypi.org/project/tempora) [![downloads](https://static.pepy.tech/badge/tempora/month)](https://pepy.tech/projects/tempora) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [portend](https://pypi.org/project/portend) [![downloads](https://static.pepy.tech/badge/portend/month)](https://pepy.tech/projects/portend) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.collections](https://pypi.org/project/jaraco.collections) [![downloads](https://static.pepy.tech/badge/jaraco.collections/month)](https://pepy.tech/projects/jaraco.collections) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [CherryPy](https://pypi.org/project/CherryPy) [![downloads](https://static.pepy.tech/badge/CherryPy/month)](https://pepy.tech/projects/CherryPy) - [ ] [distribute](https://pypi.org/project/distribute) [![downloads](https://static.pepy.tech/badge/distribute/month)](https://pepy.tech/projects/distribute) - [ ] [jaraco.text](https://pypi.org/project/jaraco.text) [![downloads](https://static.pepy.tech/badge/jaraco.text/month)](https://pepy.tech/projects/jaraco.text) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.context](https://pypi.org/project/jaraco.context) [![downloads](https://static.pepy.tech/badge/jaraco.context/month)](https://pepy.tech/projects/jaraco.context) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [keyrings.alt](https://pypi.org/project/keyrings.alt) [![downloads](https://static.pepy.tech/badge/keyrings.alt/month)](https://pepy.tech/projects/keyrings.alt) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [backports.entry-points-selectable](https://pypi.org/project/backports.entry-points-selectable) [![downloads](https://static.pepy.tech/badge/backports.entry-points-selectable/month)](https://pepy.tech/projects/backports.entry-points-selectable) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [path.py](https://pypi.org/project/path.py) [![downloads](https://static.pepy.tech/badge/path.py/month)](https://pepy.tech/projects/path.py) - [ ] [Tempita](https://pypi.org/project/Tempita) [![downloads](https://static.pepy.tech/badge/Tempita/month)](https://pepy.tech/projects/Tempita) - [ ] [Fuzzy](https://pypi.org/project/Fuzzy) [![downloads](https://static.pepy.tech/badge/Fuzzy/month)](https://pepy.tech/projects/Fuzzy) - [ ] [datadiff](https://pypi.org/project/datadiff) [![downloads](https://static.pepy.tech/badge/datadiff/month)](https://pepy.tech/projects/datadiff) - [ ] [wolframalpha](https://pypi.org/project/wolframalpha) [![downloads](https://static.pepy.tech/badge/wolframalpha/month)](https://pepy.tech/projects/wolframalpha) - [ ] [oathtool](https://pypi.org/project/oathtool) [![downloads](https://static.pepy.tech/badge/oathtool/month)](https://pepy.tech/projects/oathtool) ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) - [ ] [jaraco.logging](https://pypi.org/project/jaraco.logging) [![downloads](https://static.pepy.tech/badge/jaraco.logging/month)](https://pepy.tech/projects/jaraco.logging) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [irc](https://pypi.org/project/irc) [![downloads](https://static.pepy.tech/badge/irc/month)](https://pepy.tech/projects/irc) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [cherrypy-cors](https://pypi.org/project/cherrypy-cors) [![downloads](https://static.pepy.tech/badge/cherrypy-cors/month)](https://pepy.tech/projects/cherrypy-cors) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.stream](https://pypi.org/project/jaraco.stream) [![downloads](https://static.pepy.tech/badge/jaraco.stream/month)](https://pepy.tech/projects/jaraco.stream) ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) - [ ] [pytest-checkdocs](https://pypi.org/project/pytest-checkdocs) [![downloads](https://static.pepy.tech/badge/pytest-checkdocs/month)](https://pepy.tech/projects/pytest-checkdocs) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [pytest-enabler](https://pypi.org/project/pytest-enabler) [![downloads](https://static.pepy.tech/badge/pytest-enabler/month)](https://pepy.tech/projects/pytest-enabler) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [pip-run](https://pypi.org/project/pip-run) [![downloads](https://static.pepy.tech/badge/pip-run/month)](https://pepy.tech/projects/pip-run) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.env](https://pypi.org/project/jaraco.env) [![downloads](https://static.pepy.tech/badge/jaraco.env/month)](https://pepy.tech/projects/jaraco.env) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.itertools](https://pypi.org/project/jaraco.itertools) [![downloads](https://static.pepy.tech/badge/jaraco.itertools/month)](https://pepy.tech/projects/jaraco.itertools) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [hgtools](https://pypi.org/project/hgtools) [![downloads](https://static.pepy.tech/badge/hgtools/month)](https://pepy.tech/projects/hgtools) - [ ] [pytest-ignore-flaky](https://pypi.org/project/pytest-ignore-flaky) [![downloads](https://static.pepy.tech/badge/pytest-ignore-flaky/month)](https://pepy.tech/projects/pytest-ignore-flaky) - [ ] [jaraco.path](https://pypi.org/project/jaraco.path) [![downloads](https://static.pepy.tech/badge/jaraco.path/month)](https://pepy.tech/projects/jaraco.path) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.envs](https://pypi.org/project/jaraco.envs) [![downloads](https://static.pepy.tech/badge/jaraco.envs/month)](https://pepy.tech/projects/jaraco.envs) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [backports.datetime-timestamp](https://pypi.org/project/backports.datetime-timestamp) [![downloads](https://static.pepy.tech/badge/backports.datetime-timestamp/month)](https://pepy.tech/projects/backports.datetime-timestamp) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.versioning](https://pypi.org/project/jaraco.versioning) [![downloads](https://static.pepy.tech/badge/jaraco.versioning/month)](https://pepy.tech/projects/jaraco.versioning) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [mongo-connector](https://pypi.org/project/mongo-connector) [![downloads](https://static.pepy.tech/badge/mongo-connector/month)](https://pepy.tech/projects/mongo-connector) - [ ] [pytest-perf](https://pypi.org/project/pytest-perf) [![downloads](https://static.pepy.tech/badge/pytest-perf/month)](https://pepy.tech/projects/pytest-perf) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.ui](https://pypi.org/project/jaraco.ui) [![downloads](https://static.pepy.tech/badge/jaraco.ui/month)](https://pepy.tech/projects/jaraco.ui) - [ ] [jaraco.packaging](https://pypi.org/project/jaraco.packaging) [![downloads](https://static.pepy.tech/badge/jaraco.packaging/month)](https://pepy.tech/projects/jaraco.packaging) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.develop](https://pypi.org/project/jaraco.develop) [![downloads](https://static.pepy.tech/badge/jaraco.develop/month)](https://pepy.tech/projects/jaraco.develop) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.structures](https://pypi.org/project/jaraco.structures) [![downloads](https://static.pepy.tech/badge/jaraco.structures/month)](https://pepy.tech/projects/jaraco.structures) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [pytest-services](https://pypi.org/project/pytest-services) [![downloads](https://static.pepy.tech/badge/pytest-services/month)](https://pepy.tech/projects/pytest-services) - [ ] [rst.linker](https://pypi.org/project/rst.linker) [![downloads](https://static.pepy.tech/badge/rst.linker/month)](https://pepy.tech/projects/rst.linker) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.windows](https://pypi.org/project/jaraco.windows) [![downloads](https://static.pepy.tech/badge/jaraco.windows/month)](https://pepy.tech/projects/jaraco.windows) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.vcs](https://pypi.org/project/jaraco.vcs) [![downloads](https://static.pepy.tech/badge/jaraco.vcs/month)](https://pepy.tech/projects/jaraco.vcs) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [backports.unittest-mock](https://pypi.org/project/backports.unittest-mock) [![downloads](https://static.pepy.tech/badge/backports.unittest-mock/month)](https://pepy.tech/projects/backports.unittest-mock) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.docker](https://pypi.org/project/jaraco.docker) [![downloads](https://static.pepy.tech/badge/jaraco.docker/month)](https://pepy.tech/projects/jaraco.docker) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [suds-bis](https://pypi.org/project/suds-bis) [![downloads](https://static.pepy.tech/badge/suds-bis/month)](https://pepy.tech/projects/suds-bis) ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) - [ ] [jaraco.abode](https://pypi.org/project/jaraco.abode) [![downloads](https://static.pepy.tech/badge/jaraco.abode/month)](https://pepy.tech/projects/jaraco.abode) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.email](https://pypi.org/project/jaraco.email) [![downloads](https://static.pepy.tech/badge/jaraco.email/month)](https://pepy.tech/projects/jaraco.email) - [ ] [jaraco.net](https://pypi.org/project/jaraco.net) [![downloads](https://static.pepy.tech/badge/jaraco.net/month)](https://pepy.tech/projects/jaraco.net) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [MagicBus](https://pypi.org/project/MagicBus) [![downloads](https://static.pepy.tech/badge/MagicBus/month)](https://pepy.tech/projects/MagicBus) - [ ] [svg.charts](https://pypi.org/project/svg.charts) [![downloads](https://static.pepy.tech/badge/svg.charts/month)](https://pepy.tech/projects/svg.charts) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.mongodb](https://pypi.org/project/jaraco.mongodb) [![downloads](https://static.pepy.tech/badge/jaraco.mongodb/month)](https://pepy.tech/projects/jaraco.mongodb) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [calendra](https://pypi.org/project/calendra) [![downloads](https://static.pepy.tech/badge/calendra/month)](https://pepy.tech/projects/calendra) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.services](https://pypi.org/project/jaraco.services) [![downloads](https://static.pepy.tech/badge/jaraco.services/month)](https://pepy.tech/projects/jaraco.services) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [pmxbot](https://pypi.org/project/pmxbot) [![downloads](https://static.pepy.tech/badge/pmxbot/month)](https://pepy.tech/projects/pmxbot) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.tidelift](https://pypi.org/project/jaraco.tidelift) [![downloads](https://static.pepy.tech/badge/jaraco.tidelift/month)](https://pepy.tech/projects/jaraco.tidelift) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [event](https://pypi.org/project/event) [![downloads](https://static.pepy.tech/badge/event/month)](https://pepy.tech/projects/event) - [ ] [jaraco.clipboard](https://pypi.org/project/jaraco.clipboard) [![downloads](https://static.pepy.tech/badge/jaraco.clipboard/month)](https://pepy.tech/projects/jaraco.clipboard) - [ ] [openpack](https://pypi.org/project/openpack) [![downloads](https://static.pepy.tech/badge/openpack/month)](https://pepy.tech/projects/openpack) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [elastic2-doc-manager](https://pypi.org/project/elastic2-doc-manager) [![downloads](https://static.pepy.tech/badge/elastic2-doc-manager/month)](https://pepy.tech/projects/elastic2-doc-manager) - [ ] [jaraco.test](https://pypi.org/project/jaraco.test) [![downloads](https://static.pepy.tech/badge/jaraco.test/month)](https://pepy.tech/projects/jaraco.test) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [jaraco.pmxbot](https://pypi.org/project/jaraco.pmxbot) [![downloads](https://static.pepy.tech/badge/jaraco.pmxbot/month)](https://pepy.tech/projects/jaraco.pmxbot) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [dynpool](https://pypi.org/project/dynpool) [![downloads](https://static.pepy.tech/badge/dynpool/month)](https://pepy.tech/projects/dynpool) - [ ] [pytest-black-multipy](https://pypi.org/project/pytest-black-multipy) [![downloads](https://static.pepy.tech/badge/pytest-black-multipy/month)](https://pepy.tech/projects/pytest-black-multipy) - [ ] [cherrypy-dynpool](https://pypi.org/project/cherrypy-dynpool) [![downloads](https://static.pepy.tech/badge/cherrypy-dynpool/month)](https://pepy.tech/projects/cherrypy-dynpool) - [ ] [jaraco.modb](https://pypi.org/project/jaraco.modb) [![downloads](https://static.pepy.tech/badge/jaraco.modb/month)](https://pepy.tech/projects/jaraco.modb) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [yg.lockfile](https://pypi.org/project/yg.lockfile) [![downloads](https://static.pepy.tech/badge/yg.lockfile/month)](https://pepy.tech/projects/yg.lockfile) - [ ] [chucknorris](https://pypi.org/project/chucknorris) [![downloads](https://static.pepy.tech/badge/chucknorris/month)](https://pepy.tech/projects/chucknorris) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [nspektr](https://pypi.org/project/nspektr) [![downloads](https://static.pepy.tech/badge/nspektr/month)](https://pepy.tech/projects/nspektr) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [xlsxcessive](https://pypi.org/project/xlsxcessive) [![downloads](https://static.pepy.tech/badge/xlsxcessive/month)](https://pepy.tech/projects/xlsxcessive) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [cmdix](https://pypi.org/project/cmdix) [![downloads](https://static.pepy.tech/badge/cmdix/month)](https://pepy.tech/projects/cmdix) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [googlevoice](https://pypi.org/project/googlevoice) [![downloads](https://static.pepy.tech/badge/googlevoice/month)](https://pepy.tech/projects/googlevoice) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.financial](https://pypi.org/project/jaraco.financial) [![downloads](https://static.pepy.tech/badge/jaraco.financial/month)](https://pepy.tech/projects/jaraco.financial) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.timing](https://pypi.org/project/jaraco.timing) [![downloads](https://static.pepy.tech/badge/jaraco.timing/month)](https://pepy.tech/projects/jaraco.timing) - [ ] [jaraco.postgres](https://pypi.org/project/jaraco.postgres) [![downloads](https://static.pepy.tech/badge/jaraco.postgres/month)](https://pepy.tech/projects/jaraco.postgres) - [ ] [jaraco.compat](https://pypi.org/project/jaraco.compat) [![downloads](https://static.pepy.tech/badge/jaraco.compat/month)](https://pepy.tech/projects/jaraco.compat) - [ ] [paradocx](https://pypi.org/project/paradocx) [![downloads](https://static.pepy.tech/badge/paradocx/month)](https://pepy.tech/projects/paradocx) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [http-okapi](https://pypi.org/project/http-okapi) [![downloads](https://static.pepy.tech/badge/http-okapi/month)](https://pepy.tech/projects/http-okapi) - [ ] [jaraco.geo](https://pypi.org/project/jaraco.geo) [![downloads](https://static.pepy.tech/badge/jaraco.geo/month)](https://pepy.tech/projects/jaraco.geo) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [elastic-doc-manager](https://pypi.org/project/elastic-doc-manager) [![downloads](https://static.pepy.tech/badge/elastic-doc-manager/month)](https://pepy.tech/projects/elastic-doc-manager) - [ ] [jaraco.util](https://pypi.org/project/jaraco.util) [![downloads](https://static.pepy.tech/badge/jaraco.util/month)](https://pepy.tech/projects/jaraco.util) ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) - [ ] [compilers](https://pypi.org/project/compilers) [![downloads](https://static.pepy.tech/badge/compilers/month)](https://pepy.tech/projects/compilers) - [ ] [jaraco.apt](https://pypi.org/project/jaraco.apt) [![downloads](https://static.pepy.tech/badge/jaraco.apt/month)](https://pepy.tech/projects/jaraco.apt) - [ ] [setuptools-svn](https://pypi.org/project/setuptools-svn) [![downloads](https://static.pepy.tech/badge/setuptools-svn/month)](https://pepy.tech/projects/setuptools-svn) - [ ] [jaraco.xonsh](https://pypi.org/project/jaraco.xonsh) [![downloads](https://static.pepy.tech/badge/jaraco.xonsh/month)](https://pepy.tech/projects/jaraco.xonsh) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [vr.cli](https://pypi.org/project/vr.cli) [![downloads](https://static.pepy.tech/badge/vr.cli/month)](https://pepy.tech/projects/vr.cli) - [ ] [vr.runners](https://pypi.org/project/vr.runners) [![downloads](https://static.pepy.tech/badge/vr.runners/month)](https://pepy.tech/projects/vr.runners) - [ ] [lpaste](https://pypi.org/project/lpaste) [![downloads](https://static.pepy.tech/badge/lpaste/month)](https://pepy.tech/projects/lpaste) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [rwt](https://pypi.org/project/rwt) [![downloads](https://static.pepy.tech/badge/rwt/month)](https://pepy.tech/projects/rwt) - [ ] [jaraco.fabric](https://pypi.org/project/jaraco.fabric) [![downloads](https://static.pepy.tech/badge/jaraco.fabric/month)](https://pepy.tech/projects/jaraco.fabric) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [NAT-PMP](https://pypi.org/project/NAT-PMP) [![downloads](https://static.pepy.tech/badge/NAT-PMP/month)](https://pepy.tech/projects/NAT-PMP) - [ ] [vr.common](https://pypi.org/project/vr.common) [![downloads](https://static.pepy.tech/badge/vr.common/month)](https://pepy.tech/projects/vr.common) - [ ] [pytest-home](https://pypi.org/project/pytest-home) [![downloads](https://static.pepy.tech/badge/pytest-home/month)](https://pepy.tech/projects/pytest-home) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [fogbugz-bis](https://pypi.org/project/fogbugz-bis) [![downloads](https://static.pepy.tech/badge/fogbugz-bis/month)](https://pepy.tech/projects/fogbugz-bis) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [backports.hook-compressed](https://pypi.org/project/backports.hook-compressed) [![downloads](https://static.pepy.tech/badge/backports.hook-compressed/month)](https://pepy.tech/projects/backports.hook-compressed) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.nxt](https://pypi.org/project/jaraco.nxt) [![downloads](https://static.pepy.tech/badge/jaraco.nxt/month)](https://pepy.tech/projects/jaraco.nxt) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [motivation](https://pypi.org/project/motivation) [![downloads](https://static.pepy.tech/badge/motivation/month)](https://pepy.tech/projects/motivation) - [ ] [jaraco.video](https://pypi.org/project/jaraco.video) [![downloads](https://static.pepy.tech/badge/jaraco.video/month)](https://pepy.tech/projects/jaraco.video) - [ ] [eggmonster](https://pypi.org/project/eggmonster) [![downloads](https://static.pepy.tech/badge/eggmonster/month)](https://pepy.tech/projects/eggmonster) - [ ] [jaraco.site](https://pypi.org/project/jaraco.site) [![downloads](https://static.pepy.tech/badge/jaraco.site/month)](https://pepy.tech/projects/jaraco.site) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [vr.server](https://pypi.org/project/vr.server) [![downloads](https://static.pepy.tech/badge/vr.server/month)](https://pepy.tech/projects/vr.server) - [ ] [vr.imager](https://pypi.org/project/vr.imager) [![downloads](https://static.pepy.tech/badge/vr.imager/month)](https://pepy.tech/projects/vr.imager) - [ ] [backports.print_function](https://pypi.org/project/backports.print_function) [![downloads](https://static.pepy.tech/badge/backports.print_function/month)](https://pepy.tech/projects/backports.print_function) - [ ] [librarypaste](https://pypi.org/project/librarypaste) [![downloads](https://static.pepy.tech/badge/librarypaste/month)](https://pepy.tech/projects/librarypaste) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [backports.method_request](https://pypi.org/project/backports.method_request) [![downloads](https://static.pepy.tech/badge/backports.method_request/month)](https://pepy.tech/projects/backports.method_request) - [ ] [excuses](https://pypi.org/project/excuses) [![downloads](https://static.pepy.tech/badge/excuses/month)](https://pepy.tech/projects/excuses) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.translate](https://pypi.org/project/jaraco.translate) [![downloads](https://static.pepy.tech/badge/jaraco.translate/month)](https://pepy.tech/projects/jaraco.translate) - [ ] [backports.pdb](https://pypi.org/project/backports.pdb) [![downloads](https://static.pepy.tech/badge/backports.pdb/month)](https://pepy.tech/projects/backports.pdb) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.media](https://pypi.org/project/jaraco.media) [![downloads](https://static.pepy.tech/badge/jaraco.media/month)](https://pepy.tech/projects/jaraco.media) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [jaraco.crypto](https://pypi.org/project/jaraco.crypto) [![downloads](https://static.pepy.tech/badge/jaraco.crypto/month)](https://pepy.tech/projects/jaraco.crypto) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [pmxbot.webhooks](https://pypi.org/project/pmxbot.webhooks) [![downloads](https://static.pepy.tech/badge/pmxbot.webhooks/month)](https://pepy.tech/projects/pmxbot.webhooks) - [ ] [popquotes](https://pypi.org/project/popquotes) [![downloads](https://static.pepy.tech/badge/popquotes/month)](https://pepy.tech/projects/popquotes) - [ ] [vr.builder](https://pypi.org/project/vr.builder) [![downloads](https://static.pepy.tech/badge/vr.builder/month)](https://pepy.tech/projects/vr.builder) - [ ] [solr-doc-manager](https://pypi.org/project/solr-doc-manager) [![downloads](https://static.pepy.tech/badge/solr-doc-manager/month)](https://pepy.tech/projects/solr-doc-manager) - [ ] [jaraco.input](https://pypi.org/project/jaraco.input) [![downloads](https://static.pepy.tech/badge/jaraco.input/month)](https://pepy.tech/projects/jaraco.input) - [ ] [jaraco.home](https://pypi.org/project/jaraco.home) [![downloads](https://static.pepy.tech/badge/jaraco.home/month)](https://pepy.tech/projects/jaraco.home) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.imaging](https://pypi.org/project/jaraco.imaging) [![downloads](https://static.pepy.tech/badge/jaraco.imaging/month)](https://pepy.tech/projects/jaraco.imaging) - [ ] [vr.agent](https://pypi.org/project/vr.agent) [![downloads](https://static.pepy.tech/badge/vr.agent/month)](https://pepy.tech/projects/vr.agent) - [ ] [jaraco.keyring](https://pypi.org/project/jaraco.keyring) [![downloads](https://static.pepy.tech/badge/jaraco.keyring/month)](https://pepy.tech/projects/jaraco.keyring) - [ ] [vr.events](https://pypi.org/project/vr.events) [![downloads](https://static.pepy.tech/badge/vr.events/month)](https://pepy.tech/projects/vr.events) - [ ] [pmxbot.rss](https://pypi.org/project/pmxbot.rss) [![downloads](https://static.pepy.tech/badge/pmxbot.rss/month)](https://pepy.tech/projects/pmxbot.rss) - [ ] [jaraco.xkcd](https://pypi.org/project/jaraco.xkcd) [![downloads](https://static.pepy.tech/badge/jaraco.xkcd/month)](https://pepy.tech/projects/jaraco.xkcd) - [ ] [jaraco.office](https://pypi.org/project/jaraco.office) [![downloads](https://static.pepy.tech/badge/jaraco.office/month)](https://pepy.tech/projects/jaraco.office) - [ ] [freedompop](https://pypi.org/project/freedompop) [![downloads](https://static.pepy.tech/badge/freedompop/month)](https://pepy.tech/projects/freedompop) - [ ] [treehouse](https://pypi.org/project/treehouse) [![downloads](https://static.pepy.tech/badge/treehouse/month)](https://pepy.tech/projects/treehouse) - [ ] [dropbox-index](https://pypi.org/project/dropbox-index) [![downloads](https://static.pepy.tech/badge/dropbox-index/month)](https://pepy.tech/projects/dropbox-index) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [jaraco.zstd](https://pypi.org/project/jaraco.zstd) [![downloads](https://static.pepy.tech/badge/jaraco.zstd/month)](https://pepy.tech/projects/jaraco.zstd) ![skeleton](https://img.shields.io/badge/skeleton-2023-informational) - [ ] [recapturedocs](https://pypi.org/project/recapturedocs) [![downloads](https://static.pepy.tech/badge/recapturedocs/month)](https://pepy.tech/projects/recapturedocs) ![skeleton](https://img.shields.io/badge/skeleton-2022-informational) - [ ] [setuptools-hacks.bypass-summary-newline](https://pypi.org/project/setuptools-hacks.bypass-summary-newline) [![downloads](https://static.pepy.tech/badge/setuptools-hacks.bypass-summary-newline/month)](https://pepy.tech/projects/setuptools-hacks.bypass-summary-newline) ![skeleton](https://img.shields.io/badge/skeleton-2021-informational) - [ ] [pmxbot.nsfw](https://pypi.org/project/pmxbot.nsfw) [![downloads](https://static.pepy.tech/badge/pmxbot.nsfw/month)](https://pepy.tech/projects/pmxbot.nsfw) - [ ] [vr.launch](https://pypi.org/project/vr.launch) [![downloads](https://static.pepy.tech/badge/vr.launch/month)](https://pepy.tech/projects/vr.launch) - [ ] [pmxbot.saysomething](https://pypi.org/project/pmxbot.saysomething) [![downloads](https://static.pepy.tech/badge/pmxbot.saysomething/month)](https://pepy.tech/projects/pmxbot.saysomething) - [ ] [jaraco.parables](https://pypi.org/project/jaraco.parables) [![downloads](https://static.pepy.tech/badge/jaraco.parables/month)](https://pepy.tech/projects/jaraco.parables) - [ ] [yg.thumpy](https://pypi.org/project/yg.thumpy) [![downloads](https://static.pepy.tech/badge/yg.thumpy/month)](https://pepy.tech/projects/yg.thumpy) - [ ] [yg.eventful](https://pypi.org/project/yg.eventful) [![downloads](https://static.pepy.tech/badge/yg.eventful/month)](https://pepy.tech/projects/yg.eventful) - [ ] [Distutils](https://pypi.org/project/Distutils) [![downloads](https://static.pepy.tech/badge/Distutils/month)](https://pepy.tech/projects/Distutils) - [ ] [backports](https://pypi.org/project/backports) [![downloads](https://static.pepy.tech/badge/backports/month)](https://pepy.tech/projects/backports)

@jaraco, could you please let me know if you want to apply some additional filtering/sorting to the roadmap above?

bswck commented 1 year ago

An interesting approach would be to measureβ€”for every projectβ€”how many PyPI projects depend on it, using libraries.io. But I think it would more or less correlate with downloads/month anyway, as I am assuming (without having done any research) that most of these downloads come from pipelines that install every dependency for the first time, and dependencies referencing the same project being together aren't that common (so like, when for two projects A and B sharing the same project X as a dependency, X in fact gets installed "twice less", because only once, as it is reused in the same environment by A and B, even though I would technically call X more popular in this case). This can get even more interesting if we add distinction between pip-like and pipx-like installation methods, where a shared dependency would be installed twice for separate environments of A and B, assuming A and B are CLI applications... I could be pointing out all the things that come to my mind further, and it gets very complicated and multilayered as I dig in the rabbit hole.

Yeah, so all in all I've learned that "package popularity" isn't trivial, because both the convergence in the web of dependencies as well as the statistics of total downloads in time play a role in the correct evaluation of how popular a package really is.

Anyway though, this is just an attempt to prioritize the tasks. Since some most popular jaraco projects commonly depend on some less popular jaraco projects (downloads/month-wise!), I started off from jaraco.functools and jaraco.classes.

jaraco commented 1 year ago

Amazing analysis. Thanks!

You'll notice that libraries.io is a project by Tidelift. You may have noticed that I also work with them as they work to garner support for open source maintainers from the enterprise users. They've probably built other tooling and may even be interested in collaborating on tooling to support open source maintenance. You may want to consider signing up with them as a maintainer (there's no cost and could potentially pay) and engaging on the forums to see if there is interest in collaborating. If you need a referral or anything to get signed up, let me know.

bswck commented 12 months ago

You may want to consider signing up with them as a maintainer

Thank you! I've just applied to lift a few of my projects!


Due to a considerable number of projects that need similar work, I created a project that aims to automate the whole process as much as possibleβ€”autorefine.

MonkeyType will turn out very handy when it comes to type hints generation. I will take care of making them as sophisticated as needed. I think all these projects have enough coverage, so I will simply generate the types by running tests.

I will leverage LibCST and create custom rules if needed for modernizing the projects (some had their last releases a few years ago)β€”but this is out of scope at the moment.

Contributions & suggestions very, very welcomeβ€”I am learning.

Hopefully the tool will speed up more_itertools.consume(map(functools.partial(refine, scope="typing"), jaraco_projects)).

bswck commented 10 months ago

I've made a Coherent OSS project for the initiative: https://github.com/orgs/coherent-oss/projects/3/views/2

jaraco commented 8 months ago

I firmly believe that the best option would be being as explicit as possible when annotating types, because, as it seems, there are too few obvious cases at the end of the day.

Of course if the new type hints would appear too intricate for the eye, which I can totally understand, there is always an option of creating stubs to isolate two worlds of the implementation and the type hints, like in jaraco/jaraco.functools#22. What are your thoughts on this @jaraco?

I guess that's fine. I should probably get used to Python being more verbose and less essential.

bswck commented 8 months ago

I firmly believe that the best option would be being as explicit as possible when annotating types, because, as it seems, there are too few obvious cases at the end of the day.

Of course if the new type hints would appear too intricate for the eye, which I can totally understand, there is always an option of creating stubs to isolate two worlds of the implementation and the type hints, like in jaraco/jaraco.functools#22. What are your thoughts on this @jaraco?

I guess that's fine. I should probably get used to Python being more verbose and less essential.

Well, I guess it's just that Python wasn't built for being statically typed. πŸ€·β€β™€οΈ The good news is that due to its continuous development, the unfortunate effect of verbosity over essentialness in typing slowly decreases: take PEP 695 as an example.

Avasam commented 4 months ago

As more skeleton-based projects get typed (with a py.typed marker), I'd recommend requesting them to https://github.com/hauntsaninja/mypy_primer/blob/master/mypy_primer/projects.py . Especially for projects that are widely used in the ecosystem.