[med-svn] [Git][med-team/python-leidenalg][master] 7 commits: routine-update: New upstream version

Étienne Mollier (@emollier) gitlab at salsa.debian.org
Sun Jul 3 16:27:38 BST 2022



Étienne Mollier pushed to branch master at Debian Med / python-leidenalg


Commits:
d2d754ba by Étienne Mollier at 2022-07-03T17:20:57+02:00
routine-update: New upstream version

- - - - -
ed8c8ccc by Étienne Mollier at 2022-07-03T17:20:58+02:00
New upstream version 0.8.10
- - - - -
81fe33b9 by Étienne Mollier at 2022-07-03T17:20:59+02:00
Update upstream source from tag 'upstream/0.8.10'

Update to upstream version '0.8.10'
with Debian dir 426cd084377b04443f8be5080b1e79ef339949de
- - - - -
61d56298 by Étienne Mollier at 2022-07-03T17:20:59+02:00
routine-update: Standards-Version: 4.6.1

- - - - -
c5caedad by Étienne Mollier at 2022-07-03T17:25:26+02:00
Add typos.patch: fix typos caught by lintian.

- - - - -
5c92d480 by Étienne Mollier at 2022-07-03T17:26:34+02:00
d/control: add myself to uploaders.

- - - - -
7b1238fa by Étienne Mollier at 2022-07-03T17:27:06+02:00
ready to upload to unstable

- - - - -


9 changed files:

- .github/workflows/build.yml
- CHANGELOG
- MANIFEST.in
- debian/changelog
- debian/control
- + debian/patches/series
- + debian/patches/typos.patch
- + etc/arith_apple_m1.h
- setup.py


Changes:

=====================================
.github/workflows/build.yml
=====================================
@@ -13,7 +13,7 @@ on:
 env:
   CIBW_TEST_REQUIRES: ddt
   CIBW_TEST_COMMAND: "cd {project} && python -m unittest -v"
-  CIBW_SKIP: "cp27-* pp27-* cp35-*"
+  CIBW_SKIP: "pp* cp27-* cp35-* cp36-*"
 
 jobs:
   build_wheel_linux:
@@ -21,7 +21,7 @@ jobs:
     runs-on: ubuntu-20.04
     strategy:
       matrix:
-        wheel_arch: [x86_64, i686]
+        wheel_arch: [x86_64, i686, aarch64]
 
     steps:
       - uses: actions/checkout at v2
@@ -34,10 +34,15 @@ jobs:
         with:
           python-version: '3.8'
 
+      - name: Set up QEMU
+        if: runner.os == 'Linux'
+        uses: docker/setup-qemu-action at v1
+
       - name: Build wheels
-        uses: joerick/cibuildwheel at v1.10.0
+        uses: pypa/cibuildwheel at v2.4.0
         env:
           CIBW_BEFORE_BUILD: "yum install -y flex bison && pip install cmake && python setup.py build_c_core"
+          CIBW_ARCHS_LINUX: ${{ matrix.wheel_arch }}
           CIBW_BUILD: "*-manylinux_${{ matrix.wheel_arch }}"
 
       - uses: actions/upload-artifact at v2
@@ -47,6 +52,14 @@ jobs:
   build_wheel_macos:
     name: Build wheels on macOS
     runs-on: macos-10.15
+    strategy:
+      matrix:
+        include:
+          - cmake_arch: x86_64
+            wheel_arch: x86_64
+          - cmake_arch: arm64
+            cmake_extra_args: -DF2C_EXTERNAL_ARITH_HEADER=../../../etc/arith_apple_m1.h
+            wheel_arch: arm64
 
     steps:
       - uses: actions/checkout at v2
@@ -72,7 +85,7 @@ jobs:
           brew install autoconf automake libtool cmake
 
       - name: Build wheels
-        uses: joerick/cibuildwheel at v1.10.0
+        uses: pypa/cibuildwheel at v2.4.0
         env:
           CIBW_BEFORE_BUILD: "python setup.py build_c_core"
 
@@ -116,7 +129,7 @@ jobs:
         run: choco install winflexbison3 cmake
 
       - name: Build wheels
-        uses: joerick/cibuildwheel at v1.10.0
+        uses: pypa/cibuildwheel at v2.4.0
         env:
           CIBW_BEFORE_BUILD: "python setup.py build_c_core"
           CIBW_BUILD: "*-${{ matrix.wheel_arch }}"


=====================================
CHANGELOG
=====================================
@@ -1,3 +1,6 @@
+0.8.10
+- Fixed installation from source package (issue #101)
+
 0.8.9
 - Fixed bug with renaming of python-igraph to igraph (issue #93)
 - Removed irrelevant node_sizes argument for RBConfigurationVertexPartition and ModularityVertexPartition


=====================================
MANIFEST.in
=====================================
@@ -12,8 +12,3 @@ exclude release*
 prune .github
 
 graft vendor/source/igraph
-prune vendor/source/igraph/etc/abstracts
-prune vendor/source/igraph/etc/papers
-prune vendor/source/igraph/etc/presentations
-prune vendor/source/igraph/interfaces
-prune vendor/source/igraph/vendor/simpleraytracer


=====================================
debian/changelog
=====================================
@@ -1,3 +1,13 @@
+python-leidenalg (0.8.10-1) unstable; urgency=medium
+
+  * Team upload.
+  * New upstream version
+  * Standards-Version: 4.6.1 (routine-update)
+  * Add typos.patch: fix typos caught by lintian.
+  * d/control: add myself to uploaders.
+
+ -- Étienne Mollier <emollier at debian.org>  Sun, 03 Jul 2022 17:26:54 +0200
+
 python-leidenalg (0.8.9-1) unstable; urgency=medium
 
   * New upstream version


=====================================
debian/control
=====================================
@@ -1,6 +1,8 @@
 Source: python-leidenalg
 Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>, Nilesh Patra <nilesh at debian.org>
+Uploaders: Andreas Tille <tille at debian.org>,
+           Nilesh Patra <nilesh at debian.org>,
+           Étienne Mollier <emollier at debian.org>
 Section: science
 Priority: optional
 Build-Depends: debhelper-compat (= 13),
@@ -13,7 +15,7 @@ Build-Depends: debhelper-compat (= 13),
                python3-ddt <!nocheck>,
                python3-igraph <!nocheck>,
                python3-wheel <!nocheck>
-Standards-Version: 4.6.0
+Standards-Version: 4.6.1
 Vcs-Browser: https://salsa.debian.org/med-team/python-leidenalg
 Vcs-Git: https://salsa.debian.org/med-team/python-leidenalg.git
 Homepage: https://github.com/vtraag/leidenalg


=====================================
debian/patches/series
=====================================
@@ -0,0 +1 @@
+typos.patch


=====================================
debian/patches/typos.patch
=====================================
@@ -0,0 +1,33 @@
+Description: fix typos caught by lintian.
+Author: Étienne Mollier <emollier at debian.org>
+Forwarded: no
+Last-Update: 2022-07-03
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- python-leidenalg.orig/include/MutableVertexPartition.h
++++ python-leidenalg/include/MutableVertexPartition.h
+@@ -65,11 +65,11 @@
+     void move_node(size_t v,size_t new_comm);
+     virtual double diff_move(size_t v, size_t new_comm)
+     {
+-      throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method.");
++      throw Exception("Function not implemented. This should be implemented in a derived class, since the base class does not implement a specific method.");
+     };
+     virtual double quality()
+     {
+-      throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method.");
++      throw Exception("Function not implemented. This should be implemented in a derived class, since the base class does not implement a specific method.");
+     };
+ 
+     inline Graph* get_graph() { return this->graph; };
+--- python-leidenalg.orig/include/ResolutionParameterVertexPartition.h
++++ python-leidenalg/include/ResolutionParameterVertexPartition.h
+@@ -23,7 +23,7 @@
+ 
+     virtual double quality(double resolution_parameter)
+     {
+-      throw Exception("Function not implemented. This should be implented in a derived class, since the base class does not implement a specific method.");
++      throw Exception("Function not implemented. This should be implemented in a derived class, since the base class does not implement a specific method.");
+     };
+ 
+   private:


=====================================
etc/arith_apple_m1.h
=====================================
@@ -0,0 +1,9 @@
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Long int
+#define Intcast (int)(long)
+#define Double_Align
+#define X64_bit_pointers
+#define NANCHECK
+#define QNaN0 0x0
+#define QNaN1 0x7ff80000


=====================================
setup.py
=====================================
@@ -11,12 +11,6 @@ if sys.version_info < (3, 6):
     print("This module requires Python >= 3.6")
     sys.exit(0)
 
-# Check whether we are compiling for PyPy. Headers will not be installed
-# for PyPy.
-SKIP_HEADER_INSTALL = (platform.python_implementation() == "PyPy") or (
-    "SKIP_HEADER_INSTALL" in os.environ
-)
-
 ###########################################################################
 
 from setuptools import setup, Command, Extension
@@ -25,32 +19,46 @@ import glob
 import shlex
 import shutil
 import subprocess
-import sys
 import sysconfig
 
+from contextlib import contextmanager
 from pathlib import Path
 from select import select
 from shutil import which
 from time import sleep
+from typing import List, Iterable, Iterator, Optional, Tuple, TypeVar, Union
+
+###########################################################################
+
+LIBIGRAPH_FALLBACK_INCLUDE_DIRS = ["/usr/include/igraph", "/usr/local/include/igraph"]
+LIBIGRAPH_FALLBACK_LIBRARIES = ["igraph"]
+LIBIGRAPH_FALLBACK_LIBRARY_DIRS = []
+
+# Check whether we are compiling for PyPy. Headers will not be installed
+# for PyPy.
+SKIP_HEADER_INSTALL = (platform.python_implementation() == "PyPy") or (
+    "SKIP_HEADER_INSTALL" in os.environ
+)
 
 ###########################################################################
 
-is_windows = platform.system() == "windows"
+
+T = TypeVar("T")
 
 
-def building_on_windows_msvc():
+def building_on_windows_msvc() -> bool:
     """Returns True when using the non-MinGW CPython interpreter on Windows"""
     return platform.system() == "Windows" and sysconfig.get_platform() != "mingw"
 
 
-def exclude_from_list(items, items_to_exclude):
+def exclude_from_list(items: Iterable[T], items_to_exclude: Iterable[T]) -> List[T]:
     """Excludes certain items from a list, keeping the original order of
     the remaining items."""
     itemset = set(items_to_exclude)
     return [item for item in items if item not in itemset]
 
 
-def find_static_library(library_name, library_path):
+def find_static_library(library_name: str, library_path: List[str]) -> Optional[str]:
     """Given the raw name of a library in `library_name`, tries to find a
     static library with this name in the given `library_path`. `library_path`
     is automatically extended with common library directories on Linux and Mac
@@ -59,6 +67,7 @@ def find_static_library(library_name, library_path):
     variants = ["lib{0}.a", "{0}.a", "{0}.lib", "lib{0}.lib"]
     if is_unix_like():
         extra_libdirs = [
+            "/opt/homebrew/lib",  # for newer Homebrew installations on macOS
             "/usr/local/lib64",
             "/usr/local/lib",
             "/usr/lib/x86_64-linux-gnu",
@@ -81,15 +90,17 @@ def find_static_library(library_name, library_path):
                 return full_path
 
 
-def first(iterable):
+def first(iterable: Iterable[T]) -> T:
     """Returns the first element from the given iterable."""
     for item in iterable:
         return item
     raise ValueError("iterable is empty")
 
 
-def get_output(args, encoding="utf-8"):
-    """Returns the output of a command returning a single line of output."""
+def get_output(args, encoding: str = "utf-8") -> Tuple[str, int]:
+    """Returns the output of a command returning a single line of output, and
+    the exit code of the command.
+    """
     PIPE = subprocess.PIPE
     try:
         p = subprocess.Popen(args, shell=False, stdin=PIPE, stdout=PIPE, stderr=PIPE)
@@ -98,25 +109,23 @@ def get_output(args, encoding="utf-8"):
     except OSError:
         stdout, stderr = None, None
         returncode = 77
-    if encoding and type(stdout).__name__ == "bytes":
+    if isinstance(stdout, bytes):
         stdout = str(stdout, encoding=encoding)
-    if encoding and type(stderr).__name__ == "bytes":
+    if isinstance(stderr, bytes):
         stderr = str(stderr, encoding=encoding)
-    return stdout, returncode
+    return (stdout or ""), returncode
 
 
-def get_output_single_line(args, encoding="utf-8"):
-    """Returns the output of a command returning a single line of output,
-    stripped from any trailing newlines."""
+def get_output_single_line(args, encoding: str = "utf-8") -> Tuple[str, int]:
+    """Returns the first line of the output of a command, stripped from any
+    trailing newlines, and the exit code of the command.
+    """
     stdout, returncode = get_output(args, encoding=encoding)
-    if stdout is not None:
-        line, _, _ = stdout.partition("\n")
-    else:
-        line = None
+    line, _, _ = stdout.partition("\n")
     return line, returncode
 
 
-def is_unix_like(platform=None):
+def is_unix_like(platform: str = sys.platform) -> bool:
     """Returns whether the given platform is a Unix-like platform with the usual
     Unix filesystem. When the parameter is omitted, it defaults to ``sys.platform``
     """
@@ -129,12 +138,10 @@ def is_unix_like(platform=None):
     )
 
 
-def wait_for_keypress(seconds):
+def wait_for_keypress(seconds: float) -> None:
     """Wait for a keypress or until the given number of seconds have passed,
     whichever happens first.
     """
-    global is_windows
-
     while seconds > 0:
         if seconds > 1:
             plural = "s"
@@ -147,10 +154,10 @@ def wait_for_keypress(seconds):
         )
         sys.stdout.flush()
 
-        if is_windows:
-            from msvcrt import kbhit
+        if platform.system() == "Windows":
+            from msvcrt import kbhit  # type: ignore
 
-            for i in range(10):
+            for _ in range(10):
                 if kbhit():
                     seconds = 0
                     break
@@ -167,62 +174,48 @@ def wait_for_keypress(seconds):
     sys.stdout.write("\r" + " " * 65 + "\r")
 
 
-###########################################################################
-
-
-class IgraphCCoreBuilder(object):
-    """Superclass for classes responsible for downloading and building the
-    C core of igraph if it is not installed yet.
-    """
-
-    def create_build_config_file(self, install_folder, libraries):
-        with (install_folder / "build.cfg").open("w") as fp:
-            fp.write(repr(libraries))
-
-    def parse_pkgconfig_file(self, filename):
-        building_on_windows = building_on_windows_msvc()
-
-        if building_on_windows:
-            libraries = ["igraph"]
-        else:
-            libraries = []
-            with filename.open("r") as fp:
-                for line in fp:
-                    if line.startswith("Libs: ") or line.startswith("Libs.private: "):
-                        words = line.strip().split()
-                        libraries.extend(
-                            word[2:] for word in words if word.startswith("-l")
-                        )
-
-            if not libraries:
-                # Educated guess
-                libraries = ["igraph"]
-
-        return libraries
+ at contextmanager
+def working_directory(dir: Union[str, Path]) -> Iterator[None]:
+    cwd = os.getcwd()
+    os.chdir(dir)
+    try:
+        yield
+    finally:
+        os.chdir(cwd)
 
 
 ###########################################################################
 
 
-class IgraphCCoreCMakeBuilder(IgraphCCoreBuilder):
+class IgraphCCoreCMakeBuilder:
     """Class responsible for downloading and building the C core of igraph
     if it is not installed yet, assuming that the C core uses CMake as the
     build tool. This is the case from igraph 0.9.
-
-    Returns:
-        False if the build failed or the list of libraries to link to when
-        linking the Python interface to igraph
     """
 
-    def compile_in(self, source_folder, build_folder, install_folder):
+    def compile_in(
+        self, source_folder: Path, build_folder: Path, install_folder: Path
+    ) -> Union[bool, List[str]]:
         """Compiles igraph from its source code in the given folder.
 
-        source_folder is the name of the folder that contains igraph's source
-        files. build_folder is the name of the folder where the build should
-        be executed. Both must be absolute paths.
+        Parameters:
+            source_folder: absolute path to the folder that contains igraph's
+                source files
+            build_folder: absolute path to the folder where the build should be
+                executed
+            install_folder: absolute path to the folder where the built library
+                should be installed
+
+        Returns:
+            False if the build failed or the list of libraries to link to when
+            linking the Python interface to igraph
         """
-        global is_windows
+        with working_directory(build_folder):
+            return self._compile_in(source_folder, build_folder, install_folder)
 
+    def _compile_in(
+        self, source_folder: Path, build_folder: Path, install_folder: Path
+    ) -> Union[bool, List[str]]:
         cmake = which("cmake")
         if not cmake:
             print(
@@ -232,7 +225,6 @@ class IgraphCCoreCMakeBuilder(IgraphCCoreBuilder):
             return False
 
         build_to_source_folder = os.path.relpath(source_folder, build_folder)
-        os.chdir(build_folder)
 
         print("Configuring build...")
         args = [cmake]
@@ -245,6 +237,13 @@ class IgraphCCoreCMakeBuilder(IgraphCCoreBuilder):
         # Python shared library
         args.append("-DCMAKE_POSITION_INDEPENDENT_CODE=ON")
 
+        # No need to build tests
+        args.append("-DBUILD_TESTING=OFF")
+        
+        # Set install directory during config step instead of install step in order
+        # to avoid having the architecture name in the LIBPATH (e.g. lib/x86_64-linux-gnu)
+        args.append("-DCMAKE_INSTALL_PREFIX=" + str(install_folder))
+
         # Add any extra CMake args from environment variables
         if "IGRAPH_CMAKE_EXTRA_ARGS" in os.environ:
             args.extend(shlex.split(os.environ["IGRAPH_CMAKE_EXTRA_ARGS"]))
@@ -257,32 +256,63 @@ class IgraphCCoreCMakeBuilder(IgraphCCoreBuilder):
             return False
 
         print("Running build...")
-        retcode = subprocess.call(
-            [cmake, "--build", ".", "--config", "Release"]
-        )
+        # We are _not_ using a parallel build; this is intentional, see igraph/igraph#1755
+        retcode = subprocess.call([cmake, "--build", ".", "--config", "Release"])
         if retcode:
             return False
 
         print("Installing build...")
-        retcode = subprocess.call([cmake, "--install", ".", "--prefix", str(install_folder), "--config", "Release"])
+        retcode = subprocess.call(
+            [
+                cmake,
+                "--install",
+                ".",
+                "--config",
+                "Release",
+            ]
+        )
         if retcode:
             return False
 
-        pkgconfig_candidates = [
-            install_folder / "lib" / "pkgconfig" / "igraph.pc",
-            install_folder / "lib64" / "pkgconfig" / "igraph.pc"
-        ]
-        for candidate in pkgconfig_candidates:
-            if candidate.exists():
-                return self.parse_pkgconfig_file(candidate)
+        for candidate in install_folder.rglob("igraph.pc"):
+            return self._parse_pkgconfig_file(candidate)
+
+        raise RuntimeError(
+            "no igraph.pc was found in the installation folder of igraph"
+        )
 
-        raise RuntimeError("no igraph.pc was found in the installation folder of igraph")
+    def create_build_config_file(
+        self, install_folder: Path, libraries: List[str]
+    ) -> None:
+        with (install_folder / "build.cfg").open("w") as fp:
+            fp.write(repr(libraries))
+
+    def _parse_pkgconfig_file(self, filename: Path) -> List[str]:
+        building_on_windows = building_on_windows_msvc()
+
+        if building_on_windows:
+            libraries = ["igraph"]
+        else:
+            libraries = []
+            with filename.open("r") as fp:
+                for line in fp:
+                    if line.startswith("Libs: ") or line.startswith("Libs.private: "):
+                        words = line.strip().split()
+                        libraries.extend(
+                            word[2:] for word in words if word.startswith("-l")
+                        )
+
+            if not libraries:
+                # Educated guess
+                libraries = ["igraph"]
+
+        return libraries
 
 
 ###########################################################################
 
 
-class BuildConfiguration(object):
+class BuildConfiguration:
     def __init__(self):
         self.include_dirs = []
         self.library_dirs = []
@@ -295,25 +325,26 @@ class BuildConfiguration(object):
         self.static_extension = False
         self.external = False
         self.use_pkgconfig = False
+        self.c_core_built = False
         self._has_pkgconfig = None
         self.excluded_include_dirs = []
         self.excluded_library_dirs = []
         self.wait = platform.system() != "Windows"
 
     @property
-    def has_pkgconfig(self):
+    def has_pkgconfig(self) -> bool:
         """Returns whether ``pkg-config`` is available on the current system
         and it knows about igraph or not."""
         if self._has_pkgconfig is None:
             if self.use_pkgconfig:
-                line, exit_code = get_output_single_line(["pkg-config", "igraph"])
+                _, exit_code = get_output_single_line(["pkg-config", "igraph"])
                 self._has_pkgconfig = exit_code == 0
             else:
                 self._has_pkgconfig = False
         return self._has_pkgconfig
 
     @property
-    def build_c_core(self):
+    def build_c_core(self) -> Command:
         """Returns a class representing a custom setup.py command that builds
         the C core of igraph.
 
@@ -342,20 +373,19 @@ class BuildConfiguration(object):
         return build_c_core
 
     @property
-    def build_ext(self):
+    def build_ext(self) -> Command:
         """Returns a class that can be used as a replacement for the
         ``build_ext`` command in ``setuptools`` and that will compile the C core
         of igraph before compiling the Python extension.
         """
         from setuptools.command.build_ext import build_ext
-        from distutils.sysconfig import get_python_inc
 
         buildcfg = self
 
         class custom_build_ext(build_ext):
             def run(self):
                 # Bail out if we don't have the Python include files
-                include_dir = get_python_inc()
+                include_dir = sysconfig.get_path('include')
                 if not os.path.isfile(os.path.join(include_dir, "Python.h")):
                     print("You will need the Python headers to compile this extension.")
                     sys.exit(1)
@@ -363,7 +393,7 @@ class BuildConfiguration(object):
                 # Check whether the user asked us to discover a pre-built igraph
                 # with pkg-config
                 detected = False
-                if buildcfg.external:
+                if buildcfg.external:                
                     if buildcfg.use_pkgconfig:
                         detected = buildcfg.detect_from_pkgconfig()
                         if not detected:
@@ -372,7 +402,7 @@ class BuildConfiguration(object):
                             )
                             sys.exit(1)
                     else:
-                        buildcfg.use_educated_guess()
+                        buildcfg.use_educated_guess()                            
                 else:
                     # Build the C core from the vendored igraph source
                     self.run_command("build_c_core")
@@ -399,12 +429,16 @@ class BuildConfiguration(object):
 
                 # Add extra libraries that may have been specified
                 if "IGRAPH_EXTRA_LIBRARIES" in os.environ:
-                    extra_libraries = os.environ["IGRAPH_EXTRA_LIBRARIES"].split(',')
+                    extra_libraries = os.environ["IGRAPH_EXTRA_LIBRARIES"].split(",")
                     buildcfg.libraries.extend(extra_libraries)
 
                 # Override static specification based on environment variable
                 if "IGRAPH_STATIC_EXTENSION" in os.environ:
-                    if os.environ["IGRAPH_STATIC_EXTENSION"].lower() in ['true', '1', 'on']:
+                    if os.environ["IGRAPH_STATIC_EXTENSION"].lower() in [
+                        "true",
+                        "1",
+                        "on",
+                    ]:
                         buildcfg.static_extension = True
                     else:
                         buildcfg.static_extension = False
@@ -421,9 +455,16 @@ class BuildConfiguration(object):
 
                 # Add extra libraries that may have been specified
                 if "IGRAPH_EXTRA_DYNAMIC_LIBRARIES" in os.environ:
-                    extra_libraries = os.environ["IGRAPH_EXTRA_DYNAMIC_LIBRARIES"].split(',')
+                    extra_libraries = os.environ[
+                        "IGRAPH_EXTRA_DYNAMIC_LIBRARIES"
+                    ].split(",")
                     buildcfg.libraries.extend(extra_libraries)
 
+                # Remove C++ standard library as we will use the C++ linker
+                for lib in ("c++", "stdc++"):
+                    if lib in buildcfg.libraries:
+                        buildcfg.libraries.remove(lib)
+
                 # Prints basic build information
                 buildcfg.print_build_info()
 
@@ -434,7 +475,7 @@ class BuildConfiguration(object):
                     for extension in self.extensions
                     if extension.name == "leidenalg._c_leiden"
                 )
-                ext.include_dirs += buildcfg.include_dirs
+                ext.include_dirs += buildcfg.include_dirs                
                 buildcfg.configure(ext)
 
                 # Run the original build_ext command
@@ -451,77 +492,84 @@ class BuildConfiguration(object):
         """
         from setuptools.command.sdist import sdist
 
-        def is_git_repo(folder):
-            return os.path.exists(os.path.join(folder, ".git"))
+        def is_git_repo(folder) -> bool:
+            return (Path(folder) / ".git").exists()
 
-        def cleanup_git_repo(folder):
-            folder = str(folder)
-            cwd = os.getcwd()
-            try:
-                os.chdir(folder)
+        def cleanup_git_repo(folder) -> None:
+            with working_directory(folder):
                 if os.path.exists(".git"):
                     retcode = subprocess.call("git clean -dfx", shell=True)
                     if retcode:
                         raise RuntimeError(f"Failed to clean {folder} with git")
-            finally:
-                os.chdir(cwd)
 
         class custom_sdist(sdist):
             def run(self):
-                igraph_source_repo = os.path.join("vendor", "source", "igraph")
-                igraph_build_dir = os.path.join("vendor", "build", "igraph")
-                version_file = os.path.join(igraph_source_repo, "IGRAPH_VERSION")
+                igraph_source_repo = Path("vendor", "source", "igraph")
+                igraph_build_dir = Path("vendor", "build", "igraph")
+                version_file = igraph_source_repo / "IGRAPH_VERSION"
                 version = None
 
                 # Check whether the source repo contains an IGRAPH_VERSION file,
                 # and extract the version number from that
-                if os.path.exists(version_file):
-                    with open(version_file, "r") as fp:
-                        version = fp.read().strip().split("\n")[0]
+                if version_file.exists():
+                    version = version_file.read_text().strip().split("\n")[0]
 
                 # If no IGRAPH_VERSION file exists, but we have a git repo, try
                 # git describe
                 if not version and is_git_repo(igraph_source_repo):
-                    cwd = os.getcwd()
-                    try:
-                        os.chdir(igraph_source_repo)
-                        version = subprocess.check_output("git describe", shell=True).decode("utf-8").strip()
-                    finally:
-                        os.chdir(cwd)
+                    with working_directory(igraph_source_repo):
+                        version = (
+                            subprocess.check_output("git describe", shell=True)
+                            .decode("utf-8")
+                            .strip()
+                        )
 
                 # If we still don't have a version number, try to parse it from
                 # include/igraph_version.h
                 if not version:
-                    version_header = os.path.join(igraph_build_dir, "include", "igraph_version.h")
-                    if not os.path.exists(version_header):
-                        raise RuntimeError("You need to build the C core of igraph first before generating a source tarball of python-igraph")
+                    version_header = igraph_build_dir / "include" / "igraph_version.h"
+                    if not version_header.exists():
+                        raise RuntimeError(
+                            "You need to build the C core of igraph first before generating a source tarball of the Python interface of igraph"
+                        )
 
-                    with open(version_header, "r") as fp:
-                        lines = [line.strip() for line in fp if line.startswith("#define IGRAPH_VERSION ")]
+                    with version_header.open("r") as fp:
+                        lines = [
+                            line.strip()
+                            for line in fp
+                            if line.startswith("#define IGRAPH_VERSION ")
+                        ]
                         if len(lines) == 1:
                             version = lines[0].split('"')[1]
 
                 if not isinstance(version, str) or len(version) < 5:
-                    raise RuntimeError(f"Cannot determine the version number of the C core in {igraph_source_repo}")
+                    raise RuntimeError(
+                        f"Cannot determine the version number of the C core in {igraph_source_repo}"
+                    )
 
                 if not is_git_repo(igraph_source_repo):
-                    # python-igraph was extracted from an official tarball so
-                    # there is no need to tweak anything
+                    # The Python interface was extracted from an official
+                    # tarball so there is no need to tweak anything
                     return sdist.run(self)
                 else:
                     # Clean up vendor/source/igraph with git
                     cleanup_git_repo(igraph_source_repo)
 
                     # Copy the generated parser sources from the build folder
-                    parser_dir = os.path.join(igraph_build_dir, "src", "io", "parsers")
-                    if os.path.isdir(parser_dir):
-                        shutil.copytree(parser_dir, os.path.join(igraph_source_repo, "src", "io", "parsers"))
+                    parser_dir = igraph_build_dir / "src" / "io" / "parsers"
+                    if parser_dir.is_dir():
+                        shutil.copytree(
+                            parser_dir,
+                            igraph_source_repo / "src" / "io" / "parsers"
+                        )
                     else:
-                        raise RuntimeError(f"You need to build the C core of igraph first before generating a source tarball of python-igraph")
+                        raise RuntimeError(
+                            "You need to build the C core of igraph first before "
+                            "generating a source tarball of the Python interface"
+                        )
 
                     # Add a version file to the tarball
-                    with open(version_file, "w") as fp:
-                        fp.write(version)
+                    version_file.write_text(version)
 
                     # Run the original sdist command
                     retval = sdist.run(self)
@@ -533,7 +581,7 @@ class BuildConfiguration(object):
 
         return custom_sdist
 
-    def compile_igraph_from_vendor_source(self):
+    def compile_igraph_from_vendor_source(self) -> bool:
         """Compiles igraph from the vendored source code inside `vendor/source/igraph`.
         This folder typically comes from a git submodule.
         """
@@ -566,28 +614,31 @@ class BuildConfiguration(object):
 
         Path(build_folder).mkdir(parents=True, exist_ok=True)
 
-        cwd = os.getcwd()
-        try:
-            libraries = igraph_builder.compile_in(
-                source_folder=source_folder,
-                build_folder=build_folder,
-                install_folder=install_folder,
-            )
-        finally:
-            os.chdir(cwd)
+        libraries = igraph_builder.compile_in(
+            source_folder=source_folder,
+            build_folder=build_folder,
+            install_folder=install_folder,
+        )
+
+        if libraries is False:
+            print("Build failed for the C core of igraph.")
+            print("")
+            sys.exit(1)
+
+        assert not isinstance(libraries, bool)
 
         igraph_builder.create_build_config_file(install_folder, libraries)
 
         self.use_vendored_igraph()
         return True
 
-    def configure(self, ext):
+    def configure(self, ext) -> None:
         """Configures the given Extension object using this build configuration."""
         ext.include_dirs = exclude_from_list(
             ext.include_dirs, self.excluded_include_dirs
         )
         ext.library_dirs = exclude_from_list(
-            self.library_dirs, self.excluded_library_dirs
+            ext.library_dirs, self.excluded_library_dirs
         )
         ext.runtime_library_dirs = self.runtime_library_dirs
         ext.libraries = self.libraries
@@ -596,7 +647,7 @@ class BuildConfiguration(object):
         ext.extra_objects = self.extra_objects
         ext.define_macros = self.define_macros
 
-    def detect_from_pkgconfig(self):
+    def detect_from_pkgconfig(self) -> bool:
         """Detects the igraph include directory, library directory and the
         list of libraries to link to using ``pkg-config``."""
         if not buildcfg.has_pkgconfig:
@@ -615,7 +666,7 @@ class BuildConfiguration(object):
         self.include_dirs = [opt[2:] for opt in opts if opt.startswith("-I")]
         return True
 
-    def print_build_info(self):
+    def print_build_info(self) -> None:
         """Prints the include and library path being used for debugging purposes."""
         if self.static_extension == "only_igraph":
             build_type = "dynamic extension with vendored igraph source"
@@ -656,7 +707,7 @@ class BuildConfiguration(object):
                 self.wait = False
             elif option == "--external":
                 opts_to_remove.append(idx)
-                self.external = True
+                self.external = True                
             elif option == "--use-pkg-config":
                 opts_to_remove.append(idx)
                 self.use_pkgconfig = True
@@ -667,11 +718,6 @@ class BuildConfiguration(object):
     def replace_static_libraries(self, only=None, exclusions=None):
         """Replaces references to libraries with full paths to their static
         versions if the static version is to be found on the library path."""
-        building_on_windows = building_on_windows_msvc()
-
-        if not building_on_windows and "stdc++" not in self.libraries:
-            self.libraries.append("stdc++")
-
         if exclusions is None:
             exclusions = []
 
@@ -689,7 +735,7 @@ class BuildConfiguration(object):
             else:
                 print(f"Warning: could not find static library of {library_name}.")
 
-    def use_vendored_igraph(self):
+    def use_vendored_igraph(self) -> None:
         """Assumes that igraph is installed already in ``vendor/install/igraph`` and sets up
         the include and library paths and the library names accordingly."""
         building_on_windows = building_on_windows_msvc()
@@ -705,7 +751,9 @@ class BuildConfiguration(object):
                 buildcfg.library_dirs.append(str(candidate))
                 break
         else:
-            raise RuntimeError("cannot detect igraph library dir within " + str(vendor_dir))
+            raise RuntimeError(
+                "cannot detect igraph library dir within " + str(vendor_dir)
+            )
 
         if not buildcfg.static_extension:
             buildcfg.static_extension = "only_igraph"
@@ -716,26 +764,33 @@ class BuildConfiguration(object):
         if buildcfg_file.exists():
             buildcfg.libraries = eval(buildcfg_file.open("r").read())
 
-    def use_educated_guess(self):
-        """Tries to guess the proper library names, include and library paths."""
+    def use_educated_guess(self) -> None:
+        """Tries to guess the proper library names, include and library paths
+        if everything else failed."""
+
+        global LIBIGRAPH_FALLBACK_LIBRARIES
+        global LIBIGRAPH_FALLBACK_INCLUDE_DIRS
+        global LIBIGRAPH_FALLBACK_LIBRARY_DIRS
 
-        print("""WARNING: You are trying to install with an external igraph library.
-No include dirs or library dirs are specified, so they need to be set externally.
-If compilation fails you may adjust the following environment variables to adjust
-the required paths.
-- IGRAPH_EXTRA_INCLUDE_PATH
-- IGRAPH_EXTRA_LIBRARY_PATH
-- IGRAPH_EXTRA_LIBRARIES
-- IGRAPH_EXTRA_DYNAMIC_LIBRARIES
+        print("WARNING: we were not able to detect where igraph is installed on")
+        print("your machine (if it is installed at all). We will use the fallback")
+        print("library and include paths hardcoded in setup.py and hope that the")
+        print("C core of igraph is installed there.")
+        print("")
+        print("If the compilation fails and you are sure that igraph is installed")
+        print("on your machine, adjust the following two variables in setup.py")
+        print("accordingly and try again:")
+        print("")
+        print("- LIBIGRAPH_FALLBACK_INCLUDE_DIRS")
+        print("- LIBIGRAPH_FALLBACK_LIBRARY_DIRS")
+        print("")
 
-If a static build extension is used, we try to statically link to igraph. The extra
-libraries that are specified are then also assumed to be statically linked. If, in
-addition, some libraries need to be explicitly dynamically linked, you can specify this.
-        """)
 
-        self.libraries = ['igraph']
-        self.include_dirs = []
-        self.library_dirs = []
+        self.libraries = LIBIGRAPH_FALLBACK_LIBRARIES[:]
+        if self.static_extension:
+            self.libraries.extend(["xml2", "z", "m", "stdc++"])
+        self.include_dirs = LIBIGRAPH_FALLBACK_INCLUDE_DIRS[:]
+        self.library_dirs = LIBIGRAPH_FALLBACK_LIBRARY_DIRS[:]
 
 
 ###########################################################################
@@ -811,4 +866,4 @@ options =  dict(
     },
 )
 
-setup(**options)
\ No newline at end of file
+setup(**options)



View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/1319c64594dfbebfd272f48d07d2b5f4c8510ee2...7b1238fa8cd1509903ca08df0beea13722f8c5c4

-- 
View it on GitLab: https://salsa.debian.org/med-team/python-leidenalg/-/compare/1319c64594dfbebfd272f48d07d2b5f4c8510ee2...7b1238fa8cd1509903ca08df0beea13722f8c5c4
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20220703/5eb217f4/attachment-0001.htm>


More information about the debian-med-commit mailing list