├── .github └── workflows │ ├── changerelease.yml │ ├── nextrelease.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── action.yml ├── changerelease.png ├── changerelease ├── __init__.py ├── __main__.py ├── api.py ├── changelog.py ├── cli.py └── release.py ├── poetry.lock ├── pyproject.toml ├── scripts ├── format ├── install ├── pre-commit ├── run └── test └── tests ├── celery_changelog.rst ├── celery_pandoc_changelog.md ├── keepachangelog_example.md └── test_parsing.py /.github/workflows/changerelease.yml: -------------------------------------------------------------------------------- 1 | name: changerelease 2 | on: 3 | workflow_dispatch: {} 4 | push: 5 | paths: [CHANGELOG.md] 6 | branches: [master] 7 | tags: ["*"] 8 | 9 | jobs: 10 | sync: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: dropseed/changerelease@master 14 | with: 15 | github_token: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/nextrelease.yml: -------------------------------------------------------------------------------- 1 | name: nextrelease 2 | on: 3 | push: 4 | branches: [master] 5 | pull_request: 6 | branches: [master] 7 | types: [labeled, unlabeled, edited, synchronize] 8 | 9 | jobs: 10 | sync: 11 | if: ${{ github.event_name == 'push' || github.event_name == 'pull_request' && github.head_ref == 'nextrelease' }} 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: dropseed/nextrelease@v2 15 | with: 16 | prepare_cmd: | 17 | sed -i -e "s/version = \"[^\"]*\"/version = \"$VERSION\"/g" pyproject.toml 18 | publish_cmd: | 19 | git tag -a v$VERSION_MAJOR -m v$VERSION_MAJOR -f && git push origin v$VERSION_MAJOR -f 20 | github_token: ${{ secrets.GITHUB_TOKEN }} 21 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | on: 3 | push: {} 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | python-version: ["3.7", "3.8", "3.9", "3.10"] 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: actions/setup-python@v2 14 | with: 15 | python-version: ${{ matrix.python-version }} 16 | - run: pip install poetry 17 | - run: poetry install 18 | - run: ./scripts/test 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pytest_cache 2 | __pycache__ 3 | /.venv 4 | /.vscode 5 | *.egg-info 6 | /dist 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | Nothing right now. 11 | 12 | ## [1.5.0] - 2021-11-24 13 | 14 | - Use composite action instead of docker 15 | - Add CLS client for basic analytics 16 | - Update pandoc example 17 | 18 | ## [1.4.0] - 2021-06-29 19 | 20 | Simpler regular expression to accept more changelog styles and conversions from a different syntax (ex. reStructuredText). 21 | 22 | ## [1.3.0] - 2020-09-07 23 | 24 | - Added automatic pre-release detection 25 | - Added a `--limit` option to only sync recent versions by default in a GitHub Action 26 | - Added a `--remote-changelog` option so you don't have to have the CHANGELOG file (or cloned repo) to use changerelease 27 | 28 | ## [1.2.0] - 2020-09-06 29 | 30 | - Allows changelog content for a version to be empty, while still creating a GitHub Release for the tag. 31 | - Prints parsed version changelogs 32 | - Fail if a git tag does not exist for a version 33 | 34 | ## [1.1.1] - 2020-09-06 35 | 36 | Added a `--no-tag-prefix` option to fix an empty issue with `--tag-prefix`. 37 | 38 | ## [1.1.0] - 2020-09-06 39 | 40 | Adds a `tag_prefix` option so that tags don't have to start with a "v". You can now use this with tags like "1.0.0" in addition to "v1.0.0". 41 | 42 | ## [1.0.0] - 2020-09-05 43 | 44 | The first release! Includes the `sync` command which will sync your `CHANGELOG.md` to GitHub Release notes. 45 | 46 | [Unreleased]: https://github.com/dropseed/changerelease/compare/v1.5.0...HEAD 47 | [1.5.0]: https://github.com/dropseed/changerelease/compare/v1.4.0...v1.5.0 48 | [1.4.0]: https://github.com/dropseed/changerelease/compare/v1.3.0...v1.4.0 49 | [1.3.0]: https://github.com/dropseed/changerelease/compare/v1.2.0...v1.3.0 50 | [1.2.0]: https://github.com/dropseed/changerelease/compare/v1.1.1...v1.2.0 51 | [1.1.1]: https://github.com/dropseed/changerelease/compare/v1.1.0...v1.1.1 52 | [1.1.0]: https://github.com/dropseed/changerelease/compare/v1.0.0...v1.1.0 53 | [1.0.0]: https://github.com/dropseed/changerelease/releases/tag/v1.0.0 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dropseed 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # changerelease 2 | 3 | Automatically update your GitHub Releases from `CHANGELOG.md`. 4 | 5 | This tool expects that you follow the [Keep a Changelog](https://keepachangelog.com/) format. 6 | 7 | To use it: 8 | 9 | 1. [Keep a Changelog](https://keepachangelog.com/) 10 | 1. Git tag your versions 11 | 1. Let the changerelease GitHub Action automatically keep your GitHub Releases updated 12 | 13 | ![changerelease screenshot](changerelease.png) 14 | 15 | ## Use the GitHub Action 16 | 17 | ```yml 18 | name: changerelease 19 | on: 20 | workflow_dispatch: {} 21 | push: 22 | paths: [CHANGELOG.md] 23 | branches: [master] 24 | tags: ["*"] 25 | 26 | jobs: 27 | sync: 28 | runs-on: ubuntu-latest 29 | steps: 30 | - uses: dropseed/changerelease@v1 31 | with: 32 | github_token: ${{ secrets.GITHUB_TOKEN }} 33 | # optional 34 | tag_prefix: v 35 | changelog: CHANGELOG.md 36 | ``` 37 | 38 | ## What if my changelog isn't in Markdown? 39 | 40 | For changelogs written in reStructuredText or another syntax besides Markdown, 41 | you can run a conversion step before running changerelease. 42 | This can be a custom rendering script or something like [pandoc](https://pandoc.org/) to convert your changelog to Markdown. 43 | The only real expectation is that your version names are written in h2 headings (`## {version_name}`). 44 | 45 | ```yaml 46 | name: changerelease 47 | on: 48 | workflow_dispatch: {} 49 | push: 50 | paths: [CHANGELOG.md] 51 | branches: [master] 52 | tags: ["*"] 53 | 54 | jobs: 55 | sync: 56 | runs-on: ubuntu-latest 57 | steps: 58 | - uses: actions/checkout@v2 59 | 60 | # Convert to markdown first 61 | # https://github.com/pandoc/pandoc-action-example 62 | - uses: docker://pandoc/core:2.14 63 | with: 64 | args: "CHANGELOG.rst -f rst -t markdown -o CR_CHANGELOG.md" 65 | 66 | - uses: dropseed/changerelease@v1 67 | with: 68 | github_token: ${{ secrets.GITHUB_TOKEN }} 69 | # optional 70 | tag_prefix: v 71 | changelog: CR_CHANGELOG.md 72 | remote_changelog: false 73 | ``` 74 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: changerelease 2 | description: Automatically update your GitHub Releases from CHANGELOG.md 3 | branding: 4 | icon: upload-cloud 5 | color: white 6 | inputs: 7 | changelog: 8 | description: 'Path to your CHANGELOG' 9 | required: false 10 | default: 'CHANGELOG.md' 11 | tag_prefix: 12 | description: 'The prefix that is on SemVer tags (i.e. "v" or nothing "")' 13 | default: 'v' 14 | github_token: 15 | description: "A GitHub token that can create and modify releases" 16 | required: true 17 | limit: 18 | description: 'Limit syncing to the latest X versions' 19 | default: 5 20 | remote_changelog: 21 | description: 'Get the CHANGELOG using the GitHub API (does not require a cloned repo)' 22 | default: true 23 | runs: 24 | using: composite 25 | steps: 26 | - run: pip3 install $GITHUB_ACTION_PATH 27 | shell: bash 28 | - run: changerelease sync 29 | shell: bash 30 | env: 31 | CR_CHANGELOG: ${{ inputs.changelog }} 32 | CR_TAG_PREFIX: ${{ inputs.tag_prefix }} 33 | CR_NO_TAG_PREFIX: ${{ inputs.tag_prefix == '' }} 34 | CR_LIMIT: ${{ inputs.limit }} 35 | CR_REMOTE_CHANGELOG: ${{ inputs.remote_changelog }} 36 | GITHUB_TOKEN: ${{ inputs.github_token }} 37 | -------------------------------------------------------------------------------- /changerelease.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dropseed/changerelease/fb6d14c2fb54c09c04c817208753613c5a131225/changerelease.png -------------------------------------------------------------------------------- /changerelease/__init__.py: -------------------------------------------------------------------------------- 1 | import pkg_resources 2 | 3 | 4 | __author__ = "Dropseed" 5 | __email__ = "python@dropseed.dev" 6 | __version__ = pkg_resources.get_distribution("changerelease").version 7 | -------------------------------------------------------------------------------- /changerelease/__main__.py: -------------------------------------------------------------------------------- 1 | from .cli import cli 2 | 3 | 4 | cli() 5 | -------------------------------------------------------------------------------- /changerelease/api.py: -------------------------------------------------------------------------------- 1 | from requests import Session 2 | from urllib.parse import urljoin 3 | 4 | 5 | class APISession(Session): 6 | def __init__(self, base_url=None, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | self.base_url = base_url 9 | 10 | def request(self, method, url, *args, **kwargs): 11 | url = urljoin(self.base_url, url) 12 | return super().request(method, url, *args, **kwargs) 13 | -------------------------------------------------------------------------------- /changerelease/changelog.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | SKIP_VERSIONS = ["Unreleased"] 5 | RE_VERSION_HEADING = r"## " 6 | RE_VERSION_NAME = r"\[?([^\[\]\s]+)\]?" 7 | RE_VERSION_CONTENTS = r"([\s\S]+?)" 8 | RE_LINK_DEFINITIONS = r"\[.+\]: " 9 | RE_END_STRING = r"\Z" 10 | RE_VERSION_HEADING_LINE = f"^{RE_VERSION_HEADING}{RE_VERSION_NAME}.*$" 11 | 12 | 13 | class Changelog: 14 | def __init__(self, path, contents): 15 | self.path = path 16 | self.contents = contents 17 | self.versions = self.parse_versions() 18 | 19 | def parse_versions(self): 20 | version_names = re.findall(RE_VERSION_HEADING_LINE, self.contents, re.MULTILINE) 21 | version_names = [x for x in version_names if x not in SKIP_VERSIONS] 22 | return version_names 23 | 24 | def parse_version_content(self, version): 25 | matches = re.findall( 26 | f"^{RE_VERSION_HEADING}\[?{version}\]?.*${RE_VERSION_CONTENTS}^({RE_VERSION_HEADING}|{RE_LINK_DEFINITIONS}|{RE_END_STRING})", 27 | self.contents, 28 | re.MULTILINE, 29 | ) 30 | 31 | if not matches: 32 | return "" 33 | 34 | return matches[0][0].strip() 35 | -------------------------------------------------------------------------------- /changerelease/cli.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | import click 4 | 5 | from .release import Release 6 | from .changelog import Changelog 7 | from .api import APISession 8 | from . import __version__ 9 | 10 | 11 | @click.group() 12 | def cli(): 13 | pass 14 | 15 | 16 | @cli.command() 17 | @click.option( 18 | "--changelog", 19 | default="CHANGELOG.md", 20 | show_default=True, 21 | envvar="CR_CHANGELOG", 22 | ) 23 | @click.option("--remote-changelog", is_flag=True, envvar="CR_REMOTE_CHANGELOG") 24 | @click.option("--tag-prefix", default="v", show_default=True, envvar="CR_TAG_PREFIX") 25 | @click.option("--no-tag-prefix", default=False, is_flag=True, envvar="CR_NO_TAG_PREFIX") 26 | @click.option("--repo", envvar="GITHUB_REPOSITORY", required=True) 27 | @click.option( 28 | "--api-url", 29 | envvar="GITHUB_API_URL", 30 | default="https://api.github.com", 31 | ) 32 | @click.option("--limit", default=-1, envvar="CR_LIMIT") 33 | @click.option("--token", envvar="GITHUB_TOKEN", required=True) 34 | def sync( 35 | changelog, remote_changelog, tag_prefix, no_tag_prefix, repo, api_url, limit, token 36 | ): 37 | if no_tag_prefix: 38 | tag_prefix = "" 39 | 40 | requests_session = APISession(base_url=api_url) 41 | requests_session.headers.update( 42 | { 43 | "Accept": "application/vnd.github.v3+json", 44 | "Authorization": "token " + token, 45 | } 46 | ) 47 | 48 | if remote_changelog: 49 | click.echo(f"Fetching current {changelog} from the {repo} repo") 50 | response = requests_session.get(f"/repos/{repo}/contents/{changelog}") 51 | response.raise_for_status() 52 | changelog_contents = base64.b64decode(response.json()["content"]).decode( 53 | "utf-8" 54 | ) 55 | else: 56 | with open(changelog, "r") as f: 57 | changelog_contents = f.read() 58 | 59 | cl = Changelog(changelog, changelog_contents) 60 | 61 | outline = "-" * 80 62 | 63 | results = [] 64 | 65 | versions = cl.versions 66 | if limit > -1: 67 | click.echo(f"Limiting to {limit} of {len(versions)} versions") 68 | versions = versions[:limit] 69 | 70 | for version in versions: 71 | release = Release(repo, tag_prefix, version, requests_session) 72 | suffix = " (pre-release)" if release.prerelease else "" 73 | click.secho(f"\nSyncing version {release.version}{suffix}", bold=True) 74 | 75 | version_contents = cl.parse_version_content(version) 76 | click.echo(f"{outline}\n{version_contents or '(empty)'}\n{outline}") 77 | message, synced = release.sync(version_contents) 78 | 79 | click.secho(message, fg="green" if synced else "red") 80 | 81 | results.append(synced) 82 | 83 | if all(results): 84 | click.secho( 85 | f"\nSynced {len(results)} GitHub Releases on {repo} with {cl.path}", 86 | fg="green", 87 | ) 88 | else: 89 | failed = [x for x in results if not x] 90 | click.secho(f"Failed to sync {len(failed)} versions", fg="red") 91 | exit(1) 92 | 93 | 94 | if __name__ == "__main__": 95 | cli() 96 | -------------------------------------------------------------------------------- /changerelease/release.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | 4 | class Release: 5 | def __init__(self, repo, tag_prefix, version, requests_session): 6 | self.repo = repo 7 | self.tag_prefix = tag_prefix 8 | self.version = version 9 | self.version_tag = tag_prefix + version 10 | self.prerelease = bool(re.match("v?\d+\.\d+\.\d+-.+", self.version)) 11 | 12 | self.requests_session = requests_session 13 | 14 | self.github_data = self.get() 15 | 16 | def exists(self): 17 | return bool(self.github_data) 18 | 19 | def tag_exists(self): 20 | response = self.requests_session.get( 21 | f"/repos/{self.repo}/git/refs/tags/{self.version_tag}" 22 | ) 23 | if response.status_code == 404: 24 | return False 25 | response.raise_for_status() 26 | return True 27 | 28 | def body_matches(self, contents): 29 | return self.github_data["body"] == contents 30 | 31 | def get(self): 32 | response = self.requests_session.get( 33 | f"/repos/{self.repo}/releases/tags/{self.version_tag}" 34 | ) 35 | if response.status_code == 404: 36 | return {} 37 | response.raise_for_status() 38 | return response.json() 39 | 40 | def create(self, contents): 41 | response = self.requests_session.post( 42 | f"/repos/{self.repo}/releases", 43 | json={ 44 | "tag_name": self.version_tag, 45 | "name": self.version, 46 | "body": contents, 47 | "prerelease": self.prerelease, 48 | }, 49 | ) 50 | response.raise_for_status() 51 | return response.json() 52 | 53 | def update_body(self, contents): 54 | response = self.requests_session.patch( 55 | self.github_data["url"], json={"body": contents} 56 | ) 57 | response.raise_for_status() 58 | return response.json() 59 | 60 | def sync(self, contents): 61 | message = "" 62 | synced = True 63 | 64 | if not self.exists(): 65 | if self.tag_exists(): 66 | message = f"Release for {self.version} does not exist. Creating it..." 67 | release_data = self.create(contents) 68 | message += "\n" + release_data["html_url"] 69 | else: 70 | message = f'Git tag "{self.version_tag}" not found. A tag needs to be pushed before we can create a release for it.' 71 | synced = False 72 | elif not self.body_matches(contents): 73 | message = f"Release for {self.version} exists but the changelog doesn't match. Updating the release..." 74 | self.update_body(contents) 75 | else: 76 | message = "Release is up-to-date" 77 | 78 | return (message, synced) 79 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | name = "appnope" 3 | version = "0.1.3" 4 | description = "Disable App Nap on macOS >= 10.9" 5 | category = "dev" 6 | optional = false 7 | python-versions = "*" 8 | 9 | [[package]] 10 | name = "atomicwrites" 11 | version = "1.4.1" 12 | description = "Atomic file writes." 13 | category = "dev" 14 | optional = false 15 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" 16 | 17 | [[package]] 18 | name = "attrs" 19 | version = "22.1.0" 20 | description = "Classes Without Boilerplate" 21 | category = "dev" 22 | optional = false 23 | python-versions = ">=3.5" 24 | 25 | [package.extras] 26 | dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] 27 | docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] 28 | tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] 29 | tests_no_zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] 30 | 31 | [[package]] 32 | name = "backcall" 33 | version = "0.2.0" 34 | description = "Specifications for callback functions passed in to an API" 35 | category = "dev" 36 | optional = false 37 | python-versions = "*" 38 | 39 | [[package]] 40 | name = "black" 41 | version = "22.8.0" 42 | description = "The uncompromising code formatter." 43 | category = "dev" 44 | optional = false 45 | python-versions = ">=3.6.2" 46 | 47 | [package.dependencies] 48 | click = ">=8.0.0" 49 | mypy-extensions = ">=0.4.3" 50 | pathspec = ">=0.9.0" 51 | platformdirs = ">=2" 52 | tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} 53 | typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} 54 | typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} 55 | 56 | [package.extras] 57 | colorama = ["colorama (>=0.4.3)"] 58 | d = ["aiohttp (>=3.7.4)"] 59 | jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] 60 | uvloop = ["uvloop (>=0.15.2)"] 61 | 62 | [[package]] 63 | name = "certifi" 64 | version = "2022.9.24" 65 | description = "Python package for providing Mozilla's CA Bundle." 66 | category = "main" 67 | optional = false 68 | python-versions = ">=3.6" 69 | 70 | [[package]] 71 | name = "charset-normalizer" 72 | version = "2.1.1" 73 | description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." 74 | category = "main" 75 | optional = false 76 | python-versions = ">=3.6.0" 77 | 78 | [package.extras] 79 | unicode_backport = ["unicodedata2"] 80 | 81 | [[package]] 82 | name = "click" 83 | version = "8.1.3" 84 | description = "Composable command line interface toolkit" 85 | category = "main" 86 | optional = false 87 | python-versions = ">=3.7" 88 | 89 | [package.dependencies] 90 | colorama = {version = "*", markers = "platform_system == \"Windows\""} 91 | importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} 92 | 93 | [[package]] 94 | name = "colorama" 95 | version = "0.4.5" 96 | description = "Cross-platform colored terminal text." 97 | category = "main" 98 | optional = false 99 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 100 | 101 | [[package]] 102 | name = "decorator" 103 | version = "5.1.1" 104 | description = "Decorators for Humans" 105 | category = "dev" 106 | optional = false 107 | python-versions = ">=3.5" 108 | 109 | [[package]] 110 | name = "idna" 111 | version = "3.4" 112 | description = "Internationalized Domain Names in Applications (IDNA)" 113 | category = "main" 114 | optional = false 115 | python-versions = ">=3.5" 116 | 117 | [[package]] 118 | name = "importlib-metadata" 119 | version = "4.12.0" 120 | description = "Read metadata from Python packages" 121 | category = "main" 122 | optional = false 123 | python-versions = ">=3.7" 124 | 125 | [package.dependencies] 126 | typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} 127 | zipp = ">=0.5" 128 | 129 | [package.extras] 130 | docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] 131 | perf = ["ipython"] 132 | testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] 133 | 134 | [[package]] 135 | name = "iniconfig" 136 | version = "1.1.1" 137 | description = "iniconfig: brain-dead simple config-ini parsing" 138 | category = "dev" 139 | optional = false 140 | python-versions = "*" 141 | 142 | [[package]] 143 | name = "ipdb" 144 | version = "0.13.9" 145 | description = "IPython-enabled pdb" 146 | category = "dev" 147 | optional = false 148 | python-versions = ">=2.7" 149 | 150 | [package.dependencies] 151 | decorator = {version = "*", markers = "python_version > \"3.6\""} 152 | ipython = {version = ">=7.17.0", markers = "python_version > \"3.6\""} 153 | setuptools = "*" 154 | toml = {version = ">=0.10.2", markers = "python_version > \"3.6\""} 155 | 156 | [[package]] 157 | name = "ipython" 158 | version = "7.34.0" 159 | description = "IPython: Productive Interactive Computing" 160 | category = "dev" 161 | optional = false 162 | python-versions = ">=3.7" 163 | 164 | [package.dependencies] 165 | appnope = {version = "*", markers = "sys_platform == \"darwin\""} 166 | backcall = "*" 167 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 168 | decorator = "*" 169 | jedi = ">=0.16" 170 | matplotlib-inline = "*" 171 | pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} 172 | pickleshare = "*" 173 | prompt-toolkit = ">=2.0.0,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.1.0" 174 | pygments = "*" 175 | setuptools = ">=18.5" 176 | traitlets = ">=4.2" 177 | 178 | [package.extras] 179 | all = ["Sphinx (>=1.3)", "ipykernel", "ipyparallel", "ipywidgets", "nbconvert", "nbformat", "nose (>=0.10.1)", "notebook", "numpy (>=1.17)", "pygments", "qtconsole", "requests", "testpath"] 180 | doc = ["Sphinx (>=1.3)"] 181 | kernel = ["ipykernel"] 182 | nbconvert = ["nbconvert"] 183 | nbformat = ["nbformat"] 184 | notebook = ["ipywidgets", "notebook"] 185 | parallel = ["ipyparallel"] 186 | qtconsole = ["qtconsole"] 187 | test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments", "requests", "testpath"] 188 | 189 | [[package]] 190 | name = "jedi" 191 | version = "0.18.1" 192 | description = "An autocompletion tool for Python that can be used for text editors." 193 | category = "dev" 194 | optional = false 195 | python-versions = ">=3.6" 196 | 197 | [package.dependencies] 198 | parso = ">=0.8.0,<0.9.0" 199 | 200 | [package.extras] 201 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] 202 | testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"] 203 | 204 | [[package]] 205 | name = "matplotlib-inline" 206 | version = "0.1.6" 207 | description = "Inline Matplotlib backend for Jupyter" 208 | category = "dev" 209 | optional = false 210 | python-versions = ">=3.5" 211 | 212 | [package.dependencies] 213 | traitlets = "*" 214 | 215 | [[package]] 216 | name = "mypy-extensions" 217 | version = "0.4.3" 218 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 219 | category = "dev" 220 | optional = false 221 | python-versions = "*" 222 | 223 | [[package]] 224 | name = "packaging" 225 | version = "21.3" 226 | description = "Core utilities for Python packages" 227 | category = "dev" 228 | optional = false 229 | python-versions = ">=3.6" 230 | 231 | [package.dependencies] 232 | pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" 233 | 234 | [[package]] 235 | name = "parso" 236 | version = "0.8.3" 237 | description = "A Python Parser" 238 | category = "dev" 239 | optional = false 240 | python-versions = ">=3.6" 241 | 242 | [package.extras] 243 | qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] 244 | testing = ["docopt", "pytest (<6.0.0)"] 245 | 246 | [[package]] 247 | name = "pathspec" 248 | version = "0.10.1" 249 | description = "Utility library for gitignore style pattern matching of file paths." 250 | category = "dev" 251 | optional = false 252 | python-versions = ">=3.7" 253 | 254 | [[package]] 255 | name = "pexpect" 256 | version = "4.8.0" 257 | description = "Pexpect allows easy control of interactive console applications." 258 | category = "dev" 259 | optional = false 260 | python-versions = "*" 261 | 262 | [package.dependencies] 263 | ptyprocess = ">=0.5" 264 | 265 | [[package]] 266 | name = "pickleshare" 267 | version = "0.7.5" 268 | description = "Tiny 'shelve'-like database with concurrency support" 269 | category = "dev" 270 | optional = false 271 | python-versions = "*" 272 | 273 | [[package]] 274 | name = "platformdirs" 275 | version = "2.5.2" 276 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 277 | category = "dev" 278 | optional = false 279 | python-versions = ">=3.7" 280 | 281 | [package.extras] 282 | docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] 283 | test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] 284 | 285 | [[package]] 286 | name = "pluggy" 287 | version = "1.0.0" 288 | description = "plugin and hook calling mechanisms for python" 289 | category = "dev" 290 | optional = false 291 | python-versions = ">=3.6" 292 | 293 | [package.dependencies] 294 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 295 | 296 | [package.extras] 297 | dev = ["pre-commit", "tox"] 298 | testing = ["pytest", "pytest-benchmark"] 299 | 300 | [[package]] 301 | name = "prompt-toolkit" 302 | version = "3.0.31" 303 | description = "Library for building powerful interactive command lines in Python" 304 | category = "dev" 305 | optional = false 306 | python-versions = ">=3.6.2" 307 | 308 | [package.dependencies] 309 | wcwidth = "*" 310 | 311 | [[package]] 312 | name = "ptyprocess" 313 | version = "0.7.0" 314 | description = "Run a subprocess in a pseudo terminal" 315 | category = "dev" 316 | optional = false 317 | python-versions = "*" 318 | 319 | [[package]] 320 | name = "py" 321 | version = "1.11.0" 322 | description = "library with cross-python path, ini-parsing, io, code, log facilities" 323 | category = "dev" 324 | optional = false 325 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 326 | 327 | [[package]] 328 | name = "Pygments" 329 | version = "2.13.0" 330 | description = "Pygments is a syntax highlighting package written in Python." 331 | category = "dev" 332 | optional = false 333 | python-versions = ">=3.6" 334 | 335 | [package.extras] 336 | plugins = ["importlib-metadata"] 337 | 338 | [[package]] 339 | name = "pyparsing" 340 | version = "3.0.9" 341 | description = "pyparsing module - Classes and methods to define and execute parsing grammars" 342 | category = "dev" 343 | optional = false 344 | python-versions = ">=3.6.8" 345 | 346 | [package.extras] 347 | diagrams = ["jinja2", "railroad-diagrams"] 348 | 349 | [[package]] 350 | name = "pytest" 351 | version = "6.2.5" 352 | description = "pytest: simple powerful testing with Python" 353 | category = "dev" 354 | optional = false 355 | python-versions = ">=3.6" 356 | 357 | [package.dependencies] 358 | atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} 359 | attrs = ">=19.2.0" 360 | colorama = {version = "*", markers = "sys_platform == \"win32\""} 361 | importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} 362 | iniconfig = "*" 363 | packaging = "*" 364 | pluggy = ">=0.12,<2.0" 365 | py = ">=1.8.2" 366 | toml = "*" 367 | 368 | [package.extras] 369 | testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] 370 | 371 | [[package]] 372 | name = "requests" 373 | version = "2.28.1" 374 | description = "Python HTTP for Humans." 375 | category = "main" 376 | optional = false 377 | python-versions = ">=3.7, <4" 378 | 379 | [package.dependencies] 380 | certifi = ">=2017.4.17" 381 | charset-normalizer = ">=2,<3" 382 | idna = ">=2.5,<4" 383 | urllib3 = ">=1.21.1,<1.27" 384 | 385 | [package.extras] 386 | socks = ["PySocks (>=1.5.6,!=1.5.7)"] 387 | use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"] 388 | 389 | [[package]] 390 | name = "setuptools" 391 | version = "65.4.0" 392 | description = "Easily download, build, install, upgrade, and uninstall Python packages" 393 | category = "dev" 394 | optional = false 395 | python-versions = ">=3.7" 396 | 397 | [package.extras] 398 | docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] 399 | testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mock", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] 400 | testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] 401 | 402 | [[package]] 403 | name = "toml" 404 | version = "0.10.2" 405 | description = "Python Library for Tom's Obvious, Minimal Language" 406 | category = "dev" 407 | optional = false 408 | python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" 409 | 410 | [[package]] 411 | name = "tomli" 412 | version = "2.0.1" 413 | description = "A lil' TOML parser" 414 | category = "dev" 415 | optional = false 416 | python-versions = ">=3.7" 417 | 418 | [[package]] 419 | name = "traitlets" 420 | version = "5.4.0" 421 | description = "" 422 | category = "dev" 423 | optional = false 424 | python-versions = ">=3.7" 425 | 426 | [package.extras] 427 | test = ["pre-commit", "pytest"] 428 | 429 | [[package]] 430 | name = "typed-ast" 431 | version = "1.5.4" 432 | description = "a fork of Python 2 and 3 ast modules with type comment support" 433 | category = "dev" 434 | optional = false 435 | python-versions = ">=3.6" 436 | 437 | [[package]] 438 | name = "typing-extensions" 439 | version = "4.3.0" 440 | description = "Backported and Experimental Type Hints for Python 3.7+" 441 | category = "main" 442 | optional = false 443 | python-versions = ">=3.7" 444 | 445 | [[package]] 446 | name = "urllib3" 447 | version = "1.26.12" 448 | description = "HTTP library with thread-safe connection pooling, file post, and more." 449 | category = "main" 450 | optional = false 451 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" 452 | 453 | [package.extras] 454 | brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] 455 | secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] 456 | socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] 457 | 458 | [[package]] 459 | name = "wcwidth" 460 | version = "0.2.5" 461 | description = "Measures the displayed width of unicode strings in a terminal" 462 | category = "dev" 463 | optional = false 464 | python-versions = "*" 465 | 466 | [[package]] 467 | name = "zipp" 468 | version = "3.8.1" 469 | description = "Backport of pathlib-compatible object wrapper for zip files" 470 | category = "main" 471 | optional = false 472 | python-versions = ">=3.7" 473 | 474 | [package.extras] 475 | docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] 476 | testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] 477 | 478 | [metadata] 479 | lock-version = "1.1" 480 | python-versions = "^3.7" 481 | content-hash = "9066835a203e56b66f0a14ae5509a3d3fed8be31bffaf24075f51e689f38619a" 482 | 483 | [metadata.files] 484 | appnope = [ 485 | {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, 486 | {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, 487 | ] 488 | atomicwrites = [ 489 | {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, 490 | ] 491 | attrs = [ 492 | {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, 493 | {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, 494 | ] 495 | backcall = [ 496 | {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, 497 | {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, 498 | ] 499 | black = [ 500 | {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, 501 | {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, 502 | {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, 503 | {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, 504 | {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, 505 | {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, 506 | {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, 507 | {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, 508 | {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, 509 | {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, 510 | {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, 511 | {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, 512 | {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, 513 | {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, 514 | {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, 515 | {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, 516 | {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, 517 | {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, 518 | {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, 519 | {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, 520 | {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, 521 | {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, 522 | {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, 523 | ] 524 | certifi = [ 525 | {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, 526 | {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, 527 | ] 528 | charset-normalizer = [ 529 | {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, 530 | {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, 531 | ] 532 | click = [ 533 | {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, 534 | {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, 535 | ] 536 | colorama = [ 537 | {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, 538 | {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, 539 | ] 540 | decorator = [ 541 | {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, 542 | {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, 543 | ] 544 | idna = [ 545 | {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, 546 | {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, 547 | ] 548 | importlib-metadata = [ 549 | {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"}, 550 | {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"}, 551 | ] 552 | iniconfig = [ 553 | {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, 554 | {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, 555 | ] 556 | ipdb = [ 557 | {file = "ipdb-0.13.9.tar.gz", hash = "sha256:951bd9a64731c444fd907a5ce268543020086a697f6be08f7cc2c9a752a278c5"}, 558 | ] 559 | ipython = [ 560 | {file = "ipython-7.34.0-py3-none-any.whl", hash = "sha256:c175d2440a1caff76116eb719d40538fbb316e214eda85c5515c303aacbfb23e"}, 561 | {file = "ipython-7.34.0.tar.gz", hash = "sha256:af3bdb46aa292bce5615b1b2ebc76c2080c5f77f54bda2ec72461317273e7cd6"}, 562 | ] 563 | jedi = [ 564 | {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, 565 | {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, 566 | ] 567 | matplotlib-inline = [ 568 | {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, 569 | {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, 570 | ] 571 | mypy-extensions = [ 572 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 573 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 574 | ] 575 | packaging = [ 576 | {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, 577 | {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, 578 | ] 579 | parso = [ 580 | {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, 581 | {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, 582 | ] 583 | pathspec = [ 584 | {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, 585 | {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, 586 | ] 587 | pexpect = [ 588 | {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, 589 | {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, 590 | ] 591 | pickleshare = [ 592 | {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, 593 | {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, 594 | ] 595 | platformdirs = [ 596 | {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, 597 | {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"}, 598 | ] 599 | pluggy = [ 600 | {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, 601 | {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, 602 | ] 603 | prompt-toolkit = [ 604 | {file = "prompt_toolkit-3.0.31-py3-none-any.whl", hash = "sha256:9696f386133df0fc8ca5af4895afe5d78f5fcfe5258111c2a79a1c3e41ffa96d"}, 605 | {file = "prompt_toolkit-3.0.31.tar.gz", hash = "sha256:9ada952c9d1787f52ff6d5f3484d0b4df8952787c087edf6a1f7c2cb1ea88148"}, 606 | ] 607 | ptyprocess = [ 608 | {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, 609 | {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, 610 | ] 611 | py = [ 612 | {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, 613 | {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, 614 | ] 615 | Pygments = [ 616 | {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"}, 617 | {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"}, 618 | ] 619 | pyparsing = [ 620 | {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, 621 | {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, 622 | ] 623 | pytest = [ 624 | {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, 625 | {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, 626 | ] 627 | requests = [ 628 | {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, 629 | {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, 630 | ] 631 | setuptools = [ 632 | {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, 633 | {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, 634 | ] 635 | toml = [ 636 | {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, 637 | {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, 638 | ] 639 | tomli = [ 640 | {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, 641 | {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, 642 | ] 643 | traitlets = [ 644 | {file = "traitlets-5.4.0-py3-none-any.whl", hash = "sha256:93663cc8236093d48150e2af5e2ed30fc7904a11a6195e21bab0408af4e6d6c8"}, 645 | {file = "traitlets-5.4.0.tar.gz", hash = "sha256:3f2c4e435e271592fe4390f1746ea56836e3a080f84e7833f0f801d9613fec39"}, 646 | ] 647 | typed-ast = [ 648 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, 649 | {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, 650 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, 651 | {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, 652 | {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, 653 | {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, 654 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, 655 | {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, 656 | {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, 657 | {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, 658 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, 659 | {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, 660 | {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, 661 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, 662 | {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, 663 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, 664 | {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, 665 | {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, 666 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, 667 | {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, 668 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, 669 | {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, 670 | {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, 671 | {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, 672 | ] 673 | typing-extensions = [ 674 | {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, 675 | {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, 676 | ] 677 | urllib3 = [ 678 | {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, 679 | {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, 680 | ] 681 | wcwidth = [ 682 | {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, 683 | {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"}, 684 | ] 685 | zipp = [ 686 | {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, 687 | {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, 688 | ] 689 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "changerelease" 3 | version = "1.6.0" 4 | description = "Sync GitHub Releases with CHANGELOG.md" 5 | authors = ["Dave Gaeddert "] 6 | license = "MIT" 7 | readme = "README.md" 8 | # homepage = "https://changerelease.dropseed.io" 9 | # documentation = "https://changerelease.dropseed.io" 10 | repository = "https://github.com/dropseed/changerelease" 11 | keywords = ["changelog", "github", "release", "changes"] 12 | 13 | [tool.poetry.scripts] 14 | changerelease = "changerelease.cli:cli" 15 | 16 | [tool.poetry.dependencies] 17 | python = "^3.7" 18 | requests = "^2.24.0" 19 | click = "^8.0.0" 20 | 21 | [tool.poetry.dev-dependencies] 22 | ipdb = "^0.13.3" 23 | black = "^22.8.0" 24 | pytest = "^6.2.4" 25 | 26 | [build-system] 27 | requires = ["poetry>=0.12"] 28 | build-backend = "poetry.masonry.api" 29 | -------------------------------------------------------------------------------- /scripts/format: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | poetry run black . --exclude "/(snapshots|\.venv|\.git|\.venv)/" 3 | -------------------------------------------------------------------------------- /scripts/install: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | poetry install 3 | -------------------------------------------------------------------------------- /scripts/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | poetry run black . --check --exclude "/(snapshots|\.venv|\.git|\.venv)/" 3 | -------------------------------------------------------------------------------- /scripts/run: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | poetry run changerelease $@ 3 | -------------------------------------------------------------------------------- /scripts/test: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | poetry run pytest tests $@ 3 | -------------------------------------------------------------------------------- /tests/celery_changelog.rst: -------------------------------------------------------------------------------- 1 | .. _changelog: 2 | 3 | ================ 4 | Change history 5 | ================ 6 | 7 | This document contains change notes for bugfix & new features 8 | in the & 5.1.x series, please see :ref:`whatsnew-5.1` for 9 | an overview of what's new in Celery 5.1. 10 | 11 | .. version-5.1.2: 12 | 13 | 5.1.2 14 | ===== 15 | :release-date: 2021-06-28 16.15 P.M UTC+3:00 16 | :release-by: Omer Katz 17 | 18 | - When chords fail, correctly call errbacks. (#6814) 19 | 20 | We had a special case for calling errbacks when a chord failed which 21 | assumed they were old style. This change ensures that we call the proper 22 | errback dispatch method which understands new and old style errbacks, 23 | and adds test to confirm that things behave as one might expect now. 24 | - Avoid using the ``Event.isSet()`` deprecated alias. (#6824) 25 | - Reintroduce sys.argv default behaviour for ``Celery.start()``. (#6825) 26 | 27 | .. version-5.1.1: 28 | 29 | 5.1.1 30 | ===== 31 | :release-date: 2021-06-17 16.10 P.M UTC+3:00 32 | :release-by: Omer Katz 33 | 34 | - Fix ``--pool=threads`` support in command line options parsing. (#6787) 35 | - Fix ``LoggingProxy.write()`` return type. (#6791) 36 | - Couchdb key is now always coerced into a string. (#6781) 37 | - grp is no longer imported unconditionally. (#6804) 38 | This fixes a regression in 5.1.0 when running Celery in non-unix systems. 39 | - Ensure regen utility class gets marked as done when concertised. (#6789) 40 | - Preserve call/errbacks of replaced tasks. (#6770) 41 | - Use single-lookahead for regen consumption. (#6799) 42 | - Revoked tasks are no longer incorrectly marked as retried. (#6812, #6816) 43 | 44 | .. version-5.1.0: 45 | 46 | 5.1.0 47 | ===== 48 | :release-date: 2021-05-23 19.20 P.M UTC+3:00 49 | :release-by: Omer Katz 50 | 51 | - ``celery -A app events -c camera`` now works as expected. (#6774) 52 | - Bump minimum required Kombu version to 5.1.0. 53 | 54 | .. _version-5.1.0rc1: 55 | 56 | 5.1.0rc1 57 | ======== 58 | :release-date: 2021-05-02 16.06 P.M UTC+3:00 59 | :release-by: Omer Katz 60 | 61 | - Celery Mailbox accept and serializer parameters are initialized from configuration. (#6757) 62 | - Error propagation and errback calling for group-like signatures now works as expected. (#6746) 63 | - Fix sanitization of passwords in sentinel URIs. (#6765) 64 | - Add LOG_RECEIVED to customize logging. (#6758) 65 | 66 | .. _version-5.1.0b2: 67 | 68 | 5.1.0b2 69 | ======= 70 | :release-date: 2021-05-02 16.06 P.M UTC+3:00 71 | :release-by: Omer Katz 72 | 73 | - Fix the behavior of our json serialization which regressed in 5.0. (#6561) 74 | - Add support for SQLAlchemy 1.4. (#6709) 75 | - Safeguard against schedule entry without kwargs. (#6619) 76 | - ``task.apply_async(ignore_result=True)`` now avoids persisting the results. (#6713) 77 | - Update systemd tmpfiles path. (#6688) 78 | - Ensure AMQPContext exposes an app attribute. (#6741) 79 | - Inspect commands accept arguments again (#6710). 80 | - Chord counting of group children is now accurate. (#6733) 81 | - Add a setting :setting:`worker_cancel_long_running_tasks_on_connection_loss` 82 | to terminate tasks with late acknowledgement on connection loss. (#6654) 83 | - The ``task-revoked`` event and the ``task_revoked`` signal are not duplicated 84 | when ``Request.on_failure`` is called. (#6654) 85 | - Restore pickling support for ``Retry``. (#6748) 86 | - Add support in the redis result backend for authenticating with a username. (#6750) 87 | - The :setting:`worker_pool` setting is now respected correctly. (#6711) 88 | 89 | .. _version-5.1.0b1: 90 | 91 | 5.1.0b1 92 | ======= 93 | :release-date: 2021-04-02 10.25 P.M UTC+6:00 94 | :release-by: Asif Saif Uddin 95 | 96 | - Add sentinel_kwargs to Redis Sentinel docs. 97 | - Depend on the maintained python-consul2 library. (#6544). 98 | - Use result_chord_join_timeout instead of hardcoded default value. 99 | - Upgrade AzureBlockBlob storage backend to use Azure blob storage library v12 (#6580). 100 | - Improved integration tests. 101 | - pass_context for handle_preload_options decorator (#6583). 102 | - Makes regen less greedy (#6589). 103 | - Pytest worker shutdown timeout (#6588). 104 | - Exit celery with non zero exit value if failing (#6602). 105 | - Raise BackendStoreError when set value is too large for Redis. 106 | - Trace task optimizations are now set via Celery app instance. 107 | - Make trace_task_ret and fast_trace_task public. 108 | - reset_worker_optimizations and create_request_cls has now app as optional parameter. 109 | - Small refactor in exception handling of on_failure (#6633). 110 | - Fix for issue #5030 "Celery Result backend on Windows OS". 111 | - Add store_eager_result setting so eager tasks can store result on the result backend (#6614). 112 | - Allow heartbeats to be sent in tests (#6632). 113 | - Fixed default visibility timeout note in sqs documentation. 114 | - Support Redis Sentinel with SSL. 115 | - Simulate more exhaustive delivery info in apply(). 116 | - Start chord header tasks as soon as possible (#6576). 117 | - Forward shadow option for retried tasks (#6655). 118 | - --quiet flag now actually makes celery avoid producing logs (#6599). 119 | - Update platforms.py "superuser privileges" check (#6600). 120 | - Remove unused property `autoregister` from the Task class (#6624). 121 | - fnmatch.translate() already translates globs for us. (#6668). 122 | - Upgrade some syntax to Python 3.6+. 123 | - Add `azureblockblob_base_path` config (#6669). 124 | - Fix checking expiration of X.509 certificates (#6678). 125 | - Drop the lzma extra. 126 | - Fix JSON decoding errors when using MongoDB as backend (#6675). 127 | - Allow configuration of RedisBackend's health_check_interval (#6666). 128 | - Safeguard against schedule entry without kwargs (#6619). 129 | - Docs only - SQS broker - add STS support (#6693) through kombu. 130 | - Drop fun_accepts_kwargs backport. 131 | - Tasks can now have required kwargs at any order (#6699). 132 | - Min py-amqp 5.0.6. 133 | - min billiard is now 3.6.4.0. 134 | - Minimum kombu now is5.1.0b1. 135 | - Numerous docs fixes. 136 | - Moved CI to github action. 137 | - Updated deployment scripts. 138 | - Updated docker. 139 | - Initial support of python 3.9 added. 140 | -------------------------------------------------------------------------------- /tests/celery_pandoc_changelog.md: -------------------------------------------------------------------------------- 1 | # Change history {#changelog} 2 | 3 | This document contains change notes for bugfix & new features in the & 4 | 5.1.x series, please see `whatsnew-5.1`{.interpreted-text role="ref"} 5 | for an overview of what\'s new in Celery 5.1. 6 | 7 | ## 5.1.2 8 | 9 | release-date 10 | 11 | : 2021-06-28 16.15 P.M UTC+3:00 12 | 13 | release-by 14 | 15 | : Omer Katz 16 | 17 | - When chords fail, correctly call errbacks. (#6814) 18 | 19 | > We had a special case for calling errbacks when a chord failed 20 | > which assumed they were old style. This change ensures that we 21 | > call the proper errback dispatch method which understands new and 22 | > old style errbacks, and adds test to confirm that things behave as 23 | > one might expect now. 24 | 25 | - Avoid using the `Event.isSet()` deprecated alias. (#6824) 26 | 27 | - Reintroduce sys.argv default behaviour for `Celery.start()`. (#6825) 28 | 29 | ## 5.1.1 30 | 31 | release-date 32 | 33 | : 2021-06-17 16.10 P.M UTC+3:00 34 | 35 | release-by 36 | 37 | : Omer Katz 38 | 39 | - Fix `--pool=threads` support in command line options parsing. 40 | (#6787) 41 | 42 | - Fix `LoggingProxy.write()` return type. (#6791) 43 | 44 | - Couchdb key is now always coerced into a string. (#6781) 45 | 46 | - 47 | 48 | grp is no longer imported unconditionally. (#6804) 49 | 50 | : This fixes a regression in 5.1.0 when running Celery in non-unix 51 | systems. 52 | 53 | - Ensure regen utility class gets marked as done when concertised. 54 | (#6789) 55 | 56 | - Preserve call/errbacks of replaced tasks. (#6770) 57 | 58 | - Use single-lookahead for regen consumption. (#6799) 59 | 60 | - Revoked tasks are no longer incorrectly marked as retried. (#6812, 61 | #6816) 62 | 63 | ## 5.1.0 64 | 65 | release-date 66 | 67 | : 2021-05-23 19.20 P.M UTC+3:00 68 | 69 | release-by 70 | 71 | : Omer Katz 72 | 73 | - `celery -A app events -c camera` now works as expected. (#6774) 74 | - Bump minimum required Kombu version to 5.1.0. 75 | 76 | ## 5.1.0rc1 {#version-5.1.0rc1} 77 | 78 | release-date 79 | 80 | : 2021-05-02 16.06 P.M UTC+3:00 81 | 82 | release-by 83 | 84 | : Omer Katz 85 | 86 | - Celery Mailbox accept and serializer parameters are initialized from 87 | configuration. (#6757) 88 | - Error propagation and errback calling for group-like signatures now 89 | works as expected. (#6746) 90 | - Fix sanitization of passwords in sentinel URIs. (#6765) 91 | - Add LOG_RECEIVED to customize logging. (#6758) 92 | 93 | ## 5.1.0b2 {#version-5.1.0b2} 94 | 95 | release-date 96 | 97 | : 2021-05-02 16.06 P.M UTC+3:00 98 | 99 | release-by 100 | 101 | : Omer Katz 102 | 103 | - Fix the behavior of our json serialization which regressed in 5.0. 104 | (#6561) 105 | - Add support for SQLAlchemy 1.4. (#6709) 106 | - Safeguard against schedule entry without kwargs. (#6619) 107 | - `task.apply_async(ignore_result=True)` now avoids persisting the 108 | results. (#6713) 109 | - Update systemd tmpfiles path. (#6688) 110 | - Ensure AMQPContext exposes an app attribute. (#6741) 111 | - Inspect commands accept arguments again (#6710). 112 | - Chord counting of group children is now accurate. (#6733) 113 | - Add a setting 114 | `worker_cancel_long_running_tasks_on_connection_loss`{.interpreted-text 115 | role="setting"} to terminate tasks with late acknowledgement on 116 | connection loss. (#6654) 117 | - The `task-revoked` event and the `task_revoked` signal are not 118 | duplicated when `Request.on_failure` is called. (#6654) 119 | - Restore pickling support for `Retry`. (#6748) 120 | - Add support in the redis result backend for authenticating with a 121 | username. (#6750) 122 | - The `worker_pool`{.interpreted-text role="setting"} setting is now 123 | respected correctly. (#6711) 124 | 125 | ## 5.1.0b1 {#version-5.1.0b1} 126 | 127 | release-date 128 | 129 | : 2021-04-02 10.25 P.M UTC+6:00 130 | 131 | release-by 132 | 133 | : Asif Saif Uddin 134 | 135 | - Add sentinel_kwargs to Redis Sentinel docs. 136 | - Depend on the maintained python-consul2 library. (#6544). 137 | - Use result_chord_join_timeout instead of hardcoded default value. 138 | - Upgrade AzureBlockBlob storage backend to use Azure blob storage 139 | library v12 (#6580). 140 | - Improved integration tests. 141 | - pass_context for handle_preload_options decorator (#6583). 142 | - Makes regen less greedy (#6589). 143 | - Pytest worker shutdown timeout (#6588). 144 | - Exit celery with non zero exit value if failing (#6602). 145 | - Raise BackendStoreError when set value is too large for Redis. 146 | - Trace task optimizations are now set via Celery app instance. 147 | - Make trace_task_ret and fast_trace_task public. 148 | - reset_worker_optimizations and create_request_cls has now app as 149 | optional parameter. 150 | - Small refactor in exception handling of on_failure (#6633). 151 | - Fix for issue #5030 \"Celery Result backend on Windows OS\". 152 | - Add store_eager_result setting so eager tasks can store result on 153 | the result backend (#6614). 154 | - Allow heartbeats to be sent in tests (#6632). 155 | - Fixed default visibility timeout note in sqs documentation. 156 | - Support Redis Sentinel with SSL. 157 | - Simulate more exhaustive delivery info in apply(). 158 | - Start chord header tasks as soon as possible (#6576). 159 | - Forward shadow option for retried tasks (#6655). 160 | - \--quiet flag now actually makes celery avoid producing logs 161 | (#6599). 162 | - Update platforms.py \"superuser privileges\" check (#6600). 163 | - Remove unused property [autoregister]{.title-ref} from the Task 164 | class (#6624). 165 | - fnmatch.translate() already translates globs for us. (#6668). 166 | - Upgrade some syntax to Python 3.6+. 167 | - Add [azureblockblob_base_path]{.title-ref} config (#6669). 168 | - Fix checking expiration of X.509 certificates (#6678). 169 | - Drop the lzma extra. 170 | - Fix JSON decoding errors when using MongoDB as backend (#6675). 171 | - Allow configuration of RedisBackend\'s health_check_interval 172 | (#6666). 173 | - Safeguard against schedule entry without kwargs (#6619). 174 | - Docs only - SQS broker - add STS support (#6693) through kombu. 175 | - Drop fun_accepts_kwargs backport. 176 | - Tasks can now have required kwargs at any order (#6699). 177 | - Min py-amqp 5.0.6. 178 | - min billiard is now 3.6.4.0. 179 | - Minimum kombu now is5.1.0b1. 180 | - Numerous docs fixes. 181 | - Moved CI to github action. 182 | - Updated deployment scripts. 183 | - Updated docker. 184 | - Initial support of python 3.9 added. 185 | -------------------------------------------------------------------------------- /tests/keepachangelog_example.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | 9 | ## [1.0.0] - 2017-06-20 10 | ### Added 11 | - New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). 12 | - Version navigation. 13 | - Links to latest released version in previous versions. 14 | - "Why keep a changelog?" section. 15 | - "Who needs a changelog?" section. 16 | - "How do I make a changelog?" section. 17 | - "Frequently Asked Questions" section. 18 | - New "Guiding Principles" sub-section to "How do I make a changelog?". 19 | - Simplified and Traditional Chinese translations from [@tianshuo](https://github.com/tianshuo). 20 | - German translation from [@mpbzh](https://github.com/mpbzh) & [@Art4](https://github.com/Art4). 21 | - Italian translation from [@azkidenz](https://github.com/azkidenz). 22 | - Swedish translation from [@magol](https://github.com/magol). 23 | - Turkish translation from [@karalamalar](https://github.com/karalamalar). 24 | - French translation from [@zapashcanon](https://github.com/zapashcanon). 25 | - Brazilian Portugese translation from [@Webysther](https://github.com/Webysther). 26 | - Polish translation from [@amielucha](https://github.com/amielucha) & [@m-aciek](https://github.com/m-aciek). 27 | - Russian translation from [@aishek](https://github.com/aishek). 28 | - Czech translation from [@h4vry](https://github.com/h4vry). 29 | - Slovak translation from [@jkostolansky](https://github.com/jkostolansky). 30 | - Korean translation from [@pierceh89](https://github.com/pierceh89). 31 | - Croatian translation from [@porx](https://github.com/porx). 32 | - Persian translation from [@Hameds](https://github.com/Hameds). 33 | - Ukrainian translation from [@osadchyi-s](https://github.com/osadchyi-s). 34 | 35 | ### Changed 36 | - Start using "changelog" over "change log" since it's the common usage. 37 | - Start versioning based on the current English version at 0.3.0 to help 38 | translation authors keep things up-to-date. 39 | - Rewrite "What makes unicorns cry?" section. 40 | - Rewrite "Ignoring Deprecations" sub-section to clarify the ideal 41 | scenario. 42 | - Improve "Commit log diffs" sub-section to further argument against 43 | them. 44 | - Merge "Why can’t people just use a git log diff?" with "Commit log 45 | diffs" 46 | - Fix typos in Simplified Chinese and Traditional Chinese translations. 47 | - Fix typos in Brazilian Portuguese translation. 48 | - Fix typos in Turkish translation. 49 | - Fix typos in Czech translation. 50 | - Fix typos in Swedish translation. 51 | - Improve phrasing in French translation. 52 | - Fix phrasing and spelling in German translation. 53 | 54 | ### Removed 55 | - Section about "changelog" vs "CHANGELOG". 56 | 57 | ## [0.3.0] - 2015-12-03 58 | ### Added 59 | - RU translation from [@aishek](https://github.com/aishek). 60 | - pt-BR translation from [@tallesl](https://github.com/tallesl). 61 | - es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex). 62 | 63 | ## [0.2.0] - 2015-10-06 64 | ### Changed 65 | - Remove exclusionary mentions of "open source" since this project can 66 | benefit both "open" and "closed" source projects equally. 67 | 68 | ## [0.1.0] - 2015-10-06 69 | ### Added 70 | - Answer "Should you ever rewrite a change log?". 71 | 72 | ### Changed 73 | - Improve argument against commit logs. 74 | - Start following [SemVer](https://semver.org) properly. 75 | 76 | ## [0.0.8] - 2015-02-17 77 | ### Changed 78 | - Update year to match in every README example. 79 | - Reluctantly stop making fun of Brits only, since most of the world 80 | writes dates in a strange way. 81 | 82 | ### Fixed 83 | - Fix typos in recent README changes. 84 | - Update outdated unreleased diff link. 85 | 86 | ## [0.0.7] - 2015-02-16 87 | ### Added 88 | - Link, and make it obvious that date format is ISO 8601. 89 | 90 | ### Changed 91 | - Clarified the section on "Is there a standard change log format?". 92 | 93 | ### Fixed 94 | - Fix Markdown links to tag comparison URL with footnote-style links. 95 | 96 | ## [0.0.6] - 2014-12-12 97 | ### Added 98 | - README section on "yanked" releases. 99 | 100 | ## [0.0.5] - 2014-08-09 101 | ### Added 102 | - Markdown links to version tags on release headings. 103 | - Unreleased section to gather unreleased changes and encourage note 104 | keeping prior to releases. 105 | 106 | ## [0.0.4] - 2014-08-09 107 | ### Added 108 | - Better explanation of the difference between the file ("CHANGELOG") 109 | and its function "the change log". 110 | 111 | ### Changed 112 | - Refer to a "change log" instead of a "CHANGELOG" throughout the site 113 | to differentiate between the file and the purpose of the file — the 114 | logging of changes. 115 | 116 | ### Removed 117 | - Remove empty sections from CHANGELOG, they occupy too much space and 118 | create too much noise in the file. People will have to assume that the 119 | missing sections were intentionally left out because they contained no 120 | notable changes. 121 | 122 | ## [0.0.3] - 2014-08-09 123 | ### Added 124 | - "Why should I care?" section mentioning The Changelog podcast. 125 | 126 | ## [0.0.2] - 2014-07-10 127 | ### Added 128 | - Explanation of the recommended reverse chronological release ordering. 129 | 130 | ## [0.0.1] - 2014-05-31 131 | ### Added 132 | - This CHANGELOG file to hopefully serve as an evolving example of a 133 | standardized open source project CHANGELOG. 134 | - CNAME file to enable GitHub Pages custom domain 135 | - README now contains answers to common questions about CHANGELOGs 136 | - Good examples and basic guidelines, including proper date formatting. 137 | - Counter-examples: "What makes unicorns cry?" 138 | 139 | [Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD 140 | [1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0 141 | [0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0 142 | [0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0 143 | [0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0 144 | [0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8 145 | [0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7 146 | [0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6 147 | [0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5 148 | [0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4 149 | [0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3 150 | [0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2 151 | [0.0.1]: https://github.com/olivierlacan/keep-a-changelog/releases/tag/v0.0.1 152 | -------------------------------------------------------------------------------- /tests/test_parsing.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from changerelease.changelog import Changelog 4 | 5 | 6 | def load_changelog(filename): 7 | path = os.path.join(os.path.dirname(__file__), filename) 8 | with open(path, "r") as f: 9 | contents = f.read() 10 | return Changelog(path, contents) 11 | 12 | 13 | def test_parse_example(): 14 | cl = load_changelog("keepachangelog_example.md") 15 | assert cl.parse_versions() == [ 16 | "1.0.0", 17 | "0.3.0", 18 | "0.2.0", 19 | "0.1.0", 20 | "0.0.8", 21 | "0.0.7", 22 | "0.0.6", 23 | "0.0.5", 24 | "0.0.4", 25 | "0.0.3", 26 | "0.0.2", 27 | "0.0.1", 28 | ] 29 | assert ( 30 | cl.parse_version_content("0.3.0") 31 | == """### Added 32 | - RU translation from [@aishek](https://github.com/aishek). 33 | - pt-BR translation from [@tallesl](https://github.com/tallesl). 34 | - es-ES translation from [@ZeliosAriex](https://github.com/ZeliosAriex).""" 35 | ) 36 | 37 | 38 | def test_parse_pandoc(): 39 | """ 40 | rst converted to md using pandoc 41 | CHANGELOG.rst -f rst -t markdown -o CR_CHANGELOG.md 42 | """ 43 | cl = load_changelog("celery_pandoc_changelog.md") 44 | assert cl.parse_versions() == [ 45 | "5.1.2", 46 | "5.1.1", 47 | "5.1.0", 48 | "5.1.0rc1", 49 | "5.1.0b2", 50 | "5.1.0b1", 51 | ] 52 | assert ( 53 | cl.parse_version_content("5.1.0rc1") 54 | == """release-date 55 | 56 | : 2021-05-02 16.06 P.M UTC+3:00 57 | 58 | release-by 59 | 60 | : Omer Katz 61 | 62 | - Celery Mailbox accept and serializer parameters are initialized from 63 | configuration. (#6757) 64 | - Error propagation and errback calling for group-like signatures now 65 | works as expected. (#6746) 66 | - Fix sanitization of passwords in sentinel URIs. (#6765) 67 | - Add LOG_RECEIVED to customize logging. (#6758)""" 68 | ) 69 | assert ( 70 | cl.parse_version_content("5.1.0b1") 71 | == """release-date 72 | 73 | : 2021-04-02 10.25 P.M UTC+6:00 74 | 75 | release-by 76 | 77 | : Asif Saif Uddin 78 | 79 | - Add sentinel_kwargs to Redis Sentinel docs. 80 | - Depend on the maintained python-consul2 library. (#6544). 81 | - Use result_chord_join_timeout instead of hardcoded default value. 82 | - Upgrade AzureBlockBlob storage backend to use Azure blob storage 83 | library v12 (#6580). 84 | - Improved integration tests. 85 | - pass_context for handle_preload_options decorator (#6583). 86 | - Makes regen less greedy (#6589). 87 | - Pytest worker shutdown timeout (#6588). 88 | - Exit celery with non zero exit value if failing (#6602). 89 | - Raise BackendStoreError when set value is too large for Redis. 90 | - Trace task optimizations are now set via Celery app instance. 91 | - Make trace_task_ret and fast_trace_task public. 92 | - reset_worker_optimizations and create_request_cls has now app as 93 | optional parameter. 94 | - Small refactor in exception handling of on_failure (#6633). 95 | - Fix for issue #5030 \\"Celery Result backend on Windows OS\\". 96 | - Add store_eager_result setting so eager tasks can store result on 97 | the result backend (#6614). 98 | - Allow heartbeats to be sent in tests (#6632). 99 | - Fixed default visibility timeout note in sqs documentation. 100 | - Support Redis Sentinel with SSL. 101 | - Simulate more exhaustive delivery info in apply(). 102 | - Start chord header tasks as soon as possible (#6576). 103 | - Forward shadow option for retried tasks (#6655). 104 | - \--quiet flag now actually makes celery avoid producing logs 105 | (#6599). 106 | - Update platforms.py \\"superuser privileges\\" check (#6600). 107 | - Remove unused property [autoregister]{.title-ref} from the Task 108 | class (#6624). 109 | - fnmatch.translate() already translates globs for us. (#6668). 110 | - Upgrade some syntax to Python 3.6+. 111 | - Add [azureblockblob_base_path]{.title-ref} config (#6669). 112 | - Fix checking expiration of X.509 certificates (#6678). 113 | - Drop the lzma extra. 114 | - Fix JSON decoding errors when using MongoDB as backend (#6675). 115 | - Allow configuration of RedisBackend\\'s health_check_interval 116 | (#6666). 117 | - Safeguard against schedule entry without kwargs (#6619). 118 | - Docs only - SQS broker - add STS support (#6693) through kombu. 119 | - Drop fun_accepts_kwargs backport. 120 | - Tasks can now have required kwargs at any order (#6699). 121 | - Min py-amqp 5.0.6. 122 | - min billiard is now 3.6.4.0. 123 | - Minimum kombu now is5.1.0b1. 124 | - Numerous docs fixes. 125 | - Moved CI to github action. 126 | - Updated deployment scripts. 127 | - Updated docker. 128 | - Initial support of python 3.9 added.""" 129 | ) 130 | --------------------------------------------------------------------------------