Repository: pypa/setuptools_scm

Issue:
Regression after #800
After #800 got landed `setuptools_scm` has started breaking https://github.com/ofek/hatch-vcs (https://github.com/pypa/hatch/issues/795) .

78e7d6bb470e3c0ae5fd744e572f6e6085401a33 - can build itself, breaks hatch_vcs
bf0e8134e6b2101031acc3b3bb7b9bb4d2e6dd1b - cannot build itself, version.py:15, ImportError: cannot import name '_call_version_scheme' from partially initialized module 'setuptools_scm._entrypoints'
45ad9c82ec68096ff76a3a195598d98a7e426423 - cannot build itself, version.py:15, ImportError: cannot import name '_call_version_scheme' from partially initialized module 'setuptools_scm._entrypoints'
8e4e22fa18fc274f1839965bd7855716d72b8363 - cannot build itself, version.py:15, ImportError: cannot import name '_call_version_scheme' from partially initialized module 'setuptools_scm._entrypoints'
4208223520c72bad5ab47f31dbc4ab166874c27b - cannot build itself, version.py:15, ImportError: cannot import name '_call_version_scheme' from partially initialized module 'setuptools_scm._entrypoints'
fd04e244cdebae5398e37aa7c70bace604012673 - cannot build itself, version.py:15, ImportError: cannot import name '_call_version_scheme' from partially initialized module 'setuptools_scm._entrypoints'
91061f90e292e7aacc71bc8045b38ee1261f4c07 - cannot build itself, version.py:18 ImportError: cannot import name '_get_ep' from partially initialized module 'setuptools_scm._entrypoints'
770d5dd8d9366679865a8d25e71a381b527833d6 - works fine


Discussion:

Patch:
diff --git a/src/setuptools_scm/__init__.py b/src/setuptools_scm/__init__.py
index b29273c..faea673 100644
--- a/src/setuptools_scm/__init__.py
+++ b/src/setuptools_scm/__init__.py
@@ -6,6 +6,7 @@ from __future__ import annotations
 
 import os
 import re
+import warnings
 from typing import Any
 from typing import Pattern
 from typing import TYPE_CHECKING
@@ -133,7 +134,15 @@ def get_version(
     version_cls = _validate_version_cls(version_cls, normalize)
     del normalize
     if isinstance(tag_regex, str):
-        tag_regex = re.compile(tag_regex)
+        if tag_regex == "":
+            warnings.warn(
+                DeprecationWarning(
+                    "empty regex for tag regex is invalid, using default"
+                )
+            )
+            tag_regex = DEFAULT_TAG_REGEX
+        else:
+            tag_regex = re.compile(tag_regex)
     config = Configuration(**locals())
     maybe_version = _get_version(config)
 
@@ -143,23 +152,26 @@ def get_version(
 
 
 def _get_version(config: Configuration) -> str | None:
-    parsed_version = _do_parse(config)
-    if parsed_version is None:
-        return None
-    version_string = _format_version(
-        parsed_version,
-        version_scheme=config.version_scheme,
-        local_scheme=config.local_scheme,
-    )
-    if config.write_to is not None:
-        dump_version(
-            root=config.root,
-            version=version_string,
-            write_to=config.write_to,
-            template=config.write_to_template,
+    from ._log import magic_debug
+
+    with magic_debug():
+        parsed_version = _do_parse(config)
+        if parsed_version is None:
+            return None
+        version_string = _format_version(
+            parsed_version,
+            version_scheme=config.version_scheme,
+            local_scheme=config.local_scheme,
         )
+        if config.write_to is not None:
+            dump_version(
+                root=config.root,
+                version=version_string,
+                write_to=config.write_to,
+                template=config.write_to_template,
+            )
 
-    return version_string
+        return version_string
 
 
 # Public API
diff --git a/src/setuptools_scm/_log.py b/src/setuptools_scm/_log.py
index 35c050d..abbdd0c 100644
--- a/src/setuptools_scm/_log.py
+++ b/src/setuptools_scm/_log.py
@@ -92,3 +92,9 @@ def enable_debug(handler: logging.Handler = _default_handler) -> Iterator[None]:
         handler.setLevel(old_handler_level)
         if handler is not _default_handler:
             log.removeHandler(handler)
+
+
+@contextlib.contextmanager
+def magic_debug() -> Iterator[None]:
+    with enable_debug():
+        yield
diff --git a/src/setuptools_scm/version.py b/src/setuptools_scm/version.py
index 128533c..8cf48e8 100644
--- a/src/setuptools_scm/version.py
+++ b/src/setuptools_scm/version.py
@@ -38,10 +38,8 @@ SEMVER_LEN = 3
 def _parse_version_tag(
     tag: str | object, config: _config.Configuration
 ) -> dict[str, str] | None:
-    tagstring = tag if isinstance(tag, str) else str(tag)
-    match = config.tag_regex.match(tagstring)
+    match = config.tag_regex.match(str(tag))
 
-    result = None
     if match:
         key: str | int
         if len(match.groups()) == 1:
@@ -49,14 +47,23 @@ def _parse_version_tag(
         else:
             key = "version"
 
+        full = match.group(0)
+        log.debug("%r %r %s", tag, config.tag_regex, match)
+        log.debug(
+            "key %s data %s, %s, %r", key, match.groupdict(), match.groups(), full
+        )
         result = {
             "version": match.group(key),
-            "prefix": match.group(0)[: match.start(key)],
-            "suffix": match.group(0)[match.end(key) :],
+            "prefix": full[: match.start(key)],
+            "suffix": full[match.end(key) :],
         }
 
-    log.debug(f"tag '{tag}' parsed to {result}")
-    return result
+        log.debug("tag %r parsed to %r", tag, result)
+        return result
+    else:
+        log.debug("tag %r did not parse", tag)
+
+        return None
 
 
 def callable_or_entrypoint(group: str, callable_or_name: str | Any) -> Any:


Test patch:
diff --git a/testing/test_basic_api.py b/testing/test_basic_api.py
index f1b4c4f..6fd39bd 100644
--- a/testing/test_basic_api.py
+++ b/testing/test_basic_api.py
@@ -121,6 +121,13 @@ setup(name="myscm", use_scm_version={"fallback_version": "12.34"})
     assert res.stdout == "12.34"
 
 
+def test_get_version_blank_tag_regex() -> None:
+    with pytest.warns(
+        DeprecationWarning, match="empty regex for tag regex is invalid, using default"
+    ):
+        setuptools_scm.get_version(tag_regex="")
+
+
 @pytest.mark.parametrize(
     "version", ["1.0", "1.2.3.dev1+ge871260", "1.2.3.dev15+ge871260.d20180625", "2345"]
 )