pax_global_header 0000666 0000000 0000000 00000000064 14560504261 0014515 g ustar 00root root 0000000 0000000 52 comment=59e70d1d5d18145f5cfa078b69996102bbd8c3c6
awesomeversion-24.2.0/ 0000775 0000000 0000000 00000000000 14560504261 0014650 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/.codecov.yml 0000664 0000000 0000000 00000000417 14560504261 0017075 0 ustar 00root root 0000000 0000000 comment: false
codecov:
branch: main
coverage:
precision: 2
status:
patch: off
project:
default:
target: 100%
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
ignore:
- "tests" awesomeversion-24.2.0/.devcontainer.json 0000664 0000000 0000000 00000002056 14560504261 0020305 0 ustar 00root root 0000000 0000000 {
"name": "AwesomeVersion",
"image": "mcr.microsoft.com/vscode/devcontainers/python:0-3.11",
"postCreateCommand": "make requirements",
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"GitHub.copilot"
]
}
}
}
awesomeversion-24.2.0/.gitattributes 0000664 0000000 0000000 00000000022 14560504261 0017535 0 ustar 00root root 0000000 0000000 * text=auto eol=lf awesomeversion-24.2.0/.github/ 0000775 0000000 0000000 00000000000 14560504261 0016210 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/.github/ISSUE_TEMPLATE/ 0000775 0000000 0000000 00000000000 14560504261 0020373 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/.github/ISSUE_TEMPLATE/bug.yml 0000664 0000000 0000000 00000002106 14560504261 0021672 0 ustar 00root root 0000000 0000000 name: "Report a bug with AwesomeVersion"
description: Report an issue with AwesomeVersion
labels: "bug"
body:
- type: textarea
attributes:
label: The problem
placeholder: >-
Describe the issue you are experiencing here to communicate to the
maintainers. Tell us what you were trying to do and what happened.
validations:
required: true
- type: markdown
attributes:
value: |
## Environment
- type: input
attributes:
label: Operating system
validations:
required: true
- type: dropdown
validations:
required: true
attributes:
label: Python version
options:
- 3.8
- 3.9
- "3.10"
- "3.11"
- type: textarea
validations:
required: true
attributes:
label: Problem-relevant code
description: >-
A minimal example to reproduce the bug
render: python
- type: textarea
attributes:
label: Traceback/Error logs
description: >-
If you come across any trace or error logs, please provide them.
render: txt
- type: textarea
attributes:
label: Additional information awesomeversion-24.2.0/.github/ISSUE_TEMPLATE/config.yml 0000664 0000000 0000000 00000000033 14560504261 0022357 0 ustar 00root root 0000000 0000000 blank_issues_enabled: false awesomeversion-24.2.0/.github/ISSUE_TEMPLATE/feature_request.yml 0000664 0000000 0000000 00000001224 14560504261 0024320 0 ustar 00root root 0000000 0000000 name: "Feature request for AwesomeVersion"
description: Suggest a feature/change to be added to AwesomeVersion
labels: "enhancement"
body:
- type: textarea
validations:
required: true
attributes:
label: The idea
description: >
A good description of what you are suggesting.
- type: textarea
validations:
required: true
attributes:
label: Implementation
description: >
How do you see this being implemented?
- type: textarea
attributes:
label: Alternatives
description: >
Are there any alternative solutions or features you've considered?
- type: textarea
attributes:
label: Additional context awesomeversion-24.2.0/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000003353 14560504261 0022015 0 ustar 00root root 0000000 0000000
## Proposed change
## Type of change
- [ ] Dependency upgrade
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] New feature (which adds functionalit)
- [ ] Breaking change (fix/feature causing existing functionality to break)
- [ ] Code quality improvements to existing code or addition of tests
## Additional information
- This PR fixes or closes issue: fixes #
- This PR is related to issue:
- Link to documentation pull request:
## Checklist
- [ ] The code change is tested and works locally.
- [ ] Local tests pass.
- [ ] There is no commented out code in this PR.
- [ ] The code has been formatted using Black (`make lint`)
- [ ] Tests have been added to verify that the new code works.
awesomeversion-24.2.0/.github/dependabot.yml 0000664 0000000 0000000 00000000426 14560504261 0021042 0 ustar 00root root 0000000 0000000 version: 2
updates:
- package-ecosystem: pip
directory: "/"
schedule:
interval: daily
time: "06:00"
open-pull-requests-limit: 10
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: daily
time: "06:00"
open-pull-requests-limit: 10 awesomeversion-24.2.0/.github/release.yml 0000664 0000000 0000000 00000000066 14560504261 0020355 0 ustar 00root root 0000000 0000000 changelog:
exclude:
labels:
- dependencies awesomeversion-24.2.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14560504261 0020245 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/.github/workflows/actions.yml 0000664 0000000 0000000 00000004073 14560504261 0022434 0 ustar 00root root 0000000 0000000 name: Actions
on:
pull_request:
branches:
- main
push:
branches:
- main
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: π₯ Checkout the repository
uses: actions/checkout@v4.1.1
- name: π Set up Python 3
uses: actions/setup-python@v5
id: python
with:
python-version: 3.x
- name: π¦ Install dependencies
run: make requirements
- name: π€ Lint with Black
run: make black-check
- name: π Lint with mypy
run: make mypy
- name: β¨ Lint with pylint
run: make pylint
- name: π€ Lint with isort
run: make isort-check
test:
name: Test with Python ${{ matrix.entry.version }}
needs: lint
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
entry:
- version: "3.8"
- version: "3.9"
- version: "3.10"
- version: "3.11"
- version: "3.12"
prereleases: true
steps:
- name: π₯ Checkout the repository
uses: actions/checkout@v4.1.1
- name: π οΈ Set up Python ${{ matrix.entry.version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.entry.version }}
allow-prereleases: ${{ matrix.entry.prereleases || false }}
- name: π¦ Install dependencies
run: make requirements
- name: π Run tests
run: make test
- name: π Build
run: make build
coverage:
name: Upload coverage to Codecov
needs: test
runs-on: ubuntu-latest
steps:
- name: π₯ Checkout the repository
uses: actions/checkout@v4.1.1
with:
depth: 0
- name: π οΈ Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: π¦ Install dependencies
run: make requirements
- name: π€ Upload coverage to Codecov
run: |
make coverage
curl -sfSL https://codecov.io/bash | bash - awesomeversion-24.2.0/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000001165 14560504261 0024063 0 ustar 00root root 0000000 0000000 name: "CodeQL"
on:
push:
branches:
- main
pull_request:
branches:
- main
schedule:
- cron: '19 14 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: Checkout repository
uses: actions/checkout@v4.1.1
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: 'python'
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
awesomeversion-24.2.0/.github/workflows/demo.yml 0000664 0000000 0000000 00000001240 14560504261 0021711 0 ustar 00root root 0000000 0000000 name: Deploy demo
on:
push:
branches:
- "main"
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: 'demo'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
awesomeversion-24.2.0/.github/workflows/release.yml 0000664 0000000 0000000 00000001614 14560504261 0022412 0 ustar 00root root 0000000 0000000 name: Release
on:
release:
types:
- published
permissions: {}
jobs:
deploy:
runs-on: ubuntu-latest
name: Build package
environment:
name: release
url: https://pypi.org/project/awesomeversion
permissions:
# Used to authenticate to PyPI via OIDC.
id-token: write
steps:
- name: π₯ Checkout the repository
uses: actions/checkout@v4.1.1
- name: π Set up Python
uses: actions/setup-python@v5
id: python
with:
python-version: 3.x
- name: π¦ Install poetry
run: make install-poetry
- name: π’ Set version number
run: |
export version=${{ github.ref }}
poetry version "${version##*/}"
- name: π Build
run: poetry build --no-interaction
- name: π Publish to PyPi
uses: pypa/gh-action-pypi-publish@v1.8.11
awesomeversion-24.2.0/.gitignore 0000664 0000000 0000000 00000000135 14560504261 0016637 0 ustar 00root root 0000000 0000000 __pycache__
__target__
.mypy_cache
.pytest_cache
.coverage
coverage.xml
dist
build
*.egg-info awesomeversion-24.2.0/LICENCE.md 0000664 0000000 0000000 00000002064 14560504261 0016236 0 ustar 00root root 0000000 0000000 MIT License
Copyright (c) 2020-2022 Joakim SΓΈrensen
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. awesomeversion-24.2.0/Makefile 0000664 0000000 0000000 00000002507 14560504261 0016314 0 ustar 00root root 0000000 0000000 .DEFAULT_GOAL := help
help: ## Shows this help message
@printf "\033[1m%s\033[36m %s\033[32m %s\033[0m \n\n" "Development environment for" "ludeeus/awesomeversion" "";
@awk 'BEGIN {FS = ":.*##";} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m make %-25s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST);
@echo
requirements: install-poetry ## Install requirements
@poetry install
@poetry check
install: ## Install awesomeversion
@poetry install
install-poetry:
@curl -sSL https://install.python-poetry.org | python3 -
test: ## Run all tests
@poetry run pytest tests -rxf -x -vv -l -s --cov=./ --cov-report=xml
build: ## Build the package
@poetry build
lint: isort black mypy pylint ## Lint all files
snapshot-update: ## Update test snapshot files
@poetry run pytest tests --snapshot-update
coverage: ## Check the coverage of the package
@poetry run pytest tests -rxf -x -v -l --cov=./ --cov-report=xml > /dev/null
@poetry run coverage report
isort:
@poetry run isort awesomeversion tests
isort-check:
@poetry run isort awesomeversion tests --check-only
black:
@poetry run black --fast awesomeversion tests
black-check:
@poetry run black --check --fast awesomeversion tests
mypy:
@poetry run mypy --strict awesomeversion tests
pylint:
@poetry run pylint awesomeversion tests awesomeversion-24.2.0/README.md 0000664 0000000 0000000 00000017330 14560504261 0016133 0 ustar 00root root 0000000 0000000 # AwesomeVersion
[](https://codecov.io/gh/ludeeus/awesomeversion)


[](https://pypi.org/project/awesomeversion)

_One version package to rule them all, One version package to find them, One version package to bring them all, and in the darkness bind them._
Make anything a version object, and compare against a vast section of other version formats.
## Installation
```bash
python3 -m pip install awesomeversion
```
## AwesomeVersion class
The AwesomeVersion class takes a version as the first argument, you can also pass in additional kwargs to customize the version object.
Argument | Description
--- | ---
`version` | The version string to parse.
`ensure_strategy` | Match the `AwesomeVersion` object against spesific strategies when creating if. If it does not match `AwesomeVersionStrategyException` will be raised
`find_first_match` | If True, the version given will be scanned for the first match of the given `ensure_strategy`. Raises `AwesomeVersionStrategyException` If it is not found for any of the given strategies.
## AwesomeVersion methods
AwesomeVersion.in_range
This is a helper method to check if the version is in a range.
This method takes two arguments, `lowest` and `highest`, both are required, and returns a boolean.
> **Note** This method is the same as doing `lowest <= AwesomeVersion <= highest`
Example:
```python
from awesomeversion import AwesomeVersion
print(AwesomeVersion("1.2.2").in_range("1.2.1", "1.3"))
> True
print(AwesomeVersion("1.2.0").in_range("1.2.1", "1.3"))
> False
```
AwesomeVersion.diff
This is a helper method to get the difference between two versions.
This method takes one argument which is the version to compare against, and returns a `AwesomeVersionDiff` object.
> **Note** This method is the same as doing `AwesomeVersion - version`
Example:
```python
from awesomeversion import AwesomeVersion
> print(AwesomeVersion("1.0").diff("2.1"))
AwesomeVersionDiff(major=True, minor=True, patch=False, modifier=False, strategy=False)
```
AwesomeVersion.section
This is a helper method to get a section of the version.
This method takes one argument which is the section to get, and returns an integer representing it (or 0 if it does not exist).
Example:
```python
from awesomeversion import AwesomeVersion
> print(AwesomeVersion("1.0").section(0))
1
```
## AwesomeVersion properties
Argument | Description
--- | ---
`alpha` | This is a boolean representing if the version is an alpha version.
`beta` | This is a boolean representing if the version is a beta version.
`dev` | This is a boolean representing if the version is a dev version.
`major` | This is an `AwesomeVersion` object representing the major version or `None` if not present.
`micro` | This is an `AwesomeVersion` object representing the micro version or `None` if not present.
`minor` | This is an `AwesomeVersion` object representing the minor version or `None` if not present.
`modifier_type` | This is a string representing the modifier type of the version or `None` if not present.
`modifier` | This is a string representing the modifier of the version or `None` if not present.
`patch` | This is an `AwesomeVersion` object representing the patch version or `None` if not present.
`prefix` | This is the prefix of the version or `None` if not present.
`release_candidate` | This is a boolean representing if the version is a release candidate version.
`simple` | This is a boolean representing if the version is a simple version.
`strategy_description` | This is a `AwesomeVersionStrategyDescription` object representing the strategy description of the version.
`strategy` | This is a `AwesomeVersionStrategy` object representing the strategy of the version.
`string` | This is the string representation of the version (without the v prefix if present).
`valid` | This is a boolean representing if the version is valid (not unknown strategy).
`year` | This is alias to `major`, and is an `AwesomeVersion` object representing the year.
## Example usage
Here are some examples of how you can use this package, more examples can be found in the `tests` directory.
Basic compare
```python
from awesomeversion import AwesomeVersion
current = AwesomeVersion("1.2.2")
upstream = AwesomeVersion("1.2.3")
print(upstream > current)
> True
```
Compare beta version
```python
from awesomeversion import AwesomeVersion
current = AwesomeVersion("2021.1.0")
upstream = AwesomeVersion("2021.1.0b2")
print(current > upstream)
> True
```
Check if version is a beta version
```python
from awesomeversion import AwesomeVersion
print(AwesomeVersion("1.2.3b0").beta)
> True
print(AwesomeVersion("1.2.3").beta)
> False
```
Use AwesomeVersion with with ...
```python
from awesomeversion import AwesomeVersion
with AwesomeVersion("20.12.0") as current:
with AwesomeVersion("20.12.1") as upstream:
print(upstream > current)
> True
```
Compare AwesomeVersion with other non-AwesomeVersion formats
```python
from awesomeversion import AwesomeVersion
base = AwesomeVersion("20.12.0")
print(base > "20.12.1")
> False
print(base > "19")
> True
print(base > 5)
> True
```
## General behavior
You can test your versions on the [demo page][awesomeversion_demo].
### Modifiers
When comparing versions with modifiers, if the base version is the same the modifier will be used to determine the order.
If one of the versions do not have a modifier, the one without will be considered newer.
The order of the modifiers are:
- No modifier
- RC
- Beta
- Alpha
- Dev
Examples
```python
from awesomeversion import AwesomeVersion
print(AwesomeVersion("1.0.0") > AwesomeVersion("1.0.0b6"))
> True
print(AwesomeVersion("1.0.0") > AwesomeVersion("1.0.0.dev6"))
> True
print(AwesomeVersion("1.0.0.dev19") > AwesomeVersion("1.0.0b4"))
> False
```
### Special versions (container)
There are some special versions for container that are handled differently than typical version formats.
The special versions are in the following order:
- `dev` (newest)
- `latest`
- `beta`
- `stable` (oldest)
If only the first version is this special version, it will be considered newer.
If only the second version is this special version, it will be considered older.
Examples
```python
from awesomeversion import AwesomeVersion
print(AwesomeVersion("latest") > AwesomeVersion("1.0.0b6"))
> True
print(AwesomeVersion("1.0.0") > AwesomeVersion("latest"))
> False
print(AwesomeVersion("stable") > AwesomeVersion("latest"))
> False
print(AwesomeVersion("beta") > AwesomeVersion("dev"))
> False
```
## Contribute
**All** contributions are welcome!
1. Fork the repository
2. Clone the repository locally and open the devcontainer or use GitHub codespaces
3. Do your changes
4. Lint the files with `make lint`
5. Ensure all tests passes with `make test`
6. Ensure 100% coverage with `make coverage`
7. Commit your work, and push it to GitHub
8. Create a PR against the `main` branch
[awesomeversion_demo]: https://ludeeus.github.io/awesomeversion/ awesomeversion-24.2.0/awesomeversion/ 0000775 0000000 0000000 00000000000 14560504261 0017716 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/awesomeversion/__init__.py 0000664 0000000 0000000 00000001031 14560504261 0022022 0 ustar 00root root 0000000 0000000 """Initialize the AwesomeVersion package."""
from .awesomeversion import AwesomeVersion, AwesomeVersionDiff
from .exceptions import (
AwesomeVersionCompareException,
AwesomeVersionException,
AwesomeVersionStrategyException,
)
from .strategy import COMPARABLE_STRATEGIES, AwesomeVersionStrategy
__all__ = [
"AwesomeVersion",
"AwesomeVersionCompareException",
"AwesomeVersionDiff",
"AwesomeVersionException",
"AwesomeVersionStrategy",
"AwesomeVersionStrategyException",
"COMPARABLE_STRATEGIES",
]
awesomeversion-24.2.0/awesomeversion/awesomeversion.py 0000664 0000000 0000000 00000043235 14560504261 0023345 0 ustar 00root root 0000000 0000000 """AwesomeVersion."""
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Dict
from warnings import warn
from .comparehandlers.container import compare_handler_container
from .comparehandlers.modifier import compare_handler_semver_modifier
from .comparehandlers.sections import compare_handler_sections
from .comparehandlers.simple import compare_handler_simple
from .exceptions import AwesomeVersionCompareException, AwesomeVersionStrategyException
from .strategy import (
VERSION_STRATEGIES,
VERSION_STRATEGIES_DICT,
AwesomeVersionStrategy,
AwesomeVersionStrategyDescription,
)
from .utils.regex import (
RE_DIGIT,
RE_MODIFIER,
RE_SIMPLE,
compile_regex,
generate_full_string_regex,
)
if TYPE_CHECKING:
from .typing import EnsureStrategyIterableType, EnsureStrategyType, VersionType
class AwesomeVersion(str):
"""
AwesomeVersion class.
"""
_version: str = ""
_modifier: str | None = None
_modifier_type: str | None = None
_sections: int | None = None
_simple: bool | None = None
_ensure_strategy: EnsureStrategyIterableType = []
def __init__(
self, # pylint: disable=unused-argument
version: VersionType,
*args: Any,
ensure_strategy: EnsureStrategyType = None,
find_first_match: bool = False,
**kwargs: Any,
) -> None:
"""
Initialize AwesomeVersion.
**args**:
version:
The version to create a AwesomeVersion object from
**kwargs**:
ensure_strategy:
Match the AwesomeVersion object against spesific
strategies when creating if. If it does not match
AwesomeVersionStrategyException will be raised
find_first_match:
If True, the version given will be scanned for the first
match of the given ensure_strategy. Raises
AwesomeVersionStrategyException If it is not found
for any of the given strategies.
"""
if args:
warn(
"Positional argument for ensure_strategy is deprecated. "
"This will be removed in 2023, use keyword argument instead",
category=DeprecationWarning,
stacklevel=2,
)
ensure_strategy = args[0]
if len(args) == 2:
warn(
"Positional argument for find_first_match is deprecated. "
"This will be removed in 2023, use keyword argument instead",
category=DeprecationWarning,
stacklevel=2,
)
find_first_match = args[1]
self._version = (
version._version if isinstance(version, AwesomeVersion) else str(version)
)
if isinstance(self._version, str):
self._version = self._version.strip()
if find_first_match and not ensure_strategy:
warn(
"Can not use find_first_match without ensure_strategy",
stacklevel=2,
)
if ensure_strategy is not None:
self._ensure_strategy = ensure_strategy = (
ensure_strategy
if isinstance(ensure_strategy, (list, tuple))
else [ensure_strategy]
)
if AwesomeVersionStrategy.UNKNOWN in ensure_strategy:
raise AwesomeVersionStrategyException(
f"Can't use {AwesomeVersionStrategy.UNKNOWN.value} as ensure_strategy"
)
if find_first_match:
for strategy in self._ensure_strategy or []:
description = VERSION_STRATEGIES_DICT[strategy]
match = compile_regex(description.regex_string).search(
self._version
)
if match is not None:
self._version = match.group(0)
if self.strategy not in ensure_strategy:
raise AwesomeVersionStrategyException(
f"Strategy {self.strategy.value} does not match "
f"{[strategy.value for strategy in ensure_strategy]} for {version}"
)
if self._version and self._version[-1] == ".":
self._version = self._version[:-1]
str.__init__(self._version)
def __new__(
cls,
version: str,
*_: Any,
**__: Any,
) -> AwesomeVersion:
"""Create a new AwesomeVersion object."""
return super().__new__(cls, version)
def __enter__(self) -> AwesomeVersion:
return self
def __exit__(self, *_: Any, **__: Any) -> None:
pass
def __repr__(self) -> str:
return f""
def __str__(self) -> str:
return str(self._version)
def __eq__(self, compareto: VersionType) -> bool:
"""Check if equals to."""
if isinstance(compareto, (str, float, int)):
compareto = AwesomeVersion(compareto)
if not isinstance(compareto, AwesomeVersion):
raise AwesomeVersionCompareException("Not a valid AwesomeVersion object")
return self.string == compareto.string
def __lt__(self, compareto: VersionType) -> bool:
"""Check if less than."""
if isinstance(compareto, (str, float, int)):
compareto = AwesomeVersion(compareto)
if not isinstance(compareto, AwesomeVersion):
raise AwesomeVersionCompareException("Not a valid AwesomeVersion object")
if self.string == compareto.string:
return False
if AwesomeVersionStrategy.UNKNOWN in (self.strategy, compareto.strategy):
raise AwesomeVersionCompareException(
f"Can't compare <{self.strategy.value} {self._version}> and "
f"<{compareto.strategy.value} {compareto._version}>"
)
return self._compare_versions(compareto, self)
def __gt__(self, compareto: VersionType) -> bool:
"""Check if greater than."""
if isinstance(compareto, (str, float, int)):
compareto = AwesomeVersion(compareto)
if not isinstance(compareto, AwesomeVersion):
raise AwesomeVersionCompareException("Not a valid AwesomeVersion object")
if self.string == compareto.string:
return False
if AwesomeVersionStrategy.UNKNOWN in (self.strategy, compareto.strategy):
raise AwesomeVersionCompareException(
f"Can't compare <{self.strategy.value} {self._version}> and "
f"<{compareto.strategy.value} {compareto._version}>"
)
return self._compare_versions(self, compareto)
def __ne__(self, compareto: object) -> bool:
return not self.__eq__(compareto)
def __le__(self, compareto: object) -> bool:
return self.__eq__(compareto) or self.__lt__(compareto)
def __ge__(self, compareto: object) -> bool:
return self.__eq__(compareto) or self.__gt__(compareto)
def __sub__(self, compareto: object) -> AwesomeVersionDiff:
return self.diff(compareto)
def __hash__(self) -> int:
return str.__hash__(self.string)
def diff(self, compareto: VersionType) -> AwesomeVersionDiff:
"""Return a dictionary with differences between 2 AwesomeVersion objects."""
if isinstance(compareto, (str, float, int)):
compareto = AwesomeVersion(compareto)
if not isinstance(compareto, AwesomeVersion):
raise AwesomeVersionCompareException("Not a valid AwesomeVersion object")
return AwesomeVersionDiff(
{
"major": str(self.major) != str(compareto.major),
"minor": str(self.minor) != str(compareto.minor),
"patch": str(self.patch) != str(compareto.patch),
"modifier": self.modifier != compareto.modifier,
"strategy": self.strategy != compareto.strategy,
}
)
def in_range(self, lowest: VersionType, highest: VersionType) -> bool:
"""Check if version is in range."""
if isinstance(lowest, (str, float, int)):
lowest = AwesomeVersion(lowest)
if isinstance(highest, (str, float, int)):
highest = AwesomeVersion(highest)
if not isinstance(lowest, AwesomeVersion):
raise AwesomeVersionCompareException("Lowest version is not valid")
if not isinstance(highest, AwesomeVersion):
raise AwesomeVersionCompareException("Highest version is not valid")
return lowest <= self <= highest
def section(self, idx: int) -> int:
"""Return the value of the specified section of the version."""
if self.strategy == AwesomeVersionStrategy.HEXVER:
return int(self.string, 16) if idx == 0 else 0
if self.sections >= (idx + 1):
match = RE_DIGIT.match(self.string.split(".")[idx] or "")
if match and match.groups():
return int(match.group(1) or 0)
return 0
@staticmethod
def _compare_versions(version_a: AwesomeVersion, version_b: AwesomeVersion) -> bool:
"""Compare versions."""
for handler in (
compare_handler_container,
compare_handler_simple,
compare_handler_sections,
compare_handler_semver_modifier,
):
result = handler(version_a, version_b)
if result is not None:
return result
return False
@property
def string(self) -> str:
"""Return a string representation of the version."""
if not self._version:
return self._version
prefix = self.prefix
if prefix is None:
return self._version
return self._version[len(prefix) :]
@property
def prefix(self) -> str | None:
"""Return the version prefix if any"""
version = self._version
for prefix in ("v", "V", "v.", "V."):
if version.startswith(prefix):
return prefix
return None
@property
def alpha(self) -> bool:
"""Return a bool to indicate alpha version."""
return "a" in self.modifier if self.modifier else False
@property
def beta(self) -> bool:
"""Return a bool to indicate beta version."""
return "b" in self.modifier if self.modifier else "beta" in self.string
@property
def dev(self) -> bool:
"""Return a bool to indicate dev version."""
return "d" in self.modifier if self.modifier else "dev" in self.string
@property
def release_candidate(self) -> bool:
"""Return a bool to indicate release candidate version."""
return "rc" in self.modifier if self.modifier else "rc" in self.string
@property
def sections(self) -> int:
"""Return a int representation of the number of sections in the version."""
if self._sections is not None:
return self._sections
if self.strategy == AwesomeVersionStrategy.SEMVER:
self._sections = 3
else:
modifier = self.modifier
self._sections = len(
[
section.split(self.modifier_type)[-1]
for section in self.string.split(".")
if section and (modifier is None or section != modifier)
]
)
return self._sections
@property
def major(self) -> AwesomeVersion | None:
"""
Return a AwesomeVersion representation of the major version.
Will return None if the versions is not semver/buildver/calver/simplever/pep440.
"""
if self.strategy not in (
AwesomeVersionStrategy.SEMVER,
AwesomeVersionStrategy.BUILDVER,
AwesomeVersionStrategy.CALVER,
AwesomeVersionStrategy.SIMPLEVER,
AwesomeVersionStrategy.PEP440,
):
return None
return AwesomeVersion(self.section(0))
@property
def minor(self) -> AwesomeVersion | None:
"""
Return a AwesomeVersion representation of the minor version.
Will return None if the versions is not semver/simplever/calver/pep440
Will return None if the version does not have at least 2 sections.
"""
if (
self.strategy
not in (
AwesomeVersionStrategy.SEMVER,
AwesomeVersionStrategy.CALVER,
AwesomeVersionStrategy.SIMPLEVER,
AwesomeVersionStrategy.PEP440,
)
or self.sections < 2
):
return None
return AwesomeVersion(self.section(1))
@property
def patch(self) -> AwesomeVersion | None:
"""
Return a AwesomeVersion representation of the patch version.
Will return None if the versions is not semver/simplever/calver/pep440
Will return None if the version does not have at least 3 sections.
"""
if (
self.strategy
not in (
AwesomeVersionStrategy.SEMVER,
AwesomeVersionStrategy.CALVER,
AwesomeVersionStrategy.SIMPLEVER,
AwesomeVersionStrategy.PEP440,
)
or self.sections < 3
):
return None
return AwesomeVersion(self.section(2))
@property
def micro(self) -> AwesomeVersion | None:
"""Alias to self.patch"""
return self.patch
@property
def year(self) -> AwesomeVersion | None:
"""Alias to self.major, here to provide a better name for use in CalVer."""
return self.major
@property
def valid(self) -> bool:
"""Return True if the version is not UNKNOWN."""
return self.strategy != AwesomeVersionStrategy.UNKNOWN
@property
def modifier(self) -> str | None:
"""Return the modifier of the version if any."""
if self._modifier is not None:
return self._modifier
if self.strategy in (
AwesomeVersionStrategy.SPECIALCONTAINER,
AwesomeVersionStrategy.HEXVER,
):
return None
modifier_string = None
if (
self.strategy_description is not None
and self.strategy_description.strategy == AwesomeVersionStrategy.SEMVER
):
match = self.strategy_description.pattern.match(self.string)
if match and len(match.groups()) >= 4:
self._modifier = modifier_string = match.group(4)
else:
modifier_string = self.string.split(".")[-1]
if not modifier_string:
return None
match = RE_MODIFIER.match(modifier_string)
if match and len(match.groups()) >= 2:
self._modifier = match.group(2)
return self._modifier
@property
def modifier_type(self) -> str | None:
"""Return the modifier type of the version if any."""
if self._modifier_type is not None:
return self._modifier_type
if self.strategy == AwesomeVersionStrategy.HEXVER:
return None
match = RE_MODIFIER.match(self.modifier or "")
if match and len(match.groups()) >= 3:
self._modifier_type = match.group(3)
return self._modifier_type
@property
def strategy_description(self) -> AwesomeVersionStrategyDescription | None:
"""Return a string representation of the strategy."""
if self.strategy == AwesomeVersionStrategy.UNKNOWN:
return None
return VERSION_STRATEGIES_DICT[self.strategy]
@property
def strategy(self) -> AwesomeVersionStrategy:
"""Return the version strategy."""
version_strategies: dict[
AwesomeVersionStrategy, AwesomeVersionStrategyDescription
] = {}
for strategy in self._ensure_strategy or []:
version_strategies[strategy] = VERSION_STRATEGIES_DICT[strategy]
for description in VERSION_STRATEGIES:
if description.strategy not in version_strategies:
version_strategies[description.strategy] = description
for description in version_strategies.values():
if description.pattern.match(self.string) is not None and (
description.validate is None or description.validate(self.string)
):
return description.strategy
return AwesomeVersionStrategy.UNKNOWN
@property
def simple(self) -> bool:
"""Return True if the version string is simple."""
if self._simple is None:
self._simple = (
generate_full_string_regex(RE_SIMPLE).match(self.string) is not None
)
return self._simple
class AwesomeVersionDiff:
"""Structured output of AwesomeVersion.diff"""
def __init__(self, changes: Dict[str, bool]) -> None:
"""Initialize the AwesomeVersionDiff."""
self._changes = changes
def __repr__(self) -> str:
return (
f"AwesomeVersionDiff(major={self.major}, minor={self.minor}, "
f"patch={self.patch}, modifier={self.modifier}, strategy={self.strategy})"
)
@property
def major(self) -> bool:
"""Return True if the major version has changed."""
return self._changes["major"]
@property
def minor(self) -> bool:
"""Return True if the minor version has changed."""
return self._changes["minor"]
@property
def patch(self) -> bool:
"""Return True if the patch version has changed."""
return self._changes["patch"]
@property
def modifier(self) -> bool:
"""Return True if the modifier version has changed."""
return self._changes["modifier"]
@property
def strategy(self) -> bool:
"""Return True if the strategy has changed."""
return self._changes["strategy"]
awesomeversion-24.2.0/awesomeversion/comparehandlers/ 0000775 0000000 0000000 00000000000 14560504261 0023065 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/awesomeversion/comparehandlers/__init__.py 0000664 0000000 0000000 00000000071 14560504261 0025174 0 ustar 00root root 0000000 0000000 """Initialize the comparehandlers for AwesomeVersion."""
awesomeversion-24.2.0/awesomeversion/comparehandlers/container.py 0000664 0000000 0000000 00000001522 14560504261 0025421 0 ustar 00root root 0000000 0000000 """Special handler for container."""
from __future__ import annotations
from typing import TYPE_CHECKING
from ..strategy import AwesomeVersionStrategy
CONTAINER_VERSION_MAP = {"stable": 1, "beta": 2, "latest": 3, "dev": 4}
if TYPE_CHECKING:
from awesomeversion import AwesomeVersion
def compare_handler_container(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare handler container."""
if version_a.strategy == AwesomeVersionStrategy.SPECIALCONTAINER:
if version_b.strategy != AwesomeVersionStrategy.SPECIALCONTAINER:
return True
return (
CONTAINER_VERSION_MAP[version_a.string]
> CONTAINER_VERSION_MAP[version_b.string]
)
if version_b.strategy == AwesomeVersionStrategy.SPECIALCONTAINER:
return False
return None
awesomeversion-24.2.0/awesomeversion/comparehandlers/modifier.py 0000664 0000000 0000000 00000003454 14560504261 0025243 0 ustar 00root root 0000000 0000000 """Special handler for modifier."""
from __future__ import annotations
from typing import TYPE_CHECKING
from ..strategy import VERSION_STRATEGIES_DICT, AwesomeVersionStrategy
from ..utils.regex import RE_MODIFIER
SEMVER_MODIFIER_MAP = {"dev": 0, "alpha": 1, "beta": 2, "rc": 3}
if TYPE_CHECKING:
from awesomeversion import AwesomeVersion
def compare_handler_semver_modifier(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare handler sections."""
if AwesomeVersionStrategy.SEMVER not in (
version_a.strategy,
version_b.strategy,
) or (version_a.modifier_type is None or version_b.modifier_type is None):
return None
if version_a.modifier_type != version_b.modifier_type:
mod_a = SEMVER_MODIFIER_MAP.get(version_a.modifier_type)
mod_b = SEMVER_MODIFIER_MAP.get(version_b.modifier_type)
if mod_a is not None and mod_b is not None:
return mod_a > mod_b
ver_a_modifier, ver_b_modifier = None, None
semver_pattern = VERSION_STRATEGIES_DICT[AwesomeVersionStrategy.SEMVER].pattern
semver_match = semver_pattern.match(version_a.string)
if semver_match and len(semver_match.groups()) >= 4:
modifier_match = RE_MODIFIER.match(semver_match.group(4))
if modifier_match and len(modifier_match.groups()) >= 4:
ver_a_modifier = modifier_match.group(4)
semver_match = semver_pattern.match(version_b.string)
if semver_match and len(semver_match.groups()) >= 4:
modifier_match = RE_MODIFIER.match(semver_match.group(4))
if modifier_match and len(modifier_match.groups()) >= 4:
ver_b_modifier = modifier_match.group(4)
if not ver_a_modifier or not ver_b_modifier:
return True
return int(ver_a_modifier) > int(ver_b_modifier)
awesomeversion-24.2.0/awesomeversion/comparehandlers/sections.py 0000664 0000000 0000000 00000004776 14560504261 0025304 0 ustar 00root root 0000000 0000000 """Special handler for sections."""
from __future__ import annotations
from typing import TYPE_CHECKING
from ..utils.regex import RE_IS_SINGLE_DIGIT, RE_MODIFIER
if TYPE_CHECKING:
from ..awesomeversion import AwesomeVersion
MODIFIERS = {"rc": 3, "beta": 2, "b": 2, "alpha": 1, "a": 1, "dev": 0, "d": 0}
def compare_handler_sections(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare handler sections."""
base = compare_base_sections(version_a, version_b)
if base is not None:
return base
return compare_modifier_section(version_a, version_b)
def compare_base_sections(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare base sections between two AwesomeVersion objects."""
biggest = (
version_a.sections
if version_a.sections >= version_b.sections
else version_b.sections
)
for section in range(0, biggest):
ver_a_section = version_a.section(section)
ver_b_section = version_b.section(section)
if ver_a_section == ver_b_section:
continue
if ver_a_section > ver_b_section:
return True
if ver_a_section < ver_b_section:
return False
return None
def compare_modifier_section(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare modifiers between two AwesomeVersion objects."""
if version_a.modifier is None and version_b.modifier is not None:
return True
if version_a.modifier is not None and version_b.modifier is not None:
version_a_modifier = RE_MODIFIER.match(version_a.string.split(".")[-1])
version_b_modifier = RE_MODIFIER.match(version_b.string.split(".")[-1])
if version_a_modifier and version_b_modifier:
if version_a_modifier.group(3) == version_b_modifier.group(3):
return int(version_a_modifier.group(4) or 0) > int(
version_b_modifier.group(4) or 0
)
mod_a = MODIFIERS.get(version_a_modifier.group(3))
mod_b = MODIFIERS.get(version_b_modifier.group(3))
if mod_a is not None and mod_b is not None:
return mod_a > mod_b
return version_a_modifier.group(3) > version_a_modifier.group(3)
if RE_IS_SINGLE_DIGIT.match(version_a.modifier) and RE_IS_SINGLE_DIGIT.match(
version_b.modifier
):
return int(version_a.modifier) > int(version_b.modifier)
return None
awesomeversion-24.2.0/awesomeversion/comparehandlers/simple.py 0000664 0000000 0000000 00000000737 14560504261 0024737 0 ustar 00root root 0000000 0000000 """Special handler for simple."""
from __future__ import annotations
from typing import TYPE_CHECKING
from .sections import compare_base_sections
if TYPE_CHECKING:
from awesomeversion import AwesomeVersion
def compare_handler_simple(
version_a: AwesomeVersion,
version_b: AwesomeVersion,
) -> bool | None:
"""Compare handler simple."""
if version_a.simple and version_b.simple:
return compare_base_sections(version_a, version_b)
return None
awesomeversion-24.2.0/awesomeversion/exceptions.py 0000664 0000000 0000000 00000000550 14560504261 0022451 0 ustar 00root root 0000000 0000000 """Exceptions for AwesomeVersion."""
class AwesomeVersionException(Exception):
"""Base AwesomeVersion exception."""
class AwesomeVersionCompareException(AwesomeVersionException):
"""Thrown when compare is not possible."""
class AwesomeVersionStrategyException(AwesomeVersionException):
"""Thrown when the expected strategy does not match."""
awesomeversion-24.2.0/awesomeversion/py.typed 0000664 0000000 0000000 00000000000 14560504261 0021403 0 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/awesomeversion/strategy.py 0000664 0000000 0000000 00000005223 14560504261 0022134 0 ustar 00root root 0000000 0000000 """Strategies for AwesomeVersion."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from enum import Enum
from typing import Pattern, Tuple
from .utils.regex import (
RE_BUILDVER,
RE_CALVER,
RE_HEXVER,
RE_PEP440,
RE_SEMVER,
RE_SIMPLE,
RE_SPECIAL_CONTAINER,
generate_full_string_regex,
)
from .utils.validate import value_is_base16
class AwesomeVersionStrategy(str, Enum):
"""Strategy enum."""
BUILDVER = "BuildVer"
CALVER = "CalVer"
HEXVER = "HexVer"
SEMVER = "SemVer"
SIMPLEVER = "SimpleVer"
PEP440 = "PEP 440"
UNKNOWN = "unknown"
SPECIALCONTAINER = "SpecialContainer"
@dataclass
class AwesomeVersionStrategyDescription:
"""Description of a strategy."""
strategy: AwesomeVersionStrategy
regex_string: str
pattern: Pattern[str]
validate: Callable[[str], bool] | None = None
COMPARABLE_STRATEGIES = [
strategy
for strategy in AwesomeVersionStrategy
if strategy
not in (AwesomeVersionStrategy.UNKNOWN, AwesomeVersionStrategy.SPECIALCONTAINER)
]
VERSION_STRATEGIES: Tuple[AwesomeVersionStrategyDescription, ...] = (
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.BUILDVER,
regex_string=RE_BUILDVER,
pattern=generate_full_string_regex(RE_BUILDVER),
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.CALVER,
regex_string=RE_CALVER,
pattern=generate_full_string_regex(RE_CALVER),
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.HEXVER,
regex_string=RE_HEXVER,
pattern=generate_full_string_regex(RE_HEXVER),
validate=value_is_base16,
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.SEMVER,
regex_string=RE_SEMVER,
pattern=generate_full_string_regex(RE_SEMVER),
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.SPECIALCONTAINER,
regex_string=RE_SPECIAL_CONTAINER,
pattern=generate_full_string_regex(RE_SPECIAL_CONTAINER),
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.SIMPLEVER,
regex_string=RE_SIMPLE,
pattern=generate_full_string_regex(RE_SIMPLE),
),
AwesomeVersionStrategyDescription(
strategy=AwesomeVersionStrategy.PEP440,
regex_string=RE_PEP440,
pattern=generate_full_string_regex(RE_PEP440),
),
)
VERSION_STRATEGIES_DICT: dict[
AwesomeVersionStrategy, AwesomeVersionStrategyDescription
] = {description.strategy: description for description in VERSION_STRATEGIES}
awesomeversion-24.2.0/awesomeversion/typing.py 0000664 0000000 0000000 00000000764 14560504261 0021611 0 ustar 00root root 0000000 0000000 """"Custom types for AwesomeVersion."""
from __future__ import annotations
from typing import TYPE_CHECKING, List, Tuple, Union
from .strategy import AwesomeVersionStrategy
if TYPE_CHECKING:
from .awesomeversion import AwesomeVersion
VersionType = Union[str, float, int, object, "AwesomeVersion"]
EnsureStrategyIterableType = Union[
List[AwesomeVersionStrategy], Tuple[AwesomeVersionStrategy, ...]
]
EnsureStrategyType = Union[AwesomeVersionStrategy, EnsureStrategyIterableType, None]
awesomeversion-24.2.0/awesomeversion/utils/ 0000775 0000000 0000000 00000000000 14560504261 0021056 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/awesomeversion/utils/__init__.py 0000664 0000000 0000000 00000000000 14560504261 0023155 0 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/awesomeversion/utils/regex.py 0000664 0000000 0000000 00000002206 14560504261 0022542 0 ustar 00root root 0000000 0000000 """Regex utils for AwesomeVersion."""
import re
from typing import Pattern
# General purpose patterns
RE_IS_SINGLE_DIGIT = re.compile(r"^\d{1}$")
RE_DIGIT = re.compile(r"[a-z]*(\d+)[a-z]*")
RE_MODIFIER = re.compile(r"^((?:\d+\-|\d|))(([a-z]+)\.?(\d*))$")
# Version patterns
RE_CALVER = r"(\d{2}|\d{4})\.\d{1,2}?(\.?\d{1,2}?\.?)?(\.\d)?(\d*(\w+\d+)?)"
RE_SEMVER = (
r"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)"
r"(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?"
)
RE_PEP440 = (
r"([1-9][0-9]*!)?(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*))*((a|b|rc)"
r"(0|[1-9][0-9]*))?(\.post(0|[1-9][0-9]*))?(\.dev(0|[1-9][0-9]*))?(\.rc(0|[1-9][0-9]*))?"
)
RE_BUILDVER = r"\d+"
RE_HEXVER = r"0x[A-Fa-f0-9]+"
RE_SPECIAL_CONTAINER = r"(latest|dev|stable|beta)"
RE_SIMPLE = r"[v|V]?((\d+)(\.\d+)+)"
def compile_regex(pattern: str) -> Pattern[str]:
"""Compile a regex."""
return re.compile(pattern)
def generate_full_string_regex(string: str) -> Pattern[str]:
"""Generate a regex that matches the full string."""
return compile_regex(r"^" + string + r"$")
awesomeversion-24.2.0/awesomeversion/utils/validate.py 0000664 0000000 0000000 00000000306 14560504261 0023220 0 ustar 00root root 0000000 0000000 """Utils to validate."""
def value_is_base16(value: str) -> bool:
"""Check if a value is base16."""
try:
int(value, 16)
except ValueError:
return False
return True
awesomeversion-24.2.0/demo/ 0000775 0000000 0000000 00000000000 14560504261 0015574 5 ustar 00root root 0000000 0000000 awesomeversion-24.2.0/demo/index.html 0000664 0000000 0000000 00000012676 14560504261 0017605 0 ustar 00root root 0000000 0000000
AwesomeVersion Demo
{
"packages": ["awesomeversion"]
}
from awesomeversion import AwesomeVersion
import json
import inspect
def safe_compare(a, b):
try:
return a > b
except Exception:
return None
def version_json(version):
return json.dumps(
{
"string": version.string,
"alpha": version.alpha,
"beta": version.beta,
"dev": version.dev,
"major": version.major,
"micro": version.micro,
"minor": version.minor,
"modifier_type": version.modifier_type,
"modifier": version.modifier,
"patch": version.patch,
"prefix": version.prefix,
"release_candidate": version.release_candidate,
"sections": version.sections,
"simple": version.simple,
"strategy": version.strategy,
"valid": version.valid,
"year": version.year,
},
indent=2
)
def extract_awesomeversion_properties(*args, **kwargs):
versions = {
"a": AwesomeVersion(Element("version-input-a").element.value.strip() or None),
"b": AwesomeVersion(Element("version-input-b").element.value.strip() or None)
}
for key,version in versions.items():
if version.string == "None":
Element(f"properties-output-{key}").element.innerText = ""
Element("properties-output-diff").element.innerText = ""
continue
Element(f"properties-output-{key}").element.innerText = f"Version {key.upper()} properties:\n{version_json(version)}"
if versions["a"].string != "None" and versions["b"].string != "None":
Element("properties-output-diff").element.innerText =f"""Compare:
{json.dumps({
f"{versions['a'].string}>{versions['b'].string}": safe_compare(versions["a"],versions["b"]),
f"{versions['b'].string}>{versions['a'].string}": safe_compare(versions["b"],versions["a"]),
"diff": {
"major": versions["a"].major != versions["b"].major,
"minor": versions["a"].minor != versions["b"].minor,
"patch": versions["a"].patch != versions["b"].patch,
"modifier": versions["a"].modifier != versions["b"].modifier,
"strategy": versions["a"].strategy != versions["b"].strategy,
}
},indent=2)}"""