Skip to content

Commit

Permalink
Python 3.12 is released
Browse files Browse the repository at this point in the history
Start testing with Python 3.13
  • Loading branch information
arcivanov committed Oct 5, 2023
1 parent d6ef457 commit 8f8fb6a
Show file tree
Hide file tree
Showing 94 changed files with 1,034 additions and 982 deletions.
13 changes: 3 additions & 10 deletions .github/workflows/pybuilder.yml
Expand Up @@ -14,12 +14,11 @@ jobs:
os:
- ubuntu-latest
python-version:
- '3.12-dev'
- '3.12'
- '3.11'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
with-venv:
- 'true'
- 'false'
Expand Down Expand Up @@ -49,24 +48,18 @@ jobs:
- macos-11
- macos-12
python-version:
- '3.12'
- '3.11'
- '3.10'
- '3.9'
- '3.8'
- '3.7'
with-venv:
- 'true'
- 'false'
with-homebrew:
- 'true'
- 'false'
exclude:
- os: macos-11
python-version: '3.7'
with-homebrew: 'true'
- os: macos-12
python-version: '3.7'
with-homebrew: 'true'
- os: macos-11
python-version: '3.8'
with-homebrew: 'true'
Expand Down Expand Up @@ -98,7 +91,7 @@ jobs:
- macos-11
- macos-12
python-version:
- 'pypy-3.7'
- '3.13-dev'
- 'pypy-3.8'
- 'pypy-3.9'
with-venv:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -19,7 +19,7 @@ PyBuilder is based on the concept of dependency based programming, but it also
comes with a powerful plugin mechanism, allowing the construction of build life
cycles similar to those known from other famous (Java) build tools.

PyBuilder is running on the following versions of Python 3.7, 3.8, 3.9, 3.10, 3.11, 3.12 and PyPy 3.7, 3.8 and 3.9.
PyBuilder is running on the following versions of Python 3.8, 3.9, 3.10, 3.11, 3.12 and PyPy 3.8 and 3.9.

See the [GitHub Actions Workflow](https://github.com/pybuilder/pybuilder/actions/workflows/pybuilder.yml) for version specific output.

Expand Down
8 changes: 4 additions & 4 deletions build.py
Expand Up @@ -89,7 +89,7 @@
license = "Apache License, Version 2.0"
version = "0.13.11.dev"

requires_python = ">=3.7"
requires_python = ">=3.8"

default_task = ["analyze", "publish"]

Expand All @@ -106,8 +106,9 @@ def initialize(project):
"setuptools>=45.0.0",
"virtualenv>=20.0.0",
"importlib-resources>=1.0",
"importlib-metadata>=0.12,<5.0",
"typing-extensions",
"importlib-metadata>=0.12,<6.8.0",
"zipp<3.16.0",
"typing-extensions<4.8.0",
"colorama~=0.4.3"
])
project.set_property("vendorize_cleanup_globs", ["bin",
Expand Down Expand Up @@ -176,7 +177,6 @@ def initialize(project):
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
Expand Down
244 changes: 122 additions & 122 deletions src/main/python/pybuilder/_vendor/LICENSES

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/main/python/pybuilder/_vendor/distlib/__init__.py
Expand Up @@ -6,7 +6,7 @@
#
import logging

__version__ = '0.3.6'
__version__ = '0.3.7'

class DistlibException(Exception):
pass
Expand Down
9 changes: 6 additions & 3 deletions src/main/python/pybuilder/_vendor/distlib/database.py
Expand Up @@ -903,15 +903,18 @@ def parse_requires_data(data):
lines = data.splitlines()
for line in lines:
line = line.strip()
if line.startswith('['):
# sectioned files have bare newlines (separating sections)
if not line: # pragma: no cover
continue
if line.startswith('['): # pragma: no cover
logger.warning('Unexpected line: quitting requirement scan: %r',
line)
break
r = parse_requirement(line)
if not r:
if not r: # pragma: no cover
logger.warning('Not recognised as a requirement: %r', line)
continue
if r.extras:
if r.extras: # pragma: no cover
logger.warning('extra requirements in requires.txt are '
'not supported')
if not r.constraints:
Expand Down
5 changes: 3 additions & 2 deletions src/main/python/pybuilder/_vendor/distlib/manifest.py
Expand Up @@ -35,8 +35,9 @@
_PYTHON_VERSION = sys.version_info[:2]

class Manifest(object):
"""A list of files built by on exploring the filesystem and filtered by
applying various patterns to what we find there.
"""
A list of files built by exploring the filesystem and filtered by applying various
patterns to what we find there.
"""

def __init__(self, base=None):
Expand Down
15 changes: 8 additions & 7 deletions src/main/python/pybuilder/_vendor/distlib/markers.py
Expand Up @@ -24,21 +24,22 @@
__all__ = ['interpret']

_VERSION_PATTERN = re.compile(r'((\d+(\.\d+)*\w*)|\'(\d+(\.\d+)*\w*)\'|\"(\d+(\.\d+)*\w*)\")')
_VERSION_MARKERS = {'python_version', 'python_full_version'}

def _is_version_marker(s):
return isinstance(s, string_types) and s in _VERSION_MARKERS

def _is_literal(o):
if not isinstance(o, string_types) or not o:
return False
return o[0] in '\'"'

def _get_versions(s):
result = []
for m in _VERSION_PATTERN.finditer(s):
result.append(NV(m.groups()[0]))
return set(result)
return {NV(m.groups()[0]) for m in _VERSION_PATTERN.finditer(s)}

class Evaluator(object):
"""
This class is used to evaluate marker expessions.
This class is used to evaluate marker expressions.
"""

operations = {
Expand Down Expand Up @@ -80,11 +81,11 @@ def evaluate(self, expr, context):

lhs = self.evaluate(elhs, context)
rhs = self.evaluate(erhs, context)
if ((elhs == 'python_version' or erhs == 'python_version') and
if ((_is_version_marker(elhs) or _is_version_marker(erhs)) and
op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')):
lhs = NV(lhs)
rhs = NV(rhs)
elif elhs == 'python_version' and op in ('in', 'not in'):
elif _is_version_marker(elhs) and op in ('in', 'not in'):
lhs = NV(lhs)
rhs = _get_versions(rhs)
result = self.operations[op](lhs, rhs)
Expand Down
12 changes: 2 additions & 10 deletions src/main/python/pybuilder/_vendor/distlib/metadata.py
Expand Up @@ -136,17 +136,9 @@ def _version2fieldlist(version):
def _best_version(fields):
"""Detect the best version depending on the fields used."""
def _has_marker(keys, markers):
for marker in markers:
if marker in keys:
return True
return False

keys = []
for key, value in fields.items():
if value in ([], 'UNKNOWN', None):
continue
keys.append(key)
return any(marker in keys for marker in markers)

keys = [key for key, value in fields.items() if value not in ([], 'UNKNOWN', None)]
possible_versions = ['1.0', '1.1', '1.2', '1.3', '2.1', '2.2'] # 2.0 removed

# first let's try to see if a field is not part of one of the version
Expand Down
11 changes: 6 additions & 5 deletions src/main/python/pybuilder/_vendor/distlib/scripts.py
Expand Up @@ -168,15 +168,16 @@ def _get_shebang(self, encoding, post_interp=b'', options=None):
executable = os.path.join(sysconfig.get_path('scripts'),
'python%s' % sysconfig.get_config_var('EXE'))
else: # pragma: no cover
executable = os.path.join(
sysconfig.get_config_var('BINDIR'),
'python%s%s' % (sysconfig.get_config_var('VERSION'),
sysconfig.get_config_var('EXE')))
if not os.path.isfile(executable):
if os.name == 'nt':
# for Python builds from source on Windows, no Python executables with
# a version suffix are created, so we use python.exe
executable = os.path.join(sysconfig.get_config_var('BINDIR'),
'python%s' % (sysconfig.get_config_var('EXE')))
else:
executable = os.path.join(
sysconfig.get_config_var('BINDIR'),
'python%s%s' % (sysconfig.get_config_var('VERSION'),
sysconfig.get_config_var('EXE')))
if options:
executable = self._get_alternate_executable(executable, options)

Expand Down
25 changes: 21 additions & 4 deletions src/main/python/pybuilder/_vendor/distlib/util.py
Expand Up @@ -707,7 +707,7 @@ def __eq__(self, other):
__hash__ = object.__hash__


ENTRY_RE = re.compile(r'''(?P<name>(\w|[-.+])+)
ENTRY_RE = re.compile(r'''(?P<name>([^\[]\S*))
\s*=\s*(?P<callable>(\w+)([:\.]\w+)*)
\s*(\[\s*(?P<flags>[\w-]+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])?
''', re.VERBOSE)
Expand Down Expand Up @@ -1249,6 +1249,19 @@ def check_path(path):
for tarinfo in archive.getmembers():
if not isinstance(tarinfo.name, text_type):
tarinfo.name = tarinfo.name.decode('utf-8')

# Limit extraction of dangerous items, if this Python
# allows it easily. If not, just trust the input.
# See: https://docs.python.org/3/library/tarfile.html#extraction-filters
def extraction_filter(member, path):
"""Run tarfile.tar_filter, but raise the expected ValueError"""
# This is only called if the current Python has tarfile filters
try:
return tarfile.tar_filter(member, path)
except tarfile.FilterError as exc:
raise ValueError(str(exc))
archive.extraction_filter = extraction_filter

archive.extractall(dest_dir)

finally:
Expand Down Expand Up @@ -1435,7 +1448,7 @@ def connect(self):
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
if hasattr(ssl, 'OP_NO_SSLv2'):
context.options |= ssl.OP_NO_SSLv2
if self.cert_file:
if getattr(self, 'cert_file', None):
context.load_cert_chain(self.cert_file, self.key_file)
kwargs = {}
if self.ca_certs:
Expand Down Expand Up @@ -1908,9 +1921,13 @@ def get_host_platform():
if m:
release = m.group()
elif osname[:6] == 'darwin':
import _osx_support, distutils.sysconfig
import _osx_support
try:
from distutils import sysconfig
except ImportError:
import sysconfig
osname, release, machine = _osx_support.get_platform_osx(
distutils.sysconfig.get_config_vars(),
sysconfig.get_config_vars(),
osname, release, machine)

return '%s-%s-%s' % (osname, release, machine)
Expand Down
21 changes: 15 additions & 6 deletions src/main/python/pybuilder/_vendor/distlib/version.py
Expand Up @@ -176,9 +176,9 @@ def __str__(self):
return self._string


PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|b|c|rc)(\d+))?'
r'(\.(post)(\d+))?(\.(dev)(\d+))?'
r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$')
PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|alpha|b|beta|c|rc|pre|preview)(\d+)?)?'
r'(\.(post|r|rev)(\d+)?)?([._-]?(dev)(\d+)?)?'
r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$', re.I)


def _pep_440_key(s):
Expand All @@ -202,15 +202,24 @@ def _pep_440_key(s):
if pre == (None, None):
pre = ()
else:
pre = pre[0], int(pre[1])
if pre[1] is None:
pre = pre[0], 0
else:
pre = pre[0], int(pre[1])
if post == (None, None):
post = ()
else:
post = post[0], int(post[1])
if post[1] is None:
post = post[0], 0
else:
post = post[0], int(post[1])
if dev == (None, None):
dev = ()
else:
dev = dev[0], int(dev[1])
if dev[1] is None:
dev = dev[0], 0
else:
dev = dev[0], int(dev[1])
if local is None:
local = ()
else:
Expand Down
4 changes: 2 additions & 2 deletions src/main/python/pybuilder/_vendor/filelock/__init__.py
Expand Up @@ -24,8 +24,8 @@

if sys.platform == "win32": # pragma: win32 cover
_FileLock: type[BaseFileLock] = WindowsFileLock
else: # pragma: win32 no cover
if has_fcntl: # noqa: PLR5501
else: # pragma: win32 no cover # noqa: PLR5501
if has_fcntl:
_FileLock: type[BaseFileLock] = UnixFileLock
else:
_FileLock = SoftFileLock
Expand Down
11 changes: 9 additions & 2 deletions src/main/python/pybuilder/_vendor/filelock/_api.py
Expand Up @@ -13,8 +13,15 @@
from ._error import Timeout

if TYPE_CHECKING:
import sys
from types import TracebackType

if sys.version_info >= (3, 11): # pragma: no cover (py311+)
from typing import Self
else: # pragma: no cover (<py311)
from typing_extensions import Self


_LOGGER = logging.getLogger("filelock")


Expand Down Expand Up @@ -71,7 +78,7 @@ class BaseFileLock(ABC, contextlib.ContextDecorator):

def __init__(
self,
lock_file: str | os.PathLike[Any],
lock_file: str | os.PathLike[str],
timeout: float = -1,
mode: int = 0o644,
thread_local: bool = True, # noqa: FBT001, FBT002
Expand Down Expand Up @@ -246,7 +253,7 @@ def release(self, force: bool = False) -> None: # noqa: FBT001, FBT002
self._context.lock_counter = 0
_LOGGER.debug("Lock %s released on %s", lock_id, lock_filename)

def __enter__(self) -> BaseFileLock:
def __enter__(self) -> Self:
"""
Acquire the lock.
Expand Down
3 changes: 2 additions & 1 deletion src/main/python/pybuilder/_vendor/filelock/_soft.py
Expand Up @@ -7,14 +7,15 @@
from pathlib import Path

from ._api import BaseFileLock
from ._util import raise_on_not_writable_file
from ._util import ensure_directory_exists, raise_on_not_writable_file


class SoftFileLock(BaseFileLock):
"""Simply watches the existence of the lock file."""

def _acquire(self) -> None:
raise_on_not_writable_file(self.lock_file)
ensure_directory_exists(self.lock_file)
# first check for exists and read-only mode as the open will mask this case as EEXIST
flags = (
os.O_WRONLY # open for writing only
Expand Down
2 changes: 2 additions & 0 deletions src/main/python/pybuilder/_vendor/filelock/_unix.py
Expand Up @@ -7,6 +7,7 @@
from typing import cast

from ._api import BaseFileLock
from ._util import ensure_directory_exists

#: a flag to indicate if the fcntl API is available
has_fcntl = False
Expand All @@ -33,6 +34,7 @@ class UnixFileLock(BaseFileLock):
"""Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems."""

def _acquire(self) -> None:
ensure_directory_exists(self.lock_file)
open_flags = os.O_RDWR | os.O_CREAT | os.O_TRUNC
fd = os.open(self.lock_file, open_flags, self._context.mode)
with suppress(PermissionError): # This locked is not owned by this UID
Expand Down

0 comments on commit 8f8fb6a

Please sign in to comment.