Command-line interface to PyPI Stats API to get download stats for Python packages

Overview

pypistats

PyPI version Supported Python versions PyPI downloads Azure Pipelines status GitHub Actions status codecov GitHub DOI Code style: Black

Python 3.6+ interface to PyPI Stats API to get aggregate download statistics on Python packages on the Python Package Index without having to execute queries directly against Google BigQuery.

Data is available for the last 180 days. (For longer time periods, pypinfo can help, you'll need an API key and get free quota.)

Installation

From PyPI

pip install --upgrade pypistats

From source

git clone https://github.com/hugovk/pypistats
cd pypistats
pip install .

Example command-line use

Run pypistats with a subcommand (corresponding to PyPI Stats endpoints), then options for that subcommand.

Top-level help:

$ pypistats --help
usage: pypistats [-h] [-V] {recent,overall,python_major,python_minor,system} ...

positional arguments:
  {recent,overall,python_major,python_minor,system}

optional arguments:
  -h, --help            show this help message and exit
  -V, --version         show program's version number and exit

Help for a subcommand:

$ pypistats recent --help
usage: pypistats recent [-h] [-p {day,week,month}] [-f {html,json,markdown,rst,tsv}] [-j] [-v] package

Retrieve the aggregate download quantities for the last day/week/month

positional arguments:
  package

optional arguments:
  -h, --help            show this help message and exit
  -p {day,week,month}, --period {day,week,month}
  -f {html,json,markdown,rst,tsv}, --format {html,json,markdown,rst,tsv}
                        The format of output (default: markdown)
  -j, --json            Shortcut for "-f json" (default: False)
  -v, --verbose         Print debug messages to stderr (default: False)

Get recent downloads:

$ pypistats recent pillow
| last_day  | last_month | last_week |
| --------: | ---------: | --------: |
| 1,083,451 | 30,750,398 | 7,088,038 |

Help for another subcommand:

$ pypistats python_minor --help
usage: pypistats python_minor [-h] [-V VERSION]
                              [-f {html,json,markdown,rst,tsv}] [-j]
                              [-sd yyyy-mm[-dd]|name] [-ed yyyy-mm[-dd]|name]
                              [-m yyyy-mm|name] [-l] [-t] [-d] [--monthly]
                              [-v]
                              package

Retrieve the aggregate daily download time series by Python minor version
number

positional arguments:
  package

optional arguments:
  -h, --help            show this help message and exit
  -V VERSION, --version VERSION
                        eg. 2.7 or 3.6 (default: None)
  -f {html,json,markdown,rst,tsv}, --format {html,json,markdown,rst,tsv}
                        The format of output (default: markdown)
  -j, --json            Shortcut for "-f json" (default: False)
  -sd yyyy-mm[-dd]|name, --start-date yyyy-mm[-dd]|name
                        Start date (default: None)
  -ed yyyy-mm[-dd]|name, --end-date yyyy-mm[-dd]|name
                        End date (default: None)
  -m yyyy-mm|name, --month yyyy-mm|name
                        Shortcut for -sd & -ed for a single month (default:
                        None)
  -l, --last-month      Shortcut for -sd & -ed for last month (default: False)
  -t, --this-month      Shortcut for -sd for this month (default: False)
  -d, --daily           Show daily downloads (default: False)
  --monthly             Show monthly downloads (default: False)
  -v, --verbose         Print debug messages to stderr (default: False)

Get version downloads:

$ pypistats python_minor pillow --last-month
| category | percent | downloads  |
| -------- | ------: | ---------: |
| 3.7      |  35.93% | 11,002,680 |
| 3.6      |  33.00% | 10,107,822 |
| 3.8      |  15.04% |  4,605,236 |
| 3.9      |   5.03% |  1,540,571 |
| 3.5      |   4.73% |  1,449,591 |
| null     |   3.39% |  1,037,124 |
| 2.7      |   2.84% |    870,677 |
| 3.4      |   0.03% |     10,055 |
| 3.10     |   0.01% |      2,863 |
| 2.6      |   0.00% |         58 |
| 3.3      |   0.00% |         44 |
| 3.2      |   0.00% |         39 |
| Total    |         | 30,626,760 |

Date range: 2021-04-01 - 2021-04-30

The table is Markdown, ready for pasting in GitHub issues and PRs:

category percent downloads
3.7 35.93% 11,002,680
3.6 33.00% 10,107,822
3.8 15.04% 4,605,236
3.9 5.03% 1,540,571
3.5 4.73% 1,449,591
null 3.39% 1,037,124
2.7 2.84% 870,677
3.4 0.03% 10,055
3.10 0.01% 2,863
2.6 0.00% 58
3.3 0.00% 44
3.2 0.00% 39
Total 30,626,760

These are equivalent (in May 2019):

pypistats python_major pip --last-month
pypistats python_major pip --month april
pypistats python_major pip --month apr
pypistats python_major pip --month 2019-04

And:

pypistats python_major pip --start-date december --end-date january
pypistats python_major pip --start-date dec      --end-date jan
pypistats python_major pip --start-date 2018-12  --end-date 2019-01

Example programmatic use

Return values are from the JSON responses documented in the API: https://pypistats.org/api/

import pypistats
from pprint import pprint

# Call the API
print(pypistats.recent("pillow"))
print(pypistats.recent("pillow", "day", format="markdown"))
print(pypistats.recent("pillow", "week", format="rst"))
print(pypistats.recent("pillow", "month", format="html"))
pprint(pypistats.recent("pillow", "week", format="json"))
print(pypistats.recent("pillow", "day"))

print(pypistats.overall("pillow"))
print(pypistats.overall("pillow", mirrors=True, format="markdown"))
print(pypistats.overall("pillow", mirrors=False, format="rst"))
print(pypistats.overall("pillow", mirrors=True, format="html"))
pprint(pypistats.overall("pillow", mirrors=False, format="json"))

print(pypistats.python_major("pillow"))
print(pypistats.python_major("pillow", version=2, format="markdown"))
print(pypistats.python_major("pillow", version=3, format="rst"))
print(pypistats.python_major("pillow", version="2", format="html"))
pprint(pypistats.python_major("pillow", version="3", format="json"))

print(pypistats.python_minor("pillow"))
print(pypistats.python_minor("pillow", version=2.7, format="markdown"))
print(pypistats.python_minor("pillow", version="2.7", format="rst"))
print(pypistats.python_minor("pillow", version=3.7, format="html"))
pprint(pypistats.python_minor("pillow", version="3.7", format="json"))

print(pypistats.system("pillow"))
print(pypistats.system("pillow", os="darwin", format="markdown"))
print(pypistats.system("pillow", os="linux", format="rst"))
print(pypistats.system("pillow", os="darwin", format="html"))
pprint(pypistats.system("pillow", os="linux", format="json"))

NumPy and pandas

To use with either NumPy or pandas, make sure they are first installed, or:

pip install --upgrade "pypistats[numpy]"
pip install --upgrade "pypistats[pandas]"
pip install --upgrade "pypistats[numpy,pandas]"

Return data in a NumPy array for further processing:

print(numpy_array) # [['with_mirrors' '2019-09-20' '2.23%' 1204] # ['without_mirrors' '2019-09-20' '2.08%' 1122] # ['with_mirrors' '2019-09-19' '0.92%' 496] # ... # ['with_mirrors' '2019-10-26' '0.02%' 13] # ['without_mirrors' '2019-10-26' '0.02%' 12] # ['Total' None None 54041]] ">
import pypistats
numpy_array = pypistats.overall("pyvista", total=True, format="numpy")
print(type(numpy_array))
# 
   
print(numpy_array)
# [['with_mirrors' '2019-09-20' '2.23%' 1204]
#  ['without_mirrors' '2019-09-20' '2.08%' 1122]
#  ['with_mirrors' '2019-09-19' '0.92%' 496]
#  ...
#  ['with_mirrors' '2019-10-26' '0.02%' 13]
#  ['without_mirrors' '2019-10-26' '0.02%' 12]
#  ['Total' None None 54041]]

Or in a pandas DataFrame:

print(pandas_dataframe) # category date percent downloads # 0 with_mirrors 2019-09-20 2.23% 1204 # 1 without_mirrors 2019-09-20 2.08% 1122 # 2 with_mirrors 2019-09-19 0.92% 496 # 3 with_mirrors 2019-08-22 0.90% 489 # 4 without_mirrors 2019-09-19 0.86% 466 # .. ... ... ... ... # 354 without_mirrors 2019-11-03 0.03% 15 # 355 without_mirrors 2019-11-16 0.03% 15 # 356 with_mirrors 2019-10-26 0.02% 13 # 357 without_mirrors 2019-10-26 0.02% 12 # 358 Total None None 54041 # # [359 rows x 4 columns] ">
import pypistats
pandas_dataframe = pypistats.overall("pyvista", total=True, format="pandas")
print(type(pandas_dataframe))
# 
   
print(pandas_dataframe)
#             category        date percent  downloads
# 0       with_mirrors  2019-09-20   2.23%       1204
# 1    without_mirrors  2019-09-20   2.08%       1122
# 2       with_mirrors  2019-09-19   0.92%        496
# 3       with_mirrors  2019-08-22   0.90%        489
# 4    without_mirrors  2019-09-19   0.86%        466
# ..               ...         ...     ...        ...
# 354  without_mirrors  2019-11-03   0.03%         15
# 355  without_mirrors  2019-11-16   0.03%         15
# 356     with_mirrors  2019-10-26   0.02%         13
# 357  without_mirrors  2019-10-26   0.02%         12
# 358            Total        None    None      54041
#
# [359 rows x 4 columns]

For example, create charts with pandas:

# Show overall downloads over time, excluding mirrors
import pypistats
data = pypistats.overall("pillow", total=True, format="pandas")
data = data.groupby("category").get_group("without_mirrors").sort_values("date")

chart = data.plot(x="date", y="downloads", figsize=(10, 2))
chart.figure.show()
chart.figure.savefig("overall.png")  # alternatively

overall.png

# Show Python 3 downloads over time
import pypistats
data = pypistats.python_major("pillow", total=True, format="pandas")
data = data.groupby("category").get_group(3).sort_values("date")

chart = data.plot(x="date", y="downloads", figsize=(10, 2))
chart.figure.show()
chart.figure.savefig("python3.png")  # alternatively

python3.png

See also

Related projects

Comments
  • Added --format

    Added --format

    Related to #20

    Added --format flag (for short, -f) to cli args. --json is kept for convenience.

      -j, --json            Output JSON. Shortcut for "-f json".
      -f FORMAT, --format FORMAT
                            The format of output. Supported: json, markdown.
                            Default is "markdown".
    

    The default is markdown. The cli tool also provides a UserWarning if given format is not supported and will inform user that it will fallback to default, which is, again, markdown. An example below:

    $ pypistats recent pyairmore -f mp3  # siriously, wth?
    foo/bar/pypistats/pypistats/cli.py:132: UserWarning: Unknown format: mp3. Using "markdown".
      warnings.warn(f'Unknown format: {args.format}. Using "markdown".')
    | last_day | last_month | last_week |
    |---------:|-----------:|----------:|
    |        3 |        151 |        33 |
    

    Other Minor Changes

    • Verbose flake8 and black output on Travis
    • flake8 and black now checks pypistats/ and tests/ directory instead of whole project which makes it a little bit faster (especially black).
    • Added tests_require to setup.py.

    The only problem is that the code I provided was not tested by pytest since it is not quite possible to both mock HTTP requests and test cli at the same time. The codebase was tested by hand :cry:. This will probably drop code coverage by ~5%. If you are strict about testing, I can find a way around (then inform me, don't merge this PR).

    If you'd like to test for yourself by hand, you can clone forked copy and checkout feat/format-arg branch.

    opened by erayerdin 11
  • Fixed overall table information, fixing issue #177

    Fixed overall table information, fixing issue #177

    I've changed the way the data is manipulated when you request overall statistics. Before this fix, the table for overall looked like this: | category | percent | downloads | |-----------------|--------:|----------:| | with_mirrors | 85.66% | 239 | | without_mirrors | 14.34% | 40 | | Total | | 279 |

    Which has an incorrect value for the total row as with_mirrors is actually the total including mirrors (the naming is confusing, but that's the API's fault). Now, the table looks like this: | category | downloads | |-----------|----------:| | End Users | 40 | | Mirrors | 199 | | Total | 239 |

    hacktoberfest-accepted 
    opened by w-henderson 10
  • httpx.ConnectError on simple pypistats cli test

    httpx.ConnectError on simple pypistats cli test

    First of all, love the repo, super useful. I've used pypistats before but for some reason on a fresh env i'm getting this error:

    httpx.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)
    

    Have you seen this before? Could this be a firewall issue?

    Environment:

    • Fresh python 3.9 env
    • macos v11.6.1
    • iterm2 3.4.12

    Steps to reproduce:

    1. conda create --name test python=3.9
    2. pip install pypistats
    3. pypistats recent pillow

    Full traceback:

    Traceback (most recent call last):
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_exceptions.py", line 8, in map_exceptions
        yield
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/backends/sync.py", line 51, in start_tls
        sock = ssl_context.wrap_socket(self._sock, server_hostname=server_hostname)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/ssl.py", line 500, in wrap_socket
        return self.sslsocket_class._create(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/ssl.py", line 1040, in _create
        self.do_handshake()
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/ssl.py", line 1309, in do_handshake
        self._sslobj.do_handshake()
    ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_transports/default.py", line 60, in map_httpcore_exceptions
        yield
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_transports/default.py", line 187, in handle_request
        resp = self._pool.handle_request(req)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py", line 248, in handle_request
        raise exc
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_sync/connection_pool.py", line 232, in handle_request
        response = connection.handle_request(request)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 90, in handle_request
        raise exc
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 67, in handle_request
        stream = self._connect(request)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_sync/connection.py", line 146, in _connect
        stream = stream.start_tls(**kwargs)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/backends/sync.py", line 51, in start_tls
        sock = ssl_context.wrap_socket(self._sock, server_hostname=server_hostname)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/contextlib.py", line 137, in __exit__
        self.gen.throw(typ, value, traceback)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpcore/_exceptions.py", line 12, in map_exceptions
        raise to_exc(exc)
    httpcore.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "/Users/gbuster/miniconda3/envs/test/bin/pypistats", line 8, in <module>
        sys.exit(main())
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/pypistats/cli.py", line 338, in main
        args.func(args)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/pypistats/cli.py", line 187, in recent
        pypistats.recent(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/pypistats/__init__.py", line 446, in recent
        return pypi_stats_api(endpoint, params, **kwargs)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/pypistats/__init__.py", line 116, in pypi_stats_api
        r = httpx.get(url, headers={"User-Agent": USER_AGENT})
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_api.py", line 189, in get
        return request(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_api.py", line 100, in request
        return client.request(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_client.py", line 802, in request
        return self.send(request, auth=auth, follow_redirects=follow_redirects)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_client.py", line 889, in send
        response = self._send_handling_auth(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_client.py", line 917, in _send_handling_auth
        response = self._send_handling_redirects(
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_client.py", line 954, in _send_handling_redirects
        response = self._send_single_request(request)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_client.py", line 990, in _send_single_request
        response = transport.handle_request(request)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_transports/default.py", line 187, in handle_request
        resp = self._pool.handle_request(req)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/contextlib.py", line 137, in __exit__
        self.gen.throw(typ, value, traceback)
      File "/Users/gbuster/miniconda3/envs/test/lib/python3.9/site-packages/httpx/_transports/default.py", line 77, in map_httpcore_exceptions
        raise mapped_exc(message) from exc
    httpx.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)
    
    opened by grantbuster 8
  • Add support for NumPy and Pandas data output

    Add support for NumPy and Pandas data output

    Now you can make NumPy arrays and Pandas DataFrames from the stats queries:

    import pypistats
    import pandas as pd
    import numpy as np
    
    exec(pypistats.overall("pyvista", total=True, 
                           format="pandas",
                           table_name="downloads"))
    downloads
    
    Screen Shot 2019-09-02 at 4 21 29 PM

    And you could plot the results by:

    mirrors = downloads.groupby("category").get_group("without_mirrors").sort_values("date")
    mirrors.plot(x="date", y="downloads", figsize=(10,2))
    

    download

    enhancement 
    opened by banesullivan 8
  • Codecov failures

    Codecov failures

    Codecov is regularly failing to upload coverage, and failing the build.

    Possibly same as https://github.com/codecov/codecov-bash/issues/330.

    For example: https://github.com/hugovk/pypistats/pull/129 failed 3/24 (12.5%) jobs.

    Test / build (3.6, ubuntu-16.04)

    Run curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      bash codecov.sh -F GHA_Ubuntu_16
      shell: /bin/bash -e {0}
      env:
        pythonLocation: /opt/hostedtoolcache/Python/3.6.11/x64
        CODECOV_NAME: ubuntu-16.04 Python 3.6
    ##[error]Process completed with exit code 7.
    

    Test / build (3.7, ubuntu-16.04)

    Run curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      bash codecov.sh -F GHA_Ubuntu_16
      shell: /bin/bash -e {0}
      env:
        pythonLocation: /opt/hostedtoolcache/Python/3.7.8/x64
        CODECOV_NAME: ubuntu-16.04 Python 3.7
    ##[error]Process completed with exit code 7.
    

    Test / build (3.7, windows-latest)

    Run curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      curl --retry 8 -s https://codecov.io/bash -o codecov.sh
      bash codecov.sh -F GHA_Windows
      shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"
      env:
        pythonLocation: C:\hostedtoolcache\windows\Python\3.7.8\x64
        CODECOV_NAME: windows-latest Python 3.7
    /usr/bin/bash: codecov.sh: No such file or directory
    ##[error]Process completed with exit code 1.
    
    opened by hugovk 7
  • Bump pytablewriter[html] from 0.58.0 to 0.59.0

    Bump pytablewriter[html] from 0.58.0 to 0.59.0

    Bumps pytablewriter[html] from 0.58.0 to 0.59.0.

    Release notes

    Sourced from pytablewriter[html]'s releases.

    v0.59.0

    • Add support for Python 3.10
    • Drop support for Python 3.5
    • Markdown alignment cells respect margin #36 (Thanks to @​shawalli)
    • Add validation to margin setter
    • Make it possible to set more writer settings via writer class constructors
    • Forced to set margin to zero for CSV/sourcecode writer classes
    • Fix _repr_html_ method to properly apply writer settings
    • Fix to margin value setting changes are properly applied after written a table
    • Modify type annotations
    • Update requirements
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    changelog: skip dependencies 
    opened by dependabot[bot] 4
  • Fix overall total and percent

    Fix overall total and percent

    Fixes #177. Replaces and closes #178.

    When fetching overall downloads, the without_mirrors numbers are a subset of the with_mirrors numbers, so don't add them up.

    Before

    pypistats overall pip

    | category | percent | downloads | |-----------------|--------:|------------:| | with_mirrors | 50.50% | 344,559,191 | | without_mirrors | 49.50% | 337,696,964 | | Total | | 682,256,155 |

    After

    pypistats overall pip

    | category | percent | downloads | |-----------------|--------:|------------:| | with_mirrors | 100.00% | 344,559,191 | | without_mirrors | 98.01% | 337,696,964 | | Total | | 344,559,191 |

    More info

    @w-henderson Hi! I said I'd tag you in to this PR and say what's going on!

    Here's a description of each commit, feel free to ask if you've any questions!


    https://github.com/hugovk/pypistats/commit/e23620fdf758e4cfa7433e690b320d020b71ad52 updates the expected results from the API for a given API call.

    The test use mocking, so that when running tests, it doesn't make real network calls because we don't want to test the actual network connection or the API at the other end, just how we process the data and show outputs. So we use a mocking library requests_mock to help fake what we get from using the request library. Also makes sure the expected return values are always the same, which of course isn't true with the live service.

    Before it only faked returning "without_mirrors" data, now we fake returning both "without_mirrors" and "without_mirrors" so we can check we sum it correctly.


    The next commit https://github.com/hugovk/pypistats/commit/cc7dc2bbd1d9fa3537a26117980da5c70ca567aa changes the code to fix the test: instead of summing all the downloads, if we're dealing with data of category "with_mirrors" or "without_mirrors" (aka overall data), then only sum the "with_mirrors" downloads.

    Also updates the expected result so the total is as it should be: total == "with_mirrors".


    We also need to calculate the percentages so "with_mirrors" is 100%, and "without_mirrors" is a fraction. Luckily this is easy, we put the same code from the previous commit's _grand_total into _percent. Plus update expected output.

    https://github.com/hugovk/pypistats/commit/922f1db1048843b1a861b0da99a9b628f9edeafa


    Next, the previous two commits use the same code, let's refactor it out to avoid duplication. https://github.com/hugovk/pypistats/commit/78a196a4b3ddc5342e1608eb26186a95314b222a


    I had been doing this on Python 3.9, which skipped NumPy and pandas tests because they're not yet available for 3.9. I hadn't noticed and pushed my branch. Not to worry, the CI ran it on < 3.9 and failed. All that was needed was updating their tests' expected results so the percents/totals matched the fixed results.

    https://github.com/hugovk/pypistats/commit/d74f40bf047f08577a9ef06c30adcd5504f87ffd


    The next two commits aren't related, but I took this opportunity to slip in some updates to linting (https://github.com/hugovk/pypistats/commit/6756a63afa6a18f9c6cab5e437a314935cb90844) and simplify a CI config file (https://github.com/hugovk/pypistats/commit/f5ca670b6153a5b46962d6a42f4272eccdb48ba7).

    bug changelog: Fixed 
    opened by hugovk 4
  • Add GitHub Action to create a release from a tag

    Add GitHub Action to create a release from a tag

    Uses https://github.com/actions/create-release to simplify the release process.

    When pushing a tag, this will create a corresponding release at https://github.com/hugovk/pypistats/releases.

    Note: The body text won't be created as "* TODO" from the config, but "Release [x.y.z]". This has been fixed in the action, but not yet released: https://github.com/actions/create-release/issues/38.

    opened by hugovk 4
  • Warn if --start-date is before earliest available data

    Warn if --start-date is before earliest available data

    Fixes #85.

    Add info to README and show a warning when called with --start-date before the earliest available data:

    $ pypistats python_major torchtext --start-date 2019-06-01 --end-date 2019-06-30
    /Users/hugo/github/pypistats/src/pypistats/cli.py:232: UserWarning: Requested start date (2019-06-01) is before earliest available data (2019-07-07), because data is only available for 180 days. See https://pypistats.org/about#data
      verbose=args.verbose,
    | category | downloads |
    |----------|----------:|
    | Total    |         0 |
    
    Date range: 2019-06-01 - 2019-06-30
    

    Warning not an error, because end date can be in range:

    $ pypistats python_major torchtext --start-date 2019-06-01
    /Users/hugo/github/pypistats/src/pypistats/cli.py:232: UserWarning: Requested start date (2019-06-01) is before earliest available data (2019-07-07), because data is only available for 180 days. See https://pypistats.org/about#data
      verbose=args.verbose,
    | category | percent | downloads |
    |----------|--------:|----------:|
    | 3        |  94.26% |   177,080 |
    | 2        |   5.09% |     9,559 |
    | null     |   0.66% |     1,234 |
    | Total    |         |   187,873 |
    
    Date range: 2019-06-01 - 2020-01-03
    

    Perhaps an error could be shown when --end-date is before earliest available data?

    enhancement 
    opened by hugovk 4
  • Fail to have the data more than half year

    Fail to have the data more than half year

    It seems the download numbers are not available for the timeline more than half year.

    pypistats python_major torchtext --start-date 2019-06-01 --end-date 2019-06-30
    

    returned:

    | category | downloads |
    |----------|----------:|
    | Total    |         0 |
    
    Date range: 2019-06-01 - 2019-06-30
    
    opened by zhangguanheng66 4
  • API to access data of last 6 months

    API to access data of last 6 months

    As mentioned in documentation, timeline data is retained for 180 days. But currently I did not find a way to see how the package fared in last 6 month let's say. It gives last day, week and month.

    I would love to see a functionality which can give monthly downloads for past 6 months.

    enhancement 
    opened by drdhaval2785 4
  • Dependency Dashboard

    Dependency Dashboard

    This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

    Awaiting Schedule

    These updates are awaiting their schedule. Click on a checkbox to get an update now.

    • [ ] Update dependency httpx to v0.23.2

    Detected dependencies

    github-actions
    .github/workflows/deploy.yml
    • actions/checkout v3
    • actions/setup-python v4
    .github/workflows/labels.yml
    • actions/checkout v3
    • micnncim/action-label-syncer v1
    .github/workflows/lint.yml
    • actions/checkout v3
    • actions/setup-python v4
    • pre-commit/action v3.0.0
    .github/workflows/release-drafter.yml
    • release-drafter/release-drafter v5
    .github/workflows/require-pr-label.yml
    • mheap/github-action-required-labels v3
    .github/workflows/test.yml
    • actions/checkout v3
    • actions/setup-python v4
    • codecov/codecov-action v3
    pip_requirements
    requirements.txt
    • freezegun ==1.2.2
    • httpx ==0.23.1
    • numpy ==1.24.1
    • pandas ==1.5.2
    • platformdirs ==2.6.2
    • pytablewriter ==0.64.2
    • pytest ==7.2.0
    • pytest-cov ==4.0.0
    • python-slugify ==7.0.0
    • respx ==0.20.1

    • [ ] Check this box to trigger a request for Renovate to run again on this repository
    opened by renovate[bot] 0
Releases(1.2.1)
  • 1.2.1(Dec 3, 2022)

  • 1.2.0(Dec 3, 2022)

    Added

    • Add and use PrettyTable's SINGLE_BORDER as the default (#347) @hugovk

    Changed

    • Migrate from setuptools + setuptools_scm to hatchling + hatch-vcs (#355) @hugovk
    • Migrate setup.cfg to pyproject.toml (#354) @hugovk

    Fixed

    • Remove redundant wheel dependency from pyproject.toml (#332) @hugovk
    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(May 2, 2022)

  • 1.0.0(Nov 26, 2021)

    Added

    • Add --color option (#291) @hugovk

    Removed

    • Drop Python 3.6 and add some type hints (#282) @hugovk

    Fixed

    • Use cog to update README usage (#293) @hugovk
    Source code(tar.gz)
    Source code(zip)
  • 0.15.0(Nov 3, 2021)

  • 0.14.0(Sep 15, 2021)

  • 0.13.0(Aug 27, 2021)

    Added

    • Add support for Python 3.10 (#268) @hugovk

    Changed

    • Replace Requests with HTTPX (#88) @hugovk
    • Replace appdirs with platformdirs fork (#246) @hugovk
    • Rename master to main (#267) @hugovk
    • Convert setup.py to static setup.cfg (#244) @hugovk
    • Replace 3.9-dev with 3.9 in .travis.yml to use Python 3.9 final (#186) @CozyDoomer

    Fixed

    • Docs: Travis CI has been replaced with GHA (#250) @hugovk
    Source code(tar.gz)
    Source code(zip)
  • 0.12.1(Oct 15, 2020)

  • 0.12.0(Oct 7, 2020)

  • 0.11.0(Apr 12, 2020)

  • 0.10.1(Feb 16, 2020)

    Fixed

    • Require pytablewriter 0.48+ to fix NumpyTableWriter regression (#96) @hugovk
    • Only Python 3 is supported: don't create universal wheel (#92) @hugovk

    Other changes

    • Travis CI: test Python 3.9 alpha (#89) @hugovk
    • GHA: use release drafter to draft releases (#95) @hugovk
    • GHA: sync issue labels using GitHub Actions (#94) @hugovk
    • GHA: simplify CI config (#91) @hugovk
    • Update Azure Pipelines (#90) @hugovk
    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Jan 7, 2020)

    • Add support for NumPy and Pandas data output (#84)
    • Warn if --start-date is before earliest available data (#86)
    • Error if --end-date is before earliest available data (#87)
    Source code(tar.gz)
    Source code(zip)
  • 0.9.0(Nov 14, 2019)

  • 0.8.0(Oct 12, 2019)

  • 0.7.1(Jul 30, 2019)

  • 0.7.0(Jul 22, 2019)

    • Add User-Agent to API requests (#65)
    • Use tox and pre-commit for testing (#64)
    • Use setuptools_scm to simplify versioning during release (#59, #61, #62, #63)
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(May 14, 2019)

  • 0.5.0(Mar 31, 2019)

    • Add -v --verbose, use capped -V for version: #46
    • Add --this-month for stats so far this month: #55
    • Optional days: --start-date and --end-date can take yyyy-mm-dd or yyyy-mm: #47
    Source code(tar.gz)
    Source code(zip)
  • 0.4.1(Jan 15, 2019)

    • Specify optional dependency of pytablewriter to ensure smooth install: https://github.com/hugovk/pypistats/pull/44
    • Refactor use of pytablewriter as a method may be removed in the future: https://github.com/hugovk/pypistats/pull/42
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Jan 1, 2019)

    • Add --monthly option: https://github.com/hugovk/pypistats/pull/38
    • Add local caching of API calls: https://github.com/hugovk/pypistats/pull/39
    • Fix ValueError: month must be in 1..12: https://github.com/hugovk/pypistats/pull/41
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Dec 17, 2018)

  • 0.2.1(Nov 5, 2018)

    Fix a bug:

    • Comma-separate the thousands in recent tables, like the others

    Before

    pypistats recent pip
    | last_day | last_month | last_week |
    |---------:|-----------:|----------:|
    |  1799469 |   67307635 |  15490986 |
    

    After

    $ pypistats recent pip
    | last_day  | last_month | last_week  |
    |----------:|-----------:|-----------:|
    | 1,799,469 | 67,307,635 | 15,490,986 |
    
    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Nov 2, 2018)

A lightweight terminal-based password manager coded with Python using SQLCipher for SQLite database encryption.

password-manager A lightweight terminal-based password manager coded with Python using SQLCipher for SQLite database encryption. Screenshot Pre-requis

Leonardo de Araujo 15 Oct 15, 2022
CLI/GUI Math commands based on python 3

PyMath Commands Syntax Installation Commands: pymath add: usage: pymath add 12.5 12.5 sub: usage: pymath sub 25 12.5 div: usage: pymath div 144 12 mul

eggsnham07 0 Nov 22, 2021
Command line interface for unasync

CLI for unasync Command line interface for unasync Getting started Install Run the following command to install the package with pip: pip install unas

Leynier Gutiérrez González 3 Apr 04, 2022
Jupyter notebook client in neovim

🪐 Jupyter-Nvim Read jupyter notebooks in neovim Note: The plugin is still in alpha stage 👾 Usage Just open any *.ipynb file and voila! ✨ Contributin

Ahmed Khalf 85 Dec 29, 2022
cmdpxl: a totally practical command-line image editor

cmdpxl: a totally practical command-line image editor

Jieruei Chang 476 Jan 07, 2023
Gamma ion pump QPC ethernet Python library & CLI utility

Unofficial Gamma ion pump ethernet control CLI utility and library This is a mini Python 3 library and utility that exposes some of the functions of t

2 Jul 18, 2022
A command line interface to buy things in stregsystemet

Stregsystemet-CLI This repository is the Stregsystemet CLI, to buy things in Stregsystemet, at AAU. Use of this cli-tool is at your own risk and there

F-klubben 14 Oct 18, 2022
🐾 Get the nftables counters easier to read

nft-stats Get the nftables counters easier to read It kind of hard to read the output of nft list ruleset so there is a small program parcising the ou

7 Oct 08, 2022
Terminal-based keyboard testing

kbdtest kbdtest is a simple Python program that tests keyboard input using an interactive, terminal-based, visual keyboard display. It was originally

Ruunyox 12 Jul 19, 2022
Tarstats - A simple Python commandline application that collects statistics about tarfiles

A simple Python commandline application that collects statistics about tarfiles.

Kristian Koehntopp 13 Feb 20, 2022
Seamlessly run Python code in IPython from Vim

Seamlessly run Python code from Vim in IPython, including executing individual code cells similar to Jupyter notebooks and MATLAB. This plugin also supports other languages and REPLs such as Julia.

Hans Chen 269 Dec 20, 2022
A simple terminal-based localhost chat application written in python

Chat House A simple terminal-based localhost chat application written in python How to Use? Clone the repo git clone https://github.com/heksadecimal/c

Heks 10 Nov 09, 2021
Wordle breaker: A CLI tool to help you solve Wordle

Wordle Breaker A CLI tool to help you solve Wordle I decided to code a solution

Alex 4 Apr 27, 2022
🔖 Lemnos: A simple, light-weight command-line to-do list manager.

🔖 Lemnos: CLI To-do List Manager This is a simple program that allows one to manage a to-do list via the command-line. Example $ python3 todo.py add

Rohan Sikand 1 Dec 07, 2022
Juniper Command System is a Micro CLI Tool that allows you to manage your files, launch applications, as well as providing extra tools for OS Management.

Juniper Command System is a Micro CLI Tool that allows you to manage your files, launch applications, as well as providing extra tools for OS Management.

Juan Carlos Juárez 1 Feb 02, 2022
Pyreadline3 - Windows implementation of the GNU readline library

pyreadline3 The pyreadline3 package is based on the stale package pyreadline loc

32 Jan 06, 2023
A terminal slots programme in PY

PYSlots PyPI and Test PyPI External Links PyPI Test PyPI Install Look directly at the bugs! Version pip install pyslots "Don't look directly at the bu

Luke Batema 4 Nov 30, 2022
Python3 library for multimedia functions at the command terminal

TERMINEDIA This is a Python library allowing using a text-terminal as a low-resolution graphics output, along with keyboard realtime reading, and a co

Joao S. O. Bueno 89 Dec 17, 2022
Ntfy - 🖥️📱🔔 A utility for sending notifications, on demand and when commands finish.

About ntfy ntfy brings notification to your shell. It can automatically provide desktop notifications when long running commands finish or it can send

Daniel Schep 4.5k Jan 01, 2023
nbcommands bring the goodness of Unix commands to Jupyter notebooks.

nbcommands nbcommands bring the goodness of Unix commands to Jupyter notebooks. Installation You can simply use pip to install nbcommands: $ pip insta

Vinayak Mehta 181 Dec 23, 2022