"""
The tool to check the availability or syntax of domain, IP or URL.
::
██████╗ ██╗ ██╗███████╗██╗ ██╗███╗ ██╗ ██████╗███████╗██████╗ ██╗ ███████╗
██╔══██╗╚██╗ ██╔╝██╔════╝██║ ██║████╗ ██║██╔════╝██╔════╝██╔══██╗██║ ██╔════╝
██████╔╝ ╚████╔╝ █████╗ ██║ ██║██╔██╗ ██║██║ █████╗ ██████╔╝██║ █████╗
██╔═══╝ ╚██╔╝ ██╔══╝ ██║ ██║██║╚██╗██║██║ ██╔══╝ ██╔══██╗██║ ██╔══╝
██║ ██║ ██║ ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝
Provides everything related to the package and its version.
Author:
Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom
Special thanks:
https://pyfunceble.github.io/special-thanks.html
Contributors:
https://pyfunceble.github.io/contributors.html
Project link:
https://github.com/funilrys/PyFunceble
Project documentation:
https://pyfunceble.readthedocs.io/en/master/
Project homepage:
https://pyfunceble.github.io/
License:
::
Copyright 2017, 2018, 2019, 2020, 2021 Nissar Chababy
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from PyFunceble import helpers
[docs]class Package:
"""
Provides some packaging related abstractions.
"""
NAME = "PyFunceble"
"""
Sets the package name.
:type: str
"""
VERSION = "3.3.9. (Teal Blauwbok: Termite)"
"""
Sets the package version.
:type: str
"""
[docs]class Version:
"""
Provides a simple way to compare our own versions.
"""
[docs] @classmethod
def split_versions(cls, version, return_non_digits=False):
"""
Converts the versions to a shorter one.
:param str version: The version to split.
:param bool return_non_digits:
Activate the return of the non-digits parts of the splitted
version.
:return:
A tuple. The first index is the digit part of the version,
when the second one is the the non-digit part of the
version.
:rtype: tuple
"""
# We split the version.
splited_version = version.split(".")
def get_version_part():
"""
Provides the version part.
"""
return [x for x in splited_version if x.isdigit() or x[0].isdigit()]
def get_codename_part():
"""
Provides the codename part.
"""
try:
return [
x for x in splited_version if not x.isdigit() and not x[0].isdigit()
][0]
except IndexError:
return ""
if not return_non_digits:
# We do not have to return the non digits part of the version.
# We return the digits part of the version.
return get_version_part()
# We return a tuple with first the digits part and finally the non digit parts.
return get_version_part(), get_codename_part()
[docs] @classmethod
def literally_compare(cls, local, upstream):
"""
Compares the given versions, literally.
:param str local:
The local version converted
by :py:func:`~PyFunceble.abstracts.package.split_versions`.
:param str upstream:
The upstream version converted
by :py:func:`~PyFunceble.abstracts.package.split_versions`.
:return:
- :code:`True`: local == upstream
- :code:`False`: local != upstream
:rtype: bool
"""
return local == upstream
[docs] @classmethod
def compare(cls, upstream):
"""
Compares the given versions with the local one.
:param list local:
The local version converted
by :py:func:`~PyFunceble.abstracts.package.split_versions`.
:param list upstream:
The upstream version converted
by :py:func:`~PyFunceble.abstracts.package.split_versions`.
:return:
- :code:`True`: local < upstream
- :code:`None`: local == upstream
- :code:`False`: local > upstream
:rtype: bool, None
"""
def get_version_number_pep440(version_part):
"""
Given a version part it returns the actual version.
As example:
Given :code:`0a1` returns `0971`.
"""
result = []
for part in version_part:
if part.isdigit():
result.append(part)
else:
local_result = ""
for char in part:
if char.isdigit(): # pragma: no cover ## Safety.
local_result += local_result
else:
local_result += str(ord(char))
result.append(local_result)
return "".join(result)
def compare_them(version_number, upstream_number):
"""
Compare and provides the result of the comparison.
"""
# pylint: disable=too-many-return-statements
# ORD A ==> 65 ==> 650
if upstream_number < 650 < version_number:
return True
if version_number < 650 < upstream_number:
return False
if version_number > 650 and upstream_number > 650:
local_upstream_number = str(upstream_number)
for index, value in enumerate(str(version_number)):
try:
if value == local_upstream_number[index]:
continue
except IndexError:
# Example: Comparison of b10 to b1
return False
if value < local_upstream_number[index]:
return True
if value > local_upstream_number[index]:
return False
return None
if version_number < upstream_number:
return True
if version_number > upstream_number:
return False
return None
local_digits, _ = Version.split_versions(
Package.VERSION, return_non_digits=True
)
upstream_digits, _ = Version.split_versions(upstream, return_non_digits=True)
result = []
for index, version_number in enumerate(local_digits):
try:
version_number = int(version_number)
except ValueError:
version_number = int(get_version_number_pep440(version_number))
try:
upstream_number = int(upstream_digits[index])
except ValueError:
upstream_number = int(get_version_number_pep440(upstream_digits[index]))
result.append(compare_them(version_number, upstream_number))
try:
return [x for x in result if x is not None][0]
except IndexError:
return None
[docs] @classmethod
def is_local_dev(cls):
"""
Checks if the local version is the development version.
"""
return cls.split_versions(Package.VERSION, return_non_digits=True)[
-1
].startswith("dev")
[docs] @classmethod
def is_local_cloned(cls): # pragma: no cover
"""
Checks if the local version is was downloaded
per :code:`git clone`.
"""
if not helpers.Directory(".git").exists():
# The git directory does not exist.
# We return False, the current version is not the cloned version.
return False
# We list the list of file which can be found only in a cloned version.
list_of_file = [
".coveragerc",
".gitignore",
".PyFunceble_production.yaml",
"CODE_OF_CONDUCT.rst",
"CONTRIBUTING.rst",
"dir_structure_production.json",
"MANIFEST.in",
"README.rst",
"requirements.txt",
"setup.py",
"version.yaml",
]
# We list the list of directory which can be found only in a cloned
# version.
list_of_dir = ["docs", "PyFunceble", "tests"]
if not all([helpers.File(x).exists() for x in list_of_file]):
return False
# All required files exist in the current directory.
if not all([helpers.Directory(x).exists() for x in list_of_dir]):
return False
# All required directories exist in the current directory.
# We return True, the current version is a cloned version.
return True