Hello community,

here is the log from the commit of package python-stestr for openSUSE:Factory 
checked in at 2020-03-08 22:21:38
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-stestr (Old)
 and      /work/SRC/openSUSE:Factory/.python-stestr.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-stestr"

Sun Mar  8 22:21:38 2020 rev:14 rq:780391 version:2.6.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-stestr/python-stestr.changes      
2019-11-22 10:26:00.561263197 +0100
+++ /work/SRC/openSUSE:Factory/.python-stestr.new.26092/python-stestr.changes   
2020-03-08 22:21:41.771987083 +0100
@@ -1,0 +2,19 @@
+Fri Feb 28 21:47:29 UTC 2020 - Dirk Mueller <[email protected]>
+
+- update to 2.6.0:
+  * Add python 3.8 macOS and windows ci jobs
+  * Update test\_processor.py
+  * Update config\_file.py
+  * Update cli.py
+  * Remove 3.8 azure pipelines jobs
+  * Update stestr/scheduler.py
+  * Update to recent hacking version
+  * Add Python 3.8 support
+  * Add --pdb flag to stestr run
+  * Add unit tests around repo initialize
+  * Handle empty .stestr directory to initialize
+  * Update issue templates
+  * Escape Windows paths
+  * Stop encoding attachments text
+
+-------------------------------------------------------------------

Old:
----
  stestr-2.5.1.tar.gz

New:
----
  stestr-2.6.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-stestr.spec ++++++
--- /var/tmp/diff_new_pack.rJ22Yo/_old  2020-03-08 22:21:42.635987616 +0100
+++ /var/tmp/diff_new_pack.rJ22Yo/_new  2020-03-08 22:21:42.635987616 +0100
@@ -1,7 +1,7 @@
 #
-# spec file for package python-stestr
+# spec file for package python
 #
-# Copyright (c) 2019 SUSE LLC
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -26,7 +26,7 @@
 %bcond_with test
 %endif
 Name:           python-stestr%{psuffix}
-Version:        2.5.1
+Version:        2.6.0
 Release:        0
 Summary:        A test runner runner similar to testrepository
 License:        Apache-2.0

++++++ stestr-2.5.1.tar.gz -> stestr-2.6.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/.github/ISSUE_TEMPLATE/bug_report.md 
new/stestr-2.6.0/.github/ISSUE_TEMPLATE/bug_report.md
--- old/stestr-2.5.1/.github/ISSUE_TEMPLATE/bug_report.md       1970-01-01 
01:00:00.000000000 +0100
+++ new/stestr-2.6.0/.github/ISSUE_TEMPLATE/bug_report.md       2019-12-13 
19:59:07.000000000 +0100
@@ -0,0 +1,30 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: 'bug'
+assignees: ''
+
+---
+
+**Issue description**
+
+Include a description of the issue encountered, and what the expected behavior
+was. Also include any configuration, test suite, or other relevant information
+to reproduce the issue.
+
+Note if you encounter an error message try to re-run the command with --debug 
to print any tracebacks
+
+**Expected behavior and actual behavior**
+
+**Steps to reproduce the problem**
+
+**Specifications like the version of the project, operating system, or 
hardware**
+
+**System information**
+ - OS: [e.g. Windows10, openSUSE 15.1, Ubuntu 18.04]
+ - stestr version (`stestr --version`):
+ - Python release (`python --version`):
+ - pip packages (`pip freeze`):
+
+**Additional information**
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/stestr-2.5.1/.github/ISSUE_TEMPLATE/feature_request.md 
new/stestr-2.6.0/.github/ISSUE_TEMPLATE/feature_request.md
--- old/stestr-2.5.1/.github/ISSUE_TEMPLATE/feature_request.md  1970-01-01 
01:00:00.000000000 +0100
+++ new/stestr-2.6.0/.github/ISSUE_TEMPLATE/feature_request.md  2019-12-13 
19:59:07.000000000 +0100
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: 'enhancement'
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always 
frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features 
you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/.github/issue_template.md 
new/stestr-2.6.0/.github/issue_template.md
--- old/stestr-2.5.1/.github/issue_template.md  2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/.github/issue_template.md  1970-01-01 01:00:00.000000000 
+0100
@@ -1,24 +0,0 @@
-### Issue description
-
-Include a description of the issue encountered, and what the expected behavior
-was. Also include any configuration, test suite, or other relevant information
-to reproduce the issue.
-
-Note if you encounter an error message try to re-run the command with --debug 
to print any tracebacks
-
-#### Expected behavior and actual behavior
-
-#### Steps to reproduce the problem
-
-#### Specifications like the version of the project, operating system, or 
hardware
-
-### System information
-
-**stestr version (`stestr --version`):**
-
-**Python release (`python --version`):**
-
-**pip packages (`pip freeze`):**
-
-
-### Additional information
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/.travis.yml new/stestr-2.6.0/.travis.yml
--- old/stestr-2.5.1/.travis.yml        2019-09-03 15:17:17.000000000 +0200
+++ new/stestr-2.6.0/.travis.yml        2019-12-13 19:59:07.000000000 +0100
@@ -7,6 +7,9 @@
     - python: "3.6"
       env: TOXENV=py36
     - os: linux
+      python: 3.8
+      env: TOXENV=py38
+    - os: linux
       dist: xenial
       python: 3.7
       env: TOXENV=py37
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/AUTHORS new/stestr-2.6.0/AUTHORS
--- old/stestr-2.5.1/AUTHORS    2019-09-03 15:17:27.000000000 +0200
+++ new/stestr-2.6.0/AUTHORS    2019-12-13 19:59:21.000000000 +0100
@@ -1,8 +1,11 @@
 Alfredo Moralejo <[email protected]>
 Chandan Kumar <[email protected]>
+Dirk Mueller <[email protected]>
+Dirk Mueller <[email protected]>
+Lucian Petrut <[email protected]>
 Luigi Toscano <[email protected]>
 Masayuki Igawa <[email protected]>
 Matthew Treinish <[email protected]>
 Sergey Vilgelm <[email protected]>
-Sorin Sbarnea <[email protected]>
 Tony Breeds <[email protected]>
+pvinci <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/ChangeLog new/stestr-2.6.0/ChangeLog
--- old/stestr-2.5.1/ChangeLog  2019-09-03 15:17:27.000000000 +0200
+++ new/stestr-2.6.0/ChangeLog  2019-12-13 19:59:21.000000000 +0100
@@ -1,6 +1,24 @@
 CHANGES
 =======
 
+2.6.0
+-----
+
+* Add python 3.8 macOS and windows ci jobs
+* Update test\_processor.py
+* Update config\_file.py
+* Update cli.py
+* Remove 3.8 azure pipelines jobs
+* Update stestr/scheduler.py
+* Update to recent hacking version
+* Add Python 3.8 support
+* Add --pdb flag to stestr run
+* Add unit tests around repo initialize
+* Handle empty .stestr directory to initialize
+* Update issue templates
+* Escape Windows paths
+* Stop encoding attachments text
+
 2.5.1
 -----
 
@@ -89,28 +107,4 @@
 
 * Change title of project in readme
 * Add a better description to README Overview section
-* Fix discovery import error formatting on py3
 * Cleanup unused parameters in \_run\_tests
-* Enable doc8
-* Add all stream to repo even if some tests fail
-* Extract loading case code to \_load\_case() function
-* Make test running serially when just loading
-* Fix time measurement for load command too
-* Use reported times instead of wall time in subunit-trace
-* Add support for test class and method by path on no-discover
-
-2.1.1
------
-
-* Add support for python 3.7
-* Fix handling of unexpected success results
-* Allow stestr to be called as a module (#185)
-* Make warning and error messages use stderr
-* Add error handling for invalid input regexes
-* Cleanup the manpage section on dealing with failed tests
-* Cleanup argument help text on load command
-* Fix description for the stestr run command
-
-2.1.0
------
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/PKG-INFO new/stestr-2.6.0/PKG-INFO
--- old/stestr-2.5.1/PKG-INFO   2019-09-03 15:17:27.000000000 +0200
+++ new/stestr-2.6.0/PKG-INFO   2019-12-13 19:59:21.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: stestr
-Version: 2.5.1
+Version: 2.6.0
 Summary: A parallel Python test runner built around subunit
 Home-page: http://stestr.readthedocs.io/en/latest/
 Author: Matthew Treinish
@@ -176,6 +176,7 @@
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
 Classifier: Topic :: Software Development :: Testing
 Classifier: Topic :: Software Development :: Quality Assurance
 Provides-Extra: sql
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/azure-pipelines.yml 
new/stestr-2.6.0/azure-pipelines.yml
--- old/stestr-2.5.1/azure-pipelines.yml        2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/azure-pipelines.yml        2019-12-13 19:59:07.000000000 
+0100
@@ -19,6 +19,8 @@
         python.version: '3.6'
       Python37:
         python.version: '3.7'
+      Python38:
+        python.version: '3.8'
   steps:
   - task: UsePythonVersion@0
     inputs:
@@ -48,6 +50,8 @@
         python.version: '3.6'
       Python37:
         python.version: '3.7'
+      Python38:
+        python.version: '3.8'
   steps:
   - task: UsePythonVersion@0
     inputs:
@@ -59,4 +63,4 @@
       pip install -U tox
     displayName: 'Install dependencies'
   - script: tox -e py
-    displayName: 'Run Tox'
\ No newline at end of file
+    displayName: 'Run Tox'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/doc/source/MANUAL.rst 
new/stestr-2.6.0/doc/source/MANUAL.rst
--- old/stestr-2.5.1/doc/source/MANUAL.rst      2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/doc/source/MANUAL.rst      2019-12-13 19:59:07.000000000 
+0100
@@ -113,6 +113,21 @@
 will skip discovery and directly call the test runner on the test method in the
 specified test class.
 
+Running with pdb
+''''''''''''''''
+
+If you'd like to run pdb during the execution of the tests you should use the
+``--pdb`` flag on ``stestr run``. This flag behaves the same way as the
+``--no-discover`` flag except that it does not launch an external process to
+run the tests. This enables pdb to work as expected without any issues with the
+tradeoff that output from the test runner will occur after tests have finished
+execution.
+
+It's also worth noting that if you are using a fixture to capture stdout (which
+is a common practice for parallel test excecution) you'll likely want to
+disable that fixture when running with pdb. Those fixtures can often interfere
+with pdb's output and will sometimes capture output from pdb.
+
 Test Selection
 --------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/setup.cfg new/stestr-2.6.0/setup.cfg
--- old/stestr-2.5.1/setup.cfg  2019-09-03 15:17:27.000000000 +0200
+++ new/stestr-2.6.0/setup.cfg  2019-12-13 19:59:21.000000000 +0100
@@ -20,6 +20,7 @@
        Programming Language :: Python :: 3.5
        Programming Language :: Python :: 3.6
        Programming Language :: Python :: 3.7
+       Programming Language :: Python :: 3.8
        Topic :: Software Development :: Testing
        Topic :: Software Development :: Quality Assurance
 project_urls = 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/cli.py 
new/stestr-2.6.0/stestr/cli.py
--- old/stestr-2.5.1/stestr/cli.py      2019-09-03 15:17:17.000000000 +0200
+++ new/stestr-2.6.0/stestr/cli.py      2019-12-13 19:59:07.000000000 +0100
@@ -36,7 +36,7 @@
 
     def prepare_to_run_command(self, cmd):
         self.LOG.debug('prepare_to_run_command %s', cmd.__class__.__name__)
-        group_regex = '([^\.]*\.)*' \
+        group_regex = r'([^\.]*\.)*' \
             if cmd.app_args.parallel_class else cmd.app_args.group_regex
         cmd.app_args.group_regex = group_regex
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/commands/init.py 
new/stestr-2.6.0/stestr/commands/init.py
--- old/stestr-2.5.1/stestr/commands/init.py    2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/commands/init.py    2019-12-13 19:59:07.000000000 
+0100
@@ -12,6 +12,7 @@
 
 """Initialise a new repository."""
 
+import errno
 import sys
 
 from cliff import command
@@ -47,7 +48,7 @@
     try:
         util.get_repo_initialise(repo_type, repo_url)
     except OSError as e:
-        if e.errno != 17:
+        if e.errno != errno.EEXIST:
             raise
         repo_path = repo_url or './stestr'
         stdout.write('The specified repository directory %s already exists. '
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/commands/load.py 
new/stestr-2.6.0/stestr/commands/load.py
--- old/stestr-2.5.1/stestr/commands/load.py    2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/commands/load.py    2019-12-13 19:59:07.000000000 
+0100
@@ -13,6 +13,7 @@
 """Load data into a repository."""
 
 
+import errno
 import functools
 import os
 import sys
@@ -148,7 +149,7 @@
     used by the run command to both output the results as well as store the
     result in the repository.
 
-    :param bool force_init: Initialize the specifiedrepository if it hasn't
+    :param bool force_init: Initialize the specified repository if it hasn't
         been created.
     :param list in_streams: A list of file objects that will be saved into the
         repository
@@ -184,7 +185,17 @@
         repo = util.get_repo_open(repo_type, repo_url)
     except repository.RepositoryNotFound:
         if force_init:
-            repo = util.get_repo_initialise(repo_type, repo_url)
+            try:
+                repo = util.get_repo_initialise(repo_type, repo_url)
+            except OSError as e:
+                if e.errno != errno.EEXIST:
+                    raise
+                repo_path = repo_url or './stestr'
+                stdout.write('The specified repository directory %s already '
+                             'exists. Please check if the repository already '
+                             'exists or select a different path\n'
+                             % repo_path)
+                exit(1)
         else:
             raise
     # Not a full implementation of TestCase, but we only need to iterate
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/commands/run.py 
new/stestr-2.6.0/stestr/commands/run.py
--- old/stestr-2.5.1/stestr/commands/run.py     2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/commands/run.py     2019-12-13 19:59:07.000000000 
+0100
@@ -12,6 +12,9 @@
 
 """Run a projects tests and load them into stestr."""
 
+import errno
+import functools
+import io
 import os
 import subprocess
 import sys
@@ -30,6 +33,8 @@
 from stestr.repository import abstract as repository
 from stestr.repository import util
 from stestr import results
+from stestr.subunit_runner import program
+from stestr.subunit_runner import run as subunit_run
 from stestr.testlist import parse_list
 from stestr import user_config
 
@@ -121,6 +126,13 @@
                             help="Takes in a single test to bypasses test "
                             "discover and just execute the test specified. A "
                             "file may be used in place of a test name.")
+        parser.add_argument('--pdb', default=None, metavar='TEST_ID',
+                            help="Run a single test id with the intent of "
+                            "using pdb. This does not launch any separate "
+                            "processes to ensure pdb works as expected. It "
+                            "will bypass test discovery and just execute the "
+                            "test specified. A file may be used in place of a "
+                            "test name.")
         parser.add_argument('--random', action="store_true",
                             default=False,
                             help="Randomize the test order after they are "
@@ -232,7 +244,7 @@
             filters=filters, pretty_out=pretty_out, color=color,
             stdout=stdout, abbreviate=abbreviate,
             suppress_attachments=suppress_attachments,
-            all_attachments=all_attachments)
+            all_attachments=all_attachments, pdb=args.pdb)
 
         # Always output slowest test info if requested, regardless of other
         # test run options
@@ -273,7 +285,7 @@
                 no_discover=False, random=False, combine=False, filters=None,
                 pretty_out=True, color=False, stdout=sys.stdout,
                 abbreviate=False, suppress_attachments=False,
-                all_attachments=False):
+                all_attachments=False, pdb=False):
     """Function to execute the run command
 
     This function implements the run command. It will run the tests specified
@@ -336,6 +348,9 @@
         will not print attachments on successful test execution.
     :param bool all_attachments: When set true subunit_trace will print all
         text attachments on successful test execution.
+    :param str pdb: Takes in a single test_id to bypasses test
+        discover and just execute the test specified without launching any
+        additional processes. A file name may be used in place of a test name.
 
     :return return_code: The exit code for the command. 0 for success and > 0
         for failures.
@@ -354,7 +369,17 @@
                    "--test-path ")
             stdout.write(msg)
             exit(1)
-        repo = util.get_repo_initialise(repo_type, repo_url)
+        try:
+            repo = util.get_repo_initialise(repo_type, repo_url)
+        except OSError as e:
+            if e.errno != errno.EEXIST:
+                raise
+            repo_path = repo_url or './stestr'
+            stdout.write('The specified repository directory %s already '
+                         'exists. Please check if the repository already '
+                         'exists or select a different path\n' % repo_path)
+            return 1
+
     combine_id = None
     concurrency = _to_int(concurrency)
 
@@ -366,6 +391,17 @@
     if combine:
         latest_id = repo.latest_id()
         combine_id = six.text_type(latest_id)
+    if no_discover and pdb:
+        msg = ("--no-discover and --pdb are mutually exclusive options, "
+               "only specify one at a time")
+        stdout.write(msg)
+        return 2
+    if pdb and until_failure:
+        msg = ("pdb mode does not function with the --until-failure flag, "
+               "only specify one at a time")
+        stdout.write(msg)
+        return 2
+
     if no_discover:
         ids = no_discover
         if '::' in ids:
@@ -418,6 +454,29 @@
                 if result:
                     return result
 
+    if pdb:
+        ids = pdb
+        if '::' in ids:
+            ids = ids.replace('::', '.')
+        if ids.find('/') != -1:
+            root = ids.replace('.py', '')
+            ids = root.replace('/', '.')
+        runner = subunit_run.SubunitTestRunner
+        stream = io.BytesIO()
+        program.TestProgram(module=None, argv=['stestr', ids],
+                            testRunner=functools.partial(runner,
+                                                         stdout=stream))
+        stream.seek(0)
+        run_proc = [('subunit', stream)]
+        return load.load(in_streams=run_proc,
+                         subunit_out=subunit_out,
+                         repo_type=repo_type,
+                         repo_url=repo_url, run_id=combine_id,
+                         pretty_out=pretty_out,
+                         color=color, stdout=stdout, abbreviate=abbreviate,
+                         suppress_attachments=suppress_attachments,
+                         all_attachments=all_attachments)
+
     if failing or analyze_isolation:
         ids = _find_failing(repo)
     else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/config_file.py 
new/stestr-2.6.0/stestr/config_file.py
--- old/stestr-2.5.1/stestr/config_file.py      2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/config_file.py      2019-12-13 19:59:07.000000000 
+0100
@@ -28,11 +28,21 @@
     :param str config_file: The path to the config file to use
     """
 
+    _escape_trailing_backslash_re = re.compile(r'(?<=[^\\])\\$')
+
     def __init__(self, config_file):
         self.parser = configparser.ConfigParser()
         self.parser.read(config_file)
         self.config_file = config_file
 
+    def _sanitize_path(self, path):
+        if os.sep == '\\':
+            # Trailing backslashes have to be escaped. Othwerise, the
+            # command we're issuing will be incorrectly interpreted on
+            # Windows.
+            path = self._escape_trailing_backslash_re.sub(r'\\\\', path)
+        return path
+
     def get_run_command(self, test_ids=None, regexes=None,
                         test_path=None, top_dir=None, group_regex=None,
                         repo_type='file', repo_url=None,
@@ -104,6 +114,9 @@
         elif not top_dir:
             top_dir = './'
 
+        test_path = self._sanitize_path(test_path)
+        top_dir = self._sanitize_path(top_dir)
+
         stestr_python = sys.executable
         # let's try to be explicit, even if it means a longer set of ifs
         if sys.platform == 'win32':
@@ -120,6 +133,10 @@
                 raise RuntimeError("The Python interpreter was not found and "
                                    "PYTHON is not set")
 
+        # The python binary path may contain whitespaces.
+        if os.path.exists('"%s"' % python):
+            python = '"%s"' % python
+
         command = '%s -m stestr.subunit_runner.run discover -t "%s" "%s" ' \
                   '$LISTOPT $IDOPTION' % (python, top_dir, test_path)
         listopt = "--list"
@@ -127,11 +144,11 @@
         # If the command contains $IDOPTION read that command from config
         # Use a group regex if one is defined
         if parallel_class:
-            group_regex = '([^\.]*\.)*'
+            group_regex = r'([^\.]*\.)*'
         if not group_regex \
                 and self.parser.has_option('DEFAULT', 'parallel_class') \
                 and self.parser.getboolean('DEFAULT', 'parallel_class'):
-            group_regex = '([^\.]*\.)*'
+            group_regex = r'([^\.]*\.)*'
         if not group_regex and self.parser.has_option('DEFAULT',
                                                       'group_regex'):
             group_regex = self.parser.get('DEFAULT', 'group_regex')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/repository/file.py 
new/stestr-2.6.0/stestr/repository/file.py
--- old/stestr-2.5.1/stestr/repository/file.py  2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/repository/file.py  2019-12-13 19:59:07.000000000 
+0100
@@ -40,7 +40,14 @@
     def initialise(klass, url):
         """Create a repository at url/path."""
         base = os.path.join(os.path.expanduser(url), '.stestr')
-        os.mkdir(base)
+        try:
+            os.mkdir(base)
+        except OSError as e:
+            if e.errno == errno.EEXIST and not os.listdir(base):
+                # It shouldn't be harmful initializing an empty dir
+                pass
+            else:
+                raise
         with open(os.path.join(base, 'format'), 'wt') as stream:
             stream.write('1\n')
         result = Repository(base)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/repository/memory.py 
new/stestr-2.6.0/stestr/repository/memory.py
--- old/stestr-2.5.1/stestr/repository/memory.py        2019-09-03 
15:17:17.000000000 +0200
+++ new/stestr-2.6.0/stestr/repository/memory.py        2019-12-13 
19:59:07.000000000 +0100
@@ -14,7 +14,6 @@
 
 from extras import try_import
 
-OrderedDict = try_import('collections.OrderedDict', dict)
 from io import BytesIO
 from operator import methodcaller
 
@@ -23,6 +22,8 @@
 
 from stestr.repository import abstract as repository
 
+OrderedDict = try_import('collections.OrderedDict', dict)
+
 
 class RepositoryFactory(repository.AbstractRepositoryFactory):
     """A factory that can initialise and open memory repositories.
@@ -152,8 +153,8 @@
         duration_delta = stop - start
         duration_seconds = (
             (duration_delta.microseconds + (
-                duration_delta.seconds + duration_delta.days
-                * 24 * 3600) * 10 ** 6) / 10.0 ** 6)
+                duration_delta.seconds +
+                duration_delta.days * 24 * 3600) * 10 ** 6) / 10.0 ** 6)
         self._repository._times[test_dict['id']] = duration_seconds
 
     def stopTestRun(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/scheduler.py 
new/stestr-2.6.0/stestr/scheduler.py
--- old/stestr-2.5.1/stestr/scheduler.py        2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/scheduler.py        2019-12-13 19:59:07.000000000 
+0100
@@ -46,6 +46,9 @@
         :return: A list where each element is a distinct subset of test_ids,
             and the union of all the elements is equal to set(test_ids).
         """
+        def noop(_):
+            return None
+
         _group_callback = group_callback
         partitions = [list() for i in range(concurrency)]
         timed_partitions = [[0.0, partition] for partition in partitions]
@@ -60,7 +63,7 @@
         # Group tests: generate group_id -> test_ids.
         group_ids = collections.defaultdict(list)
         if _group_callback is None:
-            group_callback = lambda _: None
+            group_callback = noop
         else:
             group_callback = _group_callback
         for test_id in test_ids:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/subunit_trace.py 
new/stestr-2.6.0/stestr/subunit_trace.py
--- old/stestr-2.5.1/stestr/subunit_trace.py    2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/subunit_trace.py    2019-12-13 19:59:07.000000000 
+0100
@@ -123,7 +123,6 @@
             # indent attachment lines 4 spaces to make them visually
             # offset
             for line in detail.as_text().split('\n'):
-                line = line.encode('utf8')
                 stream.write("    %s\n" % line)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/test_processor.py 
new/stestr-2.6.0/stestr/test_processor.py
--- old/stestr-2.5.1/stestr/test_processor.py   2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/stestr/test_processor.py   2019-12-13 19:59:07.000000000 
+0100
@@ -104,7 +104,7 @@
 
     def setUp(self):
         super(TestProcessorFixture, self).setUp()
-        variable_regex = '\$(IDOPTION|IDFILE|IDLIST|LISTOPT)'
+        variable_regex = r'\$(IDOPTION|IDFILE|IDLIST|LISTOPT)'
         variables = {}
         list_variables = {'LISTOPT': self.listopt}
         cmd = self.template
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/tests/repository/test_file.py 
new/stestr-2.6.0/stestr/tests/repository/test_file.py
--- old/stestr-2.5.1/stestr/tests/repository/test_file.py       2019-09-03 
15:17:17.000000000 +0200
+++ new/stestr-2.6.0/stestr/tests/repository/test_file.py       2019-12-13 
19:59:07.000000000 +0100
@@ -26,9 +26,10 @@
 
 class FileRepositoryFixture(fixtures.Fixture):
 
-    def __init__(self, path=None):
+    def __init__(self, path=None, initialise=True):
         super(FileRepositoryFixture, self).__init__()
         self.path = path
+        self.initialise = initialise
 
     def setUp(self):
         super(FileRepositoryFixture, self).setUp()
@@ -37,7 +38,8 @@
         else:
             self.tempdir = tempfile.mkdtemp()
             self.addCleanup(shutil.rmtree, self.tempdir)
-        self.repo = file.RepositoryFactory().initialise(self.tempdir)
+        if self.initialise:
+            self.repo = file.RepositoryFactory().initialise(self.tempdir)
 
 
 class HomeDirTempDir(fixtures.Fixture):
@@ -70,6 +72,32 @@
             contents = stream.read()
         self.assertEqual("0\n", contents)
 
+    def test_initialise_empty_dir(self):
+        self.useFixture(FileRepositoryFixture(path=self.tempdir,
+                                              initialise=False))
+        base = os.path.join(self.tempdir, '.stestr')
+        os.mkdir(base)
+        self.assertFalse(os.path.isfile(os.path.join(base, 'format')))
+        self.repo = file.RepositoryFactory().initialise(self.tempdir)
+        self.assertTrue(os.path.isdir(base))
+        self.assertTrue(os.path.isfile(os.path.join(base, 'format')))
+        with open(os.path.join(base, 'format'), 'rt') as stream:
+            contents = stream.read()
+        self.assertEqual("1\n", contents)
+        with open(os.path.join(base, 'next-stream'), 'rt') as stream:
+            contents = stream.read()
+        self.assertEqual("0\n", contents)
+
+    def test_initialise_non_empty_dir(self):
+        self.useFixture(FileRepositoryFixture(path=self.tempdir,
+                                              initialise=False))
+        base = os.path.join(self.tempdir, '.stestr')
+        os.mkdir(base)
+        with open(os.path.join(base, 'foo'), 'wt') as stream:
+            stream.write('1\n')
+        factory = file.RepositoryFactory()
+        self.assertRaises(OSError, factory.initialise, self.tempdir)
+
     # Skip if windows since ~ in a path doesn't work there
     @testtools.skipIf(os.name == 'nt', "Windows doesn't support '~' expand")
     def test_initialise_expands_user_directory(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/tests/test_config_file.py 
new/stestr-2.6.0/stestr/tests/test_config_file.py
--- old/stestr-2.5.1/stestr/tests/test_config_file.py   2019-09-03 
15:17:17.000000000 +0200
+++ new/stestr-2.6.0/stestr/tests/test_config_file.py   2019-12-13 
19:59:07.000000000 +0100
@@ -10,12 +10,14 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import ddt
 import mock
 
 from stestr import config_file
 from stestr.tests import base
 
 
[email protected]
 class TestTestrConf(base.TestCase):
 
     @mock.patch.object(config_file.configparser, 'ConfigParser')
@@ -27,6 +29,7 @@
     @mock.patch.object(config_file.util, 'get_repo_open')
     @mock.patch.object(config_file.test_processor, 'TestProcessorFixture')
     @mock.patch.object(config_file, 'sys')
+    @mock.patch('os.path.exists', new=lambda x: True)
     def _check_get_run_command(self, mock_sys, mock_TestProcessorFixture,
                                mock_get_repo_open, platform='win32',
                                group_regex='.*', parallel_class=False,
@@ -49,7 +52,7 @@
         self.assertEqual(mock_TestProcessorFixture.return_value, fixture)
         mock_get_repo_open.assert_called_once_with('file',
                                                    None)
-        command = '%s -m stestr.subunit_runner.run discover -t "%s" "%s" ' \
+        command = '"%s" -m stestr.subunit_runner.run discover -t "%s" "%s" ' \
                   '$LISTOPT $IDOPTION' % (expected_python, 'fake_top_dir',
                                           'fake_test_path')
         # Ensure TestProcessorFixture is created with defaults except for where
@@ -107,3 +110,12 @@
         self._testr_conf.parser.has_option.return_value = False
         self._check_get_run_command(group_regex='',
                                     expected_group_callback=None)
+
+    @ddt.data(('.\\', '.\\\\'),
+              ('a\\b\\', 'a\\b\\\\'),
+              ('a\\b', 'a\\b'))
+    @ddt.unpack
+    @mock.patch('os.sep', new='\\')
+    def test_sanitize_dir_win32(self, path, expected):
+        sanitized = self._testr_conf._sanitize_path(path)
+        self.assertEqual(expected, sanitized)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr/tests/test_return_codes.py 
new/stestr-2.6.0/stestr/tests/test_return_codes.py
--- old/stestr-2.5.1/stestr/tests/test_return_codes.py  2019-09-03 
15:17:17.000000000 +0200
+++ new/stestr-2.6.0/stestr/tests/test_return_codes.py  2019-12-13 
19:59:07.000000000 +0100
@@ -209,6 +209,28 @@
         # test from a command line based test.
         self.assertRunExit('stestr --parallel-class run passing', 0)
 
+    def test_no_repo_dir(self):
+        stestr_repo_dir = os.path.join(self.directory, '.stestr')
+        shutil.rmtree(stestr_repo_dir, ignore_errors=True)
+        # We can use stestr run even if there's no repo directory.
+        self.assertRunExit('stestr run passing', 0)
+
+    def test_empty_repo_dir(self):
+        stestr_repo_dir = os.path.join(self.directory, '.stestr')
+        shutil.rmtree(stestr_repo_dir, ignore_errors=True)
+        os.mkdir(stestr_repo_dir)
+        # We can initialize an empty repo directory.
+        self.assertRunExit('stestr run passing', 0)
+
+    def test_non_empty_repo_dir(self):
+        stestr_repo_dir = os.path.join(self.directory, '.stestr')
+        shutil.rmtree(stestr_repo_dir, ignore_errors=True)
+        os.mkdir(stestr_repo_dir)
+        with open(os.path.join(stestr_repo_dir, 'foo'), 'wt') as stream:
+            stream.write('1\n')
+        # We can't initialize a non-empty repo directory.
+        self.assertRunExit('stestr run passing', 1)
+
     def test_list(self):
         self.assertRunExit('stestr list', 0)
 
@@ -249,6 +271,23 @@
             'stestr last --subunit')[0]
         self.assertRunExit('stestr load', 0, stdin=stream)
 
+    def test_load_force_init(self):
+        self.assertRunExit('stestr run passing', 0)
+        stream = self._get_cmd_stdout(
+            'stestr last --subunit')[0]
+        # NOTE: --force-init should work here because there is an properly
+        # initialized repository.
+        self.assertRunExit('stestr load --force-init', 0, stdin=stream)
+
+    def test_load_force_init_invalid(self):
+        self.assertRunExit('stestr run passing', 0)
+        stream = self._get_cmd_stdout(
+            'stestr last --subunit')[0]
+        os.remove(os.path.join(self.directory, '.stestr', 'format'))
+        # NOTE: --force-init should fail here because there is an invalid
+        # repository.
+        self.assertRunExit('stestr load --force-init', 1, stdin=stream)
+
     def test_load_from_stdin_quiet(self):
         out, err = self.assertRunExit('stestr --user-config stestr.yaml -q '
                                       'run passing', 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr.egg-info/PKG-INFO 
new/stestr-2.6.0/stestr.egg-info/PKG-INFO
--- old/stestr-2.5.1/stestr.egg-info/PKG-INFO   2019-09-03 15:17:27.000000000 
+0200
+++ new/stestr-2.6.0/stestr.egg-info/PKG-INFO   2019-12-13 19:59:21.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: stestr
-Version: 2.5.1
+Version: 2.6.0
 Summary: A parallel Python test runner built around subunit
 Home-page: http://stestr.readthedocs.io/en/latest/
 Author: Matthew Treinish
@@ -176,6 +176,7 @@
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
 Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
 Classifier: Topic :: Software Development :: Testing
 Classifier: Topic :: Software Development :: Quality Assurance
 Provides-Extra: sql
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr.egg-info/SOURCES.txt 
new/stestr-2.6.0/stestr.egg-info/SOURCES.txt
--- old/stestr-2.5.1/stestr.egg-info/SOURCES.txt        2019-09-03 
15:17:27.000000000 +0200
+++ new/stestr-2.6.0/stestr.egg-info/SOURCES.txt        2019-12-13 
19:59:21.000000000 +0100
@@ -15,7 +15,8 @@
 setup.py
 test-requirements.txt
 tox.ini
-.github/issue_template.md
+.github/ISSUE_TEMPLATE/bug_report.md
+.github/ISSUE_TEMPLATE/feature_request.md
 .travis/coveralls.sh
 doc/source/CONTRIBUTING.rst
 doc/source/MANUAL.rst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr.egg-info/pbr.json 
new/stestr-2.6.0/stestr.egg-info/pbr.json
--- old/stestr-2.5.1/stestr.egg-info/pbr.json   2019-09-03 15:17:27.000000000 
+0200
+++ new/stestr-2.6.0/stestr.egg-info/pbr.json   2019-12-13 19:59:21.000000000 
+0100
@@ -1 +1 @@
-{"git_version": "2957835", "is_release": true}
\ No newline at end of file
+{"git_version": "ff9b688", "is_release": true}
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/stestr.egg-info/requires.txt 
new/stestr-2.6.0/stestr.egg-info/requires.txt
--- old/stestr-2.5.1/stestr.egg-info/requires.txt       2019-09-03 
15:17:27.000000000 +0200
+++ new/stestr-2.6.0/stestr.egg-info/requires.txt       2019-12-13 
19:59:21.000000000 +0100
@@ -12,7 +12,7 @@
 subunit2sql>=1.8.0
 
 [test]
-hacking<0.12,>=0.11.0
+hacking<1.2.0,>=1.1.0
 mock>=2.0
 subunit2sql>=1.8.0
 coverage>=4.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/test-requirements.txt 
new/stestr-2.6.0/test-requirements.txt
--- old/stestr-2.5.1/test-requirements.txt      2019-09-03 15:17:17.000000000 
+0200
+++ new/stestr-2.6.0/test-requirements.txt      2019-12-13 19:59:07.000000000 
+0100
@@ -2,11 +2,11 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 
-hacking<0.12,>=0.11.0 # Apache-2.0
+hacking<1.2.0,>=1.1.0
 sphinx!=1.6.6,!=1.6.7,<2.0.0;python_version=='2.7'  # BSD
 sphinx!=1.6.6,!=1.6.7,!=2.1.0;python_version>='3.4'  # BSD
 mock>=2.0 # BSD
 subunit2sql>=1.8.0
 coverage>=4.0 # Apache-2.0
 ddt>=1.0.1 # MIT
-doc8>=0.8.0 # Apache-2.0
\ No newline at end of file
+doc8>=0.8.0 # Apache-2.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stestr-2.5.1/tox.ini new/stestr-2.6.0/tox.ini
--- old/stestr-2.5.1/tox.ini    2019-09-03 15:17:17.000000000 +0200
+++ new/stestr-2.6.0/tox.ini    2019-12-13 19:59:07.000000000 +0100
@@ -1,6 +1,6 @@
 [tox]
 minversion = 1.6
-envlist = py37,py36,py35,py34,py27,pep8
+envlist = py38,py37,py36,py35,py34,py27,pep8
 skipsdist = True
 
 [testenv]


Reply via email to