[
  {
    "path": ".coveragerc",
    "content": "# https://pytest-cov.readthedocs.io/\n\n[run]\nsource = semver\nbranch = True\n\n[report]\nshow_missing = true\nprecision = 1\nexclude_lines =\n    pragma: no cover\n    if __name__ == .__main__.:\n    if not hasattr\\(__builtins__, .cmp.\\):\n"
  },
  {
    "path": ".editorconfig",
    "content": "# http://editorconfig.org\nroot = true\n\n[*]\nend_of_line = lf\ncharset = utf-8\nmax_line_length = 99\n\n[*.py]\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[docs/Makefile]\nindent_style = tab\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yaml",
    "content": "name: 🐞Bug report\ndescription: Create a bug report to help us improve\n# title: ''\nlabels: [bug]\nassignees: [tomschr]\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks a lot for taking the time to fill out this bug report! 🐛\n        It will help us to improve the project for everyone. 🌟\n\n        Find help from the community on our [GitHub Discussions](https://github.com/python-semver/python-semver/discussions) page or\n        on our [Documentation](https://python-semver.readthedocs.io/en/latest/).\n\n  - type: dropdown\n    id: python_version\n    attributes:\n      label: Which version of Python is the problem with?\n      multiple: true\n      options:\n        - \"3.7\"\n        - \"3.8\"\n        - \"3.9\"\n        - \"3.10\"\n        - \"3.11\"\n        - \"3.12\"\n        - \"3.13\"\n        - \"3.14\"\n    validations:\n      required: true\n\n  - type: input\n    id: semver_version\n    attributes:\n      label: What semver version are you using?\n      description: You can find this with `pip show semver`\n      placeholder: 3.0.2\n\n  - type: dropdown\n    id: os\n    attributes:\n      label: What OS are you using? (Add more in the Environment section)\n      multiple: true\n      options:\n        - Linux\n        - Windows\n        - macOS\n        - Other\n\n  - type: textarea\n    id: situation\n    attributes:\n      label: Situation\n      description: A clear and concise description of what the bug is.\n      placeholder: Describe the problem you see...\n    validations:\n      required: true\n\n  - type: textarea\n    id: reproduction_steps\n    attributes:\n      label: How to reproduce\n      description: |\n        Steps to reproduce the behavior:\n        1. Run '...'\n        2. Scroll down to '....'\n        3. See error\n      placeholder: Describe the steps to reproduce the issue...\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected_behavior\n    attributes:\n      label: Expected behavior\n      description: A clear and concise description of what you expected to happen.\n      placeholder: Describe the expected behavior...\n    validations:\n      required: true\n\n  - type: textarea\n    id: environment\n    attributes:\n      label: Environment\n      description: Optionally provide some more details about your environment.\n      placeholder: Describe your environment...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: true\ncontact_links:\n  - name: Community Support\n    url: https://github.com/python-semver/python-semver/discussions\n    about: Ask and answer questions in our discussion forum.\n  - name: Documentation\n    url: https://python-semver.readthedocs.io/\n    about: Find more information in our documentation.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yaml",
    "content": "name: Feature request\ndescription: Suggest an idea for this project\n# title: ''\nlabels: [enhancement]\nassignees: [tomschr]\n\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        Thanks for taking the time to fill out this feature request!\n\n  - type: textarea\n    id: situation\n    attributes:\n      label: Situation\n      description: A clear and concise description of what the feature is. Ex. I'm always frustrated when [...]\n      placeholder: Describe the situation...\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected_solution\n    attributes:\n      label: Expected solution\n      description: A clear and concise description of what you want to happen.\n      placeholder: Describe the expected solution...\n    validations:\n      required: true\n\n  - type: textarea\n    id: alternatives\n    attributes:\n      label: Alternatives\n      description: A clear and concise description of any alternative solutions or features you've considered.\n      placeholder: Describe any alternatives..."
  },
  {
    "path": ".github/dependabot.yml",
    "content": "# To get started with Dependabot version updates, you'll need to specify which\n# package ecosystems to update and where the package manifests are located.\n# Please see the documentation for all configuration options:\n# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2\nupdates:\n  - package-ecosystem: \"pip\" # See documentation for possible values\n    directory: \"/\" # Location of package manifests\n    schedule:\n      interval: \"weekly\"\n      day: \"friday\"\n    labels:\n       - \"enhancement\"\n    commit-message:\n       prefix: \"pip\"\n    # Allow up to 10 open pull requests for pip dependencies\n    open-pull-requests-limit: 5\n"
  },
  {
    "path": ".github/workflows/codeql-analysis.yml",
    "content": "# For most projects, this workflow file will not need changing; you simply need\n# to commit it to your repository.\n#\n# You may wish to alter this file to override the set of languages analyzed,\n# or to provide custom queries or build logic.\n#\n# ******** NOTE ********\n# We have attempted to detect the languages in your repository. Please check\n# the `language` matrix defined below to confirm you have the correct set of\n# supported CodeQL languages.\n#\nname: \"CodeQL\"\n\non:\n  push:\n    branches: [ maint/v2, release/* ]\n  pull_request:\n    # The branches below must be a subset of the branches above\n    branches: [ master ]\n  schedule:\n    - cron: '50 16 * * 5'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'python' ]\n        # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]\n        # Learn more:\n        # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed\n\n    steps:\n    - name: Checkout repository\n      uses: actions/checkout@v4\n\n    # Initializes the CodeQL tools for scanning.\n    - name: Initialize CodeQL\n      uses: github/codeql-action/init@v3\n      with:\n        languages: ${{ matrix.language }}\n        # If you wish to specify custom queries, you can do so here or in a config file.\n        # By default, queries listed here will override any specified in a config file.\n        # Prefix the list here with \"+\" to use these queries and those in the config file.\n        # queries: ./path/to/local/query, your-org/your-repo/queries@main\n\n    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).\n    # If this step fails, then you should remove it and run the build manually (see below)\n    - name: Autobuild\n      uses: github/codeql-action/autobuild@v3\n\n    # ℹ️ Command-line programs to run using the OS shell.\n    # 📚 https://git.io/JvXDl\n\n    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines\n    #    and modify them (or add more) to build your code if your project\n    #    uses a compiled language\n\n    #- run: |\n    #   make bootstrap\n    #   make release\n\n    - name: Perform CodeQL Analysis\n      uses: github/codeql-action/analyze@v3\n"
  },
  {
    "path": ".github/workflows/python-testing.yml",
    "content": "---\nname: Python\n\n# HINT: Sync this paths with the egrep in step check_files\non:\n  push:\n    branches: [ \"master\", \"main\" ]\n    paths:\n      - 'pyproject.toml'\n      - 'setup.cfg'\n      - '**.py'\n      - '.github/workflows/*.yml'\n\n  pull_request:\n    branches: [ \"master\", \"main\" ]\n    paths:\n      - 'pyproject.toml'\n      - 'setup.cfg'\n      - '**.py'\n      - '.github/workflows/*.yml'\n\npermissions:\n  contents: read\n\nconcurrency:\n  # only cancel in-progress runs of the same workflow\n  group: ${{ github.workflow }}-${{ github.ref }}\n  cancel-in-progress: true\n\n\njobs:\n  check-files:\n    runs-on: ubuntu-latest\n    outputs:\n      can_run: ${{ steps.check_files.outputs.can_run }}\n\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 0\n\n      - name: GitHub variables\n        id: gh-vars\n        run: |\n          for var in GITHUB_WORKFLOW GITHUB_ACTION GITHUB_ACTIONS GITHUB_REPOSITORY GITHUB_EVEN_NAME GITHUB_EVENT_PATH GITHUB_WORKSPACE GITHUB_SHA GITHUB_REF GITHUB_HEAD_REF GITHUB_BASE_REF; do\n            echo \"$var = ${!var}\"\n          done\n\n      - name: Check for file changes\n        id: check_files\n        run: |\n          # ${{ github.event.after }} ${{ github.event.before }}\n          can_run=$(git diff --name-only HEAD~1 HEAD | \\\n           egrep -q '.github/workflows/|pyproject.toml|setup.cfg|\\.py$' && echo 1 || echo 0)\n          echo \"can_run=$can_run\"\n          echo \"can_run=$can_run\" >> $GITHUB_OUTPUT\n\n  skip_test:\n    runs-on: ubuntu-latest\n    needs: check-files\n    timeout-minutes: 2\n    if: ${{ needs.check-files.outputs.can_run == '0' }}\n\n    steps:\n      - name: Skip test\n        run: |\n          echo \"Nothing to do as no TOML, Python, or YAML file has been changed.\n          \"\n          echo \"Skipping.\"\n\n  check:\n    runs-on: ubuntu-latest\n    needs: check-files\n    timeout-minutes: 15\n    # needs.check-files.outputs.can_run\n    if: ${{ needs.check-files.outputs.can_run == '1' }}\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install uv\n        uses: astral-sh/setup-uv@v3\n        with:\n          enable-cache: true\n\n      - name: Set up Python 3.7\n        # check tox.ini for the lowest version\n        run: uv python install 3.7\n\n      - name: Install the project\n        run: |\n          uv sync --all-extras --group gh-action\n\n      - name: Checks\n        continue-on-error: true\n        run: uv run tox run -e checks\n\n  tests:\n    needs: check\n    runs-on: ${{ matrix.os }}\n    # continue-on-error: true\n    strategy:\n      max-parallel: 5\n      fail-fast: true\n      matrix:\n        python-version: [\"3.7\",\n                         \"3.8\",\n                         \"3.9\",\n                         \"3.10\",\n                         \"3.11\",\n                         \"3.12\",\n                         \"3.13\",\n                         ]\n        os: [\"ubuntu-latest\", \"macos-latest\"]\n        exclude:\n           - os: \"macos-latest\"\n             python-version: \"3.7\"\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Install uv\n        uses: astral-sh/setup-uv@v3\n\n      - name: Set up Python ${{ matrix.python-version }}\n        run: uv python install ${{ matrix.python-version }}\n\n      - name: Install the project\n        run: |\n          uv sync --all-extras --dev\n          uv pip install tox tox-gh-actions\n\n      - name: Checks\n        run: uv run tox run -e ${{ matrix.python-version }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Python .gitignore file from gh://github/gitignore/Python.gitignore\n#\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\nshare/python-wheels/\n*.egg-info/\n.installed.cfg\n*.egg\nMANIFEST\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.nox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n*.py,cover\n.hypothesis/\n.pytest_cache/\ncover/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\ndb.sqlite3\ndb.sqlite3-journal\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\n.pybuilder/\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\n\n# IPython\nprofile_default/\nipython_config.py\n\n# pyenv\n#   For a library or package, you might want to ignore these files since the code is\n#   intended to run in multiple environments; otherwise, check them in:\n.python-version\n\n# pipenv\n#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.\n#   However, in case of collaboration, if having platform-specific dependencies or dependencies\n#   having no cross-platform support, pipenv may install dependencies that don't work, or not\n#   install all needed dependencies.\n#Pipfile.lock\n\n# PEP 582; used by e.g. github.com/David-OConnor/pyflow\n__pypackages__/\n\n# Celery stuff\ncelerybeat-schedule\ncelerybeat.pid\n\n# SageMath parsed files\n*.sage.py\n\n# Environments\n.env\n.venv*\nenv/\nvenv/\nENV/\nenv.bak/\nvenv.bak/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\n.dmypy.json\ndmypy.json\n\n# Pyre type checker\n.pyre/\n\n# pytype static type analyzer\n.pytype/\n\n# Cython debug symbols\ncython_debug/\n\n#/-- Python\n\n#--- Kate from gh://github/gitignore/Global/Kate.gitignore\n*.kate-swp\n.swp.*\n#/--- Kate\n\n#--- Vim from gh://github/gitignore/Global/Vim.gitignore\n# Swap\n[._]*.s[a-v][a-z]\n!*.svg  # comment out if you don't need vector files\n[._]*.sw[a-p]\n[._]s[a-rt-v][a-z]\n[._]ss[a-gi-z]\n[._]sw[a-p]\n\n# Session\nSession.vim\nSessionx.vim\n\n# Temporary\n.netrwhist\n*~\n# Auto-generated tag files\ntags\n# Persistent undo\n[._]*.un~\n#/--- Vim\n\n#--- VisualStudioCode from gh://github/gitignore/Global/VisualStudioCode.gitignore\n.vscode/*\n!.vscode/settings.json\n!.vscode/tasks.json\n!.vscode/launch.json\n!.vscode/extensions.json\n*.code-workspace\n\n# Local History for Visual Studio Code\n.history/\n\n#/--- VisualStudio\n\n#--- JetBrains from gh://github/gitignore/Global/JetBrains.gitignore\n# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider\n# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839\n\n# User-specific stuff\n.idea/**/workspace.xml\n.idea/**/tasks.xml\n.idea/**/usage.statistics.xml\n.idea/**/dictionaries\n.idea/**/shelf\n\n# Generated files\n.idea/**/contentModel.xml\n\n# Sensitive or high-churn files\n.idea/**/dataSources/\n.idea/**/dataSources.ids\n.idea/**/dataSources.local.xml\n.idea/**/sqlDataSources.xml\n.idea/**/dynamic.xml\n.idea/**/uiDesigner.xml\n.idea/**/dbnavigator.xml\n\n# Gradle\n.idea/**/gradle.xml\n.idea/**/libraries\n\n# Gradle and Maven with auto-import\n# When using Gradle or Maven with auto-import, you should exclude module files,\n# since they will be recreated, and may cause churn.  Uncomment if using\n# auto-import.\n# .idea/artifacts\n# .idea/compiler.xml\n# .idea/jarRepositories.xml\n# .idea/modules.xml\n# .idea/*.iml\n# .idea/modules\n# *.iml\n# *.ipr\n\n# CMake\ncmake-build-*/\n\n# Mongo Explorer plugin\n.idea/**/mongoSettings.xml\n\n# File-based project format\n*.iws\n\n# IntelliJ\nout/\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Cursive Clojure plugin\n.idea/replstate.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n# Editor-based Rest Client\n.idea/httpRequests\n\n# Android studio 3.1+ serialized cache file\n.idea/caches/build_file_checksums.ser\n\n#/--- JetBrains\n\n# --------\n\n\n# Ignore files in the project's root:\n/*.patch\n/*.diff\n/*.py\n# but not this file:\n!/setup.py\n\ndocs/_api\n!docs/_api/semver.__about__.rst\n\n# For node\nnode_modules/\n"
  },
  {
    "path": ".pytest.ini",
    "content": "[pytest]\nnorecursedirs = .git build .env/ env/ .pyenv/ .tmp/ .eggs/ venv/\ntestpaths = tests docs\npythonpath = src tests\nfilterwarnings =\n    ignore:Function 'semver.*:DeprecationWarning\n    # ' <- This apostroph is just to fix syntax highlighting\naddopts =\n    --import-mode=importlib\n    --no-cov-on-fail\n    --cov=semver\n    --cov-report=term-missing\n    --doctest-glob='*.rst'\n    --doctest-modules\n    --doctest-report ndiff"
  },
  {
    "path": ".readthedocs.yaml",
    "content": "# .readthedocs.yaml\n# Read the Docs configuration file\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\n\n# Required\nversion: 2\n\n# Set the version of Python and other tools you might need\nbuild:\n  os: ubuntu-22.04\n  tools:\n    python: \"3.11\"\n  jobs:\n    pre_install:\n      # - curl -LsSf https://astral.sh/uv/install.sh | sh\n      - pip install uv\n      - uv export --only-group docs --no-hashes --no-color > requirements-docs.txt\n    post_install:\n      - pip install -r requirements-docs.txt\n    pre_build:\n      - make -C docs html\n\n# Build documentation in the docs/ directory with Sphinx\nsphinx:\n  configuration: docs/conf.py\n\n"
  },
  {
    "path": ".ruff.toml",
    "content": "#\n# Configuration file for ruff\n# See https://docs.astral.sh/ruff/configuration/\n\nline-length = 88\nindent-width = 4\ninclude = [\n    \"pyproject.toml\",\n    \"src/**/*.py\",\n    \"tests/**/*.py\",\n    \"docs/**/*.py\",\n]\n\n[lint]\nextend-ignore = [\n    \"RUF005\",\n    \"RUF012\",\n    # Comment contains ambiguous `’` (RIGHT SINGLE QUOTATION MARK):\n    \"RUF003\",\n    \"ISC001\",\n]\nselect = [\n    \"F\", # pyflakes\n    \"E\", # pycodestyle\n    \"I\", # isort\n    \"N\", # pep8-naming\n    \"UP\", # pyupgrade\n    \"RUF\", # ruff\n    \"B\", # flake8-bugbear\n    \"C4\", # flake8-comprehensions\n    \"ISC\", # flake8-implicit-str-concat\n    \"PTH\", # flake8-use-pathlib\n    \"SIM\", # flake8-simplify\n    \"TID\", # flake8-tidy-imports\n]\n# TODO: Remove ISC001 ignore when formatter updated: https://github.com/astral-sh/ruff/issues/8272\n\n\n[format]\n# Exclude type hint stub files from formatting.\nexclude = [\"*.pyi\"]\n\n# Like Black, use double quotes for strings.\nquote-style = \"double\"\n\n# Like Black, indent with spaces, rather than tabs.\nindent-style = \"space\"\n\n# Like Black, respect magic trailing commas.\nskip-magic-trailing-comma = false\n\ndocstring-code-format = true\ndocstring-code-line-length = \"dynamic\""
  },
  {
    "path": "CHANGELOG.rst",
    "content": "##########\nChange Log\n##########\n\nChanges for the upcoming release can be found in\nthe `\"changelog.d\" directory <https://github.com/python-semver/python-semver/tree/master/changelog.d>`_\nin our repository.\n\nThis section covers the changes between major version 2 and version 3.\n\n..\n   Do *NOT* add changelog entries here!\n\n   This changelog is managed by towncrier and is compiled at release time.\n\n   See https://python-semver.rtd.io/en/latest/development.html#changelog\n   for details.\n\n.. towncrier release notes start\n\nVersion 3.0.4\n=============\n\n:Released: 2025-01-24\n:Maintainer: Tom Schraitle\n\n\nBug Fixes\n---------\n\n* :gh:`459`: Fix 3.0.3:\n\n  * :pr:`457`: Re-enable Trove license identifier\n  * :pr:`456`: Fix source dist file\n\n\n----\n\n\nVersion 3.0.3\n=============\n\n:Released: 2025-01-18\n:Maintainer: Tom Schraitle\n\n\nBug Fixes\n---------\n\n* :pr:`453`: The check in ``_comparator`` does not match the check in :meth:`Version.compare`. \n  This breaks comparision with subclasses.\n\n\n\nImproved Documentation\n----------------------\n\n* :pr:`435`: Several small improvements for documentation:\n\n  * Add meta description to improve SEO\n  * Use canonicals on ReadTheDocs (commit 87f639f)\n  * Pin versions for reproducable doc builds (commit 03fb990)\n  * Add missing :file:`.readthedocs.yaml` file (commit ec9348a)\n  * Correct some smaller issues when building (commit f65feab)\n\n* :pr:`436`: Move search box more at the top. This makes it easier for\n  users as if the TOC is long, the search box isn't visible\n  anymore.\n\n\n\nFeatures\n--------\n\n* :pr:`439`: Improve type hints to fix TODOs\n\n\n\nInternal Changes\n----------------\n\n* :pr:`440`: Update workflow file\n\n* :pr:`446`: Add Python 3.13 to GitHub Actions\n\n* :pr:`447`: Modernize project configs with :file:`pyproject.toml` and\n  use Astral's uv command.\n\n  * In :file:`pyproject.toml`:\n\n    * Move all project related data from :file:`setup.cfg` to :file:`pyproject.toml`\n    * Use new dependency group from :pep:`735`\n    * Consolidate flake8, isort, pycodestyle with ruff\n    * Split towncrier config type \"trivial\" into \"trivial\" and \"internal\"\n\n  * Create config file for ruff (:file:`.ruff.toml`)\n  * Create config file for pytest (:file:`.pytest.ini`)\n  * Simplify :file:`tox.ini` and remove old stuff\n  * Document installation with new :command:`uv` command\n  * Simplify Sphinx config with :func:`find_version()`\n  * Update the authors\n  * Use :command:`uv` in GitHub Action :file:`python-testing.yml` workflow\n\n* Update :file:`release-procedure.md`.\n\n* :pr:`451`: Turn our Markdown issue templates into YAML\n\n\nTrivial Changes\n---------------\n\n* :pr:`438`: Replace organization placeholder in license\n\n* :pr:`445`: Improve private :func:`_nat_cmp` method:\n\n  * Remove obsolete else.\n  * Find a better way to identify digits without the :mod:`re` module.\n  * Fix docstring in :meth:`Version.compare`\n\n\n\n----\n\n\nVersion 3.0.2\n=============\n\n:Released: 2023-10-09\n:Maintainer: Tom Schraitle\n\n\nBug Fixes\n---------\n\n* :pr:`418`: Replace :class:`~collection.OrderedDict` with :class:`dict`.\n\n  The dict datatype is ordered since Python 3.7. As we do not support\n  Python 3.6 anymore, it can be considered safe to avoid :class:`~collection.OrderedDict`.\n  Related to :gh:`419`.\n\n* :pr:`426`: Fix :meth:`~semver.version.Version.replace` method to use the derived class\n  of an instance instead of :class:`~semver.version.Version` class.\n\n\n\nImproved Documentation\n----------------------\n\n* :pr:`431`: Clarify version policy for the different semver versions (v2, v3, >v3)\n  and the supported Python versions.\n\n* :gh:`432`: Improve external doc links to Python and Pydantic.\n\n\n\nFeatures\n--------\n\n* :pr:`417`: Amend GitHub Actions to check against MacOS.\n\n\n\nTrivial/Internal Changes\n------------------------\n\n* :pr:`420`: Introduce :py:class:`~typing.ClassVar` for some :class:`~semver.version.Version`\n  class variables, mainly :data:`~semver.version.Version.NAMES` and some private.\n\n* :pr:`421`: Insert mypy configuration into :file:`pyproject.toml` and remove\n  config options from :file:`tox.ini`.\n\n\n\n----\n\n\nVersion 3.0.1\n=============\n\n:Released: 2023-06-14\n:Maintainer: Tom Schraitle\n\n\nBug Fixes\n---------\n\n* :gh:`410`: Export functions properly using ``__all__`` in ``__init__.py``.\n\n\n\n----\n\n\nVersion 3.0.0\n=============\n\n:Released: 2023-04-02\n:Maintainer: Tom Schraitle\n\n\nBug Fixes\n---------\n\n* :gh:`291`: Disallow negative numbers in VersionInfo arguments\n  for ``major``, ``minor``, and ``patch``.\n\n* :gh:`310`: Rework API documentation.\n  Follow a more \"semi-manual\" attempt and add auto directives\n  into :file:`docs/api.rst`.\n\n* :gh:`344`: Allow empty string, a string with a prefix, or ``None``\n  as token in\n  :meth:`~semver.version.Version.bump_build` and\n  :meth:`~semver.version.Version.bump_prerelease`.\n\n* :gh:`374`: Correct Towncrier's config entries in the :file:`pyproject.toml` file.\n  The old entries ``[[tool.towncrier.type]]`` are deprecated and need\n  to be replaced by ``[tool.towncrier.fragment.<TYPE>]``.\n\n* :pr:`384`: General cleanup, reformat files:\n\n  * Reformat source code with black again as some config options\n    did accidentely exclude the semver source code.\n    Mostly remove some includes/excludes in the black config.\n  * Integrate concurrency in GH Action\n  * Ignore Python files on project dirs in .gitignore\n  * Remove unused patterns in MANIFEST.in\n  * Use ``extend-exclude`` for flake in :file:`setup.cfg`` and adapt list.\n  * Use ``skip_install=True`` in :file:`tox.ini` for black\n\n* :pr:`393`: Fix command :command:`python -m semver` to avoid the error \"invalid choice\"\n\n* :pr:`396`: Calling :meth:`~semver.version.Version.parse` on a derived class will show correct type of derived class.\n\n\nDeprecations\n------------\n\n* :gh:`169`: Deprecate CLI functions not imported from ``semver.cli``.\n\n* :gh:`234`: In :file:`setup.py` simplified file and remove\n  ``Tox`` and ``Clean`` classes\n\n* :gh:`284`: Deprecate the use of :meth:`~Version.isvalid`.\n\n  Rename :meth:`~semver.version.Version.isvalid`\n  to :meth:`~semver.version.Version.is_valid`\n  for consistency reasons with :meth:`~semver.version.Version.is_compatible`.\n\n\n* :pr:`290`: For semver 3.0.0-alpha0 deprecated:\n\n  * Remove anything related to Python2\n  * In :file:`tox.ini` and :file:`.travis.yml`\n    Remove targets py27, py34, py35, and pypy.\n    Add py38, py39, and nightly (allow to fail)\n  * In :file:`setup.py` simplified file and remove\n    ``Tox`` and ``Clean`` classes\n  * Remove old Python versions (2.7, 3.4, 3.5, and pypy)\n    from Travis\n\n* :gh:`372`: Deprecate support for Python 3.6.\n\n  Python 3.6 reached its end of life and isn't supported anymore.\n  At the time of writing (Dec 2022), the lowest version is 3.7.\n\n  Although the `poll <https://github.com/python-semver/python-semver/discussions/371>`_\n  didn't cast many votes, the majority agreed to remove support for\n  Python 3.6.\n\n* :pr:`402`: Keep :func:`semver.compare <semver._deprecated.compare>`.\n   Although it breaks consistency with module level functions, it seems it's\n   a much needed/used function. It's still unclear if we should deprecate\n   this function or not (that's why we use :py:exc:`PendingDeprecationWarning`).\n\n   As we don't have a uniform initializer yet, this function stays in the\n   :file:`_deprecated.py` file for the time being until we find a better solution. See :gh:`258` for details.\n\n\nFeatures\n--------\n\n* :gh:`169`: Create semver package and split code among different modules in the packages:\n\n  * Remove :file:`semver.py`\n  * Create :file:`src/semver/__init__.py`\n  * Create :file:`src/semver/cli.py` for all CLI methods\n  * Create :file:`src/semver/_deprecated.py` for the ``deprecated`` decorator and other deprecated functions\n  * Create :file:`src/semver/__main__.py` to allow calling the CLI using :command:`python -m semver`\n  * Create :file:`src/semver/_types.py` to hold type aliases\n  * Create :file:`src/semver/version.py` to hold the :class:`Version` class (old name :class:`VersionInfo`) and its utility functions\n  * Create :file:`src/semver/__about__.py` for all the metadata variables\n\n* :gh:`213`: Add typing information\n\n* :gh:`284`: Implement :meth:`~semver.version.Version.is_compatible` to make \"is self compatible with X\".\n\n* :gh:`305`: Rename :class:`~semver.version.VersionInfo` to :class:`~semver.version.Version` but keep an alias for compatibility\n\n* :pr:`359`: Add optional parameter ``optional_minor_and_patch`` in :meth:`~semver.version.Version.parse`  to allow optional\n  minor and patch parts.\n\n* :pr:`362`: Make :meth:`~semver.version.Version.match` accept a bare version string as match expression, defaulting to equality testing.\n\n* :gh:`364`: Enhance :file:`pyproject.toml` to make it possible to use the\n  :command:`pyproject-build` command from the build module.\n  For more information, see :ref:`build-semver`.\n\n* :gh:`365`: Improve :file:`pyproject.toml`.\n\n  * Use setuptools, add metadata. Taken approach from\n    `A Practical Guide to Setuptools and Pyproject.toml\n    <https://godatadriven.com/blog/a-practical-guide-to-setuptools-and-pyproject-toml/>`_.\n  * Doc: Describe building of semver\n  * Remove :file:`.travis.yml` in :file:`MANIFEST.in`\n    (not needed anymore)\n  * Distinguish between Python 3.6 and others in :file:`tox.ini`\n  * Add skip_missing_interpreters option for :file:`tox.ini`\n  * GH Action: Upgrade setuptools and setuptools-scm and test\n    against 3.11.0-rc.2\n\n\n\nImproved Documentation\n----------------------\n\n* :gh:`276`: Document how to create a sublass from :class:`~semver.version.VersionInfo` class\n\n* :gh:`284`: Document deprecation of :meth:`~semver.version.Version.isvalid`.\n\n* :pr:`290`: Several improvements in the documentation:\n\n  * New layout to distinguish from the semver2 development line.\n  * Create new logo.\n  * Remove any occurances of Python2.\n  * Describe changelog process with Towncrier.\n  * Update the release process.\n\n* :gh:`304`: Several improvements in documentation:\n\n  * Reorganize API documentation.\n  * Add migration chapter from semver2 to semver3.\n  * Distinguish between changlog for version 2 and 3\n\n* :gh:`305`: Add note about :class:`~semver.version.Version` rename.\n\n* :gh:`312`: Rework \"Usage\" section.\n\n  * Mention the rename of :class:`~semver.version.VersionInfo` to\n    :class:`~semver.version.Version` class\n  * Remove semver. prefix in doctests to make examples shorter\n  * Correct some references to dunder methods like\n    :func:`~semver.version.Version.__getitem__`,\n    :func:`~semver.version.Version.__gt__` etc.\n  * Remove inconsistencies and mention module level function as\n    deprecated and discouraged from using\n  * Make empty :py:func:`super` call in :file:`semverwithvprefix.py` example\n\n* :gh:`315`: Improve release procedure text\n\n* :gh:`335`: Add new section \"Converting versions between PyPI and semver\" the limitations\n  and possible use cases to convert from one into the other versioning scheme.\n\n* :gh:`340`: Describe how to get version from a file\n\n* :gh:`343`: Describe combining Pydantic with semver in the \"Advanced topic\"\n  section.\n\n* :gh:`350`: Restructure usage section. Create subdirectory \"usage/\" and splitted\n  all section into different files.\n\n* :gh:`351`: Introduce new topics for:\n\n  * \"Migration to semver3\"\n  * \"Advanced topics\"\n\n* :pr:`392`: Fix the example in the documentation for combining semver and pydantic.\n\n\nTrivial/Internal Changes\n------------------------\n\n* :gh:`169`: Adapted infrastructure code to the new project layout.\n\n  * Replace :file:`setup.py` with :file:`setup.cfg` because the :file:`setup.cfg` is easier to use\n  * Adapt documentation code snippets where needed\n  * Adapt tests\n  * Changed the ``deprecated`` to hardcode the ``semver`` package name in the warning.\n\n  Increase coverage to 100% for all non-deprecated APIs\n\n* :pr:`290`: Add supported Python versions to :command:`black`.\n\n* :gh:`304`: Support PEP-561 :file:`py.typed`.\n\n  According to the mentioned PEP:\n\n    \"Package maintainers who wish to support type checking\n    of their code MUST add a marker file named :file:`py.typed`\n    to their package supporting typing.\"\n\n  Add package_data to :file:`setup.cfg` to include this marker in dist\n  and whl file.\n\n* :gh:`309`: Some (private) functions from the :mod:`semver.version`\n  module has been changed.\n\n  The following functions got renamed:\n\n  * function :func:`semver.version.comparator` got renamed to\n    :func:`semver.version._comparator` as it is only useful\n    inside the :class:`~semver.version.Version` class.\n  * function :func:`semver.version.cmp` got renamed to\n    :func:`semver.version._cmp` as it is only useful\n    inside the :class:`~semver.version.Version` class.\n\n  The following functions got integrated into the\n  :class:`~semver.version.Version` class:\n\n  * function :func:`semver.version._nat_cmd` as a classmethod\n  * function :func:`semver.version.ensure_str`\n\n* :gh:`313`: Correct :file:`tox.ini` for ``changelog`` entry to skip\n  installation for semver. This should speed up the execution\n  of towncrier.\n\n* :gh:`316`: Comparisons of :class:`~semver.version.Version` class and other\n  types return now a :py:const:`NotImplemented` constant instead\n  of a :py:exc:`TypeError` exception.\n\n  The `NotImplemented`_ section of the Python documentation recommends\n  returning this constant when comparing with ``__gt__``, ``__lt__``,\n  and other comparison operators to \"to indicate that the operation is\n  not implemented with respect to the other type\".\n\n  .. _NotImplemented: https://docs.python.org/3/library/constants.html#NotImplemented\n\n* :gh:`319`: Introduce stages in :file:`.travis.yml`\n  The config file contains now two stages: check and test. If\n  check fails, the test stage won't be executed. This could\n  speed up things when some checks fails.\n\n* :gh:`322`: Switch from Travis CI to GitHub Actions.\n\n* :gh:`347`: Support Python 3.10 in GitHub Action and other config files.\n\n* :gh:`378`: Fix some typos in Towncrier configuration\n\n* :gh:`388`: For pytest, switch to the more modern :mod:`importlib` approach\n  as it doesn't require to modify :data:`sys.path`:\n  https://docs.pytest.org/en/7.2.x/explanation/pythonpath.html\n\n* :pr:`389`: Add public class variable :data:`Version.NAMES <semver.version.Version.NAMES>`.\n\n  This class variable contains a tuple of strings that contains the names of\n  all attributes of a Version (like ``\"major\"``, ``\"minor\"`` etc).\n\n  In cases we need to have dynamical values, this makes it easier to iterate.\n\n\n\n..\n    Local variables:\n    coding: utf-8\n    mode: text\n    mode: rst\n    End:\n    vim: fileencoding=utf-8 filetype=rst :\n"
  },
  {
    "path": "CITATION.cff",
    "content": "# This CITATION.cff file was generated with cffinit:\n# https://bit.ly/cffinit\n\ncff-version: 1.2.0\ntitle: python-semver\nmessage: >-\n  If you use this software, please cite it using the\n  metadata from this file.\ntype: software\n\nauthors:\n  - given-names: Kostiantyn\n    family-names: Rybnikov\n    email: k-bx@k-bx.com\n  - given-names: Tom\n    family-names: Schraitle\n    email: tom_schr@web.de\n  - given-names: Sebastian\n    family-names: Celles\n    email: s.celles@gmail.com\n  - name: \"The python-semver software team\"\n\nidentifiers:\n  - type: url\n    value: 'https://github.com/python-semver/python-semver'\n    description: GitHub python-semver/python-semver\nurl: 'https://python-semver.readthedocs.io'\nrepository-code: 'https://github.com/python-semver/python-semver'\nrepository-artifact: 'https://pypi.org/project/semver/'\n\nabstract: >-\n  A Python module for semantic versioning. Simplifies\n  comparing versions. This modules follows the\n  MAJOR.MINOR.PATCH style.\n\nkeywords:\n  - Python\n  - Python module\n  - semver\n  - versioning\n  - semantic versioning\n  - semver-format\n  - semver-tag\n  - versions\n\nreferences:\n  - authors:\n    - family-names: Preston-Werner\n      given-names: Tom\n    - name: \"The semver team\"\n    title: 'Semantic Versioning 2.0.0'\n    url: 'https://semver.org'\n    repository-code: 'https://github.com/semver/semver'\n    type: standard\n    version: 2.0.0\n    languages:\n      - ar\n      - bg\n      - ca\n      - cs\n      - da\n      - de\n      - el\n      - en\n      - es\n      - fa\n      - fr\n      - he\n      - hin\n      - hr\n      - hu\n      - hy\n      - id\n      - it\n      - ja\n      - ka\n      - kab\n      - ko\n      - nl\n      - pl\n      - pt\n      - ro\n      - ru\n      - sk\n      - sl\n      - sr\n      - sv\n      - tr\n      - uk\n      - vi\n      - zh\n    abstract: >-\n      Given a version number MAJOR.MINOR.PATCH, increment the:\n\n      1. MAJOR version when you make incompatible API changes\n      2. MINOR version when you add functionality in a backwards compatible manner\n      3. PATCH version when you make backwards compatible bug fixes\n\n      Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.\n\nlicense: BSD-3-Clause\ncommit: 3a7680dc436211227c0aeae84c9b45e0b3345b8f\nversion: 3.0.0\ndate-released: '2023-04-02'\n"
  },
  {
    "path": "CONTRIBUTING.rst",
    "content": ".. _contributing:\n\nContributing to semver\n======================\n\nThe semver source code is managed using Git and is hosted on GitHub::\n\n   git clone git://github.com/python-semver/python-semver\n\n\n\nReporting Bugs and Asking Questions\n-----------------------------------\n\nIf you think you have encountered a bug in semver or have an idea for a new\nfeature? Great! We like to hear from you!\n\nThere are several options to participate:\n\n* Open a new topic on our `GitHub discussion <gh_discussions>`_ page.\n  Tell us our ideas or ask your questions.\n\n* Look into our GitHub `issues`_ tracker or open a new issue.\n\n\nPrerequisites\n-------------\n\nBefore you make changes to the code, we would highly appreciate if you\nconsider the following general requirements:\n\n* Make sure your code adheres to the `Semantic Versioning`_ specification.\n\n* Check if your feature is covered by the Semantic Versioning specification.\n  If not, ask on its GitHub project https://github.com/semver/semver.\n\n\nMore topics\n-----------\n\n* `Running the Test Suite <docs/contribute/run-test-suite.rst>`_\n* `Documenting semver <docs/contribute/doc-semver.rst>`_\n* `Adding a Changelog Entry <docs/contribute/add-changelog-entry.rst>`_\n* `Preparing the Release <docs/contribute/release-procedure.rst>`_\n* `Finish the Release <docs/contribute/finish-release.rst>`_\n\n\n.. _black: https://black.rtfd.io\n.. _docformatter: https://pypi.org/project/docformatter/\n.. _flake8: https://flake8.rtfd.io\n.. _mypy: http://mypy-lang.org/\n.. _issues:  https://github.com/python-semver/python-semver/issues\n.. _pull request: https://github.com/python-semver/python-semver/pulls\n.. _pytest: http://pytest.org/\n.. _Semantic Versioning: https://semver.org\n.. _Sphinx style: https://sphinx-rtd-tutorial.rtfd.io/en/latest/docstrings.html\n.. _tox: https://tox.rtfd.org/\n.. _gh_discussions: https://github.com/python-semver/python-semver/discussions\n"
  },
  {
    "path": "CONTRIBUTORS",
    "content": "############\nContributors\n############\n\nPython Semver library\n#####################\n\nThis document records the primary maintainers and significant\ncontributors to this code base.\n\nThank you to everyone whose work has made this possible.\n\n\nPrimary maintainers\n===================\n\n* Tom Schraitle <tom_schr@web.de>\n* Sébastien Celles <s.celles@gmail.com>\n\nOld maintainer:\n\n* Kostiantyn Rybnikov <k-bx@k-bx.com>\n\n\nList of Contributors\n====================\n\n(in alphabetical order)\n\n* Jelo Agnasin <jelo@icannhas.com>\n* Carles Barrobés <carles@barrobes.com>\n* Eli Bishop <eli-darkly@users.noreply.github.com>\n* Peter Bittner <django@bittner.it>\n* Craig Blaszczyk <masterjakul@gmail.com>\n* Tyler Cross <tyler@crosscollab.com>\n* Dennis Felsing <def-@users.noreply.github.com>\n* Ben Finney <ben+python@benfinney.id.au>\n* Zane Geiger <zanecodes@users.noreply.github.com>\n* T. Jameson Little <t.jameson.little@gmail.com>\n* Raphael Krupinski <rafalkrupinski@users.noreply.github.com>\n* Thomas Laferriere <tlaferriere@users.noreply.github.com>\n* Zack Lalanne <zack.lalanne@gmail.com>\n* Tuure Laurinolli <tuure@laurinolli.net>\n* Damien Nadé <anvil@users.noreply.github.com>\n* Jan Pieter Waagmeester <jieter@jieter.nl>\n* Alexander Puzynia <werwolf.by@gmail.com>\n* Lexi Robinson <Lexicality@users.noreply.github.com>\n* robi-wan <robi-wan@suyu.de>\n* George Sakkis <gsakkis@users.noreply.github.com>\n* Mike Salvatore <mssalvatore@users.noreply.github.com>\n* sbrudenell <sbrudenell@users.noreply.github.com>\n* Alexander Shorin <kxepal@gmail.com>\n* Anton Talevnin <TalAntR@users.noreply.github.com>\n* Karol Werner <karol.werner@ppkt.eu>\n \n..\n    Local variables:\n    coding: utf-8\n    mode: text\n    mode: rst\n    End:\n    vim: fileencoding=utf-8 filetype=rst :\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2013, Konstantine Rybnikov\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n  Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n  Redistributions in binary form must reproduce the above copyright notice, this\n  list of conditions and the following disclaimer in the documentation and/or\n  other materials provided with the distribution.\n\n  Neither the name of the python-semver org nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include *.md\ninclude *.rst\ninclude *.txt\ninclude CONTRIBUTORS\ninclude CITATION.cff\ninclude Makefile\ninclude changelog.d/*\ngraft docs/**\ninclude tests/*.py\ninclude tox.ini\ninclude .pytest.ini\ninclude .ruff.toml\ninclude uv.lock\n\n# The dot files:\ninclude .coveragerc\ninclude .editorconfig\ninclude .gitignore\ninclude .readthedocs.yaml\n\n\nprune docs/_build\nrecursive-exclude .github  *\nprune docs/**/__pycache__\n\nglobal-exclude __pycache__\n"
  },
  {
    "path": "Makefile",
    "content": "sdist:\n\tpython setup.py sdist bdist_wheel --universal\n\n.PHONY sdist\n\n"
  },
  {
    "path": "README.rst",
    "content": "Quickstart\n==========\n\n.. teaser-begin\n\nA Python module to simplify `semantic versioning`_.\n\n|GHAction| |python-support| |downloads| |license| |docs| |black|\n|openissues| |GHDiscussion|\n\n.. teaser-end\n\nThe module follows the ``MAJOR.MINOR.PATCH`` style:\n\n* ``MAJOR`` version when you make incompatible API changes,\n* ``MINOR`` version when you add functionality in a backwards compatible manner, and\n* ``PATCH`` version when you make backwards compatible bug fixes.\n\nAdditional labels for pre-release and build metadata are supported.\n\nTo import this library, use:\n\n.. code-block:: python\n\n    >>> import semver\n\nWorking with the library is quite straightforward. To turn a version string into the\ndifferent parts, use the ``semver.Version.parse`` function:\n\n.. code-block:: python\n\n    >>> ver = semver.Version.parse('1.2.3-pre.2+build.4')\n    >>> ver.major\n    1\n    >>> ver.minor\n    2\n    >>> ver.patch\n    3\n    >>> ver.prerelease\n    'pre.2'\n    >>> ver.build\n    'build.4'\n\nTo raise parts of a version, there are a couple of functions available for\nyou. The function ``semver.Version.bump_major`` leaves the original object untouched, but\nreturns a new ``semver.Version`` instance with the raised major part:\n\n.. code-block:: python\n\n    >>> ver = semver.Version.parse(\"3.4.5\")\n    >>> ver.bump_major()\n    Version(major=4, minor=0, patch=0, prerelease=None, build=None)\n\nIt is allowed to concatenate different \"bump functions\":\n\n.. code-block:: python\n\n    >>> ver.bump_major().bump_minor()\n    Version(major=4, minor=1, patch=0, prerelease=None, build=None)\n\nTo compare two versions, semver provides the ``semver.compare`` function.\nThe return value indicates the relationship between the first and second\nversion:\n\n.. code-block:: python\n\n    >>> semver.compare(\"1.0.0\", \"2.0.0\")\n    -1\n    >>> semver.compare(\"2.0.0\", \"1.0.0\")\n    1\n    >>> semver.compare(\"2.0.0\", \"2.0.0\")\n    0\n\n\nThere are other functions to discover. Read on!\n\n\n.. |latest-version| image:: https://img.shields.io/pypi/v/semver.svg\n   :alt: Latest version on PyPI\n   :target: https://pypi.org/project/semver\n.. |python-support| image:: https://img.shields.io/pypi/pyversions/semver.svg\n   :target: https://pypi.org/project/semver\n   :alt: Python versions\n.. |downloads| image:: https://img.shields.io/pypi/dm/semver.svg\n   :alt: Monthly downloads from PyPI\n   :target: https://pypi.org/project/semver\n.. |license| image:: https://img.shields.io/pypi/l/semver.svg\n   :alt: Software license\n   :target: https://github.com/python-semver/python-semver/blob/master/LICENSE.txt\n.. |docs| image:: https://readthedocs.org/projects/python-semver/badge/?version=latest\n   :target: http://python-semver.readthedocs.io/en/latest/?badge=latest\n   :alt: Documentation Status\n.. _semantic versioning: https://semver.org/\n.. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n    :alt: Black Formatter\n.. |Gitter| image:: https://badges.gitter.im/python-semver/community.svg\n    :target: https://gitter.im/python-semver/community\n    :alt: Gitter\n.. |openissues| image:: http://isitmaintained.com/badge/open/python-semver/python-semver.svg\n    :target: http://isitmaintained.com/project/python-semver/python-semver\n    :alt: Percentage of open issues\n.. |GHAction| image:: https://github.com/python-semver/python-semver/workflows/Python/badge.svg\n    :alt: Python\n.. |GHDiscussion| image:: https://shields.io/badge/GitHub-%20Discussions-green?logo=github\n    :target: https://github.com/python-semver/python-semver/discussions\n    :alt: GitHub Discussion\n"
  },
  {
    "path": "SUPPORT.md",
    "content": "# Getting support\n\nIf you need help, try these ways:\n\n* Ask your questions on the [discussion](https://github.com/python-semver/python-semver/discussions) page.\n\n  Our forum is a good way to post your questions.\n* Read the [python-semver documentation](https://python-semver.readthedocs.io/).\n\n  The documentation contains all the information to install and use the library.\n* Suggest a new feature or a new [issue](https://github.com/python-semver/python-semver/issues/new)\n\n  If you found a problem or would like to suggest a new feature that could improve python-semver,\n  this is the place to go.\n"
  },
  {
    "path": "changelog.d/.gitignore",
    "content": "!.gitignore\n"
  },
  {
    "path": "changelog.d/460.bugfix.rst",
    "content": ":meth:`~semver.version.Version.bump_prerelease` will now add `.0` to an\nexisting prerelease when the last segment of the current prerelease, split by\ndots (`.`), is not numeric. This is to ensure the new prerelease is considered\nhigher than the previous one.\n\n:meth:`~semver.version.Version.bump_prerelease` now also support an argument\n`bump_when_empty` which will bump the patch version if there is no existing\nprerelease, to ensure the resulting version is considered a higher version than\nthe previous one."
  },
  {
    "path": "changelog.d/463.trivial.rst",
    "content": "Remove double code in :meth:`Version.bump_build`"
  },
  {
    "path": "changelog.d/README.rst",
    "content": "The ``changelog.d`` Directory\n=============================\n\n.. This file is also included into the documentation\n\n.. -text-begin-\n\nA \"Changelog\" is a record of all notable changes made to a project. Such\na changelog, in our case the :file:`CHANGELOG.rst`, is read by our *users*.\nTherefor, any description should be aimed to users instead of describing\ninternal changes which are only relevant to developers.\n\nTo avoid merge conflicts, we use the `Towncrier`_ package to manage our changelog.\n\nThe directory :file:`changelog.d` contains \"newsfragments\" which are short\nReST-formatted files.\nOn release, those news fragments are compiled into our :file:`CHANGELOG.rst`.\n\nYou don't need to install ``towncrier`` yourself, use the :command:`tox` command\nto call the tool.\n\nWe recommend to follow the steps to make a smooth integration of your changes:\n\n#. After you have created a new pull request (PR), add a new file into the\n   directory :file:`changelog.d`. Each filename follows the syntax::\n\n    <ISSUE>.<TYPE>.rst\n\n   where ``<ISSUE>`` is the GitHub issue number.\n   In case you have no issue but a pull request, prefix your number with ``pr``.\n   ``<TYPE>`` is one of:\n\n   * ``bugfix``: fixes a reported bug.\n   * ``deprecation``: informs about deprecation warnings\n   * ``doc``: improves documentation.\n   * ``feature``: adds new user facing features.\n   * ``removal``: removes obsolete or deprecated features.\n   * ``trivial``: fixes a small typo or internal change that might be noteworthy.\n\n   For example: ``123.feature.rst``, ``pr233.removal.rst``, ``456.bugfix.rst`` etc.\n\n#. Create the new file with the command::\n\n     tox -e changelog -- create 123.feature.rst\n\n   The file is created int the :file:`changelog.d/` directory.\n\n#. Open the file and describe your changes in RST format.\n\n   * Wrap symbols like modules, functions, or classes into double backticks\n     so they are rendered in a ``monospace font``.\n   * Prefer simple past tense or constructions with \"now\".\n\n#. Check your changes with::\n\n     tox -e changelog -- check\n\n#. Optionally, build a draft version of the changelog file with the command::\n\n    tox -e changelog\n\n#. Commit all your changes and push it.\n\n\nThis finishes your steps.\n\nOn release, the maintainer compiles a new :file:`CHANGELOG.rst` file by running::\n\n   tox -e changelog -- build\n\nThis will remove all newsfragments inside the :file:`changelog.d` directory,\nmaking it ready for the next release.\n\n\n\n.. _Towncrier: https://pypi.org/project/towncrier\n"
  },
  {
    "path": "changelog.d/_template.rst",
    "content": "{% for section, _ in sections.items() %}\n{% set underline = underlines[0] %}{% if section %}{{section}}\n{{ underline * section|length }}{% set underline = underlines[1] %}\n\n{% endif %}\n\n:Released: {{ versiondata.date }}\n:Maintainer:\n\n\n{% if sections[section] %}\n{% for category, val in definitions.items() if category in sections[section] %}\n{{ definitions[category]['name'] }}\n{{ underline * definitions[category]['name']|length }}\n\n{% if definitions[category]['showcontent'] %}\n{% for text, values in sections[section][category].items() %}\n{%- for value in values %}\n{% if value.startswith(\"pr\") %}\n* :pr:`{{ value[2:] }}`{% else %}\n* :gh:`{{ value[1:] }}`{% endif %}{%- endfor -%}: {{ text }}\n\n{% endfor %}\n\n{% else %}\n- {{ sections[section][category]['']|join(', ') }}\n\n{% endif %}\n{% if sections[section][category]|length == 0 %}\nNo significant changes.\n\n{% else %}\n{% endif %}\n\n{% endfor %}\n{% else %}\nNo significant changes.\n\n\n{% endif %}\n{% endfor %}\n----\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nSPHINXPROJ    = semver\nSOURCEDIR     = .\nBUILDDIR      = _build\n\n# Set the source directory for your project\nSRC_DIR       = ../src\n\n# Set the PYTHONPATH environment variable\nexport PYTHONPATH := $(SRC_DIR):$(PYTHONPATH)\n\n# Put it first so that \"make\" without argument is like \"make help\".\nhelp:\n\t@$(SPHINXBUILD) -M help \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n\n.PHONY: help Makefile\n\n# Catch-all target: route all unknown targets to Sphinx using the new\n# \"make mode\" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).\n%: Makefile\n\t@$(SPHINXBUILD) -M $@ \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n"
  },
  {
    "path": "docs/_static/css/custom.css",
    "content": "/*\nhttps://github.com/bitprophet/alabaster\n*/\n\n/* Roboto (Sans), Roboto Slab (\"serif\"), Roboto Mono*/\n@import url('https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,600;1,400&family=Roboto+Slab:wght@700&family=Roboto:ital@0;1&display=swap');\n\n.logo {\n    font-family: \"Roboto Slab\";\n}\n\nimg.logo {\n  width: 80%;\n}\n\ndiv.document {\n  margin-top: 0pt;\n}\n\ndiv.related.top {\n    margin-top: -1em;\n}\n\ndiv.related.top nav {\n    margin-bottom: 0.5em;\n    margin-top: 0.5em;\n}\n\n.sphinxsidebarwrapper .caption {\n    margin-top: 1em;\n    margin-bottom: -0.75em;\n}\n\n#searchbox {\n  margin-bottom: 1.25em;\n}\n\n.section h1 {\n    font-weight: 700;\n}\n\n.py.class {\n    margin-top: 1.5em;\n}\n\n.py.method {\n    padding-top: 0.25em;\n    padding-bottom: 1.25em;\n    border-top: 1px solid #EEE;\n}\n\n.py.function{\n    padding-top: 1.25em;\n}\n\n.related.bottom {\n    margin-top: 1em;\n}\n\nbody {\n    font-weight: 400;\n}\n\nnav#rellinks {\n    float: left;\n    width: 100%;\n}\n\nnav#rellinks li:first-child {\n    float: left;\n    text-align: left;\n    width: 50%;\n}\n\nnav#rellinks li:last-child {\n    float: right;\n    text-align: right;\n    width: 50%;\n}\n\nnav#rellinks li+li:before {\n    content: \"\";\n}\n\ndiv.related.top nav::after {\n    float: none;\n}\n"
  },
  {
    "path": "docs/_templates/layout.html",
    "content": "{#\n  Import the theme's layout.\n#}\n{% extends \"!layout.html\" %}\n\n\n{%- block extrahead %}\n  {{- super() }}\n  <meta name=\"generator\" content=\"Toms\"/>\n{% endblock %}"
  },
  {
    "path": "docs/advanced/coerce.py",
    "content": "import re\nfrom semver import Version\nfrom typing import Optional, Tuple\n\n\nBASEVERSION = re.compile(\n    r\"\"\"[vV]?\n        (?P<major>0|[1-9]\\d*)\n        (\\.\n        (?P<minor>0|[1-9]\\d*)\n        (\\.\n            (?P<patch>0|[1-9]\\d*)\n        )?\n        )?\n    \"\"\",\n    re.VERBOSE,\n)\n\n\ndef coerce(version: str) -> Tuple[Version, Optional[str]]:\n    \"\"\"\n    Convert an incomplete version string into a semver-compatible Version\n    object\n\n    * Tries to detect a \"basic\" version string (``major.minor.patch``).\n    * If not enough components can be found, missing components are\n        set to zero to obtain a valid semver version.\n\n    :param str version: the version string to convert\n    :return: a tuple with a :class:`Version` instance (or ``None``\n        if it's not a version) and the rest of the string which doesn't\n        belong to a basic version.\n    :rtype: tuple(:class:`Version` | None, str)\n    \"\"\"\n    match = BASEVERSION.search(version)\n    if not match:\n        return (None, version)\n\n    ver = {\n        key: 0 if value is None else value for key, value in match.groupdict().items()\n    }\n    ver = Version(**ver)\n    rest = match.string[match.end() :]  # noqa:E203\n    return ver, rest\n"
  },
  {
    "path": "docs/advanced/combine-pydantic-and-semver.rst",
    "content": "Combining Pydantic and semver\n=============================\n\n.. meta::\n   :description lang=en:\n      Combining Pydantic and semver\n\nAccording to its homepage, `Pydantic <https://pydantic-docs.helpmanual.io>`_\n\"enforces type hints at runtime, and provides user friendly errors when data\nis invalid.\"\n\nIf you are working with Pydantic>2.0 and pydantic-extra-types>=2.10.5 use the built in `SemanticVersion` type, which wraps the :class:`Version <semver.version.Version>` class.\n\n    .. code-block:: python\n\n        from pydantic import BaseModel\n        from pydantic_extra_types.semantic_version import SemanticVersion\n\n        class appVersion(BaseModel):\n            version: SemanticVersion\n        \n        app_version = appVersion(version=\"1.2.3\")\n\n        print(app_version.version)\n        # > 1.2.3\n\nTo work with Pydantic>2.0 and without pydantic-extra-types use the following example to define your own type:\n\n\n1. Derive a new class from :class:`~semver.version.Version`\n   first and add the magic methods :py:meth:`__get_pydantic_core_schema__`\n   and :py:meth:`__get_pydantic_json_schema__` like this:\n\n    .. code-block:: python\n\n        from typing import Annotated, Any, Callable\n        from pydantic import GetJsonSchemaHandler\n        from pydantic_core import core_schema\n        from pydantic.json_schema import JsonSchemaValue\n        from semver import Version\n\n\n        class _VersionPydanticAnnotation:\n            @classmethod\n            def __get_pydantic_core_schema__(\n                cls,\n                _source_type: Any,\n                _handler: Callable[[Any], core_schema.CoreSchema],\n            ) -> core_schema.CoreSchema:\n                def validate_from_str(value: str) -> Version:\n                    return Version.parse(value)\n\n                from_str_schema = core_schema.chain_schema(\n                    [\n                        core_schema.str_schema(),\n                        core_schema.no_info_plain_validator_function(validate_from_str),\n                    ]\n                )\n\n                return core_schema.json_or_python_schema(\n                    json_schema=from_str_schema,\n                    python_schema=core_schema.union_schema(\n                        [\n                            core_schema.is_instance_schema(Version),\n                            from_str_schema,\n                        ]\n                    ),\n                    serialization = core_schema.to_string_ser_schema(),\n                )\n\n            @classmethod\n            def __get_pydantic_json_schema__(\n                cls, _core_schema: core_schema.CoreSchema, handler: GetJsonSchemaHandler\n            ) -> JsonSchemaValue:\n                return handler(core_schema.str_schema())\n\n        ManifestVersion = Annotated[Version, _VersionPydanticAnnotation]\n\n2. Create a new model (in this example :class:`MyModel`) and derive\n   it from :py:class:`pydantic:pydantic.BaseModel`:\n\n    .. code-block:: python\n\n        import pydantic\n\n        class MyModel(pydantic.BaseModel):\n            version: _VersionPydanticAnnotation\n\n3. Use your model like this:\n\n    .. code-block:: python\n\n        model = MyModel.parse_obj({\"version\": \"1.2.3\"})\n\n   The attribute :py:attr:`model.version` will be an instance of\n   :class:`~semver.version.Version`.\n   If the version is invalid, the construction will raise a\n   :py:class:`pydantic:pydantic_core.ValidationError`.\n"
  },
  {
    "path": "docs/advanced/convert-pypi-to-semver.rst",
    "content": "Converting Versions between PyPI and semver\n===========================================\n\n.. meta::\n   :description lang=en:\n      Converting versions between PyPI and semver\n\n.. Link\n   https://packaging.pypa.io/en/latest/_modules/packaging/version.html#InvalidVersion\n\nWhen packaging for PyPI, your versions are defined through `PEP 440`_.\nThis is the standard version scheme for Python packages and\nimplemented by the :class:`packaging.version.Version` class.\n\nHowever, these versions are different from semver versions\n(cited from `PEP 440`_):\n\n* The \"Major.Minor.Patch\" (described in this PEP as \"major.minor.micro\")\n  aspects of semantic versioning (clauses 1-8 in the 2.0.0\n  specification) are fully compatible with the version scheme defined\n  in this PEP, and abiding by these aspects is encouraged.\n\n* Semantic versions containing a hyphen (pre-releases - clause 10)\n  or a plus sign (builds - clause 11) are *not* compatible with this PEP\n  and are not permitted in the public version field.\n\nIn other words, it's not always possible to convert between these different\nversioning schemes without information loss. It depends on what parts are\nused. The following table gives a mapping between these two versioning\nschemes:\n\n+--------------+----------------+\n| PyPI Version | Semver version |\n+==============+================+\n| ``epoch``    | n/a            |\n+--------------+----------------+\n| ``major``    | ``major``      |\n+--------------+----------------+\n| ``minor``    | ``minor``      |\n+--------------+----------------+\n| ``micro``    | ``patch``      |\n+--------------+----------------+\n| ``pre``      | ``prerelease`` |\n+--------------+----------------+\n| ``dev``      | ``build``      |\n+--------------+----------------+\n| ``post``     | n/a            |\n+--------------+----------------+\n\n\n.. _convert_pypi_to_semver:\n\nFrom PyPI to semver\n-------------------\n\nWe distinguish between the following use cases:\n\n\n* **\"Incomplete\" versions**\n\n  If you only have a major part, this shouldn't be a problem.\n  The initializer of :class:`semver.Version <semver.version.Version>` takes\n  care to fill missing parts with zeros (except for major).\n\n  .. code-block:: python\n\n      >>> from packaging.version import Version as PyPIVersion\n      >>> from semver import Version\n\n      >>> p = PyPIVersion(\"3.2\")\n      >>> p.release\n      (3, 2)\n      >>> Version(*p.release)\n      Version(major=3, minor=2, patch=0, prerelease=None, build=None)\n\n* **Major, minor, and patch**\n\n  This is the simplest and most compatible approch. Both versioning\n  schemes are compatible without information loss.\n\n  .. code-block:: python\n\n      >>> p = PyPIVersion(\"3.0.0\")\n      >>> p.base_version\n      '3.0.0'\n      >>> p.release\n      (3, 0, 0)\n      >>> Version(*p.release)\n      Version(major=3, minor=0, patch=0, prerelease=None, build=None)\n\n* **With** ``pre`` **part only**\n\n  A prerelease exists in both versioning schemes. As such, both are\n  a natural candidate. A prelease in PyPI version terms is the same\n  as a \"release candidate\", or \"rc\".\n\n  .. code-block:: python\n\n      >>> p = PyPIVersion(\"2.1.6.pre5\")\n      >>> p.base_version\n      '2.1.6'\n      >>> p.pre\n      ('rc', 5)\n      >>> pre = \"\".join([str(i) for i in p.pre])\n      >>> Version(*p.release, pre)\n      Version(major=2, minor=1, patch=6, prerelease='rc5', build=None)\n\n* **With only development version**\n\n  Semver doesn't have a \"development\" version.\n  However, we could use Semver's ``build`` part:\n\n  .. code-block:: python\n\n      >>> p = PyPIVersion(\"3.0.0.dev2\")\n      >>> p.base_version\n      '3.0.0'\n      >>> p.dev\n      2\n      >>> Version(*p.release, build=f\"dev{p.dev}\")\n      Version(major=3, minor=0, patch=0, prerelease=None, build='dev2')\n\n* **With a** ``post`` **version**\n\n  Semver doesn't know the concept of a post version. As such, there\n  is currently no way to convert it reliably.\n\n* **Any combination**\n\n  There is currently no way to convert a PyPI version which consists\n  of, for example, development *and* post parts.\n\n\nYou can use the following function to convert a PyPI version into\nsemver:\n\n.. code-block:: python\n\n    def convert2semver(ver: packaging.version.Version) -> semver.Version:\n        \"\"\"Converts a PyPI version into a semver version\n\n        :param ver: the PyPI version\n        :return: a semver version\n        :raises ValueError: if epoch or post parts are used\n        \"\"\"\n        if not ver.epoch:\n            raise ValueError(\"Can't convert an epoch to semver\")\n        if not ver.post:\n            raise ValueError(\"Can't convert a post part to semver\")\n\n        pre = None if not ver.pre else \"\".join([str(i) for i in ver.pre])\n        return semver.Version(*ver.release, prerelease=pre, build=ver.dev)\n\n\n.. _convert_semver_to_pypi:\n\nFrom semver to PyPI\n-------------------\n\nWe distinguish between the following use cases:\n\n\n* **Major, minor, and patch**\n\n  .. code-block:: python\n\n      >>> from packaging.version import Version as PyPIVersion\n      >>> from semver import Version\n\n      >>> v = Version(1, 2, 3)\n      >>> PyPIVersion(str(v.finalize_version()))\n      <Version('1.2.3')>\n\n* **With** ``pre`` **part only**\n\n  .. code-block:: python\n\n      >>> v = Version(2, 1, 4, prerelease=\"rc1\")\n      >>> PyPIVersion(str(v))\n      <Version('2.1.4rc1')>\n\n* **With only development version**\n\n  .. code-block:: python\n\n      >>> v = Version(3, 2, 8, build=\"dev4\")\n      >>> PyPIVersion(f\"{v.finalize_version()}{v.build}\")\n      <Version('3.2.8.dev4')>\n\nIf you are unsure about the parts of the version, the following\nfunction helps to convert the different parts:\n\n.. code-block:: python\n\n    def convert2pypi(ver: semver.Version) -> packaging.version.Version:\n        \"\"\"Converts a semver version into a version from PyPI\n\n        A semver prerelease will be converted into a\n        prerelease of PyPI.\n        A semver build will be converted into a development\n        part of PyPI\n        :param semver.Version ver: the semver version\n        :return: a PyPI version\n        \"\"\"\n        v = ver.finalize_version()\n        prerelease = ver.prerelease if ver.prerelease else \"\"\n        build = ver.build if ver.build else \"\"\n        return PyPIVersion(f\"{v}{prerelease}{build}\")\n\n\n.. _PEP 440: https://www.python.org/dev/peps/pep-0440/\n"
  },
  {
    "path": "docs/advanced/create-subclasses-from-version.rst",
    "content": ".. _sec_creating_subclasses_from_versioninfo:\n\nCreating Subclasses from Version\n================================\n\n.. meta::\n   :description lang=en:\n      Creating subclasses from Version class\n\nIf you do not like creating functions to modify the behavior of semver\n(as shown in section :ref:`sec_dealing_with_invalid_versions`), you can\nalso create a subclass of the :class:`Version <semver.version.Version>` class.\n\nFor example, if you want to output a \"v\" prefix before a version,\nbut the other behavior is the same, use the following code:\n\n.. literalinclude:: semverwithvprefix.py\n   :language: python\n   :lines: 4-\n\n\nThe derived class :class:`SemVerWithVPrefix` can be used like\nthe original class. Additionally, you can pass \"incomplete\"\nversion strings like ``v2.3``:\n\n.. code-block:: python\n\n     >>> v1 = SemVerWithVPrefix.parse(\"v1.2.3\")\n     >>> assert str(v1) == \"v1.2.3\"\n     >>> print(v1)\n     v1.2.3\n     >>> v2 = SemVerWithVPrefix.parse(\"v2.3\")\n     >>> v2 > v1\n     True\n     >>> bad = SemVerWithVPrefix.parse(\"1.2.4\")\n     Traceback (most recent call last):\n     ...\n     ValueError: '1.2.4': not a valid semantic version tag. Must start with 'v' or 'V'\n"
  },
  {
    "path": "docs/advanced/deal-with-invalid-versions.rst",
    "content": ".. _sec_dealing_with_invalid_versions:\n\nDealing with Invalid Versions\n=============================\n\n.. meta::\n   :description lang=en:\n      Dealing with invalid versions\n\nAs semver follows the semver specification, it cannot parse version\nstrings which are considered \"invalid\" by that specification. The semver\nlibrary cannot know all the possible variations so you need to help the\nlibrary a bit.\n\nFor example, if you have a version string ``v1.2`` would be an invalid\nsemver version.\nHowever, \"basic\" version strings consisting of major, minor,\nand patch part, can be easy to convert. The following function extract this\ninformation and returns a tuple with two items:\n\n.. literalinclude:: coerce.py\n   :language: python\n\n\nThe function returns a *tuple*, containing a :class:`Version <semver.version.Version>`\ninstance or None as the first element and the rest as the second element.\nThe second element (the rest) can be used to make further adjustments.\n\nFor example:\n\n.. code-block:: python\n\n    >>> coerce(\"v1.2\")\n    (Version(major=1, minor=2, patch=0, prerelease=None, build=None), '')\n    >>> coerce(\"v2.5.2-bla\")\n    (Version(major=2, minor=5, patch=2, prerelease=None, build=None), '-bla')\n"
  },
  {
    "path": "docs/advanced/display-deprecation-warnings.rst",
    "content": ".. _sec_display_deprecation_warnings:\n\nDisplaying Deprecation Warnings\n===============================\n\n.. meta::\n   :description lang=en:\n      Displaying and filtering deprecation warnings\n\nBy default,  deprecation warnings are `ignored in Python <https://docs.python.org/3/library/warnings.html#warning-categories>`_.\nThis also affects semver's own warnings.\n\nIt is recommended that you turn on deprecation warnings in your scripts. Use one of\nthe following methods:\n\n* Use the option `-Wd <https://docs.python.org/3/using/cmdline.html#cmdoption-w>`_\n  to enable default warnings:\n\n  * Directly running the Python command::\n\n       $ python3 -Wd scriptname.py\n\n  * Add the option in the shebang line (something like ``#!/usr/bin/python3``)\n    after the command::\n\n       #!/usr/bin/python3 -Wd\n\n* In your own scripts add a filter to ensure that *all* warnings are displayed:\n\n   .. code-block:: python\n\n       import warnings\n       warnings.simplefilter(\"default\")\n       # Call your semver code\n\n   For further details, see the section\n   `Overriding the default filter <https://docs.python.org/3/library/warnings.html#overriding-the-default-filter>`_\n   of the Python documentation.\n"
  },
  {
    "path": "docs/advanced/index.rst",
    "content": "Advanced topics\n===============\n\n.. meta::\n   :description lang=en:\n      Advanced topics for Python semver\n\n.. toctree::\n    :maxdepth: 1\n\n    deal-with-invalid-versions\n    create-subclasses-from-version\n    display-deprecation-warnings\n    combine-pydantic-and-semver\n    convert-pypi-to-semver\n    version-from-file\n"
  },
  {
    "path": "docs/advanced/semverwithvprefix.py",
    "content": "from semver import Version\n\n\nclass SemVerWithVPrefix(Version):\n    \"\"\"\n    A subclass of Version which allows a \"v\" prefix\n    \"\"\"\n\n    @classmethod\n    def parse(cls, version: str) -> \"SemVerWithVPrefix\":\n        \"\"\"\n        Parse version string to a Version instance.\n\n        :param version: version string with \"v\" or \"V\" prefix\n        :raises ValueError: when version does not start with \"v\" or \"V\"\n        :return: a new instance\n        \"\"\"\n        if not version[0] in (\"v\", \"V\"):\n            raise ValueError(\n                f\"{version!r}: not a valid semantic version tag. \"\n                \"Must start with 'v' or 'V'\"\n            )\n        return super().parse(version[1:], optional_minor_and_patch=True)\n\n    def __str__(self) -> str:\n        # Reconstruct the tag\n        return \"v\" + super().__str__()\n"
  },
  {
    "path": "docs/advanced/version-from-file.rst",
    "content": ".. _sec_reading_versions_from_file:\n\nReading Versions from File\n==========================\n\n.. meta::\n   :description lang=en:\n      Reading versions from file\n\nIn cases where a version is stored inside a file, one possible solution\nis to use the following function:\n\n.. code-block:: python\n\n    import os\n    from typing import Union\n    from semver.version import Version\n\n    def get_version(path: Union[str, os.PathLike]) -> semver.Version:\n        \"\"\"\n        Construct a Version object from a file\n        \n        :param path: A text file only containing the semantic version\n        :return: A :class:`Version` object containing the semantic\n                 version from the file.\n        \"\"\"\n        version = open(path,\"r\").read().strip()\n        return Version.parse(version)\n"
  },
  {
    "path": "docs/api.rst",
    "content": ".. _api:\n\nAPI Reference\n=============\n\n.. meta::\n   :description lang=en:\n      API reference about Python semver\n\n.. currentmodule:: semver\n\n\nMetadata :mod:`semver.__about__`\n--------------------------------\n\n.. automodule:: semver.__about__\n\n\nDeprecated Functions in :mod:`semver._deprecated`\n-------------------------------------------------\n\n.. automodule:: semver._deprecated\n\n.. autofunction:: semver._deprecated.compare\n\n.. autofunction:: semver._deprecated.bump_build\n\n.. autofunction:: semver._deprecated.bump_major\n\n.. autofunction:: semver._deprecated.bump_minor\n\n.. autofunction:: semver._deprecated.bump_patch\n\n.. autofunction:: semver._deprecated.bump_prerelease\n\n.. autofunction:: semver._deprecated.deprecated\n\n.. autofunction:: semver._deprecated.finalize_version\n\n.. autofunction:: semver._deprecated.format_version\n\n.. autofunction:: semver._deprecated.match\n\n.. autofunction:: semver._deprecated.max_ver\n\n.. autofunction:: semver._deprecated.min_ver\n\n.. autofunction:: semver._deprecated.parse\n\n.. autofunction:: semver._deprecated.parse_version_info\n\n.. autofunction:: semver._deprecated.replace\n\n\n\nCLI Parsing :mod:`semver.cli`\n-----------------------------\n\n.. automodule:: semver.cli\n\n.. autofunction:: semver.cli.cmd_bump\n\n.. autofunction:: semver.cli.cmd_check\n\n.. autofunction:: semver.cli.cmd_compare\n\n.. autofunction:: semver.cli.createparser\n\n.. autofunction:: semver.cli.main\n\n.. autofunction:: semver.cli.process\n\n\nEntry point :mod:`semver.__main__`\n----------------------------------\n\n.. automodule:: semver.__main__\n\n\n\nVersion Handling :mod:`semver.version`\n--------------------------------------\n\n.. automodule:: semver.version\n\n.. autoclass:: semver.version.VersionInfo\n\n.. autoclass:: semver.version.Version\n   :members:\n   :special-members: __iter__, __eq__, __ne__, __lt__, __le__, __gt__, __ge__, __getitem__, __hash__, __repr__, __str__\n"
  },
  {
    "path": "docs/build-semver.rst",
    "content": ".. _build-semver:\n\nBuilding semver\n===============\n\n.. meta::\n   :description lang=en:\n      Building semver\n\n.. _Installing uv: https://docs.astral.sh/uv/getting-started/installation/\n\n\nThis project changed its way how it is built over time. We used to have\na :file:`setup.py` file, but switched to a :file:`pyproject.toml` setup.\n\nThe build process is managed by :command:`uv` command.\n\nYou need:\n\n* Python 3.7 or newer.\n\n* The :mod:`setuptools` module version 61 or newer which is used as\n  a build backend.\n\n* The command :command:`uv` from Astral. Refer to the section\n  `Installing uv`_  for more information.\n\n\nTo build semver, run::\n\n    uv build\n\nAfter the command is finished, you can find two files in the :file:`dist` folder: a ``.tar.gz`` and a ``.whl`` file."
  },
  {
    "path": "docs/changelog-semver3-devel.rst",
    "content": "\n#############################\nChangelog semver3 development\n#############################\n\nThis site contains all the changes during the development phase.\n\n.. _semver-3.0.0-dev.4:\n\nVersion 3.0.0-dev.4\n===================\n\n:Released: 2022-12-18\n:Maintainer:\n\n\n.. _semver-3.0.0-dev.4-bugfixes:\n\nBug Fixes\n---------\n\n* :gh:`374`: Correct Towncrier's config entries in the :file:`pyproject.toml` file.\n  The old entries ``[[tool.towncrier.type]]`` are deprecated and need\n  to be replaced by ``[tool.towncrier.fragment.<TYPE>]``.\n\n\n\n.. _semver-3.0.0-dev.4-deprecations:\n\nDeprecations\n------------\n\n* :gh:`372`: Deprecate support for Python 3.6.\n\n  Python 3.6 reached its end of life and isn't supported anymore.\n  At the time of writing (Dec 2022), the lowest version is 3.7.\n\n  Although the `poll <https://github.com/python-semver/python-semver/discussions/371>`_\n  didn't cast many votes, the majority agree to remove support for\n  Python 3.6.\n\n\n.. _semver-3.0.0-dev.4-doc:\n\nImproved Documentation\n----------------------\n\n* :gh:`335`: Add new section \"Converting versions between PyPI and semver\" the limitations\n  and possible use cases to convert from one into the other versioning scheme.\n\n* :gh:`340`: Describe how to get version from a file\n\n* :gh:`343`: Describe combining Pydantic with semver in the \"Advanced topic\"\n  section.\n\n* :gh:`350`: Restructure usage section. Create subdirectory \"usage/\" and splitted\n  all section into different files.\n\n* :gh:`351`: Introduce new topics for:\n\n  * \"Migration to semver3\"\n  * \"Advanced topics\"\n\n\n.. _semver-3.0.0-dev.4-features:\n\nFeatures\n--------\n\n* :pr:`359`: Add optional parameter ``optional_minor_and_patch`` in :meth:`.Version.parse`  to allow optional\n  minor and patch parts.\n\n* :pr:`362`: Make :meth:`.Version.match` accept a bare version string as match expression, defaulting to\n  equality testing.\n\n* :gh:`364`: Enhance :file:`pyproject.toml` to make it possible to use the\n  :command:`pyproject-build` command from the build module.\n  For more information, see :ref:`build-semver`.\n\n* :gh:`365`: Improve :file:`pyproject.toml`.\n\n  * Use setuptools, add metadata. Taken approach from\n    `A Practical Guide to Setuptools and Pyproject.toml\n    <https://godatadriven.com/blog/a-practical-guide-to-setuptools-and-pyproject-toml/>`_.\n  * Doc: Describe building of semver\n  * Remove :file:`.travis.yml` in :file:`MANIFEST.in`\n    (not needed anymore)\n  * Distinguish between Python 3.6 and others in :file:`tox.ini`\n  * Add skip_missing_interpreters option for :file:`tox.ini`\n  * GH Action: Upgrade setuptools and setuptools-scm and test\n    against 3.11.0-rc.2\n\n\n.. _semver-3.0.0-dev.4-internal:\n\nTrivial/Internal Changes\n------------------------\n\n* :gh:`378`: Fix some typos in Towncrier configuration\n\n\n\n----\n\n.. _semver-3.0.0-dev.3:\n\nVersion 3.0.0-dev.3\n===================\n\n:Released: 2022-01-19\n:Maintainer: Tom Schraitle\n\n\n.. _semver-3.0.0-dev.3-bugfixes:\n\nBug Fixes\n---------\n\n* :gh:`310`: Rework API documentation.\n  Follow a more \"semi-manual\" attempt and add auto directives\n  into :file:`docs/api.rst`.\n\n\n.. _semver-3.0.0-dev.3-docs:\n\nImproved Documentation\n----------------------\n\n* :gh:`312`: Rework \"Usage\" section.\n\n  * Mention the rename of :class:`~semver.version.VersionInfo` to\n    :class:`~semver.version.Version` class\n  * Remove semver. prefix in doctests to make examples shorter\n  * Correct some references to dunder methods like\n    :func:`~semver.version.Version.__getitem__`,\n    :func:`~semver.version.Version.__gt__` etc.\n  * Remove inconsistencies and mention module level function as\n    deprecated and discouraged from using\n  * Make empty :py:class:`python:super` call in :file:`semverwithvprefix.py` example\n\n* :gh:`315`: Improve release procedure text\n\n\n.. _semver-3.0.0-dev.3-trivial:\n\nTrivial/Internal Changes\n------------------------\n\n* :gh:`309`: Some (private) functions from the :mod:`semver.version`\n  module has been changed.\n\n  The following functions got renamed:\n\n  * function :func:`semver.version.comparator` got renamed to\n    :func:`semver.version._comparator` as it is only useful\n    inside the :class:`~semver.version.Version` class.\n  * function :func:`semver.version.cmp` got renamed to\n    :func:`semver.version._cmp` as it is only useful\n    inside the :class:`~semver.version.Version` class.\n\n  The following functions got integrated into the\n  :class:`~semver.version.Version` class:\n\n  * function :func:`semver.version._nat_cmd` as a classmethod\n  * function :func:`semver.version.ensure_str`\n\n* :gh:`313`: Correct :file:`tox.ini` for ``changelog`` entry to skip\n  installation for semver. This should speed up the execution\n  of towncrier.\n\n* :gh:`316`: Comparisons of :class:`~semver.version.Version` class and other\n  types return now a :py:data:`python:NotImplemented` constant instead\n  of a :py:exc:`python:TypeError` exception.\n\n  In the Python documentation, :py:data:`python:NotImplemented` recommends\n  returning this constant when comparing with :py:meth:`__gt__ <python:object.__gt__>`, :py:meth:`__lt__ <python:object.__lt__>`,\n  and other comparison operators \"to indicate that the operation is\n  not implemented with respect to the other type\".\n\n* :gh:`319`: Introduce stages in :file:`.travis.yml`\n  The config file contains now two stages: check and test. If\n  check fails, the test stage won't be executed. This could\n  speed up things when some checks fails.\n\n* :gh:`322`: Switch from Travis CI to GitHub Actions.\n\n* :gh:`347`: Support Python 3.10 in GitHub Action and other config files.\n\n\n\n----\n\n.. _semver-3.0.0-dev.2:\n\nVersion 3.0.0-dev.2\n===================\n\n:Released: 2020-11-01\n:Maintainer: Tom Schraitle\n\n\n.. _semver-3.0.0-dev.2-deprecations:\n\nDeprecations\n------------\n\n* :gh:`169`: Deprecate CLI functions not imported from :mod:`semver.cli`.\n\n\n.. _semver-3.0.0-dev.2-features:\n\nFeatures\n--------\n\n* :gh:`169`: Create semver package and split code among different modules in the packages.\n\n  * Remove :file:`semver.py`\n  * Create :file:`src/semver/__init__.py`\n  * Create :file:`src/semver/cli.py` for all CLI methods\n  * Create :file:`src/semver/_deprecated.py` for the ``deprecated`` decorator and other deprecated functions\n  * Create :file:`src/semver/__main__.py` to allow calling the CLI using :command:`python -m semver`\n  * Create :file:`src/semver/_types.py` to hold type aliases\n  * Create :file:`src/semver/version.py` to hold the :class:`~semver.version.Version` class (old name :class:`~semver.version.VersionInfo`) and its utility functions\n  * Create :file:`src/semver/__about__.py` for all the metadata variables\n\n* :gh:`305`: Rename :class:`~semver.version.VersionInfo` to :class:`~semver.version.Version` but keep an alias for compatibility\n\n\n.. _semver-3.0.0-dev.2-docs:\n\nImproved Documentation\n----------------------\n\n* :gh:`304`: Several improvements in documentation:\n\n  * Reorganize API documentation.\n  * Add migration chapter from semver2 to semver3.\n  * Distinguish between changlog for version 2 and 3\n\n* :gh:`305`: Add note about :class:`~semver.version.Version` rename.\n\n\n.. _semver-3.0.0-dev.2-trivial:\n\nTrivial/Internal Changes\n------------------------\n\n* :gh:`169`: Adapted infrastructure code to the new project layout.\n\n  * Replace :file:`setup.py` with :file:`setup.cfg` because the :file:`setup.cfg` is easier to use\n  * Adapt documentation code snippets where needed\n  * Adapt tests\n  * Changed the ``deprecated`` to hardcode the ``semver`` package name in the warning.\n\n  Increase coverage to 100% for all non-deprecated APIs\n\n* :gh:`304`: Support PEP-561 :file:`py.typed`.\n\n  According to the mentioned PEP:\n\n    \"Package maintainers who wish to support type checking\n    of their code MUST add a marker file named :file:`py.typed`\n    to their package supporting typing.\"\n\n  Add package_data to :file:`setup.cfg` to include this marker in dist\n  and whl file.\n\n\n\n----\n\n.. _semver-3.0.0-dev.1:\n\nVersion 3.0.0-dev.1\n===================\n\n:Released: 2020-10-26\n:Maintainer: Tom Schraitle\n\n\n.. _semver-3.0.0-dev.1-deprecations:\n\nDeprecations\n------------\n\n* :pr:`290`: For semver 3.0.0-alpha0:\n\n  * Remove anything related to Python2\n  * In :file:`tox.ini` and :file:`.travis.yml`\n    Remove targets py27, py34, py35, and pypy.\n    Add py38, py39, and nightly (allow to fail)\n  * In :file:`setup.py` simplified file and remove\n    ``Tox`` and ``Clean`` classes\n  * Remove old Python versions (2.7, 3.4, 3.5, and pypy)\n    from Travis\n\n* :gh:`234`: In :file:`setup.py` simplified file and remove\n  ``Tox`` and ``Clean`` classes\n\n\n.. _semver-3.0.0-dev.1-features:\n\nFeatures\n--------\n\n* :pr:`290`: Create semver 3.0.0-alpha0\n\n  * Update :file:`README.rst`, mention maintenance\n    branch ``maint/v2``.\n  * Remove old code mainly used for Python2 compatibility,\n    adjusted code to support Python3 features.\n  * Split test suite into separate files under :file:`tests/`\n    directory\n  * Adjust and update :file:`setup.py`. Requires Python >=3.6.*\n    Extract metadata directly from source (affects all the :data:`~semver.__about__.__version__`,\n    :data:`~semver.__about__.__author__` etc. variables)\n\n* :gh:`270`: Configure Towncrier (:pr:`273`:)\n\n  * Add :file:`changelog.d/.gitignore` to keep this directory\n  * Create :file:`changelog.d/README.rst` with some descriptions\n  * Add :file:`changelog.d/_template.rst` as Towncrier template\n  * Add ``[tool.towncrier]`` section in :file:`pyproject.toml`\n  * Add \"changelog\" target into :file:`tox.ini`. Use it like\n    :command:`tox -e changelog -- CMD` whereas ``CMD`` is a\n    Towncrier command. The default :command:`tox -e changelog`\n    calls Towncrier to create a draft of the changelog file\n    and output it to stdout.\n  * Update documentation and add include a new section\n    \"Changelog\" included from :file:`changelog.d/README.rst`.\n\n* :gh:`276`: Document how to create a sublass from :class:`~semver.version.VersionInfo` class\n\n* :gh:`213`: Add typing information\n\n\n.. _semver-3.0.0-dev.1-bugfixes:\n\nBug Fixes\n---------\n\n* :gh:`291`: Disallow negative numbers in VersionInfo arguments\n  for ``major``, ``minor``, and ``patch``.\n\n\n.. _semver-3.0.0-dev.1-docs:\n\nImproved Documentation\n----------------------\n\n* :pr:`290`: Several improvements in the documentation:\n\n  * New layout to distinguish from the semver2 development line.\n  * Create new logo.\n  * Remove any occurances of Python2.\n  * Describe changelog process with Towncrier.\n  * Update the release process.\n\n\n.. _semver-3.0.0-dev.1-trivial:\n\nTrivial/Internal Changes\n------------------------\n\n* :pr:`290`: Add supported Python versions to :command:`black`.\n"
  },
  {
    "path": "docs/changelog.rst",
    "content": ".. _change-log:\n\n.. include:: ../CHANGELOG.rst\n"
  },
  {
    "path": "docs/conf.py",
    "content": "#!/usr/bin/env python3\n#\n# python-semver documentation build configuration file\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\n\nimport os\nimport re\nfrom datetime import date\nfrom pathlib import Path\n\nSRC_DIR = Path(__file__).absolute().parent.parent / \"src\"\nYEAR = date.today().year\n\n\ndef find_version(path: Path) -> str:\n    \"\"\"\n    Build a path from *file_paths* and search for a ``__version__``\n    string inside.\n    \"\"\"\n    content = Path(path).read_text(encoding=\"utf-8\")\n\n    version_match = re.search(\n        r\"^__version__ = ['\\\"]([^'\\\"]*)['\\\"]\",\n        content,\n        re.MULTILINE\n    )\n    if version_match:\n        return version_match.group(1)\n\n    raise RuntimeError(\"Unable to find version string.\")\n\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#\n# needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx_autodoc_typehints\",\n    \"sphinx.ext.intersphinx\",\n    \"sphinx.ext.extlinks\",\n]\n\n# Autodoc configuration\nautoclass_content = \"class\"\nautodoc_typehints = \"signature\"\nautodoc_member_order = \"alphabetical\"\nadd_function_parentheses = True\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\n#\nsource_suffix = \".rst\"\n\n# The master toctree document.\nmaster_doc = \"index\"\n\n# General information about the project.\nproject = \"python-semver\"\ncopyright = f\"{YEAR}, Kostiantyn Rybnikov and all\"\nauthor = \"Kostiantyn Rybnikov, Tom Schraitle, Sebastien Celles, and others\"\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nrelease = find_version(SRC_DIR / \"semver/__about__.py\")\n# The full version, including alpha/beta/rc tags.\nversion = release  # .rsplit(u\".\", 1)[0]\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = \"en\"\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This patterns also effect to html_static_path and html_extra_path\nexclude_patterns = [\"_build\", \"Thumbs.db\", \".DS_Store\"]\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"sphinx\"\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = False\n\n# Markup to shorten external links\n# See https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html\nextlinks = {\n    \"gh\": (\"https://github.com/python-semver/python-semver/issues/%s\", \"#%s\"),\n    \"pr\": (\"https://github.com/python-semver/python-semver/pull/%s\", \"PR #%s\"),\n}\n\n# Link to other projects’ documentation\n# See https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html\nintersphinx_mapping = {\n    # Download it from the root with:\n    # wget -O docs/inventories/python-objects.inv https://docs.python.org/3/objects.inv\n    \"python\": (\"https://docs.python.org/3\", (None, \"inventories/python-objects.inv\")),\n    # wget -O docs/inventories/pydantic.inv https://docs.pydantic.dev/latest/objects.inv\n    \"pydantic\": (\n        \"https://docs.pydantic.dev/latest/\",\n        (None, \"inventories/pydantic.inv\"),\n    ),\n}\n# Avoid side-effects (namely that documentations local references can\n# suddenly resolve to an external location.)\nintersphinx_disabled_reftypes = [\"*\"]\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = \"alabaster\"\ntemplates_path = [\"_templates\"]\n\nGITHUB_URL = \"https://github.com/python-semver/python-semver\"\n\nhtml_theme_options = {\n    # -- Basics\n    #: Text blurb about your project to appear under the logo:\n    # \"description\": \"Semantic versioning\",\n    #: Makes the sidebar \"fixed\" or pinned in place:\n    \"fixed_sidebar\": True,\n    #: Relative path to $PROJECT/_static to logo image:\n    \"logo\": \"logo.svg\",\n    #: Set to true to insert your site's project name under\n    #: the logo:\n    # \"logo_name\": True,\n    #: CSS width specifier controller default sidebar width:\n    \"sidebar_width\": \"25%\",\n    #: CSS width specifier controlling default content/page width:\n    \"page_width\": \"auto\",\n    #: CSS width specifier controlling default body text width:\n    \"body_max_width\": \"auto\",\n    #\n    # -- Service Links and Badges\n    #: Contains project name and user of GitHub:\n    \"github_user\": \"python-semver\",\n    \"github_repo\": \"python-semver\",\n    #: whether to link to your GitHub:\n    \"github_button\": True,\n    #:\n    \"github_type\": \"star\",\n    #: whether to apply a \"Fork me on Github\" banner\n    #: in the top right corner of the page:\n    # \"github_banner\": True,\n    #\n    # -- Non-service sidebar control\n    #: Dictionary mapping link names to link targets:\n    \"extra_nav_links\": {\n        \"PyPI\": \"https://pypi.org/project/semver/\",\n        \"Libraries.io\": \"https://libraries.io/pypi/semver\",\n    },\n    #: Boolean determining whether all TOC entries that\n    #: are not ancestors of the current page are collapsed:\n    \"sidebar_collapse\": True,\n    #\n    # -- Header/footer options\n    #: used to display next and previous links above and\n    #: below the main page content\n    \"show_relbars\": True,\n    \"show_relbar_top\": True,\n    #\n    # -- Style colors\n    # \"anchor\": \"\",\n    # \"anchor_hover_bg\": \"\",\n    # \"anchor_hover_fg\": \"\",\n    \"narrow_sidebar_fg\": \"lightgray\",\n    #\n    # -- Fonts\n    # \"code_font_size\": \"\",\n    \"font_family\": \"'Roboto',sans-serif\",\n    \"head_font_family\": \"'Roboto Slab',serif\",\n    \"code_font_family\": \"'Roboto Mono',monospace\",\n    \"font_size\": \"1.20rem\",\n}\n\nhtml_static_path = [\"_static\"]\nhtml_css_files = [\"css/custom.css\"]\n\nhtml_sidebars = {\n    \"**\": [\n        \"about.html\",  # theme_logo\n        # 'relations.html',  # prev and next\n        \"searchbox.html\",  # basic/searchbox.html\n        \"navigation.html\",  # TOC\n        # 'donate.html',\n    ]\n}\n\n# Canonical link relation\nif os.environ.get(\"READTHEDOCS_CANONICAL_URL\"):\n    html_baseurl = f\"{os.environ['READTHEDOCS_CANONICAL_URL']}\"\n\n# html_logo = \"logo.svg\"\n\n# -- Options for HTMLHelp output ------------------------------------------\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = \"semverdoc\"\n\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    #\n    # 'papersize': 'letterpaper',\n    # The font size ('10pt', '11pt' or '12pt').\n    #\n    # 'pointsize': '10pt',\n    # Additional stuff for the LaTeX preamble.\n    #\n    # 'preamble': '',\n    # Latex figure (float) alignment\n    #\n    # 'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [\n    (\n        master_doc,\n        \"semver.tex\",\n        \"python-semver Documentation\",\n        \"Kostiantyn Rybnikov and all\",\n        \"manual\",\n    )\n]\n\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nmanpage_doc = \"pysemver\"\n\nman_pages = [\n    (\n        manpage_doc,\n        \"pysemver\",\n        \"Helper script for Semantic Versioning\",\n        [\"Thomas Schraitle\"],\n        1,\n    )\n]\n\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (\n        master_doc,\n        \"semver\",\n        \"python-semver Documentation\",\n        author,\n        \"semver\",\n        \"One line description of project.\",\n        \"Miscellaneous\",\n    )\n]\n"
  },
  {
    "path": "docs/contribute/add-changelog-entry.rst",
    "content": ".. _add-changelog:\n\nAdding a Changelog Entry\n========================\n\n.. meta::\n   :description lang=en:\n      Adding a changelog entry with Towncrier\n\n.. include:: ../../changelog.d/README.rst\n    :start-after: -text-begin-"
  },
  {
    "path": "docs/contribute/doc-semver.rst",
    "content": ".. _doc:\n\nDocumenting semver\n==================\n\n.. meta::\n   :description lang=en:\n      Documenting semver with type annotations, docstrings, Sphinx directives\n\nDocumenting the features of semver is very important. It gives our developers\nan overview what is possible with semver, how it \"feels\", and how it is\nused efficiently.\n\n.. note::\n\n    To build the documentation locally use the following command::\n\n      $ tox -e docs\n\n    The built documentation is available in :file:`docs/_build/html`.\n\n\nA new feature is *not* complete if it isn't proberly documented. A good\ndocumentation includes:\n\n  * **Type annotations**\n\n    This library supports type annotations. Therefore, each function\n    or method requires types for each arguments and return objects.\n    Exception of this rule is ``self``.\n\n  * **A docstring**\n\n    Each docstring contains a summary line, a linebreak, an optional\n    directive (see next item), the description of its arguments in\n    `Sphinx style`_, and an optional doctest.\n    The docstring is extracted and reused in the :ref:`api` section.\n    An appropriate docstring looks like this::\n\n         def to_tuple(self) -> VersionTuple:\n            \"\"\"\n            Convert the Version object to a tuple.\n\n            .. versionadded:: 2.10.0\n               Renamed ``VersionInfo._astuple`` to ``VersionInfo.to_tuple`` to\n               make this function available in the public API.\n\n            :return: a tuple with all the parts\n\n            >>> semver.Version(5, 3, 1).to_tuple()\n            (5, 3, 1, None, None)\n\n            \"\"\"\n\n  * **An optional directive**\n\n    If you introduce a new feature, change a function/method, or remove something,\n    it is a good practice to introduce Sphinx directives into the docstring.\n    This gives the reader an idea what version is affected by this change.\n\n    The first required argument, ``VERSION``, defines the version when this change\n    was introduced. You can choose from:\n\n    * ``.. versionadded:: VERSION``\n\n      Use this directive to describe a new feature.\n\n    * ``.. versionchanged:: VERSION``\n\n      Use this directive to describe when something has changed, for example,\n      new parameters were added, changed side effects, different return values, etc.\n\n    * ``.. deprecated:: VERSION``\n\n      Use this directive when a feature is deprecated. Describe what should\n      be used instead, if appropriate.\n\n\n    Add such a directive *after* the summary line, as shown above.\n\n  * **The documentation**\n\n    A docstring is good, but in most cases it is too short. API documentation\n    cannot replace good user documentation.\n    Describe *how* to use your new feature in the documentation.\n    Here you can give your readers more examples, describe it in a broader\n    context, or show edge cases.\n\n\n.. _Sphinx style: https://sphinx-rtd-tutorial.rtfd.io/en/latest/docstrings.html\n"
  },
  {
    "path": "docs/contribute/finish-release.rst",
    "content": ".. _finish-release:\n\nFinish the Release\n==================\n\n.. meta::\n   :description lang=en:\n      Finish the semver release by creating tags\n\n1. Create a tag:\n\n   $ git tag -a x.x.x\n\n   It’s recommended to use the generated Tox output from the Changelog.\n\n2. Push the tag:\n\n   $ git push –tags\n\n3. In `GitHub Release\n   page <https://github.com/python-semver/python-semver/release>`_\n   document the new release. Select the tag from the last step and copy\n   the content of the tag description into the release description.\n\n4. Announce it in\n   https://github.com/python-semver/python-semver/discussions/categories/announcements.\n\nYou’re done! Celebrate!\n"
  },
  {
    "path": "docs/contribute/index.rst",
    "content": ".. _contributing:\n\nContributing to semver\n======================\n\n.. meta::\n   :description lang=en:\n      Contributing to Python semver\n\nThe semver source code is managed using Git and is hosted on GitHub::\n\n   git clone git://github.com/python-semver/python-semver\n\n\n.. include:: prerequisites.rst\n   :start-after: -text-begin-\n\n\n.. toctree::\n    :maxdepth: 1\n    :caption: More topics\n    :includehidden:\n\n    report-bugs\n    run-test-suite\n    doc-semver\n    add-changelog-entry\n    release-procedure\n    finish-release\n\n\n.. _pull request: https://github.com/python-semver/python-semver/pulls\n"
  },
  {
    "path": "docs/contribute/prerequisites.rst",
    "content": "Prerequisites\n-------------\n\n.. meta::\n   :description lang=en:\n      Overview of prerequisites for contributing\n\n.. -text-begin-\n\nBefore you make changes to the code, we would highly appreciate if you\nconsider the following general requirements:\n\n* Make sure your code adheres to the `Semantic Versioning`_ specification.\n\n* Check if your feature is covered by the Semantic Versioning specification.\n  If not, ask on its GitHub project https://github.com/semver/semver.\n\n\n.. _Semantic Versioning: https://semver.org\n"
  },
  {
    "path": "docs/contribute/release-procedure.rst",
    "content": "Release Procedure\n=================\n\n.. meta::\n   :description lang=en:\n      Release procedure: prepare and create the release\n\nThe following procedures gives a short overview of what steps are needed\nto create a new release.\n\nThese steps are interesting for the release manager only.\n\n\nPrepare the Release\n-------------------\n\n1. Verify that:\n\n   -  all issues for a new release are closed:\n      https://github.com/python-semver/python-semver/issues.\n\n   -  all pull requests that should be included in this release are\n      merged: https://github.com/python-semver/python-semver/pulls.\n\n   -  continuous integration for latest build was passing:\n      https://github.com/python-semver/python-semver/actions.\n\n2. Create a new branch ``release/<VERSION>``.\n\n3. If one or several supported Python versions have been removed or\n   added, verify that the following files have been updated:\n\n   - :file:`setup.cfg`\n   - :file:`tox.ini`\n   - :file:`.git/workflows/pythonpackage.yml`\n   - :file:`.github/workflows/python-testing.yml`\n\n4. Verify that the version in file :file:`src/semver/__about__.py`\n   has been updated and follows the `Semver <https://semver.org>`_\n   specification.\n\n5. Add eventually new contributor(s) to\n   `CONTRIBUTORS <https://github.com/python-semver/python-semver/blob/master/CONTRIBUTORS>`_.\n\n6. Check if all changelog entries are created. If some are missing,\n   `create\n   them <https://python-semver.readthedocs.io/en/latest/development.html#adding-a-changelog-entry>`__.\n\n7. Show the new draft\n   `CHANGELOG <https://github.com/python-semver/python-semver/blob/master/CHANGELOG.rst>`_ entry for the latest release with:\n\n   ::\n\n      $ tox -e changelog\n\n   Check the output. If you are not happy, update the files in the\n   ``changelog.d/`` directory. If everything is okay, build the new\n   ``CHANGELOG`` with:\n\n   ::\n\n      $ tox -e changelog -- build\n\n8. Build the documentation and check the output:\n\n   ::\n\n      $ tox -e docs\n\n9. Commit all changes, push, and create a pull request.\n\nCreate the New Release\n----------------------\n\n1. Ensure that long description\n   (`README.rst <https://github.com/python-semver/python-semver/blob/master/README.rst>`_)\n   can be correctly rendered by Pypi using\n   ``restview --long-description``\n\n2. Clean up your local Git repository. Be careful, as it **will remove\n   all files** which are not versioned by Git:\n\n   ::\n\n      $ git clean -xfd\n\n   Before you create your distribution files, clean the directory too:\n\n   ::\n\n      $ rm dist/*\n\n3. Create the distribution files (wheel and source):\n\n   ::\n\n      $ tox -e prepare-dist\n\n4. Upload the wheel and source to TestPyPI first:\n\n   .. code:: bash\n\n      $ twine upload --repository-url https://test.pypi.org/legacy/  dist/*\n\n   If you have a ``~/.pypirc`` with a ``testpypi`` section, the upload\n   can be simplified:\n\n   ::\n\n      $ twine upload --repository testpypi dist/*\n\n5. Check if everything is okay with the wheel. Check also the web site\n   ``https://test.pypi.org/project/<VERSION>/``\n\n6. If everything looks fine, merge the pull request.\n\n7. Upload to PyPI:\n\n   .. code:: bash\n\n      $ git clean -xfd\n      $ tox -e prepare-dist\n      $ twine upload dist/*\n\n8. Go to https://pypi.org/project/semver/ to verify that new version is\n   online and the page is rendered correctly.\n\n"
  },
  {
    "path": "docs/contribute/report-bugs.rst",
    "content": ".. _report-bugs:\n\nReporting Bugs and Asking Questions\n-----------------------------------\n\n.. meta::\n   :description lang=en:\n      Reporting bugs and asking questions about semver\n\nIf you think you have encountered a bug in semver or have an idea for a new\nfeature? Great! We like to hear from you!\n\nThere are several options to participate:\n\n* Open a new topic on our `GitHub discussion <gh_discussions>`_ page.\n  Tell us our ideas or ask your questions.\n\n* Look into our GitHub `issues`_ tracker or open a new issue.\n\n\n.. _issues:  https://github.com/python-semver/python-semver/issues\n.. _gh_discussions: https://github.com/python-semver/python-semver/discussions\n"
  },
  {
    "path": "docs/contribute/run-test-suite.rst",
    "content": ".. _testsuite:\n\nRunning the Test Suite\n======================\n\n.. meta::\n   :description lang=en:\n      Running the test suite through tox\n\nWe use `pytest`_ and `tox`_ to run tests against all supported Python\nversions.  All test dependencies are resolved automatically.\n\nYou can decide to run the complete test suite or only part of it:\n\n* To run all tests, use::\n\n     $ tox\n\n  If you have not all Python interpreters installed on your system\n  it will probably give you some errors (``InterpreterNotFound``).\n  To avoid such errors, use::\n\n     $ tox --skip-missing-interpreters\n\n  It is possible to use one or more specific Python versions. Use the ``-e``\n  option and one or more abbreviations (``py37`` for Python 3.7,\n  ``py38`` for Python 3.8 etc.)::\n\n      $ tox -e py37\n      $ tox -e py37,py38\n\n  To get a complete list and a short description, run::\n\n      $ tox -av\n\n* To run only a specific test, pytest requires the syntax\n  ``TEST_FILE::TEST_FUNCTION``.\n\n  For example, the following line tests only the function\n  :func:`test_immutable_major` in the file :file:`test_bump.py` for all\n  Python versions::\n\n      $ tox -e py37 -- tests/test_bump.py::test_should_bump_major\n\n  By default, pytest prints only a dot for each test function. To\n  reveal the executed test function, use the following syntax::\n\n     $ tox -- -v\n\n  You can combine the specific test function with the ``-e`` option, for\n  example, to limit the tests for Python 3.7 and 3.8 only::\n\n      $ tox -e py37,py38 -- tests/test_bump.py::test_should_bump_major\n\nOur code is checked against formatting, style, type, and docstring issues\n(`black`_, `flake8`_, `mypy`_, and `docformatter`_).\nIt is recommended to run your tests in combination with :command:`checks`,\nfor example::\n\n   $ tox -e checks,py37,py38\n\n\n.. _black: https://black.rtfd.io\n.. _docformatter: https://pypi.org/project/docformatter/\n.. _flake8: https://flake8.rtfd.io\n.. _mypy: http://mypy-lang.org/\n.. _pytest: http://pytest.org/\n.. _tox: https://tox.rtfd.org/\n"
  },
  {
    "path": "docs/index.rst",
    "content": "Semver |version| -- Semantic Versioning\n=======================================\n\n.. meta::\n   :description lang=en:\n      Semantic versioning for Python\n\n.. include:: readme.rst\n\n\n.. toctree::\n   :maxdepth: 2\n   :caption: Contents\n   :hidden:\n   :numbered:\n\n   build-semver\n   install\n   usage/index\n   migration/index\n   advanced/index\n   contribute/index\n   version-policy\n   api\n\n.. toctree::\n   :maxdepth: 2\n   :caption: CLI\n   :hidden:\n\n   pysemver\n\n\n.. toctree::\n   :maxdepth: 1\n   :caption: Development\n   :hidden:\n\n   changelog\n   changelog-semver3-devel\n\n\nIndices and Tables\n==================\n\n* :ref:`genindex`\n* :ref:`modindex`\n* :ref:`search`\n"
  },
  {
    "path": "docs/install.rst",
    "content": "Installing semver\n=================\n\n.. meta::\n   :description lang=en:\n      Installing semver on the system\n\nRelease Policy\n--------------\n\nAs semver uses `Semantic Versioning`_, breaking changes are only introduced in major\nreleases (incremented ``X`` in \"X.Y.Z\").\nRefer to section :ref:`version-policy` for a general overview.\n\nFor users who want or need to stay with major 3 releases only, add the\nfollowing version restriction (:file:`setup.py`, :file:`requirements.txt`,\nor :file:`pyproject.toml`)::\n\n    semver>=3,<4\n\nThis line avoids surprises. You will get any updates within the major 3 release like 3.1.x and above. However, you will never get an update for semver 4.0.0.\n\nFor users who have to stay with major 2 releases only, use the following line::\n\n    semver>=2,<3\n\n\nWith Pip\n--------\n\n.. code-block:: bash\n   :name: install-pip\n\n    pip3 install semver\n\nIf you want to install this specific version (for example, 3.0.0), use the command :command:`pip`\nwith an URL and its version:\n\n.. parsed-literal::\n\n    pip3 install git+https://github.com/python-semver/python-semver.git@3.0.0\n\n\nWith uv\n-------\n\nFirst, install the :command:`uv` command. Refer to https://docs.astral.sh/uv/getting-started/installation/ for more information.\n\nThen use the command :command:`uv` to install the package:\n\n.. code-block:: bash\n   :name: install-uv\n\n    uv pip install semver\n\n\nLinux Distributions\n-------------------\n\n.. note::\n\n   Some Linux distributions can have outdated packages.\n   These outdated packages does not contain the latest bug fixes or new features.\n   If you need a newer package, you have these option:\n\n    * Ask the maintainer to update the package.\n    * Update the package for your favorite distribution and submit it.\n    * Use a Python virtual environment and :command:`pip install`.\n\n\nArch Linux\n^^^^^^^^^^\n\n1. Enable the community repositories first:\n\n   .. code-block:: ini\n\n      [community]\n      Include = /etc/pacman.d/mirrorlist\n\n2. Install the package::\n\n    $ pacman -Sy python-semver\n\n\nDebian\n^^^^^^\n\n1. Update the package index::\n\n    $  sudo apt-get update\n\n2. Install the package::\n\n    $ sudo apt-get install python3-semver\n\n\nFedora\n^^^^^^\n\n.. code-block:: bash\n\n    $ dnf install python3-semver\n\n\nFreeBSD\n^^^^^^^\n\n.. code-block:: bash\n\n    $ pkg install py36-semver\n\nopenSUSE\n^^^^^^^^\n\n1. Enable the ``devel:languages:python`` repository of the Open Build Service::\n\n    $ sudo zypper addrepo --refresh \\\n      --name devel_languages_python \\\n      \"https://download.opensuse.org/repositories/devel:/languages:/python/\\$releasever\"\n\n2. Install the package::\n\n    $ sudo zypper install --repo devel_languages_python python3-semver\n\n\nUbuntu\n^^^^^^\n\n1. Update the package index::\n\n    $ sudo apt-get update\n\n2. Install the package::\n\n    $ sudo apt-get install python3-semver\n\n\n.. _semantic versioning: https://semver.org/\n"
  },
  {
    "path": "docs/make.bat",
    "content": "@ECHO OFF\r\n\r\npushd %~dp0\r\n\r\nREM Command file for Sphinx documentation\r\n\r\nif \"%SPHINXBUILD%\" == \"\" (\r\n\tset SPHINXBUILD=python -msphinx\r\n)\r\nset SOURCEDIR=.\r\nset BUILDDIR=_build\r\nset SPHINXPROJ=semver\r\n\r\nif \"%1\" == \"\" goto help\r\n\r\n%SPHINXBUILD% >NUL 2>NUL\r\nif errorlevel 9009 (\r\n\techo.\r\n\techo.The Sphinx module was not found. Make sure you have Sphinx installed,\r\n\techo.then set the SPHINXBUILD environment variable to point to the full\r\n\techo.path of the 'sphinx-build' executable. Alternatively you may add the\r\n\techo.Sphinx directory to PATH.\r\n\techo.\r\n\techo.If you don't have Sphinx installed, grab it from\r\n\techo.http://sphinx-doc.org/\r\n\texit /b 1\r\n)\r\n\r\n%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\r\ngoto end\r\n\r\n:help\r\n%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\r\n\r\n:end\r\npopd\r\n"
  },
  {
    "path": "docs/migration/index.rst",
    "content": "Migrating to semver3\n====================\n\n.. meta::\n   :description lang=en:\n      Migrating from semver version 2 to version 3\n\n.. toctree::\n    :maxdepth: 1\n\n    migratetosemver3\n    replace-deprecated-functions.rst\n"
  },
  {
    "path": "docs/migration/migratetosemver3.rst",
    "content": ".. _semver2-to-3:\n\nMigrating from semver2 to semver3\n=================================\n\n.. meta::\n   :description lang=en:\n      Migrating from semver2 to semver3\n\nThis section describes the visible differences for\nusers and how your code stays compatible for semver3.\nSome changes are backward incompatible.\n\nAlthough the development team tries to make the transition\nto semver3 as smooth as possible, at some point change\nis inevitable.\n\nFor a more detailed overview of all the changes, refer\nto our :ref:`change-log`.\n\n\nUse Version instead of VersionInfo\n----------------------------------\n\nThe :class:`~semver.version.VersionInfo` has been renamed to\n:class:`~semver.version.Version` to have a more succinct name.\nAn alias has been created to preserve compatibility but\nusing the old name has been deprecated and will be removed\nin future versions.\n\nIf you still need the old version, use this line:\n\n.. code-block:: python\n\n   from semver.version import Version as VersionInfo\n\n\n\nUse semver.cli instead of semver\n--------------------------------\n\nAll functions related to CLI parsing are moved to :mod:`semver.cli`.\nIf you need such functions, like :meth:`~semver.cli.cmd_bump`,\nimport it from :mod:`semver.cli` in the future:\n\n.. code-block:: python\n\n   from semver.cli import cmd_bump\n\n\nUse semver.Version.is_valid instead of semver.Version.isvalid\n-------------------------------------------------------------\n\nThe pull request :pr:`284` introduced the method :meth:`~semver.version.Version.is_compatible`. To keep consistency, the development team\ndecided to rename the :meth:`~semver.Version.isvalid` to :meth:`~semver.Version.is_valid`.\n"
  },
  {
    "path": "docs/migration/replace-deprecated-functions.rst",
    "content": ".. _sec_replace_deprecated_functions:\n\nReplacing Deprecated Functions\n==============================\n\n.. meta::\n   :description lang=en:\n      Replacing deprecated functions\n\n.. versionchanged:: 2.10.0\n   The development team of semver has decided to deprecate certain functions on\n   the module level. The preferred way of using semver is through the\n   :class:`~semver.version.Version` class.\n\nThe deprecated functions can still be used in version 2.10.0 and above.\nHowever, in future versions of semver, the deprecated functions will be removed.\n\n\nDeprecated Module Level Functions\n---------------------------------\n\nThe following list shows the deprecated module level functions and how you can replace\nthem with code which is compatible for future versions:\n\n* :func:`semver.bump_major <semver._deprecated.bump_major>`,\n  :func:`semver.bump_minor <semver._deprecated.bump_minor>`,\n  :func:`semver.bump_patch <semver._deprecated.bump_patch>`,\n  :func:`semver.bump_prerelease <semver._deprecated.bump_prerelease>`,\n  :func:`semver.bump_build <semver._deprecated.bump_build>`\n\n  Replace them with the respective methods of the :class:`~semver.version.Version`\n  class.\n  For example, the function :func:`semver.bump_major <semver._deprecated.bump_major>` is replaced by\n  :meth:`Version.bump_major <semver.version.Version.bump_major>` and calling the ``str(versionobject)``:\n\n  .. code-block:: python\n\n     >>> s1 = semver.bump_major(\"3.4.5\")\n     >>> s2 = str(Version.parse(\"3.4.5\").bump_major())\n     >>> s1 == s2\n     True\n\n  Likewise with the other module level functions.\n\n* :func:`semver.finalize_version <semver._deprecated.finalize_version>`\n\n  Replace it with :meth:`Version.finalize_version <semver.version.Version.finalize_version>`:\n\n  .. code-block:: python\n\n     >>> s1 = semver.finalize_version('1.2.3-rc.5')\n     >>> s2 = str(semver.Version.parse('1.2.3-rc.5').finalize_version())\n     >>> s1 == s2\n     True\n\n* :func:`semver.format_version <semver._deprecated.format_version>`\n\n  Replace it with ``str(versionobject)``:\n\n  .. code-block:: python\n\n     >>> s1 = semver.format_version(5, 4, 3, 'pre.2', 'build.1')\n     >>> s2 = str(Version(5, 4, 3, 'pre.2', 'build.1'))\n     >>> s1 == s2\n     True\n\n* :func:`semver.max_ver <semver._deprecated.max_ver>`\n\n  Replace it with ``max(version1, version2, ...)`` or ``max([version1, version2, ...])`` and a ``key``:\n\n  .. code-block:: python\n\n     >>> s1 = semver.max_ver(\"1.2.3\", \"1.2.4\")\n     >>> s2 = max(\"1.2.3\", \"1.2.4\", key=Version.parse)\n     >>> s1 == s2\n     True\n\n* :func:`semver.min_ver <semver._deprecated.min_ver>`\n\n  Replace it with ``min(version1, version2, ...)`` or ``min([version1, version2, ...])`` and a ``key``:\n\n  .. code-block:: python\n\n     >>> s1 = semver.min_ver(\"1.2.3\", \"1.2.4\")\n     >>> s2 = min(\"1.2.3\", \"1.2.4\", key=Version.parse)\n     >>> s1 == s2\n     True\n\n* :func:`semver.parse <semver._deprecated.parse>`\n\n  Replace it with :meth:`Version.parse <semver.version.Version.parse>` and call\n  :meth:`Version.to_dict <semver.version.Version.to_dict>`:\n\n  .. code-block:: python\n\n     >>> v1 = semver.parse(\"1.2.3\")\n     >>> v2 = Version.parse(\"1.2.3\").to_dict()\n     >>> v1 == v2\n     True\n\n* :func:`semver.parse_version_info <semver._deprecated.parse_version_info>`\n\n  Replace it with :meth:`Version.parse <semver.version.Version.parse>`:\n\n  .. code-block:: python\n\n     >>> v1 = semver.parse_version_info(\"3.4.5\")\n     >>> v2 = Version.parse(\"3.4.5\")\n     >>> v1 == v2\n     True\n\n* :func:`semver.replace <semver._deprecated.replace>`\n\n  Replace it with :meth:`Version.replace <semver.version.Version.replace>`:\n\n  .. code-block:: python\n\n     >>> s1 = semver.replace(\"1.2.3\", major=2, patch=10)\n     >>> s2 = str(Version.parse('1.2.3').replace(major=2, patch=10))\n     >>> s1 == s2\n     True\n\n\nDeprected Version methods\n-------------------------\n\nThe following list shows the deprecated methods of the :class:`~semver.version.Version` class.\n\n* :meth:`Version.isvalid <semver.version.Version.isvalid>`\n\n   Replace it with :meth:`Version.is_valid <semver.version.Version.is_valid>`:\n\n\nDeprecated Classes\n------------------\n\n* :class:`VersionInfo <semver.version.VersionInfo>`\n\n   The class was renamed to :class:`~semver.version.Version`.\n   Don't use the old name anymore."
  },
  {
    "path": "docs/pysemver.rst",
    "content": ":orphan:\n\npysemver |version|\n==================\n\n.. meta::\n   :description lang=en:\n      Commandline tool pysemver describing all commands and options\n\nSynopsis\n--------\n\n.. _invocation:\n\n.. code:: bash\n\n   pysemver <COMMAND> <OPTION>...\n\n\nDescription\n-----------\n\nThe semver library provides a command line interface with the name\n:command:`pysemver` to make the functionality accessible for shell\nscripts. The script supports several subcommands.\n\n\nGlobal Options\n~~~~~~~~~~~~~~\n\n.. program:: pysemver\n\n.. option:: -h, --help\n\n   Display usage summary.\n\n.. option:: --version\n\n   Show program's version number and exit.\n\n\nCommands\n--------\n\n.. HINT: Sort the subcommands alphabetically\n\npysemver bump\n~~~~~~~~~~~~~\n\nBump a version.\n\n.. code:: bash\n\n   pysemver bump <PART> <VERSION>\n\n.. option:: <PART>\n\n    The part to bump. Valid strings are ``major``, ``minor``,\n    ``patch``, ``prerelease``, or ``build``. The part has the\n    following effects:\n\n    * ``major``: Raise the major part of the version and set\n      minor and patch to zero, remove prerelease and build.\n    * ``minor``: Raise the minor part of the version and set\n      patch to zero, remove prerelease and build.\n    * ``patch``: Raise the patch part of the version and\n      remove prerelease and build.\n    * ``prerelease`` Raise the prerelease of the version and\n      remove the build part.\n    * ``build``: Raise the build part.\n\n.. option:: <VERSION>\n\n    The version to bump.\n\nTo bump a version, you pass the name of the part (``major``, ``minor``,\n``patch``, ``prerelease``, or ``build``) and the version string.\nThe bumped version is printed on standard out::\n\n   $ pysemver bump major 1.2.3\n   2.0.0\n   $ pysemver bump minor 1.2.3\n   1.3.0\n\nIf you pass a version string which is not a valid semantical version,\nyou get an error message and a return code != 0::\n\n   $ pysemver bump build 1.5\n   ERROR 1.5 is not valid SemVer string\n\n\npysemver check\n~~~~~~~~~~~~~~\n\nChecks if a string is a valid semver version.\n\n.. code:: bash\n\n   pysemver check <VERSION>\n\n.. option:: <VERSION>\n\n    The version string to check.\n\nThe *error code* returned by the script indicates if the\nversion is valid (=0) or not (!=0)::\n\n    $ pysemver check 1.2.3; echo $?\n    0\n    $ pysemver check 2.1; echo $?\n    ERROR Invalid version '2.1'\n    2\n\n\npysemver compare\n~~~~~~~~~~~~~~~~\n\nCompare two versions.\n\n.. code:: bash\n\n   pysemver compare <VERSION1> <VERSION2>\n\n.. option:: <VERSION1>\n\n    First version\n\n.. option:: <VERSION2>\n\n    Second version\n\nWhen you compare two versions, the result is printed on *standard out*,\nto indicates which is the bigger version:\n\n* ``-1`` if first version is smaller than the second version,\n* ``0`` if both versions are the same,\n* ``1`` if the first version is greater than the second version.\n\n\nReturn Code\n-----------\n\nThe *return code* of the script (accessible by ``$?`` from the Bash)\nindicates if the subcommand returned successfully nor not. It is *not*\nmeant as the result of the subcommand.\n\nThe result of the subcommand is printed on the standard out channel\n(\"stdout\" or ``0``), any error messages to standard error (\"stderr\" or\n``2``).\n\nFor example, to compare two versions, the command expects two valid\nsemver versions::\n\n    $ pysemver compare 1.2.3 2.4.0\n    -1\n    $ echo $?\n    0\n\nThe return code is zero, but the result is ``-1``.\n\nHowever, if you pass invalid versions, you get this situation::\n\n    $ pysemver compare 1.2.3 2.4\n    ERROR 2.4 is not valid SemVer string\n    $ echo $?\n    2\n\nIf you use the :command:`pysemver` in your own scripts, check the\nreturn code first before you process the standard output.\n\n\nSee also\n--------\n\n:Documentation: https://python-semver.readthedocs.io/\n:Source code:   https://github.com/python-semver/python-semver\n:Bug tracker:   https://github.com/python-semver/python-semver/issues\n"
  },
  {
    "path": "docs/readme.rst",
    "content": "If you are searching for how to stay compatible\nwith semver3, refer to :ref:`semver2-to-3`.\n\n.. include:: ../README.rst\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "# Sphinx requirements file for documentation\n# Required in .readthedocs.yaml\nsphinx==7.0.1\nsphinx-argparse==0.4.0\nsphinx-autodoc-typehints==1.24.0\n"
  },
  {
    "path": "docs/usage/access-parts-of-a-version.rst",
    "content": ".. _sec.properties.parts:\n\nAccessing Parts of a Version Through Names\n==========================================\n\n.. meta::\n   :description lang=en:\n      Accessing parts of a version through names\n\nThe :class:`~semver.version.Version` class contains attributes to access the different\nparts of a version:\n\n.. code-block:: python\n\n    >>> v = Version.parse(\"3.4.5-pre.2+build.4\")\n    >>> v.major\n    3\n    >>> v.minor\n    4\n    >>> v.patch\n    5\n    >>> v.prerelease\n    'pre.2'\n    >>> v.build\n    'build.4'\n\nHowever, the attributes are read-only. You cannot change any of the above attributes.\nIf you do, you get an :py:exc:`python:AttributeError`::\n\n    >>> v.minor = 5\n    Traceback (most recent call last):\n    ...\n    AttributeError: attribute 'minor' is readonly\n\nIf you need to replace different parts of a version, refer to section :ref:`sec.replace.parts`.\n\nIn case you need the different parts of a version stepwise, iterate over the :class:`~semver.version.Version` instance::\n\n    >>> for item in Version.parse(\"3.4.5-pre.2+build.4\"):\n    ...     print(item)\n    3\n    4\n    5\n    pre.2\n    build.4\n    >>> list(Version.parse(\"3.4.5-pre.2+build.4\"))\n    [3, 4, 5, 'pre.2', 'build.4']\n"
  },
  {
    "path": "docs/usage/access-parts-through-index.rst",
    "content": ".. _sec.getitem.parts:\n\nAccessing Parts Through Index Numbers\n=====================================\n\n.. meta::\n   :description lang=en:\n      Accessing parts through index numbers\n\n.. versionadded:: 2.10.0\n\nAnother way to access parts of a version is to use an index notation. The underlying\n:class:`~semver.version.Version` object allows to access its data through\nthe magic method :meth:`~semver.version.Version.__getitem__`.\n\nFor example, the ``major`` part can be accessed by index number 0 (zero).\nLikewise the other parts:\n\n.. code-block:: python\n\n    >>> ver = Version.parse(\"10.3.2-pre.5+build.10\")\n    >>> ver[0], ver[1], ver[2], ver[3], ver[4]\n    (10, 3, 2, 'pre.5', 'build.10')\n\nIf you need more than one part at the same time, use the slice notation:\n\n.. code-block:: python\n\n    >>> ver[0:3]\n    (10, 3, 2)\n\nOr, as an alternative, you can pass a :func:`slice` object:\n\n.. code-block:: python\n\n    >>> sl = slice(0,3)\n    >>> ver[sl]\n    (10, 3, 2)\n\nNegative numbers or undefined parts raise an :py:exc:`python:IndexError` exception:\n\n.. code-block:: python\n\n    >>> ver = Version.parse(\"10.3.2\")\n    >>> ver[3]\n    Traceback (most recent call last):\n    ...\n    IndexError: Version part undefined\n    >>> ver[-2]\n    Traceback (most recent call last):\n    ...\n    IndexError: Version index cannot be negative\n"
  },
  {
    "path": "docs/usage/check-compatible-semver-version.rst",
    "content": "Checking for a Compatible Semver Version\n========================================\n\n.. meta::\n   :description lang=en:\n      Check for a compatible semver version\n\nTo check if a *change* from a semver version ``a`` to a semver\nversion ``b`` is *compatible* according to semver rule, use the method\n:meth:`~semver.version.Version.is_compatible`.\n\nThe expression ``a.is_compatible(b) is True`` if one of the following\nstatements is true:\n\n* both versions are equal, or\n* both majors are equal and higher than 0. The same applies for both\n  minor parts. Both pre-releases are equal, or\n* both majors are equal and higher than 0. The minor of ``b``'s\n  minor version is higher then ``a``'s. Both pre-releases are equal.\n\nIn all other cases, the result is false.\n\nKeep in mind, the method *does not* check patches!\n\n\n* Two different majors:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 1, 1)\n      >>> b = Version(2, 0, 0)\n      >>> a.is_compatible(b)\n      False\n      >>> b.is_compatible(a)\n      False\n\n* Two different minors:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 1, 0) \n      >>> b = Version(1, 0, 0)\n      >>> a.is_compatible(b)\n      False\n      >>> b.is_compatible(a)\n      True\n\n* The same two majors and minors:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 1, 1) \n      >>> b = Version(1, 1, 0) \n      >>> a.is_compatible(b)\n      True\n      >>> b.is_compatible(a)\n      True\n\n* Release and pre-release:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 1, 1)\n      >>> b = Version(1, 0, 0,'rc1')\n      >>> a.is_compatible(b)\n      False\n      >>> b.is_compatible(a)\n      False\n\n* Different pre-releases:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 0, 0, 'rc1')\n      >>> b = Version(1, 0, 0, 'rc2')\n      >>> a.is_compatible(b)\n      False\n      >>> b.is_compatible(a)\n      False\n\n* Identical pre-releases:\n\n  .. code-block:: python\n\n      >>> a = Version(1, 0, 0,'rc1')\n      >>> b = Version(1, 0, 0,'rc1')\n      >>> a.is_compatible(b)\n      True\n\n* All major zero versions are incompatible with anything but itself:\n\n  .. code-block:: python\n\n      >>> Version(0, 1, 0).is_compatible(Version(0, 1, 1))\n      False\n\n      # Only identical versions are compatible for major zero versions:\n      >>> Version(0, 1, 0).is_compatible(Version(0, 1, 0))\n      True\n"
  },
  {
    "path": "docs/usage/check-valid-semver-version.rst",
    "content": "Checking for a Valid Semver Version\n===================================\n\n.. meta::\n   :description lang=en:\n      Checking for a valid semver version\n\nIf you need to check a string if it is a valid semver version, use the\nclassmethod :meth:`~semver.version.Version.is_valid`:\n\n.. code-block:: python\n\n    >>> Version.is_valid(\"1.0.0\")\n    True\n    >>> Version.is_valid(\"invalid\")\n    False\n"
  },
  {
    "path": "docs/usage/compare-versions-through-expression.rst",
    "content": "Comparing Versions through an Expression\n========================================\n\n.. meta::\n   :description lang=en:\n      Comparing versions through an expression\n\nIf you need a more fine-grained approach of comparing two versions,\nuse the :meth:`~semver.version.Version.match` function. It expects two arguments:\n\n1. a version string\n2. a match expression\n\nCurrently, the match expression supports the following operators:\n\n* ``<`` smaller than\n* ``>`` greater than\n* ``>=`` greater or equal than\n* ``<=`` smaller or equal than\n* ``==`` equal\n* ``!=`` not equal\n\nThat gives you the following possibilities to express your condition:\n\n.. code-block:: python\n\n    >>> Version.parse(\"2.0.0\").match(\">=1.0.0\")\n    True\n    >>> Version.parse(\"1.0.0\").match(\">1.0.0\")\n    False\n\nIf no operator is specified, the match expression is interpreted as a\nversion to be compared for equality. This allows handling the common\ncase of version compatibility checking through either an exact version\nor a match expression very easy to implement, as the same code will\nhandle both cases:\n\n.. code-block:: python\n\n    >>> Version.parse(\"2.0.0\").match(\"2.0.0\")\n    True\n    >>> Version.parse(\"1.0.0\").match(\"3.5.1\")\n    False\n"
  },
  {
    "path": "docs/usage/compare-versions.rst",
    "content": "Comparing Versions\n==================\n\n.. meta::\n   :description lang=en:\n      Comparing versions with semver.compare and the Version class\n\nTo compare two versions depends on your type:\n\n* **Two strings**\n\n  Use :func:`semver.compare <semver._deprecated.compare>`::\n\n    >>> semver.compare(\"1.0.0\", \"2.0.0\")\n    -1\n    >>> semver.compare(\"2.0.0\", \"1.0.0\")\n    1\n    >>> semver.compare(\"2.0.0\", \"2.0.0\")\n    0\n\n  The return value is negative if ``version1 < version2``, zero if\n  ``version1 == version2`` and strictly positive if ``version1 > version2``.\n\n* **Two** :class:`~semver.version.Version` **instances**\n\n  Use the specific operator. Currently, the operators ``<``,\n  ``<=``, ``>``, ``>=``, ``==``, and ``!=`` are supported::\n\n    >>> v1 = Version.parse(\"3.4.5\")\n    >>> v2 = Version.parse(\"3.5.1\")\n    >>> v1 < v2\n    True\n    >>> v1 > v2\n    False\n\n* **A** :class:`~semver.version.Version` **type and a** :func:`tuple` **or** :func:`list`\n\n  Use the operator as with two :class:`~semver.version.Version` types::\n\n    >>> v = Version.parse(\"3.4.5\")\n    >>> v > (1, 0)\n    True\n    >>> v < [3, 5]\n    True\n\n  The opposite does also work::\n\n    >>> (1, 0) < v\n    True\n    >>> [3, 5] > v\n    True\n\n* **A** :class:`~semver.version.Version` **type and a** :func:`str`\n\n  You can use also raw strings to compare::\n\n    >>> v > \"1.0.0\"\n    True\n    >>> v < \"3.5.0\"\n    True\n\n  The opposite does also work::\n\n    >>> \"1.0.0\" < v\n    True\n    >>> \"3.5.0\" > v\n    True\n\n  However, if you compare incomplete strings, you get a :py:exc:`python:ValueError` exception::\n\n    >>> v > \"1.0\"\n    Traceback (most recent call last):\n    ...\n    ValueError: 1.0 is not valid SemVer string\n\n* **A** :class:`~semver.version.Version` **type and a** :func:`dict`\n\n  You can also use a dictionary. In contrast to strings, you can have an \"incomplete\"\n  version (as the other parts are set to zero)::\n\n   >>> v > dict(major=1)\n   True\n\n  The opposite does also work::\n\n   >>> dict(major=1) < v\n   True\n\n  If the dictionary contains unknown keys, you get a :py:exc:`python:TypeError` exception::\n\n    >>> v > dict(major=1, unknown=42)\n    Traceback (most recent call last):\n    ...\n    TypeError: ... got an unexpected keyword argument 'unknown'\n\n\nOther types cannot be compared.\n\nIf you need to convert some types into others, refer to :ref:`sec.convert.versions`.\n\nThe use of these comparison operators also implies that you can use builtin\nfunctions that leverage this capability; builtins including, but not limited to: :func:`max`, :func:`min`\n(for examples, see :ref:`sec_max_min`) and :func:`sorted`.\n"
  },
  {
    "path": "docs/usage/convert-version-into-different-types.rst",
    "content": ".. _sec.convert.versions:\n\nConverting a Version instance into Different Types\n==================================================\n\n.. meta::\n   :description lang=en:\n      Converting a version instance into different types\n\n\nSometimes it is needed to convert a :class:`~semver.version.Version` instance into\na different type. For example, for displaying or to access all parts.\n\nIt is possible to convert a :class:`~semver.version.Version` instance:\n\n* Into a string with the builtin function :func:`str`::\n\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\"))\n    '3.4.5-pre.2+build.4'\n\n* Into a dictionary with :meth:`~semver.version.Version.to_dict`::\n\n    >>> v = Version(major=3, minor=4, patch=5)\n    >>> v.to_dict()\n    {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': None, 'build': None}\n\n* Into a tuple with :meth:`~semver.version.Version.to_tuple`::\n\n    >>> v = Version(major=5, minor=4, patch=2)\n    >>> v.to_tuple()\n    (5, 4, 2, None, None)\n"
  },
  {
    "path": "docs/usage/create-a-version.rst",
    "content": "Creating a Version\n==================\n\n.. meta::\n   :description lang=en:\n      Creating a version using different methods\n\n.. versionchanged:: 3.0.0\n\n  The former :class:`~semver.version.VersionInfo` class\n  has been renamed to :class:`~semver.version.Version`.\n\nThe preferred way to create a new version is with the class\n:class:`~semver.version.Version`.\n\n.. note::\n\n   In the previous major release semver 2 it was possible to\n   create a version with module level functions.\n   However, module level functions are marked as *deprecated*\n   since version 2.x.y now.\n   These functions will be removed.\n   For details, see the sections :ref:`sec_replace_deprecated_functions`\n   and :ref:`sec_display_deprecation_warnings`.\n\nA :class:`~semver.version.Version` instance can be created in different ways:\n\n* From a Unicode string::\n\n    >>> from semver.version import Version\n    >>> Version.parse(\"3.4.5-pre.2+build.4\")\n    Version(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')\n    >>> Version.parse(u\"5.3.1\")\n    Version(major=5, minor=3, patch=1, prerelease=None, build=None)\n\n* From a byte string::\n\n    >>> Version.parse(b\"2.3.4\")\n    Version(major=2, minor=3, patch=4, prerelease=None, build=None)\n\n* From individual parts by a dictionary::\n\n    >>> d = {'major': 3, 'minor': 4, 'patch': 5,  'prerelease': 'pre.2', 'build': 'build.4'}\n    >>> Version(**d)\n    Version(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')\n\n  Keep in mind, the ``major``, ``minor``, ``patch`` parts has to\n  be positive integers or strings, otherwise a :py:exc:`python:ValueError` is raised:\n\n      >>> d = {'major': -3, 'minor': 4, 'patch': 5,  'prerelease': 'pre.2', 'build': 'build.4'}\n      >>> Version(**d)\n      Traceback (most recent call last):\n      ...\n      ValueError: 'major' is negative. A version can only be positive.\n\n  As a minimum requirement, your dictionary needs at least the ``major``\n  key, others can be omitted. You get a :py:exc:`python:TypeError` if your\n  dictionary contains invalid keys.\n  Only the keys ``major``, ``minor``, ``patch``, ``prerelease``, and ``build``\n  are allowed.\n\n* From a tuple::\n\n    >>> t = (3, 5, 6)\n    >>> Version(*t)\n    Version(major=3, minor=5, patch=6, prerelease=None, build=None)\n\n  You can pass either an integer or a string for ``major``, ``minor``, or\n  ``patch``::\n\n    >>> Version(\"3\", \"5\", 6)\n    Version(major=3, minor=5, patch=6, prerelease=None, build=None)\n\nThe old, deprecated module level functions are still available but\nusing them are discoraged. They are available to convert old code\nto semver3.\n\nIf you need them, they return different builtin objects (string and dictionary).\nKeep in mind, once you have converted a version into a string or dictionary,\nit's an ordinary builtin object. It's not a special version object like\nthe :class:`~semver.version.Version` class anymore.\n\nDepending on your use case, the following methods are available:\n\n* From individual version parts into a string\n\n  In some cases you only need a string from your version data::\n\n    >>> semver.format_version(3, 4, 5, 'pre.2', 'build.4')\n    '3.4.5-pre.2+build.4'\n\n* From a string into a dictionary\n\n  To access individual parts, you can use the function :func:`~semver._deprecated.parse`::\n\n    >>> semver.parse(\"3.4.5-pre.2+build.4\")\n    {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': 'pre.2', 'build': 'build.4'}\n\n  If you pass an invalid version string you will get a :py:exc:`python:ValueError`::\n\n    >>> semver.parse(\"1.2\")\n    Traceback (most recent call last):\n    ...\n    ValueError: 1.2 is not valid SemVer string\n"
  },
  {
    "path": "docs/usage/determine-version-equality.rst",
    "content": "Determining Version Equality\n============================\n\n.. meta::\n   :description lang=en:\n      Determining verison equality\n\nVersion equality means for semver, that major, minor, patch, and prerelease\nparts are equal in both versions you compare. The build part is ignored.\nFor example::\n\n    >>> v = Version.parse(\"1.2.3-rc4+1e4664d\")\n    >>> v == \"1.2.3-rc4+dedbeef\"\n    True\n\nThis also applies when a :class:`Version <semver.version.Version>` is a member of a set, or a\ndictionary key::\n\n    >>> d = {}\n    >>> v1 = Version.parse(\"1.2.3-rc4+1e4664d\")\n    >>> v2 = Version.parse(\"1.2.3-rc4+dedbeef\")\n    >>> d[v1] = 1\n    >>> d[v2]\n    1\n    >>> s = set()\n    >>> s.add(v1)\n    >>> v2 in s\n    True\n\n"
  },
  {
    "path": "docs/usage/get-min-and-max-of-multiple-versions.rst",
    "content": ".. _sec_max_min:\n\nGetting Minimum and Maximum of Multiple Versions\n================================================\n\n.. meta::\n   :description lang=en:\n      Getting minimum and maximum of multiple versions\n\n.. versionchanged:: 2.10.2\n   The functions :func:`semver.max_ver` and :func:`semver.min_ver` are deprecated in\n   favor of their builtin counterparts :func:`max` and :func:`min`.\n\nSince :class:`~semver.version.Version` implements\n:meth:`~semver.version.Version.__gt__` and\n:meth:`~semver.version.Version.__lt__`, it can be used with builtins requiring:\n\n.. code-block:: python\n\n    >>> max([Version(0, 1, 0), Version(0, 2, 0), Version(0, 1, 3)])\n    Version(major=0, minor=2, patch=0, prerelease=None, build=None)\n    >>> min([Version(0, 1, 0), Version(0, 2, 0), Version(0, 1, 3)])\n    Version(major=0, minor=1, patch=0, prerelease=None, build=None)\n\nIncidentally, using :func:`map`, you can get the min or max version of any number of versions of the same type\n(convertible to :class:`~semver.version.Version`).\n\nFor example, here are the maximum and minimum versions of a list of version strings:\n\n.. code-block:: python\n\n    >>> max(['1.1.0', '1.2.0', '2.1.0', '0.5.10', '0.4.99'], key=Version.parse)\n    '2.1.0'\n    >>> min(['1.1.0', '1.2.0', '2.1.0', '0.5.10', '0.4.99'], key=Version.parse)\n    '0.4.99'\n\nAnd the same can be done with tuples:\n\n.. code-block:: python\n\n    >>> max(map(lambda v: Version(*v), [(1, 1, 0), (1, 2, 0), (2, 1, 0), (0, 5, 10), (0, 4, 99)])).to_tuple()\n    (2, 1, 0, None, None)\n    >>> min(map(lambda v: Version(*v), [(1, 1, 0), (1, 2, 0), (2, 1, 0), (0, 5, 10), (0, 4, 99)])).to_tuple()\n    (0, 4, 99, None, None)\n\nFor dictionaries, it is very similar to finding the max version tuple: see :ref:`sec.convert.versions`.\n"
  },
  {
    "path": "docs/usage/increase-parts-of-a-version_prereleases.rst",
    "content": ".. _increase-parts-of-a-version:\n\nIncreasing Parts of a Version Taking into Account Prereleases\n=============================================================\n\n.. versionadded:: 2.10.0\n   Added :meth:`~semver.version.Version.next_version`.\n\nIf you want to raise your version and take prereleases into account,\nthe function :meth:`~semver.version.Version.next_version`\nwould perhaps a better fit.\n\n\n.. code-block:: python\n\n    >>> v = Version.parse(\"3.4.5-pre.2+build.4\")\n    >>> str(v.next_version(part=\"prerelease\"))\n    '3.4.5-pre.3'\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").next_version(part=\"patch\"))\n    '3.4.5'\n    >>> str(Version.parse(\"3.4.5+build.4\").next_version(part=\"patch\"))\n    '3.4.5'\n    >>> str(Version.parse(\"0.1.4\").next_version(\"prerelease\"))\n    '0.1.5-rc.1'\n"
  },
  {
    "path": "docs/usage/index.rst",
    "content": "Using semver\n============\n\n.. toctree::\n\n   semver_org-version\n   semver-version\n   create-a-version\n   parse-version-string\n   check-valid-semver-version\n   check-compatible-semver-version\n   access-parts-of-a-version\n   access-parts-through-index\n   replace-parts-of-a-version\n   convert-version-into-different-types\n   raise-parts-of-a-version\n   increase-parts-of-a-version_prereleases\n   compare-versions\n   determine-version-equality\n   compare-versions-through-expression\n   get-min-and-max-of-multiple-versions\n"
  },
  {
    "path": "docs/usage/parse-version-string.rst",
    "content": "Parsing a Version String\n========================\n\n\"Parsing\" in this context means to identify the different parts in a string.\nUse the function :meth:`~semver.version.Version.parse`::\n\n    >>> Version.parse(\"3.4.5-pre.2+build.4\")\n    Version(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')\n\nSet the parameter ``optional_minor_and_patch=True`` to allow optional\nminor and patch parts. Optional parts are set to zero. By default (False), the\nversion string to parse has to follow the semver specification::\n\n    >>> Version.parse(\"1.2\", optional_minor_and_patch=True)\n    Version(major=1, minor=2, patch=0, prerelease=None, build=None)\n"
  },
  {
    "path": "docs/usage/raise-parts-of-a-version.rst",
    "content": "Raising Parts of a Version\n==========================\n\n.. note::\n\n   Keep in mind, by default, \"raising\" the pre-release for a version without an existing\n   prerelease part, only will make your complete version *lower* than before.\n\n   For example, having version ``1.0.0`` and raising the pre-release\n   will lead to ``1.0.0-rc.1``, but ``1.0.0-rc.1`` is smaller than ``1.0.0``.\n\n   To avoid this, set `bump_when_empty=True` in the\n   :meth:`~semver.version.Version.bump_prerelease` method, or by using the\n   method :meth:`~semver.version.Version.next_version`\n   in section :ref:`increase-parts-of-a-version`.\n\n\nThe ``semver`` module contains the following functions to raise parts of\na version:\n\n* :meth:`~semver.version.Version.bump_major`: raises the major part and set all other parts to\n  zero. Set ``prerelease`` and ``build`` to ``None``.\n* :meth:`~semver.version.Version.bump_minor`: raises the minor part and sets ``patch`` to zero.\n  Set ``prerelease`` and ``build`` to ``None``.\n* :meth:`~semver.version.Version.bump_patch`: raises the patch part. Set ``prerelease`` and\n  ``build`` to ``None``.\n* :meth:`~semver.version.Version.bump_prerelease`: raises the prerelease part and set\n  ``build`` to ``None``.\n* :meth:`~semver.version.Version.bump_build`: raises the build part.\n\n\n.. code-block:: python\n\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").bump_major())\n    '4.0.0'\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").bump_minor())\n    '3.5.0'\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").bump_patch())\n    '3.4.6'\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").bump_prerelease())\n    '3.4.5-pre.3'\n    >>> str(Version.parse(\"3.4.5-pre.2+build.4\").bump_build())\n    '3.4.5-pre.2+build.5'\n\nLikewise the module level functions :func:`semver.bump_major`.\n\nFor the methods :meth:`~semver.version.Version.bump_prerelease`\nand :meth:`~semver.version.Version.bump_build` it's possible to pass an empty string or ``None``.\nHowever, it gives different results:\n\n.. code-block:: python\n\n    >>> str(Version.parse(\"3.4.5\").bump_prerelease(''))\n    '3.4.5-1'\n    >>> str(Version.parse(\"3.4.5\").bump_prerelease(None))\n    '3.4.5-rc.1'\n\nAn empty string removes any prefix whereas ``None`` is the same as calling\nthe method without any argument.\n\nIf you already have a prerelease, the argument for the method\nis not taken into account:\n\n.. code-block:: python\n\n    >>> str(Version.parse(\"3.4.5-rc.1\").bump_prerelease(None))\n    '3.4.5-rc.2'\n    >>> str(Version.parse(\"3.4.5-rc.1\").bump_prerelease(''))\n    '3.4.5-rc.2'\n\nTo ensure correct ordering, we append `.0` to the last prerelease identifier\nif it's not numeric. This prevents cases where `rc9` would incorrectly sort\nlower than `rc10` (non-numeric identifiers are compared alphabetically):\n\n.. code-block:: python\n\n    >>> str(Version.parse(\"3.4.5-rc9\").bump_prerelease())\n    '3.4.5-rc9.0'\n    >>> str(Version.parse(\"3.4.5-rc.9\").bump_prerelease())\n    '3.4.5-rc.10'\n\n"
  },
  {
    "path": "docs/usage/replace-parts-of-a-version.rst",
    "content": ".. _sec.replace.parts:\n\nReplacing Parts of a Version\n============================\n\nIf you want to replace different parts of a version, but leave other parts\nunmodified, use the function :meth:`~semver.version.Version.replace`:\n\n   >>> version = semver.Version.parse(\"1.4.5-pre.1+build.6\")\n   >>> version.replace(major=2, minor=2)\n   Version(major=2, minor=2, patch=5, prerelease='pre.1', build='build.6')\n\nIf you pass invalid keys you get an exception::\n\n   >>> version = semver.Version.parse(\"1.4.5-pre.1+build.6\")\n   >>> version.replace(invalidkey=2)\n   Traceback (most recent call last):\n   ...\n   TypeError: replace() got 1 unexpected keyword argument(s): invalidkey\n"
  },
  {
    "path": "docs/usage/semver-version.rst",
    "content": "Getting the Version of semver\n=============================\n\nTo know the version of semver itself, use the following construct::\n\n   >>> semver.__version__\n   '3.0.4'\n"
  },
  {
    "path": "docs/usage/semver_org-version.rst",
    "content": "Getting the Implemented semver.org Version\n==========================================\n\nThe semver.org page is the authoritative specification of how semantic\nversioning is defined.\nTo know which version of semver.org is implemented in the semver library,\nuse the following constant::\n\n   >>> semver.SEMVER_SPEC_VERSION\n   '2.0.0'\n"
  },
  {
    "path": "docs/version-policy.rst",
    "content": ".. _version-policy:\n\nVersion Policy\n==============\n\n.. |MAINT| replace:: ``maint/v2``\n.. _MAINT: https://github.com/python-semver/python-semver/tree/maint/v2\n.. |CHANGELOG| replace:: ``Changelog``\n.. _CHANGELOG: https://github.com/python-semver/python-semver/blob/maint/v2/CHANGELOG.rst\n\nThe move from v2 to v3 introduced many changes and deprecated module functions.\nThe main functionality is handled by the :class:`~semver.version.Version` class\nnow. Find more information in the section :ref:`semver2-to-3`.\n\n\nsemver Version 2\n----------------\n\nActive development of major version 2 has stopped. No new features nor\nbackports will be integrated.\nWe recommend to upgrade your workflow to Python 3 to gain support,\nbugfixes, and new features.\n\nIf you still need this old version, use the  |MAINT|_ branch. There you\ncan look for the |CHANGELOG|_ if you need some details about the history.\n\n\nsemver Version 3\n----------------\n\nWe will not intentionally make breaking changes in minor releases of V3.\n\nMethods marked as ``deprecated`` raise a warning message when used from the\n:py:mod:`python:warnings` module.\nRefer to section :ref:`sec_display_deprecation_warnings` to get more information about how to customize it.\nCheck section :ref:`sec_replace_deprecated_functions` to make your code\nready for future major releases.\n\n\nsemver Version 3 and beyond\n---------------------------\n\nMethods that were marked as deprecated will be very likely be removed.\n\n\nSupport for Python versions\n---------------------------\n\nThis project will drop support for a Python version when the\nfollowing conditions are met:\n\n* The Python version has reached `EOL <https://devguide.python.org/versions/>`_.\n"
  },
  {
    "path": "pyproject.toml",
    "content": "#\n#\n# See also https://setuptools.pypa.io/en/latest/userguide/pyproject_config.html\n#\n# General idea taken from\n# https://godatadriven.com/blog/a-practical-guide-to-setuptools-and-pyproject-toml/\n\n[build-system]\nrequires = [\n  \"setuptools>=61\",\n  # \"setuptools-scm>=8\",\n]\nbuild-backend = \"setuptools.build_meta\"\n\n\n[project]\nrequires-python = \">=3.7\"\nname = \"semver\"\ndescription = \"Python helper for Semantic Versioning (https://semver.org)\"\nreadme = \"README.rst\"\n# PEP 639\n# licence = \"BSD-2-Clause\"\n# readme.content-type = \"text/x-rst\"\nlicense = { file = \"LICENSE.txt\" }\nauthors = [\n  {name = \"Kostiantyn Rybnikov\", email = \"k-bx@k-bx.com\"},\n  {name = \"Tom Schraitle\", email = \"toms@suse.de\"},\n]\nmaintainers = [\n  {name = \"Tom Schraitle\", email = \"toms@suse.de\"},\n  {name = \"Sebastien Celles\", email = \"s.celles@gmail.com\"},\n]\ndynamic = [\"version\",]\nclassifiers = [\n    \"Environment :: Web Environment\",\n    \"Intended Audience :: Developers\",\n    \"Development Status :: 5 - Production/Stable\",\n    \"License :: OSI Approved :: BSD License\",\n    \"Operating System :: OS Independent\",\n    \"Programming Language :: Python :: 3\",\n    \"Programming Language :: Python :: 3.7\",\n    \"Programming Language :: Python :: 3.8\",\n    \"Programming Language :: Python :: 3.9\",\n    \"Programming Language :: Python :: 3.10\",\n    \"Programming Language :: Python :: 3.11\",\n    \"Programming Language :: Python :: 3.12\",\n    \"Programming Language :: Python :: 3.13\",\n    \"Programming Language :: Python :: 3.14\",\n    \"Topic :: Software Development :: Libraries :: Python Modules\",\n]\n\n\n[project.urls]\n\"GitHub Homepage\" = \"https://github.com/python-semver/python-semver\"\nChangelog = \"https://python-semver.readthedocs.io/en/latest/changelog.html\"\nDocumentation = \"https://python-semver.rtfd.io\"\nReleases = \"https://github.com/python-semver/python-semver/releases\"\n\"Bug Tracker\" = \"https://github.com/python-semver/python-semver/issues\"\n\n\n[project.scripts]\npysemver = \"semver.cli:main\"\n\n\n[dependency-groups]\n# See https://github.com/astral-sh/uv/issues/5632\n# See https://peps.python.org/pep-0735/\ntyping = [\n  \"mypy\",\n  \"pyright\",\n]\nformatting = [\n  \"black\",\n  \"ruff\",\n  \"docformatter\",\n]\ntest = [\n  \"tox\",\n  \"pytest\",\n  \"pytest-cov\",\n  \n]\npublish = [\n  \"twine\",\n  # pyproject-build is required for building the package\n  \"build\",\n]\nchangelog = [\n  \"towncrier\",\n]\ndocs = [\n  # Required in .readthedocs.yaml\n  \"sphinx\",  # ==7.0.1\n  \"sphinx-argparse\",  # ==0.4.0\n  \"sphinx-autodoc-typehints\",  # ==1.24.0\n  \"restview\",\n]\ndevel = [\n  {include-group = \"typing\"},\n  {include-group = \"formatting\"},\n  {include-group = \"test\"},\n  {include-group = \"changelog\"},\n  {include-group = \"docs\"},\n  {include-group = \"publish\"},\n]\n# Only needed when using GitHub Actions\ngh-action = [\n  {include-group = \"devel\"},\n  \"tox-gh-actions\",\n]\n\n# --- Setuptools configuration ---\n[tool.setuptools]\npackage-dir = {\"\" = \"src\"}\npackage-data = { \"semver\" = [\"py.typed\"] }\ninclude-package-data = true\n\n\n[tool.setuptools.packages.find]\n# Is that still necessary?\n# list of folders that contain the packages ([\".\"] by default)\nwhere = [\"src\"]\n\n\n[tool.setuptools.dynamic]\nversion = {attr = \"semver.__about__.__version__\"}\n\n\n# ---------------------------------\n[tool.setuptools_scm]\nversion_scheme = \"post-release\"\nlocal_scheme = \"dirty-tag\"\n\n\n[tool.mypy]\n# ignore_missing_imports = true\ncheck_untyped_defs = true\nshow_error_codes = true\n# strict = true\npretty = true\n\n\n[tool.black]\nline-length = 88\ntarget-version = ['py37', 'py38', 'py39', 'py310', 'py311']\n# diff = true\n\n\n[tool.docformatter]\nwrap-summaries = 80\nclose-quotes-on-newline = true\n# make-summary-multi-line = true\nblack = true\npre-summary-newline = true\nrecursive = true\n\n\n[tool.towncrier]\npackage = \"semver\"\npackage_dir = \"src\"\nfilename = \"CHANGELOG.rst\"\ndirectory = \"changelog.d/\"\ntitle_format = \"Version {version}\"\ntemplate = \"changelog.d/_template.rst\"\n# issue_format = \"`#{issue} <https://github.com/python-attrs/attrs/issues/{issue}>`_\"\n# issue_format = \":gh:`{issue}`\"\n\n\n[tool.towncrier.fragment.breaking]\nname = \"Breaking Changes\"\n\n[tool.towncrier.fragment.bugfix]\nname = \"Bug Fixes\"\n\n[tool.towncrier.fragment.deprecation]\nname = \"Deprecations\"\n\n[tool.towncrier.fragment.doc]\nname = \"Improved Documentation\"\n\n[tool.towncrier.fragment.feature]\nname = \"Features\"\n\n[tool.towncrier.fragment.removal]\nname = \"Removals\"\n\n[tool.towncrier.fragment.trivial]\nname = \"Trivial Changes\"\n\n[tool.towncrier.fragment.internal]\nname = \"Internal Changes\"\n"
  },
  {
    "path": "release-procedure.md",
    "content": "# Release Procedure\n\nThe following procedures gives a short overview of what steps are needed to\ncreate a new release.\n\n## Prepare your environment\n\n1. Create your API tokens:\n\n   1. From the [PyPI test server](https://test.pypi.org/manage/account/token/).\n\n   1. From the official [PyPI server](https://test.pypi.org/manage/account/token/).\n\n   1. Save both tokens it in a safe place like your password manager.\n\n1. Create a file `~/.pypirc` with file mode 0600 and the following minimal content:\n\n       # Protect the file with chmod 0600 ~/.pypirc\n       [distutils]\n       index-servers =\n            test-semver\n            semver\n\n       [test-semver]\n       repository = https://test.pypi.org/legacy/\n       username = __token__\n       password = <YOUR_TEST_API_TOKEN>\n\n       [semver]\n       repository = https://pypi.org/legacy/\n       username = __token__\n       password = <YOUR_API_TOKEN>\n\n1. Install uv as shown in Astral's [Installing uv](https://docs.astral.sh/uv/getting-started/installation/) documentation.\n\n1. Update the project's environment:\n\n       uv sync --group devel\n\n1. Activate your environment:\n\n       source .venv/bin/activate\n\n## Prepare the Release\n\n1. Create a new branch `release/<VERSION>`.\n\n1. If one or several supported **Python** versions have been removed or added, verify that the following files have been updated:\n   * `pyproject.toml` (look into the key `project.requires-python` and `project.classifiers`)\n   * `tox.ini`\n   * `.git/workflows/pythonpackage.yml`\n   * `CITATION.cff`\n\n1. Verify that:\n\n   * the version has been updated and follow <https://semver.org>:\n        * `src/semver/__about__.py`\n        * `docs/usage/semver-version.rst`\n\n   * all issues for a new release are closed: <https://github.com/python-semver/python-semver/issues>.\n\n   * all pull requests that should be included in this release are merged: <https://github.com/python-semver/python-semver/pulls>.\n\n   * continuous integration for latest build was passing:\n     <https://github.com/python-semver/python-semver/actions>.\n\n1. Add eventually new contributor(s) to [CONTRIBUTORS](https://github.com/python-semver/python-semver/blob/master/CONTRIBUTORS).\n\n1. Create the changelog:\n\n    1. Check if all changelog entries are created. If some are missing, [create them](https://python-semver.readthedocs.io/en/latest/development.html#adding-a-changelog-entry).\n\n    1. Show the new draft [CHANGELOG](https://github.com/python-semver/python-semver/blob/master/CHANGELOG.rst) entry for the latest release with:\n\n           uvx tox r -e changelog\n\n    1. Check the output. If you are not happy, update the files in the\n    `changelog.d/` directory.\n    If everything is okay, build the new `CHANGELOG` with:\n\n           uvx tox r -e changelog -- build\n\n1. Build the documentation and check the output:\n\n       uvx tox r -e docs\n\n1. Commit all changes, push, and create a pull request.\n\n\n## Create the New Release\n\n1. Ensure that long description ([README.rst](https://github.com/python-semver/python-semver/blob/master/README.rst)) can be correctly rendered by Pypi using `uvx restview -b README.rst`\n\n1. Clean up your local Git repository. Be careful,\n   as it **will remove all files** which are not\n   versioned by Git:\n\n       git clean -xfd\n\n   Before you create your distribution files, clean\n   the directory too:\n\n       rm dist/*\n\n1. Create the distribution files (wheel and source):\n\n       uvx tox r -e prepare-dist\n\n1. Upload the wheel and source to TestPyPI first:\n\n       twine upload --verbose --repository test-semver dist/*\n\n   (Normally you would do it with `uv publish`, but for some unknown reason it didn't work for me.)\n\n1. Check if everything is okay with the wheel.\n   Check also the web site `https://test.pypi.org/project/<VERSION>/`\n\n# Finish the release\n\n1. If everything looks fine, merge the pull request.\n\n1. Upload to PyPI:\n\n       $ git clean -xfd\n       $ tox r -e prepare-dist\n       $ twine upload --verbose --repository semver dist/*\n\n1. Go to https://pypi.org/project/semver/ to verify that new version is online and the page is rendered correctly.\n\n1. Create a tag:\n\n       git tag -a x.y.z\n\n   It's recommended to use the generated Tox output from the Changelog.\n\n1. Push the tag:\n\n       git push origin x.y.z\n\n1. In [GitHub Release page](https://github.com/python-semver/python-semver/release) document the new release.\n   Select the tag from the last step and copy the content of the tag description into the release description.\n\n1. Announce it in <https://github.com/python-semver/python-semver/discussions/categories/announcements>.\n\nYou're done! Celebrate!\n"
  },
  {
    "path": "setup.cfg",
    "content": "#\n# Metadata for setup.py\n#\n# See https://setuptools.rtfd.io/en/latest/userguide/declarative_config.html\n\n\n[pycodestyle]\ncount = False\nignore = E203,E701\n# E226,E302,E41\nmax-line-length = 88\nstatistics = True\nexclude =\n    src/semver/__init__.py\n    .env,\n    .eggs,\n    .tox,\n    .git,\n    docs\n"
  },
  {
    "path": "src/semver/__about__.py",
    "content": "\"\"\"\nMetadata about semver.\n\nContains information about semver's version, the implemented version\nof the semver specifictation, author, maintainers, and description.\n\n.. autodata:: __author__\n\n.. autodata:: __description__\n\n.. autodata:: __maintainer__\n\n.. autodata:: __version__\n\n.. autodata:: SEMVER_SPEC_VERSION\n\"\"\"\n\n#: Semver version\n__version__ = \"3.0.4\"\n\n#: Original semver author\n__author__ = \"Kostiantyn Rybnikov\"\n\n#: Author's email address\n__author_email__ = \"k-bx@k-bx.com\"\n\n#: Current maintainer\n__maintainer__ = [\"Sebastien Celles\", \"Tom Schraitle\"]\n\n#: Maintainer's email address\n__maintainer_email__ = \"s.celles@gmail.com\"\n\n#: Short description about semver\n__description__ = \"Python helper for Semantic Versioning (https://semver.org)\"\n\n#: Supported semver specification\nSEMVER_SPEC_VERSION = \"2.0.0\"\n"
  },
  {
    "path": "src/semver/__init__.py",
    "content": "\"\"\"\nSemver package major release 3.\n\nA Python module for semantic versioning. Simplifies comparing versions.\n\"\"\"\n\nfrom ._deprecated import (\n    bump_build,\n    bump_major,\n    bump_minor,\n    bump_patch,\n    compare,\n    bump_prerelease,\n    finalize_version,\n    format_version,\n    match,\n    max_ver,\n    min_ver,\n    parse,\n    parse_version_info,\n    replace,\n    cmd_bump,\n    cmd_compare,\n    cmd_nextver,\n    cmd_check,\n    createparser,\n    process,\n    main,\n)\nfrom .version import Version, VersionInfo\nfrom .__about__ import (\n    __version__,\n    __author__,\n    __maintainer__,\n    __author_email__,\n    __description__,\n    __maintainer_email__,\n    SEMVER_SPEC_VERSION,\n)\n\n__all__ = [\n    \"bump_build\",\n    \"bump_major\",\n    \"bump_minor\",\n    \"bump_patch\",\n    \"compare\",\n    \"bump_prerelease\",\n    \"finalize_version\",\n    \"format_version\",\n    \"match\",\n    \"max_ver\",\n    \"min_ver\",\n    \"parse\",\n    \"parse_version_info\",\n    \"replace\",\n    \"cmd_bump\",\n    \"cmd_compare\",\n    \"cmd_nextver\",\n    \"cmd_check\",\n    \"createparser\",\n    \"process\",\n    \"main\",\n    \"Version\",\n    \"VersionInfo\",\n    \"__version__\",\n    \"__author__\",\n    \"__maintainer__\",\n    \"__author_email__\",\n    \"__description__\",\n    \"__maintainer_email__\",\n    \"SEMVER_SPEC_VERSION\",\n]\n"
  },
  {
    "path": "src/semver/__main__.py",
    "content": "\"\"\"\nModule to support call with :file:`__main__.py`. Used to support the following\ncall::\n\n    $ python3 -m semver ...\n\nThis makes it also possible to \"run\" a wheel like in this command::\n\n    $ python3 semver-3*-py3-none-any.whl/semver -h\n\n\"\"\"\n\nimport os.path\nimport sys\nfrom typing import List, Optional\n\nfrom semver import cli\n\n\ndef main(cliargs: Optional[List[str]] = None) -> int:\n    if __package__ == \"\":\n        path = os.path.dirname(os.path.dirname(__file__))\n        sys.path[0:0] = [path]\n\n    return cli.main(cliargs)\n\n\nif __name__ == \"__main__\":\n    sys.exit(main(sys.argv[1:]))\n"
  },
  {
    "path": "src/semver/_deprecated.py",
    "content": "\"\"\"\nContains all deprecated functions.\n\n.. autofunction: deprecated\n\"\"\"\n\nimport inspect\nimport warnings\nfrom functools import partial, wraps\nfrom types import FrameType\nfrom typing import Type, Callable, Optional, cast\n\nfrom . import cli\nfrom .version import Version\nfrom ._types import Decorator, F\n\n\ndef deprecated(\n    func: Optional[F] = None,\n    *,\n    replace: Optional[str] = None,\n    version: Optional[str] = None,\n    remove: Optional[str] = None,\n    category: Type[Warning] = DeprecationWarning,\n) -> Decorator:\n    \"\"\"\n    Decorates a function to output a deprecation warning.\n\n    :param func: the function to decorate\n    :param replace: the function to replace (use the full qualified\n        name like ``semver.version.Version.bump_major``.\n    :param version: the first version when this function was deprecated.\n    :param category: allow you to specify the deprecation warning class\n        of your choice. By default, it's  :class:`DeprecationWarning`, but\n        you can choose :class:`PendingDeprecationWarning` or a custom class.\n    :return: decorated function which is marked as deprecated\n    \"\"\"\n\n    if func is None:\n        return partial(\n            deprecated,\n            replace=replace,\n            version=version,\n            remove=remove,\n            category=category,\n        )\n\n    @wraps(func)\n    def wrapper(*args, **kwargs) -> Callable[..., F]:\n        msg_list = [\"Function 'semver.{f}' is deprecated.\"]\n\n        if version:\n            msg_list.append(\"Deprecated since version {v}. \")\n\n        if not remove:\n            msg_list.append(\"This function will be removed in semver 3.\")\n        else:\n            msg_list.append(str(remove))\n\n        if replace:\n            msg_list.append(\"Use {r!r} instead.\")\n        else:\n            msg_list.append(\"Use the respective 'semver.Version.{r}' instead.\")\n\n        f = cast(F, func).__qualname__\n        r = replace or f\n\n        frame = cast(FrameType, cast(FrameType, inspect.currentframe()).f_back)\n\n        msg = \" \".join(msg_list)\n        warnings.warn_explicit(\n            msg.format(f=f, r=r, v=version),\n            category=category,\n            filename=inspect.getfile(frame.f_code),\n            lineno=frame.f_lineno,\n        )\n        # As recommended in the Python documentation\n        # https://docs.python.org/3/library/inspect.html#the-interpreter-stack\n        # better remove the interpreter stack:\n        del frame\n        return func(*args, **kwargs)  # type: ignore\n\n    return wrapper\n\n\n@deprecated(\n    version=\"3.0.0\",\n    remove=\"Still under investigation, see #258.\",\n    category=PendingDeprecationWarning,\n)\ndef compare(ver1: str, ver2: str) -> int:\n    \"\"\"\n    Compare two versions strings.\n\n    .. deprecated:: 3.0.0\n       The situation of this function is unclear and it might\n       disappear in the future.\n       If possible, use :meth:`semver.version.Version.compare`.\n       See :gh:`258` for details.\n\n    :param ver1: first version string\n    :param ver2: second version string\n    :return: The return value is negative if ver1 < ver2,\n             zero if ver1 == ver2 and strictly positive if ver1 > ver2\n\n    >>> semver.compare(\"1.0.0\", \"2.0.0\")\n    -1\n    >>> semver.compare(\"2.0.0\", \"1.0.0\")\n    1\n    >>> semver.compare(\"2.0.0\", \"2.0.0\")\n    0\n    \"\"\"\n    return Version.parse(ver1).compare(ver2)\n\n\n@deprecated(version=\"2.10.0\")\ndef parse(version):\n    \"\"\"\n    Parse version to major, minor, patch, pre-release, build parts.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.parse` instead.\n\n    :param version: version string\n    :return: dictionary with the keys 'build', 'major', 'minor', 'patch',\n             and 'prerelease'. The prerelease or build keys can be None\n             if not provided\n    :rtype: dict\n\n    >>> ver = semver.parse('3.4.5-pre.2+build.4')\n    >>> ver['major']\n    3\n    >>> ver['minor']\n    4\n    >>> ver['patch']\n    5\n    >>> ver['prerelease']\n    'pre.2'\n    >>> ver['build']\n    'build.4'\n    \"\"\"\n    return Version.parse(version).to_dict()\n\n\n@deprecated(replace=\"semver.version.Version.parse\", version=\"2.10.0\")\ndef parse_version_info(version):\n    \"\"\"\n    Parse version string to a Version instance.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.parse` instead.\n    .. versionadded:: 2.7.2\n       Added :func:`semver.parse_version_info`\n\n    :param version: version string\n    :return: a :class:`VersionInfo` instance\n\n    >>> version_info = semver.Version.parse(\"3.4.5-pre.2+build.4\")\n    >>> version_info.major\n    3\n    >>> version_info.minor\n    4\n    >>> version_info.patch\n    5\n    >>> version_info.prerelease\n    'pre.2'\n    >>> version_info.build\n    'build.4'\n    \"\"\"\n    return Version.parse(version)\n\n\n@deprecated(version=\"2.10.0\")\ndef match(version, match_expr):\n    \"\"\"\n    Compare two versions strings through a comparison.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.match` instead.\n\n    :param str version: a version string\n    :param str match_expr: operator and version; valid operators are\n          <   smaller than\n          >   greater than\n          >=  greator or equal than\n          <=  smaller or equal than\n          ==  equal\n          !=  not equal\n    :return: True if the expression matches the version, otherwise False\n    :rtype: bool\n\n    >>> semver.match(\"2.0.0\", \">=1.0.0\")\n    True\n    >>> semver.match(\"1.0.0\", \">1.0.0\")\n    False\n    \"\"\"\n    ver = Version.parse(version)\n    return ver.match(match_expr)\n\n\n@deprecated(replace=\"max\", version=\"2.10.2\")\ndef max_ver(ver1, ver2):\n    \"\"\"\n    Returns the greater version of two versions strings.\n\n    .. deprecated:: 2.10.2\n       Use :func:`max` instead.\n\n    :param ver1: version string 1\n    :param ver2: version string 2\n    :return: the greater version of the two\n    :rtype: :class:`Version`\n\n    >>> semver.max_ver(\"1.0.0\", \"2.0.0\")\n    '2.0.0'\n    \"\"\"\n    return str(max(ver1, ver2, key=Version.parse))\n\n\n@deprecated(replace=\"min\", version=\"2.10.2\")\ndef min_ver(ver1, ver2):\n    \"\"\"\n    Returns the smaller version of two versions strings.\n\n    .. deprecated:: 2.10.2\n       Use Use :func:`min` instead.\n\n    :param ver1: version string 1\n    :param ver2: version string 2\n    :return: the smaller version of the two\n    :rtype: :class:`Version`\n\n    >>> semver.min_ver(\"1.0.0\", \"2.0.0\")\n    '1.0.0'\n    \"\"\"\n    return str(min(ver1, ver2, key=Version.parse))\n\n\n@deprecated(replace=\"str(versionobject)\", version=\"2.10.0\")\ndef format_version(major, minor, patch, prerelease=None, build=None):\n    \"\"\"\n    Format a version string according to the Semantic Versioning specification.\n\n    .. deprecated:: 2.10.0\n       Use ``str(Version(VERSION)`` instead.\n\n    :param int major: the required major part of a version\n    :param int minor: the required minor part of a version\n    :param int patch: the required patch part of a version\n    :param str prerelease: the optional prerelease part of a version\n    :param str build: the optional build part of a version\n    :return: the formatted string\n    :rtype: str\n\n    >>> semver.format_version(3, 4, 5, 'pre.2', 'build.4')\n    '3.4.5-pre.2+build.4'\n    \"\"\"\n    return str(Version(major, minor, patch, prerelease, build))\n\n\n@deprecated(version=\"2.10.0\")\ndef bump_major(version):\n    \"\"\"\n    Raise the major part of the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.bump_major` instead.\n\n    :param: version string\n    :return: the raised version string\n    :rtype: str\n\n    >>> semver.bump_major(\"3.4.5\")\n    '4.0.0'\n    \"\"\"\n    return str(Version.parse(version).bump_major())\n\n\n@deprecated(version=\"2.10.0\")\ndef bump_minor(version):\n    \"\"\"\n    Raise the minor part of the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.bump_minor` instead.\n\n    :param: version string\n    :return: the raised version string\n    :rtype: str\n\n    >>> semver.bump_minor(\"3.4.5\")\n    '3.5.0'\n    \"\"\"\n    return str(Version.parse(version).bump_minor())\n\n\n@deprecated(version=\"2.10.0\")\ndef bump_patch(version):\n    \"\"\"\n    Raise the patch part of the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.bump_patch` instead.\n\n    :param: version string\n    :return: the raised version string\n    :rtype: str\n\n    >>> semver.bump_patch(\"3.4.5\")\n    '3.4.6'\n    \"\"\"\n    return str(Version.parse(version).bump_patch())\n\n\n@deprecated(version=\"2.10.0\")\ndef bump_prerelease(version, token=\"rc\"):\n    \"\"\"\n    Raise the prerelease part of the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.bump_prerelease` instead.\n\n    :param version: version string\n    :param token: defaults to 'rc'\n    :return: the raised version string\n    :rtype: str\n\n    >>> semver.bump_prerelease('3.4.5', 'dev')\n    '3.4.5-dev.1'\n    \"\"\"\n    return str(Version.parse(version).bump_prerelease(token))\n\n\n@deprecated(version=\"2.10.0\")\ndef bump_build(version, token=\"build\"):\n    \"\"\"\n    Raise the build part of the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.bump_build` instead.\n\n    :param version: version string\n    :param token: defaults to 'build'\n    :return: the raised version string\n    :rtype: str\n\n    >>> semver.bump_build('3.4.5-rc.1+build.9')\n    '3.4.5-rc.1+build.10'\n    \"\"\"\n    return str(Version.parse(version).bump_build(token))\n\n\n@deprecated(version=\"2.10.0\")\ndef finalize_version(version):\n    \"\"\"\n    Remove any prerelease and build metadata from the version string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.finalize_version` instead.\n\n    .. versionadded:: 2.7.9\n       Added :func:`finalize_version`\n\n    :param version: version string\n    :return: the finalized version string\n    :rtype: str\n\n    >>> semver.finalize_version('1.2.3-rc.5')\n    '1.2.3'\n    \"\"\"\n    verinfo = Version.parse(version)\n    return str(verinfo.finalize_version())\n\n\n@deprecated(version=\"2.10.0\")\ndef replace(version, **parts):\n    \"\"\"\n    Replace one or more parts of a version and return the new string.\n\n    .. deprecated:: 2.10.0\n       Use :meth:`~semver.version.Version.replace` instead.\n    .. versionadded:: 2.9.0\n       Added :func:`replace`\n\n    :param version: the version string to replace\n    :param parts: the parts to be updated. Valid keys are:\n      ``major``, ``minor``, ``patch``, ``prerelease``, or ``build``\n    :return: the replaced version string\n    :raises TypeError: if ``parts`` contains invalid keys\n\n    >>> import semver\n    >>> semver.replace(\"1.2.3\", major=2, patch=10)\n    '2.2.10'\n    \"\"\"\n    return str(Version.parse(version).replace(**parts))\n\n\n# CLI\ncmd_bump = deprecated(cli.cmd_bump, replace=\"semver.cli.cmd_bump\", version=\"3.0.0\")\ncmd_check = deprecated(cli.cmd_check, replace=\"semver.cli.cmd_check\", version=\"3.0.0\")\ncmd_compare = deprecated(\n    cli.cmd_compare, replace=\"semver.cli.cmd_compare\", version=\"3.0.0\"\n)\ncmd_nextver = deprecated(\n    cli.cmd_nextver, replace=\"semver.cli.cmd_nextver\", version=\"3.0.0\"\n)\ncreateparser = deprecated(\n    cli.createparser, replace=\"semver.cli.createparser\", version=\"3.0.0\"\n)\nprocess = deprecated(cli.process, replace=\"semver.cli.process\", version=\"3.0.0\")\nmain = deprecated(cli.main, replace=\"semver.cli.main\", version=\"3.0.0\")\n"
  },
  {
    "path": "src/semver/_types.py",
    "content": "\"\"\"Typing for semver.\"\"\"\n\nfrom functools import partial\nfrom typing import Union, Optional, Tuple, Dict, Iterable, Callable, TypeVar\n\nVersionPart = Union[int, Optional[str]]\nVersionTuple = Tuple[int, int, int, Optional[str], Optional[str]]\nVersionDict = Dict[str, VersionPart]\nVersionIterator = Iterable[VersionPart]\nString = Union[str, bytes]\nF = TypeVar(\"F\", bound=Callable)\nDecorator = Union[Callable[..., F], partial]\n"
  },
  {
    "path": "src/semver/cli.py",
    "content": "\"\"\"\nCLI parsing for :command:`pysemver` command.\n\nEach command in :command:`pysemver` is mapped to a ``cmd_`` function.\nThe :func:`main <semver.cli.main>` function calls\n:func:`createparser <semver.cli.createparser>` and\n:func:`process <semver.cli.process>` to parse and process\nall the commandline options.\n\nThe result of each command is printed on stdout.\n\"\"\"\n\nimport argparse\nimport sys\nfrom typing import cast, List, Optional\n\nfrom .version import Version\nfrom .__about__ import __version__\n\n\ndef cmd_bump(args: argparse.Namespace) -> str:\n    \"\"\"\n    Subcommand: Bumps a version.\n\n    Synopsis: bump <PART> <VERSION>\n    <PART> can be major, minor, patch, prerelease, or build\n\n    :param args: The parsed arguments\n    :return: the new, bumped version\n    \"\"\"\n    maptable = {\n        \"major\": \"bump_major\",\n        \"minor\": \"bump_minor\",\n        \"patch\": \"bump_patch\",\n        \"prerelease\": \"bump_prerelease\",\n        \"build\": \"bump_build\",\n    }\n    if args.bump is None:\n        # When bump is called without arguments,\n        # print the help and exit\n        args.parser.parse_args([\"bump\", \"-h\"])\n\n    ver = Version.parse(args.version)\n    # get the respective method and call it\n    func = getattr(ver, maptable[cast(str, args.bump)])\n    return str(func())\n\n\ndef cmd_check(args: argparse.Namespace) -> None:\n    \"\"\"\n    Subcommand: Checks if a string is a valid semver version.\n\n    Synopsis: check <VERSION>\n\n    :param args: The parsed arguments\n    \"\"\"\n    if Version.is_valid(args.version):\n        return None\n    raise ValueError(\"Invalid version %r\" % args.version)\n\n\ndef cmd_compare(args: argparse.Namespace) -> str:\n    \"\"\"\n    Subcommand: Compare two versions.\n\n    Synopsis: compare <VERSION1> <VERSION2>\n\n    :param args: The parsed arguments\n    \"\"\"\n    ver1 = Version.parse(args.version1)\n    return str(ver1.compare(args.version2))\n\n\ndef cmd_nextver(args: argparse.Namespace) -> str:\n    \"\"\"\n    Subcommand: Determines the next version, taking prereleases into account.\n\n    Synopsis: nextver <VERSION> <PART>\n\n    :param args: The parsed arguments\n    \"\"\"\n    version = Version.parse(args.version)\n    return str(version.next_version(args.part))\n\n\ndef createparser() -> argparse.ArgumentParser:\n    \"\"\"\n    Create an :class:`argparse.ArgumentParser` instance.\n\n    :return: parser instance\n    \"\"\"\n    parser = argparse.ArgumentParser(prog=__package__, description=__doc__)\n\n    parser.add_argument(\n        \"--version\", action=\"version\", version=\"%(prog)s \" + __version__\n    )\n\n    s = parser.add_subparsers()\n    # create compare subcommand\n    parser_compare = s.add_parser(\"compare\", help=\"Compare two versions\")\n    parser_compare.set_defaults(func=cmd_compare)\n    parser_compare.add_argument(\"version1\", help=\"First version\")\n    parser_compare.add_argument(\"version2\", help=\"Second version\")\n\n    # create bump subcommand\n    parser_bump = s.add_parser(\"bump\", help=\"Bumps a version\")\n    parser_bump.set_defaults(func=cmd_bump)\n    sb = parser_bump.add_subparsers(title=\"Bump commands\", dest=\"bump\")\n\n    # Create subparsers for the bump subparser:\n    for p in (\n        sb.add_parser(\"major\", help=\"Bump the major part of the version\"),\n        sb.add_parser(\"minor\", help=\"Bump the minor part of the version\"),\n        sb.add_parser(\"patch\", help=\"Bump the patch part of the version\"),\n        sb.add_parser(\"prerelease\", help=\"Bump the prerelease part of the version\"),\n        sb.add_parser(\"build\", help=\"Bump the build part of the version\"),\n    ):\n        p.add_argument(\"version\", help=\"Version to raise\")\n\n    # Create the check subcommand\n    parser_check = s.add_parser(\n        \"check\", help=\"Checks if a string is a valid semver version\"\n    )\n    parser_check.set_defaults(func=cmd_check)\n    parser_check.add_argument(\"version\", help=\"Version to check\")\n\n    # Create the nextver subcommand\n    parser_nextver = s.add_parser(\n        \"nextver\", help=\"Determines the next version, taking prereleases into account.\"\n    )\n    parser_nextver.set_defaults(func=cmd_nextver)\n    parser_nextver.add_argument(\"version\", help=\"Version to raise\")\n    parser_nextver.add_argument(\n        \"part\", help=\"One of 'major', 'minor', 'patch', or 'prerelease'\"\n    )\n    return parser\n\n\ndef process(args: argparse.Namespace) -> str:\n    \"\"\"\n    Process the input from the CLI.\n\n    :param args: The parsed arguments\n    :param parser: the parser instance\n    :return: result of the selected action\n    \"\"\"\n    if not hasattr(args, \"func\"):\n        args.parser.print_help()\n        raise SystemExit()\n\n    # Call the respective function object:\n    return args.func(args)\n\n\ndef main(cliargs: Optional[List[str]] = None) -> int:\n    \"\"\"\n    Entry point for the application script.\n\n    :param list cliargs: Arguments to parse or None (=use :class:`sys.argv`)\n    :return: error code\n    \"\"\"\n    try:\n        parser = createparser()\n        args = parser.parse_args(args=cliargs)\n        # Save parser instance:\n        args.parser = parser\n        result = process(args)\n        if result is not None:\n            print(result)\n        return 0\n\n    except (ValueError, TypeError) as err:\n        print(\"ERROR\", err, file=sys.stderr)\n        return 2\n"
  },
  {
    "path": "src/semver/py.typed",
    "content": ""
  },
  {
    "path": "src/semver/version.py",
    "content": "\"\"\"Version handling by a semver compatible version class.\"\"\"\n\nimport re\nfrom functools import wraps\nfrom typing import (\n    Any,\n    ClassVar,\n    Dict,\n    Iterable,\n    Optional,\n    Pattern,\n    SupportsInt,\n    Tuple,\n    Union,\n    cast,\n    Callable,\n    Collection,\n    Type,\n    TypeVar,\n)\n\nfrom ._types import (\n    VersionTuple,\n    VersionDict,\n    VersionIterator,\n    String,\n    VersionPart,\n)\n\n# These types are required here because of circular imports\nComparable = Union[\"Version\", Dict[str, VersionPart], Collection[VersionPart], str]\nComparator = Callable[[\"Version\", Comparable], bool]\n\nT = TypeVar(\"T\", bound=\"Version\")\nT_cmp = TypeVar(\"T_cmp\", tuple, str, int)\n\n\ndef _comparator(operator: Comparator) -> Comparator:\n    \"\"\"Wrap a Version binary op method in a type-check.\"\"\"\n\n    @wraps(operator)\n    def wrapper(self: \"Version\", other: Comparable) -> bool:\n        comparable_types = (\n            type(self),\n            dict,\n            tuple,\n            list,\n            *String.__args__,  # type: ignore\n        )\n        if not isinstance(other, comparable_types):\n            return NotImplemented\n        return operator(self, other)\n\n    return wrapper\n\n\ndef _cmp(a: T_cmp, b: T_cmp) -> int:\n    \"\"\"Return negative if a<b, zero if a==b, positive if a>b.\"\"\"\n    return (a > b) - (a < b)\n\n\nclass Version:\n    \"\"\"\n    A semver compatible version class.\n\n    See specification at https://semver.org.\n\n    :param major: version when you make incompatible API changes.\n    :param minor: version when you add functionality in a backwards-compatible manner.\n    :param patch: version when you make backwards-compatible bug fixes.\n    :param prerelease: an optional prerelease string\n    :param build: an optional build string\n    \"\"\"\n\n    __slots__ = (\"_major\", \"_minor\", \"_patch\", \"_prerelease\", \"_build\")\n\n    #: The names of the different parts of a version\n    NAMES: ClassVar[Tuple[str, ...]] = tuple([item[1:] for item in __slots__])\n\n    #: Regex for number in a build\n    _LAST_NUMBER: ClassVar[Pattern[str]] = re.compile(r\"(?:[^\\d]*(\\d+)[^\\d]*)+\")\n    #: Regex for number in a prerelease\n    _LAST_PRERELEASE: ClassVar[Pattern[str]] = re.compile(r\"^(.*\\.)?(\\d+)$\")\n    #: Regex template for a semver version\n    _REGEX_TEMPLATE: ClassVar[\n        str\n    ] = r\"\"\"\n            ^\n            (?P<major>0|[1-9]\\d*)\n            (?:\n                \\.\n                (?P<minor>0|[1-9]\\d*)\n                (?:\n                    \\.\n                    (?P<patch>0|[1-9]\\d*)\n                ){opt_patch}\n            ){opt_minor}\n            (?:-(?P<prerelease>\n                (?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)\n                (?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*\n            ))?\n            (?:\\+(?P<build>\n                [0-9a-zA-Z-]+\n                (?:\\.[0-9a-zA-Z-]+)*\n            ))?\n            $\n        \"\"\"\n    #: Regex for a semver version\n    _REGEX: ClassVar[Pattern[str]] = re.compile(\n        _REGEX_TEMPLATE.format(opt_patch=\"\", opt_minor=\"\"),\n        re.VERBOSE,\n    )\n    #: Regex for a semver version that might be shorter\n    _REGEX_OPTIONAL_MINOR_AND_PATCH: ClassVar[Pattern[str]] = re.compile(\n        _REGEX_TEMPLATE.format(opt_patch=\"?\", opt_minor=\"?\"),\n        re.VERBOSE,\n    )\n\n    def __init__(\n        self,\n        major: SupportsInt,\n        minor: SupportsInt = 0,\n        patch: SupportsInt = 0,\n        prerelease: Optional[Union[String, int]] = None,\n        build: Optional[Union[String, int]] = None,\n    ):\n        # Build a dictionary of the arguments except prerelease and build\n        version_parts = {\"major\": int(major), \"minor\": int(minor), \"patch\": int(patch)}\n\n        for name, value in version_parts.items():\n            if value < 0:\n                raise ValueError(\n                    \"{!r} is negative. A version can only be positive.\".format(name)\n                )\n\n        self._major = version_parts[\"major\"]\n        self._minor = version_parts[\"minor\"]\n        self._patch = version_parts[\"patch\"]\n        self._prerelease = None if prerelease is None else str(prerelease)\n        self._build = None if build is None else str(build)\n\n    @classmethod\n    def _nat_cmp(cls, a: Optional[str], b: Optional[str]) -> int:\n        def cmp_prerelease_tag(a, b):\n            if isinstance(a, int) and isinstance(b, int):\n                return _cmp(a, b)\n            elif isinstance(a, int):\n                return -1\n            elif isinstance(b, int):\n                return 1\n            else:\n                return _cmp(a, b)\n\n        a_parts = [int(x) if x.isdigit() else x for x in (a or \"\").split(\".\")]\n        b_parts = [int(x) if x.isdigit() else x for x in (b or \"\").split(\".\")]\n\n        for sub_a, sub_b in zip(a_parts, b_parts):\n            cmp_result = cmp_prerelease_tag(sub_a, sub_b)\n            if cmp_result != 0:\n                return cmp_result\n\n        return _cmp(len(a_parts), len(b_parts))\n\n    @property\n    def major(self) -> int:\n        \"\"\"The major part of a version (read-only).\"\"\"\n        return self._major\n\n    @major.setter\n    def major(self, value):\n        raise AttributeError(\"attribute 'major' is readonly\")\n\n    @property\n    def minor(self) -> int:\n        \"\"\"The minor part of a version (read-only).\"\"\"\n        return self._minor\n\n    @minor.setter\n    def minor(self, value):\n        raise AttributeError(\"attribute 'minor' is readonly\")\n\n    @property\n    def patch(self) -> int:\n        \"\"\"The patch part of a version (read-only).\"\"\"\n        return self._patch\n\n    @patch.setter\n    def patch(self, value):\n        raise AttributeError(\"attribute 'patch' is readonly\")\n\n    @property\n    def prerelease(self) -> Optional[str]:\n        \"\"\"The prerelease part of a version (read-only).\"\"\"\n        return self._prerelease\n\n    @prerelease.setter\n    def prerelease(self, value):\n        raise AttributeError(\"attribute 'prerelease' is readonly\")\n\n    @property\n    def build(self) -> Optional[str]:\n        \"\"\"The build part of a version (read-only).\"\"\"\n        return self._build\n\n    @build.setter\n    def build(self, value):\n        raise AttributeError(\"attribute 'build' is readonly\")\n\n    def to_tuple(self) -> VersionTuple:\n        \"\"\"\n        Convert the Version object to a tuple.\n\n        .. versionadded:: 2.10.0\n           Renamed :meth:`Version._astuple` to :meth:`Version.to_tuple` to\n           make this function available in the public API.\n\n        :return: a tuple with all the parts\n\n        >>> semver.Version(5, 3, 1).to_tuple()\n        (5, 3, 1, None, None)\n        \"\"\"\n        return (self.major, self.minor, self.patch, self.prerelease, self.build)\n\n    def to_dict(self) -> VersionDict:\n        \"\"\"\n        Convert the Version object to an dict.\n\n        .. versionadded:: 2.10.0\n           Renamed :meth:`Version._asdict` to :meth:`Version.to_dict` to\n           make this function available in the public API.\n\n        :return: an dict with the keys in the order ``major``, ``minor``,\n          ``patch``, ``prerelease``, and ``build``.\n\n        >>> semver.Version(3, 2, 1).to_dict()\n        {'major': 3, 'minor': 2, 'patch': 1, 'prerelease': None, 'build': None}\n        \"\"\"\n        return dict(\n            major=self.major,\n            minor=self.minor,\n            patch=self.patch,\n            prerelease=self.prerelease,\n            build=self.build,\n        )\n\n    def __iter__(self) -> VersionIterator:\n        \"\"\"Return iter(self).\"\"\"\n        yield from self.to_tuple()\n\n    @staticmethod\n    def _increment_prerelease(string: str) -> str:\n        \"\"\"\n        Check if the last part of a dot-separated string is numeric. If yes,\n        increase them. Else, add '.0'\n\n        :param string: the prerelease version to increment\n        :return: the incremented string\n        \"\"\"\n        match = Version._LAST_PRERELEASE.search(string)\n        if match:\n            next_ = str(int(match.group(2)) + 1)\n            string = match.group(1) + next_ if match.group(1) else next_\n        else:\n            string += \".0\"\n        return string\n\n    @staticmethod\n    def _increment_string(string: str) -> str:\n        \"\"\"\n        Look for the last sequence of number(s) in a string and increment.\n\n        :param string: the string to search for.\n        :return: the incremented string\n\n        Source:\n        http://code.activestate.com/recipes/442460-increment-numbers-in-a-string/#c1\n        \"\"\"\n        match = Version._LAST_NUMBER.search(string)\n        if match:\n            next_ = str(int(match.group(1)) + 1)\n            start, end = match.span(1)\n            string = string[: max(end - len(next_), start)] + next_ + string[end:]\n        return string\n\n    def bump_major(self) -> \"Version\":\n        \"\"\"\n        Raise the major part of the version, return a new object but leave self\n        untouched.\n\n        :return: new object with the raised major part\n\n        >>> ver = semver.parse(\"3.4.5\")\n        >>> ver.bump_major()\n        Version(major=4, minor=0, patch=0, prerelease=None, build=None)\n        \"\"\"\n        cls = type(self)\n        return cls(self._major + 1)\n\n    def bump_minor(self) -> \"Version\":\n        \"\"\"\n        Raise the minor part of the version, return a new object but leave self\n        untouched.\n\n        :return: new object with the raised minor part\n\n        >>> ver = semver.parse(\"3.4.5\")\n        >>> ver.bump_minor()\n        Version(major=3, minor=5, patch=0, prerelease=None, build=None)\n        \"\"\"\n        cls = type(self)\n        return cls(self._major, self._minor + 1)\n\n    def bump_patch(self) -> \"Version\":\n        \"\"\"\n        Raise the patch part of the version, return a new object but leave self\n        untouched.\n\n        :return: new object with the raised patch part\n\n        >>> ver = semver.parse(\"3.4.5\")\n        >>> ver.bump_patch()\n        Version(major=3, minor=4, patch=6, prerelease=None, build=None)\n        \"\"\"\n        cls = type(self)\n        return cls(self._major, self._minor, self._patch + 1)\n\n    def bump_prerelease(\n        self,\n        token: Optional[str] = \"rc\",\n        bump_when_empty: Optional[bool] = False\n    ) -> \"Version\":\n        \"\"\"\n        Raise the prerelease part of the version, return a new object but leave\n        self untouched.\n\n        .. versionchanged:: 3.1.0\n           Parameter `bump_when_empty` added. When set to true, bumps the patch version\n           when called with a version that has no prerelease segment, so the return\n           value will be considered a newer version.\n\n           Adds `.0` to the prerelease if the last part of the dot-separated\n           prerelease is not a number.\n\n        :param token: defaults to ``'rc'``\n        :return: new :class:`Version` object with the raised prerelease part.\n            The original object is not modified.\n\n        >>> ver = semver.parse(\"3.4.5\")\n        >>> ver.bump_prerelease().prerelease\n        'rc.1'\n        >>> ver.bump_prerelease('').prerelease\n        '1'\n        >>> ver.bump_prerelease(None).prerelease\n        'rc.1'\n        >>> str(ver.bump_prerelease(bump_when_empty=True))\n        '3.4.6-rc.1'\n        \"\"\"\n        cls = type(self)\n        patch = self._patch\n        if self._prerelease is not None:\n            prerelease = cls._increment_prerelease(self._prerelease)\n        else:\n            if bump_when_empty:\n                patch += 1\n            if token == \"\":\n                prerelease = \"1\"\n            elif token is None:\n                prerelease = \"rc.1\"\n            else:\n                prerelease = str(token) + \".1\"\n\n        return cls(self._major, self._minor, patch, prerelease)\n\n    def bump_build(self, token: Optional[str] = \"build\") -> \"Version\":\n        \"\"\"\n        Raise the build part of the version, return a new object but leave self\n        untouched.\n\n        :param token: defaults to ``'build'``\n        :return: new :class:`Version` object with the raised build part.\n            The original object is not modified.\n\n        >>> ver = semver.parse(\"3.4.5-rc.1+build.9\")\n        >>> ver.bump_build()\n        Version(major=3, minor=4, patch=5, prerelease='rc.1', \\\nbuild='build.10')\n        \"\"\"\n        cls = type(self)\n        if self._build is not None:\n            build = self._build\n        elif token == \"\":\n            build = \"0\"\n        elif token is None:\n            build = \"build.0\"\n        else:\n            build = str(token) + \".0\"\n\n        build = cls._increment_string(build)\n        return cls(self._major, self._minor, self._patch, self._prerelease, build)\n\n    def compare(self, other: Comparable) -> int:\n        \"\"\"\n        Compare self with other.\n\n        :param other: the second version\n        :return: The return value is negative if ver1 < ver2,\n             zero if ver1 == ver2 and strictly positive if ver1 > ver2\n\n        >>> Version.parse(\"1.0.0\").compare(\"2.0.0\")\n        -1\n        >>> Version.parse(\"2.0.0\").compare(\"1.0.0\")\n        1\n        >>> Version.parse(\"2.0.0\").compare(\"2.0.0\")\n        0\n        \"\"\"\n        cls = type(self)\n        if isinstance(other, String.__args__):  # type: ignore\n            other = cls.parse(other)\n        elif isinstance(other, dict):\n            other = cls(**other)\n        elif isinstance(other, (tuple, list)):\n            other = cls(*other)\n        elif not isinstance(other, cls):\n            raise TypeError(\n                f\"Expected str, bytes, dict, tuple, list, or {cls.__name__} instance, \"\n                f\"but got {type(other)}\"\n            )\n\n        v1 = self.to_tuple()[:3]\n        v2 = other.to_tuple()[:3]\n        x = _cmp(v1, v2)\n        if x:\n            return x\n\n        rc1, rc2 = self.prerelease, other.prerelease\n        rccmp = self._nat_cmp(rc1, rc2)\n\n        if not rccmp:\n            return 0\n        if not rc1:\n            return 1\n        elif not rc2:\n            return -1\n\n        return rccmp\n\n    def next_version(self, part: str, prerelease_token: str = \"rc\") -> \"Version\":\n        \"\"\"\n        Determines next version, preserving natural order.\n\n        .. versionadded:: 2.10.0\n\n        This function is taking prereleases into account.\n        The \"major\", \"minor\", and \"patch\" raises the respective parts like\n        the ``bump_*`` functions. The real difference is using the\n        \"prerelease\" part. It gives you the next patch version of the\n        prerelease, for example:\n\n        >>> str(semver.parse(\"0.1.4\").next_version(\"prerelease\"))\n        '0.1.5-rc.1'\n\n        :param part: One of \"major\", \"minor\", \"patch\", or \"prerelease\"\n        :param prerelease_token: prefix string of prerelease, defaults to 'rc'\n        :return: new object with the appropriate part raised\n        \"\"\"\n        cls = type(self)\n        # \"build\" is currently not used, that's why we use [:-1]\n        validparts = cls.NAMES[:-1]\n        if part not in validparts:\n            raise ValueError(\n                f\"Invalid part. Expected one of {validparts}, but got {part!r}\"\n            )\n        version = self\n        if (version.prerelease or version.build) and (\n            part == \"patch\"\n            or (part == \"minor\" and version.patch == 0)\n            or (part == \"major\" and version.minor == version.patch == 0)\n        ):\n            return version.replace(prerelease=None, build=None)\n\n        # Only check the main parts:\n        if part in cls.NAMES[:3]:\n            return getattr(version, \"bump_\" + part)()\n        else:\n            return version.bump_prerelease(prerelease_token, bump_when_empty=True)\n\n    @_comparator\n    def __eq__(self, other: Comparable) -> bool:  # type: ignore\n        return self.compare(other) == 0\n\n    @_comparator\n    def __ne__(self, other: Comparable) -> bool:  # type: ignore\n        return self.compare(other) != 0\n\n    @_comparator\n    def __lt__(self, other: Comparable) -> bool:\n        return self.compare(other) < 0\n\n    @_comparator\n    def __le__(self, other: Comparable) -> bool:\n        return self.compare(other) <= 0\n\n    @_comparator\n    def __gt__(self, other: Comparable) -> bool:\n        return self.compare(other) > 0\n\n    @_comparator\n    def __ge__(self, other: Comparable) -> bool:\n        return self.compare(other) >= 0\n\n    def __getitem__(\n        self, index: Union[int, slice]\n    ) -> Union[int, Optional[str], Tuple[Union[int, str], ...]]:\n        \"\"\"\n        self.__getitem__(index) <==> self[index] Implement getitem.\n\n        If the part  requested is undefined, or a part of the range requested\n        is undefined, it will throw an index error.\n        Negative indices are not supported.\n\n        :param index: a positive integer indicating the\n               offset or a :func:`slice` object\n        :raises IndexError: if index is beyond the range or a part is None\n        :return: the requested part of the version at position index\n\n        >>> ver = semver.Version.parse(\"3.4.5\")\n        >>> ver[0], ver[1], ver[2]\n        (3, 4, 5)\n        \"\"\"\n        if isinstance(index, int):\n            index = slice(index, index + 1)\n        index = cast(slice, index)\n\n        if (\n            isinstance(index, slice)\n            and (index.start is not None and index.start < 0)\n            or (index.stop is not None and index.stop < 0)\n        ):\n            raise IndexError(\"Version index cannot be negative\")\n\n        part = tuple(\n            filter(lambda p: p is not None, cast(Iterable, self.to_tuple()[index]))\n        )\n\n        if len(part) == 1:\n            return part[0]\n        elif not part:\n            raise IndexError(\"Version part undefined\")\n        return part\n\n    def __repr__(self) -> str:\n        s = \", \".join(\"%s=%r\" % (key, val) for key, val in self.to_dict().items())\n        return \"%s(%s)\" % (type(self).__name__, s)\n\n    def __str__(self) -> str:\n        version = \"%d.%d.%d\" % (self.major, self.minor, self.patch)\n        if self.prerelease:\n            version += \"-%s\" % self.prerelease\n        if self.build:\n            version += \"+%s\" % self.build\n        return version\n\n    def __hash__(self) -> int:\n        return hash(self.to_tuple()[:4])\n\n    def finalize_version(self) -> \"Version\":\n        \"\"\"\n        Remove any prerelease and build metadata from the version.\n\n        :return: a new instance with the finalized version string\n\n        >>> str(semver.Version.parse('1.2.3-rc.5').finalize_version())\n        '1.2.3'\n        \"\"\"\n        cls = type(self)\n        return cls(self.major, self.minor, self.patch)\n\n    def match(self, match_expr: str) -> bool:\n        \"\"\"\n        Compare self to match a match expression.\n\n        :param match_expr: optional operator and version; valid operators are\n              ``<``   smaller than\n              ``>``   greater than\n              ``>=``  greator or equal than\n              ``<=``  smaller or equal than\n              ``==``  equal\n              ``!=``  not equal\n        :return: True if the expression matches the version, otherwise False\n\n        >>> semver.Version.parse(\"2.0.0\").match(\">=1.0.0\")\n        True\n        >>> semver.Version.parse(\"1.0.0\").match(\">1.0.0\")\n        False\n        >>> semver.Version.parse(\"4.0.4\").match(\"4.0.4\")\n        True\n        \"\"\"\n        prefix = match_expr[:2]\n        if prefix in (\">=\", \"<=\", \"==\", \"!=\"):\n            match_version = match_expr[2:]\n        elif prefix and prefix[0] in (\">\", \"<\"):\n            prefix = prefix[0]\n            match_version = match_expr[1:]\n        elif match_expr and match_expr[0] in \"0123456789\":\n            prefix = \"==\"\n            match_version = match_expr\n        else:\n            raise ValueError(\n                \"match_expr parameter should be in format <op><ver>, \"\n                \"where <op> is one of \"\n                \"['<', '>', '==', '<=', '>=', '!=']. \"\n                \"You provided: %r\" % match_expr\n            )\n\n        possibilities_dict = {\n            \">\": (1,),\n            \"<\": (-1,),\n            \"==\": (0,),\n            \"!=\": (-1, 1),\n            \">=\": (0, 1),\n            \"<=\": (-1, 0),\n        }\n\n        possibilities = possibilities_dict[prefix]\n        cmp_res = self.compare(match_version)\n\n        return cmp_res in possibilities\n\n    @classmethod\n    def parse(\n        cls: Type[T], version: String, optional_minor_and_patch: bool = False\n    ) -> T:\n        \"\"\"\n        Parse version string to a Version instance.\n\n        .. versionchanged:: 2.11.0\n           Changed method from static to classmethod to\n           allow subclasses.\n        .. versionchanged:: 3.0.0\n           Added optional parameter ``optional_minor_and_patch`` to allow\n           optional minor and patch parts.\n\n        :param version: version string\n        :param optional_minor_and_patch: if set to true, the version string to parse \\\n           can contain optional minor and patch parts. Optional parts are set to zero.\n           By default (False), the version string to parse has to follow the semver\n           specification.\n        :return: a new :class:`Version` instance\n        :raises ValueError: if version is invalid\n        :raises TypeError: if version contains the wrong type\n\n        >>> semver.Version.parse('3.4.5-pre.2+build.4')\n        Version(major=3, minor=4, patch=5, \\\nprerelease='pre.2', build='build.4')\n        \"\"\"\n        if isinstance(version, bytes):\n            version = version.decode(\"UTF-8\")\n        elif not isinstance(version, String.__args__):  # type: ignore\n            raise TypeError(\"not expecting type '%s'\" % type(version))\n\n        if optional_minor_and_patch:\n            match = cls._REGEX_OPTIONAL_MINOR_AND_PATCH.match(version)\n        else:\n            match = cls._REGEX.match(version)\n        if match is None:\n            raise ValueError(f\"{version} is not valid SemVer string\")\n\n        matched_version_parts: Dict[str, Any] = match.groupdict()\n        if not matched_version_parts[\"minor\"]:\n            matched_version_parts[\"minor\"] = 0\n        if not matched_version_parts[\"patch\"]:\n            matched_version_parts[\"patch\"] = 0\n\n        return cls(**matched_version_parts)\n\n    def replace(self, **parts: Union[int, Optional[str]]) -> \"Version\":\n        \"\"\"\n        Replace one or more parts of a version and return a new :class:`Version`\n        object, but leave self untouched.\n\n        .. versionadded:: 2.9.0\n           Added :func:`Version.replace`\n\n        :param parts: the parts to be updated. Valid keys are:\n          ``major``, ``minor``, ``patch``, ``prerelease``, or ``build``\n        :return: the new :class:`~semver.version.Version` object with\n          the changed parts\n        :raises TypeError: if ``parts`` contain invalid keys\n        \"\"\"\n        version = self.to_dict()\n        version.update(parts)\n        try:\n            return type(self)(**version)  # type: ignore\n        except TypeError:\n            unknownkeys = set(parts) - set(self.to_dict())\n            error = \"replace() got %d unexpected keyword argument(s): %s\" % (\n                len(unknownkeys),\n                \", \".join(unknownkeys),\n            )\n            raise TypeError(error)\n\n    @classmethod\n    def is_valid(cls, version: str) -> bool:\n        \"\"\"\n        Check if the string is a valid semver version.\n\n        .. versionadded:: 2.9.1\n\n        .. versionchanged:: 3.0.0\n           Renamed from :meth:`~semver.version.Version.isvalid`\n\n        :param version: the version string to check\n        :return: True if the version string is a valid semver version, False\n                 otherwise.\n        \"\"\"\n        try:\n            cls.parse(version)\n            return True\n        except ValueError:\n            return False\n\n    def is_compatible(self, other: \"Version\") -> bool:\n        \"\"\"\n        Check if current version is compatible with other version.\n\n        The result is True, if either of the following is true:\n\n        * both versions are equal, or\n        * both majors are equal and higher than 0. Same for both minors.\n          Both pre-releases are equal, or\n        * both majors are equal and higher than 0. The minor of b's\n          minor version is higher then a's. Both pre-releases are equal.\n\n        The algorithm does *not* check patches.\n\n        .. versionadded:: 3.0.0\n\n        :param other: the version to check for compatibility\n        :return: True, if ``other`` is compatible with the old version,\n                 otherwise False\n\n        >>> Version(1, 1, 0).is_compatible(Version(1, 0, 0))\n        False\n        >>> Version(1, 0, 0).is_compatible(Version(1, 1, 0))\n        True\n        \"\"\"\n        if not isinstance(other, Version):\n            raise TypeError(f\"Expected a Version type but got {type(other)}\")\n\n        # All major-0 versions should be incompatible with anything but itself\n        if (0 == self.major == other.major) and (self[:4] != other[:4]):\n            return False\n\n        return (\n            (self.major == other.major)\n            and (other.minor >= self.minor)\n            and (self.prerelease == other.prerelease)\n        )\n\n\n#: Keep the VersionInfo name for compatibility\nVersionInfo = Version\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "import sys\n\nimport pytest\n\nimport semver\n\nfrom coerce import coerce  # noqa:E402\nfrom semverwithvprefix import SemVerWithVPrefix  # noqa:E402\nimport packaging.version\n\n\n@pytest.fixture(autouse=True)\ndef add_semver(doctest_namespace):\n    doctest_namespace[\"Version\"] = semver.version.Version\n    doctest_namespace[\"semver\"] = semver\n    doctest_namespace[\"coerce\"] = coerce\n    doctest_namespace[\"SemVerWithVPrefix\"] = SemVerWithVPrefix\n    doctest_namespace[\"PyPIVersion\"] = packaging.version.Version\n\n\n@pytest.fixture\ndef version():\n    \"\"\"\n    Creates a version\n\n    :return: a version type\n    :rtype: Version\n    \"\"\"\n    return semver.Version(\n        major=1, minor=2, patch=3, prerelease=\"alpha.1.2\", build=\"build.11.e0f985a\"\n    )\n"
  },
  {
    "path": "tests/test_bump.py",
    "content": "import pytest\n\nfrom semver import (\n    bump_build,\n    bump_major,\n    bump_minor,\n    bump_patch,\n    bump_prerelease,\n    compare,\n    parse_version_info,\n)\n\n\ndef test_should_bump_major():\n    assert bump_major(\"3.4.5\") == \"4.0.0\"\n\n\ndef test_should_bump_minor():\n    assert bump_minor(\"3.4.5\") == \"3.5.0\"\n\n\ndef test_should_bump_patch():\n    assert bump_patch(\"3.4.5\") == \"3.4.6\"\n\n\ndef test_should_versioninfo_bump_major_and_minor():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"4.1.0\")\n    assert v.bump_major().bump_minor() == expected\n\n\ndef test_should_versioninfo_bump_minor_and_patch():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.5.1\")\n    assert v.bump_minor().bump_patch() == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_patch_and_prerelease():\n    v = parse_version_info(\"3.4.5-rc.1\")\n    expected = parse_version_info(\"3.4.6-rc.1\")\n    assert v.bump_patch().bump_prerelease() == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_patch_and_prerelease_with_token():\n    v = parse_version_info(\"3.4.5-dev.1\")\n    expected = parse_version_info(\"3.4.6-dev.1\")\n    assert v.bump_patch().bump_prerelease(\"dev\") == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_prerelease_and_build():\n    v = parse_version_info(\"3.4.5-rc.1+build.1\")\n    expected = parse_version_info(\"3.4.5-rc.2+build.2\")\n    assert v.bump_prerelease().bump_build() == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_prerelease_and_build_with_token():\n    v = parse_version_info(\"3.4.5-rc.1+b.1\")\n    expected = parse_version_info(\"3.4.5-rc.2+b.2\")\n    assert v.bump_prerelease().bump_build(\"b\") == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_multiple():\n    v = parse_version_info(\"3.4.5-rc.1+build.1\")\n    expected = parse_version_info(\"3.4.5-rc.2+build.2\")\n    assert v.bump_prerelease().bump_build().bump_build() == expected\n    assert v.compare(expected) == -1\n    expected = parse_version_info(\"3.4.5-rc.3\")\n    assert v.bump_prerelease().bump_build().bump_build().bump_prerelease() == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_prerelease_with_empty_str():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.5-1\")\n    assert v.bump_prerelease(\"\") == expected\n    assert v.compare(expected) == 1\n\n\ndef test_should_versioninfo_bump_prerelease_with_none():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.5-rc.1\")\n    assert v.bump_prerelease(None) == expected\n    assert v.compare(expected) == 1\n\n\ndef test_should_versioninfo_bump_prerelease_nonnumeric():\n    v = parse_version_info(\"3.4.5-rc1\")\n    expected = parse_version_info(\"3.4.5-rc1.0\")\n    assert v.bump_prerelease(None) == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_prerelease_nonnumeric_nine():\n    v = parse_version_info(\"3.4.5-rc9\")\n    expected = parse_version_info(\"3.4.5-rc9.0\")\n    assert v.bump_prerelease(None) == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_prerelease_bump_patch():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.6-rc.1\")\n    assert v.bump_prerelease(bump_when_empty=True) == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_patch_and_prerelease_bump_patch():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.7-rc.1\")\n    assert v.bump_patch().bump_prerelease(bump_when_empty=True) == expected\n    assert v.compare(expected) == -1\n\n\ndef test_should_versioninfo_bump_build_with_empty_str():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.5+1\")\n    assert v.bump_build(\"\") == expected\n    assert v.compare(expected) == 0\n\n\ndef test_should_versioninfo_bump_build_with_none():\n    v = parse_version_info(\"3.4.5\")\n    expected = parse_version_info(\"3.4.5+build.1\")\n    assert v.bump_build(None) == expected\n    assert v.compare(expected) == 0\n\n\ndef test_should_ignore_extensions_for_bump():\n    assert bump_patch(\"3.4.5-rc1+build4\") == \"3.4.6\"\n\n\n@pytest.mark.parametrize(\n    \"version,token,expected,expected_compare\",\n    [\n        (\"3.4.5-rc.9\", None, \"3.4.5-rc.10\", -1),\n        (\"3.4.5\", None, \"3.4.5-rc.1\", 1),\n        (\"3.4.5\", \"dev\", \"3.4.5-dev.1\", 1),\n        (\"3.4.5\", \"\", \"3.4.5-rc.1\", 1),\n    ],\n)\ndef test_should_bump_prerelease(version, token, expected, expected_compare):\n    token = \"rc\" if not token else token\n    assert bump_prerelease(version, token) == expected\n    assert compare(version, expected) == expected_compare\n\ndef test_should_ignore_build_on_prerelease_bump():\n    assert bump_prerelease(\"3.4.5-rc.1+build.4\") == \"3.4.5-rc.2\"\n\n\n@pytest.mark.parametrize(\n    \"version,expected\",\n    [\n        (\"3.4.5-rc.1+build.9\", \"3.4.5-rc.1+build.10\"),\n        (\"3.4.5-rc.1+0009.dev\", \"3.4.5-rc.1+0010.dev\"),\n        (\"3.4.5-rc.1\", \"3.4.5-rc.1+build.1\"),\n        (\"3.4.5\", \"3.4.5+build.1\"),\n    ],\n)\ndef test_should_bump_build(version, expected):\n    assert bump_build(version) == expected\n    assert compare(version, expected) == 0"
  },
  {
    "path": "tests/test_compare.py",
    "content": "import pytest\n\nimport semver\nfrom semver import Version, compare\n\n\n@pytest.mark.parametrize(\n    \"left,right\",\n    [\n        (\"1.0.0\", \"2.0.0\"),\n        (\"1.0.0-alpha\", \"1.0.0-alpha.1\"),\n        (\"1.0.0-alpha.1\", \"1.0.0-alpha.beta\"),\n        (\"1.0.0-alpha.beta\", \"1.0.0-beta\"),\n        (\"1.0.0-beta\", \"1.0.0-beta.2\"),\n        (\"1.0.0-beta.2\", \"1.0.0-beta.11\"),\n        (\"1.0.0-beta.11\", \"1.0.0-rc.1\"),\n        (\"1.0.0-rc.1\", \"1.0.0\"),\n    ],\n)\ndef test_should_get_less(left, right):\n    assert compare(left, right) == -1\n\n\n@pytest.mark.parametrize(\n    \"left,right\",\n    [\n        (\"2.0.0\", \"1.0.0\"),\n        (\"1.0.0-alpha.1\", \"1.0.0-alpha\"),\n        (\"1.0.0-alpha.beta\", \"1.0.0-alpha.1\"),\n        (\"1.0.0-beta\", \"1.0.0-alpha.beta\"),\n        (\"1.0.0-beta.2\", \"1.0.0-beta\"),\n        (\"1.0.0-beta.11\", \"1.0.0-beta.2\"),\n        (\"1.0.0-rc.1\", \"1.0.0-beta.11\"),\n        (\"1.0.0\", \"1.0.0-rc.1\"),\n    ],\n)\ndef test_should_get_greater(left, right):\n    assert compare(left, right) == 1\n\n\n@pytest.mark.parametrize(\n    \"left,right\", [(\"foo\", \"bar\"), (\"1.0\", \"1.0.0\"), (\"1.x\", \"1.0.0\")]\n)\ndef test_should_raise_value_error_for_invalid_value(left, right):\n    with pytest.raises(ValueError):\n        compare(left, right)\n\n\ndef test_should_follow_specification_comparison():\n    \"\"\"\n    produce comparison chain:\n    1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-beta.2 < 1.0.0-beta.11\n    < 1.0.0-rc.1 < 1.0.0-rc.1+build.1 < 1.0.0 < 1.0.0+0.3.7 < 1.3.7+build\n    < 1.3.7+build.2.b8f12d7 < 1.3.7+build.11.e0f985a\n    and in backward too.\n    \"\"\"\n    chain = [\n        \"1.0.0-alpha\",\n        \"1.0.0-alpha.1\",\n        \"1.0.0-beta.2\",\n        \"1.0.0-beta.11\",\n        \"1.0.0-rc.1\",\n        \"1.0.0\",\n        \"1.3.7+build\",\n    ]\n    versions = zip(chain[:-1], chain[1:])\n    for low_version, high_version in versions:\n        assert (\n            compare(low_version, high_version) == -1\n        ), \"%s should be lesser than %s\" % (low_version, high_version)\n        assert (\n            compare(high_version, low_version) == 1\n        ), \"%s should be higher than %s\" % (high_version, low_version)\n\n\n@pytest.mark.parametrize(\"left,right\", [(\"1.0.0-beta.2\", \"1.0.0-beta.11\")])\ndef test_should_compare_rc_builds(left, right):\n    assert compare(left, right) == -1\n\n\n@pytest.mark.parametrize(\n    \"left,right\", [(\"1.0.0-rc.1\", \"1.0.0\"), (\"1.0.0-rc.1+build.1\", \"1.0.0\")]\n)\ndef test_should_compare_release_candidate_with_release(left, right):\n    assert compare(left, right) == -1\n\n\n@pytest.mark.parametrize(\n    \"left,right\",\n    [\n        (\"2.0.0\", \"2.0.0\"),\n        (\"1.1.9-rc.1\", \"1.1.9-rc.1\"),\n        (\"1.1.9+build.1\", \"1.1.9+build.1\"),\n        (\"1.1.9-rc.1+build.1\", \"1.1.9-rc.1+build.1\"),\n    ],\n)\ndef test_should_say_equal_versions_are_equal(left, right):\n    assert compare(left, right) == 0\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [(\"1.1.9-rc.1\", \"1.1.9-rc.1+build.1\", 0), (\"1.1.9-rc.1\", \"1.1.9+build.1\", -1)],\n)\ndef test_should_compare_versions_with_build_and_release(left, right, expected):\n    assert compare(left, right) == expected\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [\n        (\"1.0.0+build.1\", \"1.0.0\", 0),\n        (\"1.0.0-alpha.1+build.1\", \"1.0.0-alpha.1\", 0),\n        (\"1.0.0+build.1\", \"1.0.0-alpha.1\", 1),\n        (\"1.0.0+build.1\", \"1.0.0-alpha.1+build.1\", 1),\n    ],\n)\ndef test_should_ignore_builds_on_compare(left, right, expected):\n    assert compare(left, right) == expected\n\n\ndef test_should_get_more_rc1():\n    assert compare(\"1.0.0-rc1\", \"1.0.0-rc0\") == 1\n\n\ndef test_should_compare_prerelease_with_numbers_and_letters():\n    v1 = Version(major=1, minor=9, patch=1, prerelease=\"1unms\", build=None)\n    v2 = Version(major=1, minor=9, patch=1, prerelease=None, build=\"1asd\")\n    assert v1 < v2\n    assert compare(\"1.9.1-1unms\", \"1.9.1+1\") == -1\n\n\ndef test_should_compare_version_info_objects():\n    v1 = Version(major=0, minor=10, patch=4)\n    v2 = Version(major=0, minor=10, patch=4, prerelease=\"beta.1\", build=None)\n\n    # use `not` to enforce using comparision operators\n    assert v1 != v2\n    assert v1 > v2\n    assert v1 >= v2\n    assert not (v1 < v2)\n    assert not (v1 <= v2)\n    assert not (v1 == v2)\n\n    v3 = Version(major=0, minor=10, patch=4)\n\n    assert not (v1 != v3)\n    assert not (v1 > v3)\n    assert v1 >= v3\n    assert not (v1 < v3)\n    assert v1 <= v3\n    assert v1 == v3\n\n    v4 = Version(major=0, minor=10, patch=5)\n    assert v1 != v4\n    assert not (v1 > v4)\n    assert not (v1 >= v4)\n    assert v1 < v4\n    assert v1 <= v4\n    assert not (v1 == v4)\n\n\ndef test_should_compare_version_dictionaries():\n    v1 = Version(major=0, minor=10, patch=4)\n    v2 = dict(major=0, minor=10, patch=4, prerelease=\"beta.1\", build=None)\n\n    assert v1 != v2\n    assert v1 > v2\n    assert v1 >= v2\n    assert not (v1 < v2)\n    assert not (v1 <= v2)\n    assert not (v1 == v2)\n\n    v3 = dict(major=0, minor=10, patch=4)\n\n    assert not (v1 != v3)\n    assert not (v1 > v3)\n    assert v1 >= v3\n    assert not (v1 < v3)\n    assert v1 <= v3\n    assert v1 == v3\n\n    v4 = dict(major=0, minor=10, patch=5)\n    assert v1 != v4\n    assert not (v1 > v4)\n    assert not (v1 >= v4)\n    assert v1 < v4\n    assert v1 <= v4\n    assert not (v1 == v4)\n\n\n@pytest.mark.parametrize(\n    \"t\",  # fmt: off\n    (\n        (1, 0, 0),\n        (1, 0),\n        (1,),\n        (1, 0, 0, \"pre.2\"),\n        (1, 0, 0, \"pre.2\", \"build.4\"),\n    ),  # fmt: on\n)\ndef test_should_compare_version_tuples(t):\n    v0 = Version(major=0, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n    v1 = Version(major=3, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n\n    assert v0 < t\n    assert v0 <= t\n    assert v0 != t\n    assert not v0 == t\n    assert v1 > t\n    assert v1 >= t\n    # Symmetric\n    assert t > v0\n    assert t >= v0\n    assert t < v1\n    assert t <= v1\n    assert t != v0\n    assert not t == v0\n\n\n@pytest.mark.parametrize(\n    \"lst\",  # fmt: off\n    (\n        [1, 0, 0],\n        [1, 0],\n        [1],\n        [1, 0, 0, \"pre.2\"],\n        [1, 0, 0, \"pre.2\", \"build.4\"],\n    ),  # fmt: on\n)\ndef test_should_compare_version_list(lst):\n    v0 = Version(major=0, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n    v1 = Version(major=3, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n\n    assert v0 < lst\n    assert v0 <= lst\n    assert v0 != lst\n    assert not v0 == lst\n    assert v1 > lst\n    assert v1 >= lst\n    # Symmetric\n    assert lst > v0\n    assert lst >= v0\n    assert lst < v1\n    assert lst <= v1\n    assert lst != v0\n    assert not lst == v0\n\n\n@pytest.mark.parametrize(\n    \"s\",  # fmt: off\n    (\n        \"1.0.0\",\n        # \"1.0\",\n        # \"1\",\n        \"1.0.0-pre.2\",\n        \"1.0.0-pre.2+build.4\",\n    ),  # fmt: on\n)\ndef test_should_compare_version_string(s):\n    v0 = Version(major=0, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n    v1 = Version(major=3, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n\n    assert v0 < s\n    assert v0 <= s\n    assert v0 != s\n    assert not v0 == s\n    assert v1 > s\n    assert v1 >= s\n    # Symmetric\n    assert s > v0\n    assert s >= v0\n    assert s < v1\n    assert s <= v1\n    assert s != v0\n    assert not s == v0\n\n\n@pytest.mark.parametrize(\"s\", (\"1\", \"1.0\", \"1.0.x\"))\ndef test_should_not_allow_to_compare_invalid_versionstring(s):\n    v = Version(major=3, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n    with pytest.raises(ValueError):\n        v < s\n    with pytest.raises(ValueError):\n        s > v\n\n\ndef test_should_not_allow_to_compare_version_with_int():\n    v1 = Version(major=3, minor=4, patch=5, prerelease=\"pre.2\", build=\"build.4\")\n    with pytest.raises(TypeError):\n        v1 > 1\n    with pytest.raises(TypeError):\n        1 > v1\n    with pytest.raises(TypeError):\n        semver.compare(1)\n\n\ndef test_should_compare_prerelease_and_build_with_numbers():\n    assert Version(major=1, minor=9, patch=1, prerelease=1, build=1) < Version(\n        major=1, minor=9, patch=1, prerelease=2, build=1\n    )\n    assert Version(1, 9, 1, 1, 1) < Version(1, 9, 1, 2, 1)\n    assert Version(\"2\") < Version(10)\n    assert Version(\"2\") < Version(\"10\")\n"
  },
  {
    "path": "tests/test_deprecated_functions.py",
    "content": "from argparse import Namespace\n\nimport pytest\n\nfrom semver import (\n    parse,\n    parse_version_info,\n    match,\n    max_ver,\n    min_ver,\n    format_version,\n    bump_major,\n    bump_minor,\n    bump_patch,\n    bump_prerelease,\n    bump_build,\n    finalize_version,\n    replace,\n    cmd_bump,\n    cmd_compare,\n    cmd_check,\n    cmd_nextver,\n    createparser,\n    process,\n    main,\n)\nfrom semver._deprecated import deprecated\n\n\n@pytest.mark.parametrize(\n    \"func, args, kwargs\",\n    [\n        (bump_build, (\"1.2.3\",), {}),\n        (bump_major, (\"1.2.3\",), {}),\n        (bump_minor, (\"1.2.3\",), {}),\n        (bump_patch, (\"1.2.3\",), {}),\n        (bump_prerelease, (\"1.2.3\",), {}),\n        (format_version, (3, 4, 5), {}),\n        (finalize_version, (\"1.2.3-rc.5\",), {}),\n        (match, (\"1.0.0\", \">=1.0.0\"), {}),\n        (parse, (\"1.2.3\",), {}),\n        (parse_version_info, (\"1.2.3\",), {}),\n        (replace, (\"1.2.3\",), dict(major=2, patch=10)),\n        (max_ver, (\"1.2.3\", \"1.2.4\"), {}),\n        (min_ver, (\"1.2.3\", \"1.2.4\"), {}),\n        (cmd_bump, (Namespace(bump=\"major\", version=\"1.2.3\"),), {}),\n        (cmd_compare, (Namespace(version1=\"1.2.3\", version2=\"2.1.3\"),), {}),\n        (cmd_check, (Namespace(version=\"1.2.3\"),), {}),\n        (cmd_nextver, (Namespace(version=\"1.2.3\", part=\"major\"),), {}),\n        (createparser, (), {}),\n        (\n            process,\n            (Namespace(func=cmd_compare, version1=\"1.2.3\", version2=\"2.1.3\"),),\n            {},\n        ),\n        (main, ([\"bump\", \"major\", \"1.2.3\"],), {}),\n    ],\n)\ndef test_should_raise_deprecation_warnings(func, args, kwargs):\n    with pytest.warns(\n        DeprecationWarning, match=r\"Function 'semver.[_a-zA-Z]+' is deprecated.\"\n    ) as record:\n        func(*args, **kwargs)\n        if not record:\n            pytest.fail(\"Expected a DeprecationWarning for {}\".format(func.__name__))\n    assert len(record), \"Expected one DeprecationWarning record\"\n\n\ndef test_deprecated_deco_without_argument():\n    @deprecated\n    def mock_func():\n        return True\n\n    with pytest.deprecated_call():\n        assert mock_func()\n"
  },
  {
    "path": "tests/test_docstrings.py",
    "content": "import inspect\n\nimport pytest\n\nimport semver\n\n\ndef getallfunctions(module=semver):\n    def getfunctions(_module):\n        for _, func in inspect.getmembers(_module, inspect.isfunction):\n            # Make sure you only investigate functions from our modules:\n            if not func.__name__.startswith(\"_\") and func.__module__.startswith(\n                _module.__name__\n            ):\n                yield func\n\n    def getmodules(_module):\n        for _, m in inspect.getmembers(_module, inspect.ismodule):\n            if m.__package__.startswith(_module.__package__):\n                yield m\n\n    for ff in getfunctions(module):\n        yield ff\n    # for mm in getmodules(module):\n    #    for ff in getfunctions(mm):\n    #        yield ff\n\n\nSEMVERFUNCS = [func for func in getallfunctions()]\n\n\n@pytest.mark.parametrize(\n    \"func\", SEMVERFUNCS, ids=[func.__name__ for func in SEMVERFUNCS]\n)\ndef test_fordocstrings(func):\n    assert func.__doc__, \"Need a docstring for function %r from module %r\" % (\n        func.__name__,\n        func.__module__,\n    )\n"
  },
  {
    "path": "tests/test_format.py",
    "content": "import pytest\n\nfrom semver import Version, finalize_version, format_version\n\n\n@pytest.mark.parametrize(\n    \"version,expected\",\n    [\n        (\"1.2.3\", \"1.2.3\"),\n        (\"1.2.3-rc.5\", \"1.2.3\"),\n        (\"1.2.3+build.2\", \"1.2.3\"),\n        (\"1.2.3-rc.1+build.5\", \"1.2.3\"),\n        (\"1.2.3-alpha\", \"1.2.3\"),\n        (\"1.2.0\", \"1.2.0\"),\n    ],\n)\ndef test_should_finalize_version(version, expected):\n    assert finalize_version(version) == expected\n\n\ndef test_should_correctly_format_version():\n    assert format_version(3, 4, 5) == \"3.4.5\"\n    assert format_version(3, 4, 5, \"rc.1\") == \"3.4.5-rc.1\"\n    assert format_version(3, 4, 5, prerelease=\"rc.1\") == \"3.4.5-rc.1\"\n    assert format_version(3, 4, 5, build=\"build.4\") == \"3.4.5+build.4\"\n    assert format_version(3, 4, 5, \"rc.1\", \"build.4\") == \"3.4.5-rc.1+build.4\"\n\n\ndef test_parse_method_for_version_info():\n    s_version = \"1.2.3-alpha.1.2+build.11.e0f985a\"\n    v = Version.parse(s_version)\n    assert str(v) == s_version\n\n\n@pytest.mark.parametrize(\n    \"version, expected\",\n    [\n        (\n            Version(major=1, minor=2, patch=3, prerelease=None, build=None),\n            \"Version(major=1, minor=2, patch=3, prerelease=None, build=None)\",\n        ),\n        (\n            Version(major=1, minor=2, patch=3, prerelease=\"r.1\", build=None),\n            \"Version(major=1, minor=2, patch=3, prerelease='r.1', build=None)\",\n        ),\n        (\n            Version(major=1, minor=2, patch=3, prerelease=\"dev.1\", build=None),\n            \"Version(major=1, minor=2, patch=3, prerelease='dev.1', build=None)\",\n        ),\n        (\n            Version(major=1, minor=2, patch=3, prerelease=\"dev.1\", build=\"b.1\"),\n            \"Version(major=1, minor=2, patch=3, prerelease='dev.1', build='b.1')\",\n        ),\n        (\n            Version(major=1, minor=2, patch=3, prerelease=\"r.1\", build=\"b.1\"),\n            \"Version(major=1, minor=2, patch=3, prerelease='r.1', build='b.1')\",\n        ),\n        (\n            Version(major=1, minor=2, patch=3, prerelease=\"r.1\", build=\"build.1\"),\n            \"Version(major=1, minor=2, patch=3, prerelease='r.1', build='build.1')\",\n        ),\n    ],\n)\ndef test_repr(version, expected):\n    assert repr(version) == expected\n"
  },
  {
    "path": "tests/test_immutable.py",
    "content": "import pytest\n\n\ndef test_immutable_major(version):\n    with pytest.raises(AttributeError, match=\"attribute 'major' is readonly\"):\n        version.major = 9\n\n\ndef test_immutable_minor(version):\n    with pytest.raises(AttributeError, match=\"attribute 'minor' is readonly\"):\n        version.minor = 9\n\n\ndef test_immutable_patch(version):\n    with pytest.raises(AttributeError, match=\"attribute 'patch' is readonly\"):\n        version.patch = 9\n\n\ndef test_immutable_prerelease(version):\n    with pytest.raises(AttributeError, match=\"attribute 'prerelease' is readonly\"):\n        version.prerelease = \"alpha.9.9\"\n\n\ndef test_immutable_build(version):\n    with pytest.raises(AttributeError, match=\"attribute 'build' is readonly\"):\n        version.build = \"build.99.e0f985a\"\n\n\ndef test_immutable_unknown_attribute(version):\n    with pytest.raises(\n        AttributeError, match=\".* object has no attribute 'new_attribute'\"\n    ):\n        version.new_attribute = \"forbidden\"\n"
  },
  {
    "path": "tests/test_index.py",
    "content": "import pytest\n\nfrom semver import Version\n\n\n@pytest.mark.parametrize(\n    \"version, index, expected\",\n    [\n        # Simple positive indices\n        (\"1.2.3-rc.0+build.0\", 0, 1),\n        (\"1.2.3-rc.0+build.0\", 1, 2),\n        (\"1.2.3-rc.0+build.0\", 2, 3),\n        (\"1.2.3-rc.0+build.0\", 3, \"rc.0\"),\n        (\"1.2.3-rc.0+build.0\", 4, \"build.0\"),\n        (\"1.2.3-rc.0\", 0, 1),\n        (\"1.2.3-rc.0\", 1, 2),\n        (\"1.2.3-rc.0\", 2, 3),\n        (\"1.2.3-rc.0\", 3, \"rc.0\"),\n        (\"1.2.3\", 0, 1),\n        (\"1.2.3\", 1, 2),\n        (\"1.2.3\", 2, 3),\n        # Special cases\n        (\"1.0.2\", 1, 0),\n    ],\n)\ndef test_version_info_should_be_accessed_with_index(version, index, expected):\n    version_info = Version.parse(version)\n    assert version_info[index] == expected\n\n\n@pytest.mark.parametrize(\n    \"version, slice_object, expected\",\n    [\n        # Slice indices\n        (\"1.2.3-rc.0+build.0\", slice(0, 5), (1, 2, 3, \"rc.0\", \"build.0\")),\n        (\"1.2.3-rc.0+build.0\", slice(0, 4), (1, 2, 3, \"rc.0\")),\n        (\"1.2.3-rc.0+build.0\", slice(0, 3), (1, 2, 3)),\n        (\"1.2.3-rc.0+build.0\", slice(0, 2), (1, 2)),\n        (\"1.2.3-rc.0+build.0\", slice(3, 5), (\"rc.0\", \"build.0\")),\n        (\"1.2.3-rc.0\", slice(0, 4), (1, 2, 3, \"rc.0\")),\n        (\"1.2.3-rc.0\", slice(0, 3), (1, 2, 3)),\n        (\"1.2.3-rc.0\", slice(0, 2), (1, 2)),\n        (\"1.2.3\", slice(0, 10), (1, 2, 3)),\n        (\"1.2.3\", slice(0, 3), (1, 2, 3)),\n        (\"1.2.3\", slice(0, 2), (1, 2)),\n        # Special cases\n        (\"1.2.3-rc.0+build.0\", slice(3), (1, 2, 3)),\n        (\"1.2.3-rc.0+build.0\", slice(0, 5, 2), (1, 3, \"build.0\")),\n        (\"1.2.3-rc.0+build.0\", slice(None, 5, 2), (1, 3, \"build.0\")),\n        (\"1.2.3-rc.0+build.0\", slice(5, 0, -2), (\"build.0\", 3)),\n        (\"1.2.0-rc.0+build.0\", slice(3), (1, 2, 0)),\n    ],\n)\ndef test_version_info_should_be_accessed_with_slice_object(\n    version, slice_object, expected\n):\n    version_info = Version.parse(version)\n    assert version_info[slice_object] == expected\n\n\n@pytest.mark.parametrize(\n    \"version, index\",\n    [\n        (\"1.2.3\", 3),\n        (\"1.2.3\", slice(3, 4)),\n        (\"1.2.3\", 4),\n        (\"1.2.3\", slice(4, 5)),\n        (\"1.2.3\", 5),\n        (\"1.2.3\", slice(5, 6)),\n        (\"1.2.3-rc.0\", 5),\n        (\"1.2.3-rc.0\", slice(5, 6)),\n        (\"1.2.3-rc.0\", 6),\n        (\"1.2.3-rc.0\", slice(6, 7)),\n    ],\n)\ndef test_version_info_should_throw_index_error(version, index):\n    version_info = Version.parse(version)\n    with pytest.raises(IndexError, match=r\"Version part undefined\"):\n        version_info[index]\n\n\n@pytest.mark.parametrize(\n    \"version, index\",\n    [\n        (\"1.2.3\", -1),\n        (\"1.2.3\", -2),\n        (\"1.2.3\", slice(-2, 2)),\n        (\"1.2.3\", slice(2, -2)),\n        (\"1.2.3\", slice(-2, -2)),\n    ],\n)\ndef test_version_info_should_throw_index_error_when_negative_index(version, index):\n    version_info = Version.parse(version)\n    with pytest.raises(IndexError, match=r\"Version index cannot be negative\"):\n        version_info[index]\n"
  },
  {
    "path": "tests/test_match.py",
    "content": "import pytest\n\nfrom semver import match\n\n\ndef test_should_match_simple():\n    assert match(\"2.3.7\", \">=2.3.6\") is True\n\n\ndef test_should_no_match_simple():\n    assert match(\"2.3.7\", \">=2.3.8\") is False\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [\n        (\"2.3.7\", \"!=2.3.8\", True),\n        (\"2.3.7\", \"!=2.3.6\", True),\n        (\"2.3.7\", \"!=2.3.7\", False),\n    ],\n)\ndef test_should_match_not_equal(left, right, expected):\n    assert match(left, right) is expected\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [\n        (\"2.3.7\", \"2.3.7\", True),\n        (\"2.3.6\", \"2.3.6\", True),\n        (\"2.3.7\", \"4.3.7\", False),\n    ],\n)\ndef test_should_match_equal_by_default(left, right, expected):\n    assert match(left, right) is expected\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [\n        (\"2.3.7\", \"<2.4.0\", True),\n        (\"2.3.7\", \">2.3.5\", True),\n        (\"2.3.7\", \"<=2.3.9\", True),\n        (\"2.3.7\", \">=2.3.5\", True),\n        (\"2.3.7\", \"==2.3.7\", True),\n        (\"2.3.7\", \"!=2.3.7\", False),\n    ],\n)\ndef test_should_not_raise_value_error_for_expected_match_expression(\n    left, right, expected\n):\n    assert match(left, right) is expected\n\n\n@pytest.mark.parametrize(\n    \"left,right\", [(\"2.3.7\", \"=2.3.7\"), (\"2.3.7\", \"~2.3.7\"), (\"2.3.7\", \"^2.3.7\")]\n)\ndef test_should_raise_value_error_for_unexpected_match_expression(left, right):\n    with pytest.raises(ValueError):\n        match(left, right)\n\n\n@pytest.mark.parametrize(\"left,right\", [(\"1.0.0\", \"\"), (\"1.0.0\", \"!\")])\ndef test_should_raise_value_error_for_invalid_match_expression(left, right):\n    with pytest.raises(ValueError):\n        match(left, right)\n"
  },
  {
    "path": "tests/test_max-min.py",
    "content": "import pytest\n\nfrom semver import max_ver, min_ver\n\n\ndef test_should_get_max():\n    assert max_ver(\"3.4.5\", \"4.0.2\") == \"4.0.2\"\n\n\ndef test_should_get_max_same():\n    assert max_ver(\"3.4.5\", \"3.4.5\") == \"3.4.5\"\n\n\ndef test_should_get_min():\n    assert min_ver(\"3.4.5\", \"4.0.2\") == \"3.4.5\"\n\n\ndef test_should_get_min_same():\n    assert min_ver(\"3.4.5\", \"3.4.5\") == \"3.4.5\"\n\n\n@pytest.mark.parametrize(\n    \"left,right,expected\",\n    [\n        (\"1.2.3-rc.2\", \"1.2.3-rc.10\", \"1.2.3-rc.2\"),\n        (\"1.2.3-rc2\", \"1.2.3-rc10\", \"1.2.3-rc10\"),\n        # identifiers with letters or hyphens are compared lexically in ASCII sort\n        # order.\n        (\"1.2.3-Rc10\", \"1.2.3-rc10\", \"1.2.3-Rc10\"),\n        # Numeric identifiers always have lower precedence than non-numeric\n        # identifiers.\n        (\"1.2.3-2\", \"1.2.3-rc\", \"1.2.3-2\"),\n        # A larger set of pre-release fields has a higher precedence than a\n        # smaller set, if all of the preceding identifiers are equal.\n        (\"1.2.3-rc.2.1\", \"1.2.3-rc.2\", \"1.2.3-rc.2\"),\n        # When major, minor, and patch are equal, a pre-release version has lower\n        # precedence than a normal version.\n        (\"1.2.3\", \"1.2.3-1\", \"1.2.3-1\"),\n        (\"1.0.0-alpha\", \"1.0.0-alpha.1\", \"1.0.0-alpha\"),\n    ],\n)\ndef test_prerelease_order(left, right, expected):\n    assert min_ver(left, right) == expected\n"
  },
  {
    "path": "tests/test_parsing.py",
    "content": "import pytest\n\nfrom semver import Version, parse, parse_version_info\n\n\n@pytest.mark.parametrize(\n    \"version,expected\",\n    [\n        # no. 1\n        (\n            \"1.2.3-alpha.1.2+build.11.e0f985a\",\n            {\n                \"major\": 1,\n                \"minor\": 2,\n                \"patch\": 3,\n                \"prerelease\": \"alpha.1.2\",\n                \"build\": \"build.11.e0f985a\",\n            },\n        ),\n        # no. 2\n        (\n            \"1.2.3-alpha-1+build.11.e0f985a\",\n            {\n                \"major\": 1,\n                \"minor\": 2,\n                \"patch\": 3,\n                \"prerelease\": \"alpha-1\",\n                \"build\": \"build.11.e0f985a\",\n            },\n        ),\n        (\n            \"0.1.0-0f\",\n            {\"major\": 0, \"minor\": 1, \"patch\": 0, \"prerelease\": \"0f\", \"build\": None},\n        ),\n        (\n            \"0.0.0-0foo.1\",\n            {\"major\": 0, \"minor\": 0, \"patch\": 0, \"prerelease\": \"0foo.1\", \"build\": None},\n        ),\n        (\n            \"0.0.0-0foo.1+build.1\",\n            {\n                \"major\": 0,\n                \"minor\": 0,\n                \"patch\": 0,\n                \"prerelease\": \"0foo.1\",\n                \"build\": \"build.1\",\n            },\n        ),\n    ],\n)\ndef test_should_parse_version(version, expected):\n    result = parse(version)\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"version,expected\",\n    [\n        # no. 1\n        (\n            \"1.2-alpha.1.2+build.11.e0f985a\",\n            {\n                \"major\": 1,\n                \"minor\": 2,\n                \"patch\": 0,\n                \"prerelease\": \"alpha.1.2\",\n                \"build\": \"build.11.e0f985a\",\n            },\n        ),\n        # no. 2\n        (\n            \"1-alpha-1+build.11.e0f985a\",\n            {\n                \"major\": 1,\n                \"minor\": 0,\n                \"patch\": 0,\n                \"prerelease\": \"alpha-1\",\n                \"build\": \"build.11.e0f985a\",\n            },\n        ),\n        (\n            \"0.1-0f\",\n            {\"major\": 0, \"minor\": 1, \"patch\": 0, \"prerelease\": \"0f\", \"build\": None},\n        ),\n        (\n            \"0-0foo.1\",\n            {\"major\": 0, \"minor\": 0, \"patch\": 0, \"prerelease\": \"0foo.1\", \"build\": None},\n        ),\n        (\n            \"0-0foo.1+build.1\",\n            {\n                \"major\": 0,\n                \"minor\": 0,\n                \"patch\": 0,\n                \"prerelease\": \"0foo.1\",\n                \"build\": \"build.1\",\n            },\n        ),\n    ],\n)\ndef test_should_parse_version_with_optional_minor_and_patch(version, expected):\n    result = Version.parse(version, optional_minor_and_patch=True)\n    assert result == expected\n\n\ndef test_parse_version_info_str_hash():\n    s_version = \"1.2.3-alpha.1.2+build.11.e0f985a\"\n    v = parse_version_info(s_version)\n    assert v.__str__() == s_version\n    d = {}\n    d[v] = \"\"  # to ensure that Version are hashable\n\n\n@pytest.mark.parametrize(\n    \"version,expected\",\n    [\n        # no. 1\n        (\n            \"1.2.3-rc.0+build.0\",\n            {\n                \"major\": 1,\n                \"minor\": 2,\n                \"patch\": 3,\n                \"prerelease\": \"rc.0\",\n                \"build\": \"build.0\",\n            },\n        ),\n        # no. 2\n        (\n            \"1.2.3-rc.0.0+build.0\",\n            {\n                \"major\": 1,\n                \"minor\": 2,\n                \"patch\": 3,\n                \"prerelease\": \"rc.0.0\",\n                \"build\": \"build.0\",\n            },\n        ),\n    ],\n)\ndef test_should_parse_zero_prerelease(version, expected):\n    result = parse(version)\n    assert result == expected\n\n\n@pytest.mark.parametrize(\"version\", [\"01.2.3\", \"1.02.3\", \"1.2.03\"])\ndef test_should_raise_value_error_for_zero_prefixed_versions(version):\n    with pytest.raises(ValueError):\n        parse(version)\n\n\ndef test_equal_versions_have_equal_hashes():\n    v1 = parse_version_info(\"1.2.3-alpha.1.2+build.11.e0f985a\")\n    v2 = parse_version_info(\"1.2.3-alpha.1.2+build.22.a589f0e\")\n    assert v1 == v2\n    assert hash(v1) == hash(v2)\n    d = {}\n    d[v1] = 1\n    d[v2] = 2\n    assert d[v1] == 2\n    s = set()\n    s.add(v1)\n    assert v2 in s\n\n\ndef test_parse_method_for_version_info():\n    s_version = \"1.2.3-alpha.1.2+build.11.e0f985a\"\n    v = Version.parse(s_version)\n    assert str(v) == s_version\n\n\ndef test_next_version_with_invalid_parts():\n    version = Version.parse(\"1.0.1\")\n    with pytest.raises(ValueError):\n        version.next_version(\"invalid\")\n\n\n@pytest.mark.parametrize(\n    \"version, part, expected\",\n    [\n        # major\n        (\"1.0.4-rc.1\", \"major\", \"2.0.0\"),\n        (\"1.1.0-rc.1\", \"major\", \"2.0.0\"),\n        (\"1.1.4-rc.1\", \"major\", \"2.0.0\"),\n        (\"1.2.3\", \"major\", \"2.0.0\"),\n        (\"1.0.0-rc.1\", \"major\", \"1.0.0\"),\n        # minor\n        (\"0.2.0-rc.1\", \"minor\", \"0.2.0\"),\n        (\"0.2.5-rc.1\", \"minor\", \"0.3.0\"),\n        (\"1.3.1\", \"minor\", \"1.4.0\"),\n        # patch\n        (\"1.3.2\", \"patch\", \"1.3.3\"),\n        (\"0.1.5-rc.2\", \"patch\", \"0.1.5\"),\n        # prerelease\n        (\"0.1.4\", \"prerelease\", \"0.1.5-rc.1\"),\n        (\"0.1.5-rc.1\", \"prerelease\", \"0.1.5-rc.2\"),\n        # special cases\n        (\"0.2.0-rc.1\", \"patch\", \"0.2.0\"),  # same as \"minor\"\n        (\"1.0.0-rc.1\", \"patch\", \"1.0.0\"),  # same as \"major\"\n        (\"1.0.0-rc.1\", \"minor\", \"1.0.0\"),  # same as \"major\"\n    ],\n)\ndef test_next_version_with_versioninfo(version, part, expected):\n    ver = Version.parse(version)\n    next_version = ver.next_version(part)\n    assert isinstance(next_version, Version)\n    assert str(next_version) == expected\n"
  },
  {
    "path": "tests/test_pysemver-cli.py",
    "content": "from argparse import Namespace\nfrom contextlib import contextmanager\nfrom unittest.mock import patch\n\nimport pytest\n\nfrom semver import (\n    cmd_bump,\n    cmd_check,\n    cmd_compare,\n    cmd_nextver,\n    createparser,\n    main,\n    __main__,\n)\n\n\n@contextmanager\ndef does_not_raise(item):\n    yield item\n\n\n@pytest.mark.parametrize(\n    \"cli,expected\",\n    [\n        ([\"bump\", \"major\", \"1.2.3\"], Namespace(bump=\"major\", version=\"1.2.3\")),\n        ([\"bump\", \"minor\", \"1.2.3\"], Namespace(bump=\"minor\", version=\"1.2.3\")),\n        ([\"bump\", \"patch\", \"1.2.3\"], Namespace(bump=\"patch\", version=\"1.2.3\")),\n        (\n            [\"bump\", \"prerelease\", \"1.2.3\"],\n            Namespace(bump=\"prerelease\", version=\"1.2.3\"),\n        ),\n        ([\"bump\", \"build\", \"1.2.3\"], Namespace(bump=\"build\", version=\"1.2.3\")),\n        # ---\n        ([\"compare\", \"1.2.3\", \"2.1.3\"], Namespace(version1=\"1.2.3\", version2=\"2.1.3\")),\n        # ---\n        ([\"check\", \"1.2.3\"], Namespace(version=\"1.2.3\")),\n    ],\n)\ndef test_should_parse_cli_arguments(cli, expected):\n    parser = createparser()\n    assert parser\n    result = parser.parse_args(cli)\n    del result.func\n    assert result == expected\n\n\n@pytest.mark.parametrize(\n    \"func,args,expectation\",\n    [\n        # bump subcommand\n        (cmd_bump, Namespace(bump=\"major\", version=\"1.2.3\"), does_not_raise(\"2.0.0\")),\n        (cmd_bump, Namespace(bump=\"minor\", version=\"1.2.3\"), does_not_raise(\"1.3.0\")),\n        (cmd_bump, Namespace(bump=\"patch\", version=\"1.2.3\"), does_not_raise(\"1.2.4\")),\n        (\n            cmd_bump,\n            Namespace(bump=\"prerelease\", version=\"1.2.3-rc1\"),\n            does_not_raise(\"1.2.3-rc1.0\"),\n        ),\n        (\n            cmd_bump,\n            Namespace(bump=\"build\", version=\"1.2.3+build.13\"),\n            does_not_raise(\"1.2.3+build.14\"),\n        ),\n        # compare subcommand\n        (\n            cmd_compare,\n            Namespace(version1=\"1.2.3\", version2=\"2.1.3\"),\n            does_not_raise(\"-1\"),\n        ),\n        (\n            cmd_compare,\n            Namespace(version1=\"1.2.3\", version2=\"1.2.3\"),\n            does_not_raise(\"0\"),\n        ),\n        (\n            cmd_compare,\n            Namespace(version1=\"2.4.0\", version2=\"2.1.3\"),\n            does_not_raise(\"1\"),\n        ),\n        # check subcommand\n        (cmd_check, Namespace(version=\"1.2.3\"), does_not_raise(None)),\n        (cmd_check, Namespace(version=\"1.2\"), pytest.raises(ValueError)),\n        # nextver subcommand\n        (\n            cmd_nextver,\n            Namespace(version=\"1.2.3\", part=\"major\"),\n            does_not_raise(\"2.0.0\"),\n        ),\n        (\n            cmd_nextver,\n            Namespace(version=\"1.2\", part=\"major\"),\n            pytest.raises(ValueError),\n        ),\n        (\n            cmd_nextver,\n            Namespace(version=\"1.2.3\", part=\"nope\"),\n            pytest.raises(ValueError),\n        ),\n    ],\n)\ndef test_should_process_parsed_cli_arguments(func, args, expectation):\n    with expectation as expected:\n        result = func(args)\n        assert result == expected\n\n\ndef test_should_process_print(capsys):\n    rc = main([\"bump\", \"major\", \"1.2.3\"])\n    assert rc == 0\n    captured = capsys.readouterr()\n    assert captured.out.rstrip() == \"2.0.0\"\n\n\ndef test_should_process_raise_error(capsys):\n    rc = main([\"bump\", \"major\", \"1.2\"])\n    assert rc != 0\n    captured = capsys.readouterr()\n    assert captured.err.startswith(\"ERROR\")\n\n\ndef test_should_raise_systemexit_when_called_with_empty_arguments():\n    with pytest.raises(SystemExit):\n        main([])\n\n\ndef test_should_raise_systemexit_when_bump_iscalled_with_empty_arguments():\n    with pytest.raises(SystemExit):\n        main([\"bump\"])\n\n\ndef test_should_process_check_iscalled_with_valid_version(capsys):\n    result = main([\"check\", \"1.1.1\"])\n    assert not result\n    captured = capsys.readouterr()\n    assert not captured.out\n\n\n@pytest.mark.parametrize(\"package_name\", [\"\", \"semver\"])\ndef test_main_file_should_call_cli_main(package_name):\n    with patch(\"semver.__main__.cli.main\") as mocked_main:\n        with patch(\"semver.__main__.__package__\", package_name):\n            __main__.main()\n            mocked_main.assert_called_once()\n"
  },
  {
    "path": "tests/test_replace.py",
    "content": "import pytest\n\nfrom semver import Version, replace\n\n\n@pytest.mark.parametrize(\n    \"version,parts,expected\",\n    [\n        (\"3.4.5\", dict(major=2), \"2.4.5\"),\n        (\"3.4.5\", dict(major=\"2\"), \"2.4.5\"),\n        (\"3.4.5\", dict(major=2, minor=5), \"2.5.5\"),\n        (\"3.4.5\", dict(minor=2), \"3.2.5\"),\n        (\"3.4.5\", dict(major=2, minor=5, patch=10), \"2.5.10\"),\n        (\"3.4.5\", dict(major=2, minor=5, patch=10, prerelease=\"rc1\"), \"2.5.10-rc1\"),\n        (\n            \"3.4.5\",\n            dict(major=2, minor=5, patch=10, prerelease=\"rc1\", build=\"b1\"),\n            \"2.5.10-rc1+b1\",\n        ),\n        (\"3.4.5-alpha.1.2\", dict(major=2), \"2.4.5-alpha.1.2\"),\n        (\"3.4.5-alpha.1.2\", dict(build=\"x1\"), \"3.4.5-alpha.1.2+x1\"),\n        (\"3.4.5+build1\", dict(major=2), \"2.4.5+build1\"),\n    ],\n)\ndef test_replace_method_replaces_requested_parts(version, parts, expected):\n    assert replace(version, **parts) == expected\n\n\ndef test_replace_raises_TypeError_for_invalid_keyword_arg():\n    with pytest.raises(TypeError, match=r\"replace\\(\\).*unknown.*\"):\n        assert replace(\"1.2.3\", unknown=\"should_raise\")\n\n\n@pytest.mark.parametrize(\n    \"version,parts,expected\",\n    [\n        (\"3.4.5\", dict(major=2, minor=5), \"2.5.5\"),\n        (\"3.4.5\", dict(major=2, minor=5, patch=10), \"2.5.10\"),\n        (\"3.4.5-alpha.1.2\", dict(major=2), \"2.4.5-alpha.1.2\"),\n        (\"3.4.5-alpha.1.2\", dict(build=\"x1\"), \"3.4.5-alpha.1.2+x1\"),\n        (\"3.4.5+build1\", dict(major=2), \"2.4.5+build1\"),\n    ],\n)\ndef test_should_return_versioninfo_with_replaced_parts(version, parts, expected):\n    assert Version.parse(version).replace(**parts) == Version.parse(expected)\n\n\ndef test_replace_raises_ValueError_for_non_numeric_values():\n    with pytest.raises(ValueError):\n        Version.parse(\"1.2.3\").replace(major=\"x\")\n"
  },
  {
    "path": "tests/test_semver.py",
    "content": "import pytest  # noqa\n\nfrom semver import Version\n\n\n@pytest.mark.parametrize(\n    \"string,expected\", [(\"rc\", \"rc\"), (\"rc.1\", \"rc.2\"), (\"2x\", \"3x\")]\n)\ndef test_should_private_increment_string(string, expected):\n    assert Version._increment_string(string) == expected\n\n\n@pytest.mark.parametrize(\n    \"ver\",\n    [\n        {\"major\": -1},\n        {\"major\": 1, \"minor\": -2},\n        {\"major\": 1, \"minor\": 2, \"patch\": -3},\n        {\"major\": 1, \"minor\": -2, \"patch\": 3},\n    ],\n)\ndef test_should_not_allow_negative_numbers(ver):\n    with pytest.raises(ValueError, match=\".* is negative. .*\"):\n        Version(**ver)\n\n\ndef test_should_versioninfo_to_dict(version):\n    resultdict = version.to_dict()\n    assert isinstance(resultdict, dict), \"Got type from to_dict\"\n    assert list(resultdict.keys()) == [\"major\", \"minor\", \"patch\", \"prerelease\", \"build\"]\n\n\ndef test_should_versioninfo_to_tuple(version):\n    result = version.to_tuple()\n    assert isinstance(result, tuple), \"Got type from to_dict\"\n    assert len(result) == 5, \"Different length from to_tuple()\"\n\n\ndef test_version_info_should_be_iterable(version):\n    assert tuple(version) == (\n        version.major,\n        version.minor,\n        version.patch,\n        version.prerelease,\n        version.build,\n    )\n\n\ndef test_should_be_able_to_use_strings_as_major_minor_patch():\n    v = Version(\"1\", \"2\", \"3\")\n    assert isinstance(v.major, int)\n    assert isinstance(v.minor, int)\n    assert isinstance(v.patch, int)\n    assert v.prerelease is None\n    assert v.build is None\n    assert Version(\"1\", \"2\", \"3\") == Version(1, 2, 3)\n\n\ndef test_using_non_numeric_string_as_major_minor_patch_throws():\n    with pytest.raises(ValueError):\n        Version(\"a\")\n    with pytest.raises(ValueError):\n        Version(1, \"a\")\n    with pytest.raises(ValueError):\n        Version(1, 2, \"a\")\n\n\ndef test_should_be_able_to_use_integers_as_prerelease_build():\n    v = Version(1, 2, 3, 4, 5)\n    assert isinstance(v.prerelease, str)\n    assert isinstance(v.build, str)\n    assert Version(1, 2, 3, 4, 5) == Version(1, 2, 3, \"4\", \"5\")\n\n\ndef test_should_versioninfo_isvalid():\n    assert Version.is_valid(\"1.0.0\") is True\n    assert Version.is_valid(\"foo\") is False\n\n\ndef test_versioninfo_compare_should_raise_when_passed_invalid_value():\n    with pytest.raises(TypeError):\n        Version(1, 2, 3).compare(4)\n\n\n@pytest.mark.parametrize(\n    \"old, new\",\n    [\n        ((1, 2, 3), (1, 2, 3)),\n        ((1, 2, 3), (1, 2, 4)),\n        ((1, 2, 4), (1, 2, 3)),\n        ((1, 2, 3, \"rc.0\"), (1, 2, 4, \"rc.0\")),\n        ((0, 1, 0), (0, 1, 0)),\n    ],\n)\ndef test_should_succeed_compatible_match(old, new):\n    old = Version(*old)\n    new = Version(*new)\n    assert old.is_compatible(new)\n\n\n@pytest.mark.parametrize(\n    \"old, new\",\n    [\n        ((1, 1, 0), (1, 0, 0)),\n        ((2, 0, 0), (1, 5, 0)),\n        ((1, 2, 3, \"rc.1\"), (1, 2, 3, \"rc.0\")),\n        ((1, 2, 3, \"rc.1\"), (1, 2, 4, \"rc.0\")),\n        ((0, 1, 0), (0, 1, 1)),\n        ((1, 0, 0), (1, 0, 0, \"rc1\")),\n        ((1, 0, 0, \"rc1\"), (1, 0, 0)),\n    ],\n)\ndef test_should_fail_compatible_match(old, new):\n    old = Version(*old)\n    new = Version(*new)\n    assert not old.is_compatible(new)\n\n\n@pytest.mark.parametrize(\n    \"wrongtype\",\n    [\n        \"wrongtype\",\n        dict(a=2),\n        list(),\n    ],\n)\ndef test_should_fail_with_incompatible_type_for_compatible_match(wrongtype):\n    with pytest.raises(TypeError, match=\"Expected a Version type .*\"):\n        v = Version(1, 2, 3)\n        v.is_compatible(wrongtype)\n\n\ndef test_should_succeed_with_compatible_subclass_for_is_compatible():\n    class CustomVersion(Version): ...\n\n    assert CustomVersion(1, 0, 0).is_compatible(Version(1, 0, 0))\n"
  },
  {
    "path": "tests/test_subclass.py",
    "content": "from semver import Version\nimport pytest\n\n\ndef test_subclass_from_versioninfo():\n    class SemVerWithVPrefix(Version):\n        @classmethod\n        def parse(cls, version):\n            if not version[0] in (\"v\", \"V\"):\n                raise ValueError(\n                    \"{v!r}: version must start with 'v' or 'V'\".format(v=version)\n                )\n            return super().parse(version[1:])\n\n        def __str__(self):\n            # Reconstruct the tag.\n            return \"v\" + super().__str__()\n\n    v = SemVerWithVPrefix.parse(\"v1.2.3\")\n    assert str(v) == \"v1.2.3\"\n\n\ndef test_replace_from_subclass():\n    # Issue#426\n    # Taken from the example \"Creating Subclasses from Version\"\n    class SemVerWithVPrefix(Version):\n        \"\"\"\n        A subclass of Version which allows a \"v\" prefix\n        \"\"\"\n\n        @classmethod\n        def parse(cls, version: str) -> \"SemVerWithVPrefix\":\n            \"\"\"\n            Parse version string to a Version instance.\n\n            :param version: version string with \"v\" or \"V\" prefix\n            :raises ValueError: when version does not start with \"v\" or \"V\"\n            :return: a new instance\n            \"\"\"\n            if not version[0] in (\"v\", \"V\"):\n                raise ValueError(\n                    f\"{version!r}: not a valid semantic version tag. \"\n                    \"Must start with 'v' or 'V'\"\n                )\n            return super().parse(version[1:], optional_minor_and_patch=True)\n\n        def __str__(self) -> str:\n            # Reconstruct the tag\n            return \"v\" + super().__str__()\n\n    version = SemVerWithVPrefix.parse(\"v1.1.0\")\n    dev_version = version.replace(prerelease=\"dev.0\")\n\n    assert str(dev_version) == \"v1.1.0-dev.0\"\n\n\ndef test_compare_with_subclass():\n    class SemVerSubclass(Version):\n        pass\n\n    with pytest.raises(TypeError):\n        SemVerSubclass.parse(\"1.0.0\").compare(Version.parse(\"1.0.0\"))\n    assert Version.parse(\"1.0.0\").compare(SemVerSubclass.parse(\"1.0.0\")) == 0\n\n    assert (\n        SemVerSubclass.parse(\"1.0.0\").__eq__(Version.parse(\"1.0.0\")) is NotImplemented\n    )\n    assert Version.parse(\"1.0.0\").__eq__(SemVerSubclass.parse(\"1.0.0\")) is True\n\n    assert SemVerSubclass.parse(\"1.0.0\") == Version.parse(\"1.0.0\")\n    assert Version.parse(\"1.0.0\") == SemVerSubclass.parse(\"1.0.0\")\n"
  },
  {
    "path": "tests/test_typeerror-274.py",
    "content": "import pytest\nimport semver\n\n\ndef test_should_work_with_string_and_bytes():\n    result = semver.compare(\"1.1.0\", b\"1.2.2\")\n    assert result == -1\n    result = semver.compare(b\"1.1.0\", \"1.2.2\")\n    assert result == -1\n\n\ndef test_should_not_work_with_invalid_args():\n    with pytest.raises(TypeError):\n        semver.version.Version.parse(8)\n"
  },
  {
    "path": "tox.ini",
    "content": "[tox]\nenvlist =\n    checks\n    py3{7,8,9,10,11,12,13}\nisolated_build = True\nskip_missing_interpreters = True\n\n[gh-actions]\npython =\n    # setuptools >=62 needs Python >=3.7\n    3.7: py37,checks\n    3.8: py38\n    3.9: py39\n    3.10: py310\n    3.11: py311\n    3.12: py312\n    3.13: py313\n\n\n[testenv]\ndescription = Run test suite for {basepython}\nskip_install = true\nallowlist_externals = make\ncommands = pytest {posargs:}\ndeps =\n    pytest\n    pytest-cov\n    setuptools>=62.0\n    setuptools-scm\nsetenv =\n    PIP_DISABLE_PIP_VERSION_CHECK = 1\ndownloads = true\n\n\n[testenv:mypy]\ndescription = Check code style\nbasepython = python3\ndeps = mypy\ncommands = mypy {posargs:src}\n\n\n[testenv:docstrings]\ndescription = Check for PEP257 compatible docstrings\nbasepython = python3\ndeps = docformatter\ncommands =\n\tdocformatter --check --diff {posargs:src}\n\n\n[testenv:checks]\ndescription = Run code style checks\nbasepython = python3\ndeps =\n    ruff\ncommands =\n    ruff check\n\n\n[testenv:docs]\ndescription = Build HTML documentation\nbasepython = python3\ndeps = -r{toxinidir}/docs/requirements.txt\nskip_install = true\nallowlist_externals =\n    make\n    echo\n    uvx\ncommands =\n    uvx make -C docs html\ncommands_post =\n    echo \"Find the HTML documentation at file://{toxinidir}/docs/_build/html/index.html\"\n\n\n[testenv:man]\ndescription = Build the manpage\nbasepython = python3\ndeps = sphinx\nskip_install = true\ncommands = make -C docs man\n\n\n[testenv:prepare-dist]\ndescription = Prepare for TestPyPI\nbasepython = python3\ndeps =\n    twine\n    build\ncommands =\n    # Same as python3 -m build\n    pyproject-build\n    twine check dist/*\n\n\n[testenv:changelog]\ndescription = Run towncrier to check, build, or create the CHANGELOG.rst\nbasepython = python3\nskip_install = true\ndeps =\n    git+https://github.com/twisted/towncrier.git\ncommands =\n    towncrier {posargs:build --draft}\n"
  }
]