Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,28 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
python-version: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15']

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false

- name: Install uv + caching
uses: astral-sh/setup-uv@v10.0.0
with:
enable-cache: true
cache-dependency-glob: |
setup.*
tox.ini
pyproject.toml
python-version: ${{ matrix.python-version }}

- name: Install depenencies (Ubuntu)
- name: Install dependencies (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y mercurial subversion

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox tox-gh-actions

- name: Test with tox
run: tox
run: uvx --with tox-uv --with tox-gh-actions tox
6 changes: 4 additions & 2 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ Changelog
=========


2.1.1 (unreleased)
3.0.0 (unreleased)
------------------

- Nothing changed yet.
- Add support for Python 3.14 and 3.15. [maurits]

- Require Python 3.10 or higher. [maurits]


2.1.0 (2026-08-20)
Expand Down
1 change: 0 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
include *.rst
include *.ini
prune mr.developer.addon
3 changes: 0 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
[bdist_wheel]
universal = 1

[zest.releaser]
version-levels = 2

Expand Down
17 changes: 5 additions & 12 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from setuptools import setup


version = '2.1.1.dev0'
version = '3.0.0.dev0'


install_requires = [
'setuptools',
'zc.buildout',
'six',
]

tests_require = [
Expand All @@ -33,25 +32,19 @@ def get_text_from_file(fn):
classifiers=[
"Development Status :: 5 - Production/Stable",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Framework :: Buildout",
"Topic :: Software Development :: Libraries :: Python Modules"],
keywords='buildout extension vcs git develop',
author='Florian Schulze',
author_email='florian.schulze@gmx.net',
url='http://github.com/fschulze/mr.developer',
url='https://github.com/fschulze/mr.developer',
license='BSD',
packages=['mr', 'mr.developer', 'mr.developer.tests'],
package_dir={'': 'src'},
Expand All @@ -61,7 +54,7 @@ def get_text_from_file(fn):
install_requires=install_requires,
tests_require=tests_require,
extras_require=extras_require,
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
python_requires=">=3.10",
test_suite='mr.developer.tests',
entry_points="""
[console_scripts]
Expand Down
8 changes: 4 additions & 4 deletions src/mr/developer/bazaar.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class BazaarError(common.WCError):
class BazaarWorkingCopy(common.BaseWorkingCopy):

def __init__(self, source):
super(BazaarWorkingCopy, self).__init__(source)
super().__init__(source)
self.bzr_executable = common.which('bzr')

def bzr_branch(self, **kwargs):
Expand All @@ -32,7 +32,7 @@ def bzr_branch(self, **kwargs):
stdout, stderr = cmd.communicate()
if cmd.returncode != 0:
raise BazaarError(
'bzr branch for %r failed.\n%s' % (name, stderr))
f'bzr branch for {name!r} failed.\n{stderr}')
if kwargs.get('verbose', False):
return stdout

Expand All @@ -49,7 +49,7 @@ def bzr_pull(self, **kwargs):
stdout, stderr = cmd.communicate()
if cmd.returncode != 0:
raise BazaarError(
'bzr pull for %r failed.\n%s' % (name, stderr))
f'bzr pull for {name!r} failed.\n{stderr}')
if kwargs.get('verbose', False):
return stdout

Expand Down Expand Up @@ -81,7 +81,7 @@ def matches(self):
stdout, stderr = cmd.communicate()
if cmd.returncode != 0:
raise BazaarError(
'bzr info for %r failed.\n%s' % (name, stderr))
f'bzr info for {name!r} failed.\n{stderr}')
return (self.source['url'] in stdout.split())

def status(self, **kwargs):
Expand Down
22 changes: 10 additions & 12 deletions src/mr/developer/commands.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from __future__ import print_function
from mr.developer.common import logger, memoize, WorkingCopies, yesno
import argparse
import errno
import os
import re
import shutil
import six
import stat
import subprocess
import sys
Expand All @@ -15,7 +13,7 @@
class ChoicesPseudoAction(argparse.Action):

def __init__(self, *args, **kwargs):
sup = super(ChoicesPseudoAction, self)
sup = super()
sup.__init__(dest=args[0], option_strings=list(args), help=kwargs.get('help'), nargs=0)


Expand All @@ -36,11 +34,11 @@ def _fill_text(self, text, width, indent):
result = []
for line in text.split("\n"):
for line2 in textwrap.fill(line, width).split("\n"):
result.append("%s%s" % (indent, line2))
result.append(f"{indent}{line2}")
return "\n".join(result)


class Command(object):
class Command:
def __init__(self, develop):
self.develop = develop

Expand Down Expand Up @@ -71,7 +69,7 @@ def get_packages(self, args, auto_checkout=False,

if len(result) == 0:
if len(args) > 1:
regexps = "%s or '%s'" % (", ".join("'%s'" % x for x in args[:-1]), args[-1])
regexps = "{} or '{}'".format(", ".join("'%s'" % x for x in args[:-1]), args[-1])
else:
regexps = "'%s'" % args[0]
logger.error("No package matched %s." % regexps)
Expand Down Expand Up @@ -302,7 +300,7 @@ def __call__(self, args):
for name in sorted(cmds):
cmd = cmds[name]
if len(cmd['aliases']):
header = "%s (%s)" % (name, ", ".join(cmd['aliases']))
header = "{} ({})".format(name, ", ".join(cmd['aliases']))
else:
header = name
print(header)
Expand All @@ -319,7 +317,7 @@ def __call__(self, args):
for name in sorted(cmds):
cmd = cmds[name]
if len(cmd['aliases']):
print(" %s (%s)" % (name, ", ".join(cmd['aliases'])))
print(" {} ({})".format(name, ", ".join(cmd['aliases'])))
else:
print(" %s" % name)

Expand Down Expand Up @@ -464,7 +462,7 @@ def __call__(self, args):
else:
info.append("#")
if args.long:
info.append("(%s) %s %s" % (source['kind'], name, source['url']))
info.append("({}) {} {}".format(source['kind'], name, source['url']))
else:
info.append(name)
print(" ".join(info))
Expand Down Expand Up @@ -560,7 +558,7 @@ def __call__(self, args):
need_force = False
if source['kind'] != 'svn':
need_force = True
logger.warn("The directory of package '%s' at '%s' might contain unrecoverable files and will not be removed without --force." % (name, path))
logger.warn(f"The directory of package '{name}' at '{path}' might contain unrecoverable files and will not be removed without --force.")
if workingcopies.status(source) != 'clean':
need_force = True
logger.warn("The package '%s' is dirty and will not be removed without --force." % name)
Expand All @@ -578,7 +576,7 @@ def __call__(self, args):
if answer == 'all':
force_all = True

logger.info("Removing package '%s' at '%s'." % (name, path))
logger.info(f"Removing package '{name}' at '{path}'.")
if not args.dry_run:
shutil.rmtree(source['path'],
ignore_errors=False,
Expand Down Expand Up @@ -756,7 +754,7 @@ def __call__(self, args):
info.append(name)
print(" ".join(info))
if args.verbose:
if six.PY3 and isinstance(output, six.binary_type):
if isinstance(output, bytes):
output = output.decode('utf8')
output = output.strip()
if output:
Expand Down
Loading