Skip to content

Commit

Permalink
Merge branch 'master' into cottsay/symlink-data
Browse files Browse the repository at this point in the history
  • Loading branch information
cottsay committed Oct 11, 2023
2 parents e4799ea + a6aef15 commit 131cfeb
Show file tree
Hide file tree
Showing 17 changed files with 141 additions and 80 deletions.
2 changes: 1 addition & 1 deletion colcon_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2016-2020 Dirk Thomas
# Licensed under the Apache License, Version 2.0

__version__ = '0.12.1'
__version__ = '0.15.0'
7 changes: 4 additions & 3 deletions colcon_core/extension_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ def get_all_extension_points():
entry_points = defaultdict(dict)
seen = set()
for dist in distributions():
if dist.name in seen:
dist_name = dist.metadata['Name']
if dist_name in seen:
continue
seen.add(dist.name)
seen.add(dist_name)
for entry_point in dist.entry_points:
# skip groups which are not registered as extension points
if entry_point.group not in colcon_extension_points:
Expand All @@ -69,7 +70,7 @@ def get_all_extension_points():
f"from '{dist._path}' "
f"overwriting '{previous}'")
entry_points[entry_point.group][entry_point.name] = \
(entry_point.value, dist.name, dist.version)
(entry_point.value, dist_name, dist.version)
return entry_points


Expand Down
2 changes: 1 addition & 1 deletion colcon_core/package_augmentation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def update_metadata(desc, key, value):
old_value |= value
return

if type(old_value) != type(value):
if type(old_value) is not type(value):
logger.warning(
f"update package '{desc.name}' metadata '{key}' from value "
f"'{old_value}' to '{value}'")
Expand Down
2 changes: 1 addition & 1 deletion colcon_core/package_descriptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def __hash__(self): # noqa: D105
return hash((self.type, self.name))

def __eq__(self, other): # noqa: D105
if type(self) != type(other):
if type(self) is not type(other):
return NotImplemented
if (self.type, self.name) != (other.type, other.name):
return False
Expand Down
18 changes: 11 additions & 7 deletions colcon_core/task/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ async def check_call(


async def run(
context, cmd, *, cwd=None, env=None, shell=False, use_pty=None,
capture_output=None
context, cmd, *, use_pty=None, capture_output=None, **other_popen_kwargs
):
"""
Run the command described by cmd.
Expand All @@ -159,10 +158,11 @@ async def run(
All output to `stdout` and `stderr` is posted as `StdoutLine` and
`StderrLine` events to the event queue.
See the documentation of `subprocess.Popen()
<https://docs.python.org/3/library/subprocess.html#subprocess.Popen>` for
other parameters.
:param cmd: The command and its arguments
:param cwd: the working directory for the subprocess
:param env: a dictionary with environment variables
:param shell: whether to use the shell as the program to execute
:param use_pty: whether to use a pseudo terminal
:param capture_output: whether to store stdout and stderr
:returns: the result of the completed process
Expand All @@ -174,12 +174,16 @@ def stdout_callback(line):
def stderr_callback(line):
context.put_event_into_queue(StderrLine(line))

cwd = other_popen_kwargs.get('cwd', None)
env = other_popen_kwargs.get('env', None)
shell = other_popen_kwargs.get('shell', False)

context.put_event_into_queue(
Command(cmd, cwd=cwd, env=env, shell=shell))
completed = await colcon_core_subprocess_run(
cmd, stdout_callback, stderr_callback,
cwd=cwd, env=env, shell=shell, use_pty=use_pty,
capture_output=capture_output)
use_pty=use_pty, capture_output=capture_output,
**other_popen_kwargs)
context.put_event_into_queue(
CommandEnded(
cmd, cwd=cwd, env=env, shell=shell,
Expand Down
4 changes: 4 additions & 0 deletions colcon_core/task/python/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ async def build(self, *, additional_hooks=None): # noqa: D102
env = dict(env)
env['PYTHONPATH'] = str(prefix_override) + os.pathsep + \
python_lib + os.pathsep + env.get('PYTHONPATH', '')
# coverage capture interferes with sitecustomize
# See also: https://docs.python.org/3/library/site.html#module-site
# See also: colcon/colcon-core#579
env.pop('COV_CORE_SOURCE', None)

# determine if setuptools specific commands are available
available_commands = await self._get_available_commands(
Expand Down
2 changes: 1 addition & 1 deletion colcon_core/verb/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ def update_object(
return

severity = 5 \
if old_value is None or type(old_value) == type(value) \
if old_value is None or type(old_value) is type(value) \
else logging.WARNING
logger.log(
severity, f"overwrite package '{package_name}' {argument_type} "
Expand Down
4 changes: 1 addition & 3 deletions publish-python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ artifacts:
config:
repository: dirk-thomas/colcon
distributions:
- ubuntu:bionic
- ubuntu:focal
- ubuntu:jammy
- debian:stretch
- debian:buster
- debian:bullseye
- debian:bookworm
5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ filterwarnings =
ignore:The loop argument is deprecated::asyncio
ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated::pydocstyle
ignore:Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated::pyreadline
# Suppress resource warnings pending investigation
always::ResourceWarning
junit_suite_name = colcon-core
markers =
flake8
linter
python_classes = !TestFailure

[options.entry_points]
Expand Down
4 changes: 2 additions & 2 deletions stdeb.cfg
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[colcon-core]
No-Python2:
Depends3: python3-distlib, python3-empy, python3-pytest, python3-setuptools, python3 (>= 3.8) | python3-importlib-metadata
Depends3: python3-distlib, python3-empy, python3-packaging, python3-pytest, python3-setuptools, python3 (>= 3.8) | python3-importlib-metadata
Recommends3: python3-pytest-cov
Suggests3: python3-pytest-repeat, python3-pytest-rerunfailures
Suite: bionic focal jammy stretch buster bullseye
Suite: focal jammy bullseye bookworm
X-Python3-Version: >= 3.6
1 change: 1 addition & 0 deletions test/spell_check.words
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ junit
levelname
libexec
lineno
linter
linux
lstrip
mkdtemp
Expand Down
4 changes: 2 additions & 2 deletions test/test_argument_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ def test_argument_default():
unwrap_default_value(value)
default_value = wrap_default_value(value)
assert is_default_value(default_value)
assert type(default_value) != type(value)
assert type(default_value) is not type(value)
with pytest.raises(ValueError):
wrap_default_value(default_value)
unwrapped_value = unwrap_default_value(default_value)
assert value == unwrapped_value

value = 42
unchanged_value = wrap_default_value(value)
assert type(unchanged_value) == type(value)
assert type(unchanged_value) is type(value)
assert unchanged_value == value
131 changes: 86 additions & 45 deletions test/test_build_python.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,60 +45,101 @@ def monkey_patch_put_event_into_queue(monkeypatch):
)


def test_build_package():
def _test_build_package(tmp_path_str, *, symlink_install):
event_loop = new_event_loop()
asyncio.set_event_loop(event_loop)
try:
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
tmp_path = Path(tmp_path_str)
python_build_task = PythonBuildTask()
package = PackageDescriptor(tmp_path / 'src')
package.name = 'test_package'
package.type = 'python'
tmp_path = Path(tmp_path_str)
python_build_task = PythonBuildTask()
package = PackageDescriptor(tmp_path / 'src')
package.name = 'test_package'
package.type = 'python'
package.metadata['get_python_setup_options'] = lambda _: {
'packages': ['my_module'],
}

context = TaskContext(
pkg=package,
args=SimpleNamespace(
path=str(tmp_path / 'src'),
build_base=str(tmp_path / 'build'),
install_base=str(tmp_path / 'install'),
symlink_install=False,
),
dependencies={}
)
python_build_task.set_context(context=context)
context = TaskContext(
pkg=package,
args=SimpleNamespace(
path=str(tmp_path / 'src'),
build_base=str(tmp_path / 'build'),
install_base=str(tmp_path / 'install'),
symlink_install=symlink_install,
),
dependencies={}
)
python_build_task.set_context(context=context)

pkg = python_build_task.context.pkg

pkg.path.mkdir(exist_ok=True)
(pkg.path / 'setup.py').write_text(
'from setuptools import setup\n'
'setup(\n'
' name="test_package",\n'
' packages=["my_module"],\n'
')\n'
)
(pkg.path / 'my_module').mkdir(exist_ok=True)
(pkg.path / 'my_module' / '__init__.py').touch()

src_base = Path(python_build_task.context.args.path)

source_files_before = set(src_base.rglob('*'))
rc = event_loop.run_until_complete(python_build_task.build())
assert not rc
source_files_after = set(src_base.rglob('*'))
assert source_files_before == source_files_after

build_base = Path(python_build_task.context.args.build_base)
assert build_base.rglob('my_module/__init__.py')

return Path(python_build_task.context.args.install_base)
finally:
event_loop.close()

pkg = python_build_task.context.pkg

pkg.path.mkdir()
(pkg.path / 'setup.py').write_text(
'from setuptools import setup\n'
'setup(\n'
' name="test_package",\n'
' packages=["my_module"],\n'
')\n'
)
(pkg.path / 'my_module').mkdir()
(pkg.path / 'my_module' / '__init__.py').touch()
def test_build_package():
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
install_base = _test_build_package(tmp_path_str, symlink_install=False)

src_base = Path(python_build_task.context.args.path)
assert 1 == len(list(install_base.rglob('my_module/__init__.py')))

source_files_before = set(src_base.rglob('*'))
rc = event_loop.run_until_complete(python_build_task.build())
assert not rc
source_files_after = set(src_base.rglob('*'))
assert source_files_before == source_files_after
pkg_info, = install_base.rglob('PKG-INFO')
assert 'Name: test-package' in pkg_info.read_text().splitlines()

build_base = Path(python_build_task.context.args.build_base)
assert 1 == len(list(build_base.rglob('my_module/__init__.py')))

install_base = Path(python_build_task.context.args.install_base)
assert 1 == len(list(install_base.rglob('my_module/__init__.py')))
def test_build_package_symlink():
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
install_base = _test_build_package(tmp_path_str, symlink_install=True)

pkg_info, = install_base.rglob('PKG-INFO')
assert 'Name: test-package' in pkg_info.read_text().splitlines()
finally:
event_loop.close()
assert 1 == len(list(install_base.rglob('test-package.egg-link')))


def test_build_package_symlink_first():
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
install_base = _test_build_package(tmp_path_str, symlink_install=True)

assert 1 == len(list(install_base.rglob('test-package.egg-link')))
assert 0 == len(list(install_base.rglob('PKG-INFO')))

install_base = _test_build_package(tmp_path_str, symlink_install=False)

assert 0 == len(list(install_base.rglob('test-package.egg-link')))
assert 1 == len(list(install_base.rglob('PKG-INFO')))


def test_build_package_symlink_second():
with TemporaryDirectory(prefix='test_colcon_') as tmp_path_str:
install_base = _test_build_package(tmp_path_str, symlink_install=False)

assert 0 == len(list(install_base.rglob('test-package.egg-link')))
assert 1 == len(list(install_base.rglob('PKG-INFO')))

install_base = _test_build_package(tmp_path_str, symlink_install=True)

assert 1 == len(list(install_base.rglob('test-package.egg-link')))
assert 0 == len(list(install_base.rglob('PKG-INFO')))


def test_build_package_libexec_pattern():
Expand Down Expand Up @@ -126,7 +167,7 @@ def test_build_package_libexec_pattern():

pkg = python_build_task.context.pkg

pkg.path.mkdir()
pkg.path.mkdir(exist_ok=True)
(pkg.path / 'setup.py').write_text(
'from setuptools import setup\n'
'setup()\n'
Expand All @@ -144,7 +185,7 @@ def test_build_package_libexec_pattern():
'[install]\n'
'install-scripts=$base/lib/test_package\n'
)
(pkg.path / 'my_module').mkdir()
(pkg.path / 'my_module').mkdir(exist_ok=True)
(pkg.path / 'my_module' / '__init__.py').write_text(
'def main():\n'
' print("Hello, World!")\n'
Expand Down
3 changes: 3 additions & 0 deletions test/test_copyright_license.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
from pathlib import Path
import sys

import pytest


@pytest.mark.linter
def test_copyright_license():
missing = check_files([
Path(__file__).parents[1],
Expand Down
6 changes: 5 additions & 1 deletion test/test_extension_point.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ class Dist():
version = '0.0.0'

def __init__(self, entry_points):
self.name = f'dist-{id(self)}'
self.metadata = {'Name': f'dist-{id(self)}'}
self._entry_points = entry_points

@property
def entry_points(self):
return list(self._entry_points)

@property
def name(self):
return self.metadata['Name']


def iter_entry_points(*, group=None):
if group == EXTENSION_POINT_GROUP_NAME:
Expand Down
15 changes: 8 additions & 7 deletions test/test_flake8.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
from pathlib import Path
import sys

from flake8 import LOG
from flake8.api.legacy import get_style_guide
from pydocstyle.utils import log
import pytest


# avoid debug / info / warning messages from flake8 internals
LOG.setLevel(logging.ERROR)
@pytest.mark.flake8
@pytest.mark.linter
def test_flake8():
from flake8.api.legacy import get_style_guide

# avoid debug / info / warning messages from flake8 internals
logging.getLogger('flake8').setLevel(logging.ERROR)

def test_flake8():
# for some reason the pydocstyle logger changes to an effective level of 1
# set higher level to prevent the output to be flooded with debug messages
log.setLevel(logging.WARNING)
logging.getLogger('pydocstyle').setLevel(logging.WARNING)

style_guide = get_style_guide(
extend_ignore=['D100', 'D104'],
Expand Down
Loading

0 comments on commit 131cfeb

Please sign in to comment.