--- /dev/null
+Software License Agreement (BSD License)
+
+Copyright (c) 2012, Willow Garage, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Neither the name of Willow Garage, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: catkin_pkg
-Version: 0.4.23
+Version: 1.0.0
Summary: catkin package library
Home-page: http://wiki.ros.org/catkin_pkg
Author: Dirk Thomas
Author-email: dthomas@osrfoundation.org
+Maintainer: ROS Infrastructure Team
License: BSD
-Description: Library for retrieving information about catkin packages.
+Project-URL: Source code, https://github.com/ros-infrastructure/catkin_pkg
+Project-URL: Issue tracker, https://github.com/ros-infrastructure/catkin_pkg/issues
Keywords: catkin,ROS
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: License :: OSI Approved :: BSD License
+Requires-Python: >=3.6
+Provides-Extra: test
+License-File: LICENSE
+
+Library for retrieving information about catkin packages.
+
Continuous Integration
----------------------
-+--------------------------------------------------------------------------+--------------------------------------------------------------------+
-| `Build Status <https://travis-ci.org/ros-infrastructure/catkin_pkg>`_. | .. image:: https://travis-ci.org/ros-infrastructure/catkin_pkg.png |
-+--------------------------------------------------------------------------+--------------------------------------------------------------------+
+.. image:: https://github.com/ros-infrastructure/catkin_pkg/actions/workflows/ci.yaml/badge.svg?branch=master&event=push
+ :target: https://github.com/ros-infrastructure/catkin_pkg/actions/workflows/ci.yaml?query=branch%3Amaster+event%3Apush
+[flake8]
+extend-ignore = C403,C404,C405,D100,D101,D102,D103,D104,D105,D106,D107,D203,D212,D404,I202,W605
+import-order-style = google
+max-complexity = 54
+max-line-length = 200
+show-source = true
+statistics = true
+
+[tool:pytest]
+junit_suite_name = catkin_pkg
+markers =
+ flake8
+ linter
+
+[coverage:run]
+source = catkin_pkg
+
[egg_info]
tag_build =
tag_date = 0
-#!/usr/bin/env python
+#!/usr/bin/env python3
import os
-import sys
from setuptools import setup
-install_requires = [
- 'docutils',
- 'python-dateutil',
- 'pyparsing',
-]
-
-# argparse is part of the standard library since Python 2.7
-if sys.version_info[0] == 2 and sys.version_info[1] < 7:
- install_requires.append('argparse')
kwargs = {
'name': 'catkin_pkg',
# same version as in:
# - src/catkin_pkg/__init__.py
# - stdeb.cfg
- 'version': '0.4.23',
+ 'version': '1.0.0',
'packages': ['catkin_pkg', 'catkin_pkg.cli'],
'package_dir': {'': 'src'},
'package_data': {'catkin_pkg': ['templates/*.in']},
]},
'author': 'Dirk Thomas',
'author_email': 'dthomas@osrfoundation.org',
+ 'maintainer': 'ROS Infrastructure Team',
+ 'project_urls': {
+ 'Source code':
+ 'https://github.com/ros-infrastructure/catkin_pkg',
+ 'Issue tracker':
+ 'https://github.com/ros-infrastructure/catkin_pkg/issues',
+ },
'url': 'http://wiki.ros.org/catkin_pkg',
'keywords': ['catkin', 'ROS'],
'classifiers': [
'Programming Language :: Python',
'License :: OSI Approved :: BSD License'
],
+ 'python_requires': '>=3.6',
'description': 'catkin package library',
'long_description': 'Library for retrieving information about catkin packages.',
'license': 'BSD',
- 'install_requires': install_requires,
+ 'install_requires': [
+ 'docutils',
+ 'python-dateutil',
+ 'pyparsing',
+ 'setuptools',
+ ],
+ 'extras_require': {
+ 'test': [
+ 'flake8',
+ 'flake8-blind-except',
+ 'flake8-builtins',
+ 'flake8-class-newline',
+ 'flake8-comprehensions',
+ 'flake8-deprecated',
+ 'flake8-docstrings',
+ 'flake8-import-order',
+ 'flake8-quotes',
+ 'pytest',
+ ]},
}
if 'SKIP_PYTHON_MODULES' in os.environ:
kwargs['packages'] = []
-Metadata-Version: 1.1
+Metadata-Version: 2.1
Name: catkin-pkg
-Version: 0.4.23
+Version: 1.0.0
Summary: catkin package library
Home-page: http://wiki.ros.org/catkin_pkg
Author: Dirk Thomas
Author-email: dthomas@osrfoundation.org
+Maintainer: ROS Infrastructure Team
License: BSD
-Description: Library for retrieving information about catkin packages.
+Project-URL: Source code, https://github.com/ros-infrastructure/catkin_pkg
+Project-URL: Issue tracker, https://github.com/ros-infrastructure/catkin_pkg/issues
Keywords: catkin,ROS
Platform: UNKNOWN
Classifier: Programming Language :: Python
Classifier: License :: OSI Approved :: BSD License
+Requires-Python: >=3.6
+Provides-Extra: test
+License-File: LICENSE
+
+Library for retrieving information about catkin packages.
+
+LICENSE
README.rst
+setup.cfg
setup.py
src/catkin_pkg/__init__.py
src/catkin_pkg/changelog.py
docutils
-pyparsing
python-dateutil
+pyparsing
+setuptools
+
+[test]
+flake8
+flake8-blind-except
+flake8-builtins
+flake8-class-newline
+flake8-comprehensions
+flake8-deprecated
+flake8-docstrings
+flake8-import-order
+flake8-quotes
+pytest
# same version as in:
# - setup.py
# - stdeb.cfg
-__version__ = '0.4.23'
+__version__ = '1.0.0'
elif isinstance(child, docutils.nodes.title) or isinstance(child, docutils.nodes.subtitle):
version, date = None, None
# See if the title has a text element in it
- if len(child.children) > 0 and isinstance(child.children[0], docutils.nodes.Text):
+ if len(child.children) > 0 and any(isinstance(c, docutils.nodes.Text) for c in child.traverse()):
# Extract version and date from (sub-)title
- title_text = child.children[0].rawsource
+ title_text = child.astext()
try:
version, date = version_and_date_from_title(title_text)
except InvalidSectionTitle:
else:
# bump the version number
new_version = bump_version(version, args.bump)
- update_versions(packages.keys(), new_version)
+ update_versions(packages, new_version)
print('%s -> %s' % (version, new_version))
- except Exception as e:
+ except Exception as e: # noqa: B902
sys.exit(str(e))
def commit_files(base_path, vcs_type, packages, packages_with_changelogs, message, dry_run=False):
cmd = [_find_executable(vcs_type), 'commit', '-m', message]
cmd += [os.path.join(p, PACKAGE_MANIFEST_FILENAME) for p in packages.keys()]
+ cmd += [s for s in [os.path.join(p, 'setup.py') for p in packages.keys()] if os.path.exists(s)]
cmd += [path for path, _, _ in packages_with_changelogs.values()]
if not dry_run:
try:
# complain about packages with upper case character since they won't be releasable with bloom
unsupported_pkg_names = []
invalid_pkg_names = []
+ valid_build_types = ['catkin', 'ament_cmake', 'ament_python']
for package in packages.values():
- build_types = [export.content for export in package.exports if export.tagname == 'build_type']
- build_type = build_types[0] if build_types else 'catkin'
- if build_type not in ('catkin', 'ament_cmake'):
+ build_types = package.get_unconditional_build_types()
+ if any(build_type not in valid_build_types for build_type in build_types):
unsupported_pkg_names.append(package.name)
if package.name != package.name.lower():
invalid_pkg_names.append(package.name)
if unsupported_pkg_names:
print(
fmt(
- "@{yf}Warning: the following package are not of build_type catkin or ament_cmake and may require manual steps to release': %s" %
- ', '.join([('@{boldon}%s@{boldoff}' % p) for p in sorted(unsupported_pkg_names)])
+ "@{yf}Warning: the following package are not of build_type %s and may require manual steps to release': %s" %
+ (str(valid_build_types), ', '.join([('@{boldon}%s@{boldoff}' % p) for p in sorted(unsupported_pkg_names)]))
), file=sys.stderr)
if not args.non_interactive and not prompt_continue('Continue anyway', default=False):
raise RuntimeError(fmt('@{rf}Aborted release, verify that unsupported packages are ready to be released or release manually.'))
raise RuntimeError(fmt(
"@{rf}Invalid metapackage at path '@{boldon}%s@{boldoff}':\n %s\n\nSee requirements for metapackages: %s" %
(os.path.abspath(pkg_path), str(e), metapackage.DEFINITION_URL)))
+ # verify that the setup.py files don't have modifications pending
+ setup_py_path = os.path.join(pkg_path, 'setup.py')
+ if os.path.exists(setup_py_path) and has_changes(base_path, setup_py_path, vcs_type):
+ local_modifications.append(setup_py_path)
# fetch current version and verify that all packages have same version number
old_version = verify_equal_package_versions(packages.values())
(new_version, ', '.join([('@{boldon}%s@{boldoff}' % p) for p in sorted(missing_changelogs_but_forthcoming.keys())]))))
# bump version number
- update_versions(packages.keys(), new_version)
+ update_versions(packages, new_version)
print(fmt("@{gf}Bump version@{reset} of all packages from '@{bf}%s@{reset}' to '@{bf}@{boldon}%s@{boldoff}@{reset}'" % (old_version, new_version)))
pushed = None
return os.path.join(os.path.dirname(__file__), rel_path)
-def configure_file(template_file, environment): # noqa: D402
+def configure_file(template_file, environment):
"""
Evaluate a .in template file used in CMake with configure_file().
:returns: string with evaluates template
:raises: KeyError for placeholders in the template which are not
in the environment
- """
+ """ # noqa: D402
with open(template_file, 'r') as f:
template = f.read()
return configure_string(template, environment)
import re
import sys
import xml.dom.minidom as dom
+from xml.parsers.expat import ExpatError
from catkin_pkg.condition import evaluate_condition
'version',
'version_compatibility',
'description',
+ 'plaintext_description',
'maintainers',
'licenses',
'urls',
return build_type_exports[0]
raise InvalidPackage('Only one <build_type> element is permitted.', self.filename)
+ def get_unconditional_build_types(self):
+ """
+ Return values of export/build_type elements without conditional filtering, or ['catkin'] if unspecified.
+
+ :returns: package build types
+ :rtype: List[str]
+ """
+ build_type_exports = [e.content for e in self.exports if e.tagname == 'build_type']
+ if not build_type_exports:
+ return ['catkin']
+ return build_type_exports
+
def has_invalid_metapackage_dependencies(self):
"""
Return True if this package has invalid dependencies for a metapackage.
data = data.encode('utf-8')
try:
root = dom.parseString(data)
- except Exception:
+ except ExpatError:
# invalid XML
return False
data = data.encode('utf-8')
try:
root = dom.parseString(data)
- except Exception as ex:
+ except ExpatError as ex:
raise InvalidPackage('The manifest contains invalid XML:\n%s' % ex, filename)
pkg = Package(filename)
# description
pkg.description = _get_node_value(_get_node(root, 'description', filename), allow_xml=True, apply_str=False)
+ pkg.plaintext_description = re.sub(' +(\n+) +', r'\1', _get_node_text(_get_node(root, 'description', filename)), flags=re.MULTILINE)
# at least one maintainer, all must have email
maintainers = _get_nodes(root, 'maintainer')
return value
+def _get_node_text(node, strip=True):
+ value = ''
+ for child in node.childNodes:
+ if child.nodeType == child.TEXT_NODE:
+ value += re.sub(r'\s+', ' ', child.data)
+ elif child.nodeType == child.ELEMENT_NODE:
+ if child.tagName == 'br':
+ value += '\n'
+ else:
+ value += _get_node_text(child, strip=False)
+ else:
+ assert 'unreachable'
+ if strip:
+ value = value.strip()
+ return value
+
+
def _get_node_attr(node, attr, default=False):
""":param default: False means value is required."""
if node.hasAttribute(attr):
return new_package_str
+def _replace_setup_py_version(setup_py_str, new_version):
+ """
+ Replace the version tag in contents if there is only one instance and it is using a literal as the version.
+
+ :param str package_str: contents of setup.py
+ :param str new_version: new version number
+ :returns: new setup.py string
+ :rtype: str
+ :raises RuntimeError:
+ """
+ # try to replace contents
+ new_setup_py_str, number_of_subs = re.subn(
+ r'version=([\'"])\d+\.\d+\.\d+([\'"]),',
+ r'version=\g<1>%s\g<2>,' % new_version,
+ setup_py_str)
+ if number_of_subs == 0:
+ raise RuntimeError("Failed to find a normal version statement, e.g.: version='1.2.3',")
+ if number_of_subs != 1:
+ raise RuntimeError('Illegal number of version statements: %s' % (number_of_subs))
+ return new_setup_py_str
+
+
def _check_for_version_comment(package_str, new_version):
"""
Check if a comment is present behind the version tag and return it.
return comment
-def update_versions(paths, new_version):
+def update_versions(packages, new_version):
"""
- Bulk replace of version: searches for package.xml files directly in given folders and replaces version tag within.
+ Bulk replace of version: searches for package.xml and setup.py files directly in given folders and replaces version tag within.
- :param list paths: folder names
+ :param dict packages: dict from folder names to package xml objects in those folders
:param str new_version: version string "int.int.int"
:raises RuntimeError: if any one package.xml cannot be updated
"""
files = {}
- for path in paths:
+ for path, package_obj in packages.items():
+ # Update any package.xml files.
package_path = os.path.join(path, 'package.xml')
with open(package_path, 'r') as f:
package_str = f.read()
except RuntimeError as rue:
raise RuntimeError('Could not bump version number in file %s: %s' % (package_path, str(rue)))
files[package_path] = new_package_str
+ # Update any setup.py files.
+ setup_py_path = os.path.join(path, 'setup.py')
+ if os.path.exists(setup_py_path):
+ # Only update setup.py for ament_python packages.
+ build_types = package_obj.get_unconditional_build_types()
+ if 'ament_python' in build_types:
+ with open(setup_py_path, 'r') as f:
+ setup_py_str = f.read()
+ try:
+ new_setup_py_str = _replace_setup_py_version(setup_py_str, new_version)
+ except RuntimeError as exc:
+ raise RuntimeError('Could not bump version number in file %s: %s' % (setup_py_path, str(exc)))
+ files[setup_py_path] = new_setup_py_str
+
# if all replacements successful, write back modified package.xml
for package_path, new_package_str in files.items():
with open(package_path, 'w') as f:
if len(section.children) > 0 and isinstance(section.children[0], docutils.nodes.title):
title = section.children[0]
if title and len(title.children) > 0 and isinstance(title.children[0], docutils.nodes.Text):
- title_text = title.children[0].rawsource
+ title_text = title.children[0].astext()
if FORTHCOMING_LABEL.lower() in title_text.lower():
if forthcoming_label:
raise RuntimeError('Found multiple forthcoming sections')
from .package import parse_package_string
-def find_package_paths(basepath, exclude_paths=None, exclude_subspaces=False):
+DEFAULT_IGNORE_MARKERS = {'AMENT_IGNORE', 'CATKIN_IGNORE', 'COLCON_IGNORE'}
+
+
+def find_package_paths(basepath, exclude_paths=None, exclude_subspaces=False, ignore_markers=DEFAULT_IGNORE_MARKERS):
"""
Crawls the filesystem to find package manifest files.
- When a subfolder contains either of the following files it is ignored:
+ When a subfolder contains either of the files mentioned in ``ignore_markers`` it is ignored. By default, these are:
- ``AMENT_IGNORE``
- ``CATKIN_IGNORE``
- ``COLCON_IGNORE``
:param exclude_paths: A list of paths which should not be searched, ``list``
:param exclude_subspaces: The flag is subfolders containing a .catkin file should not be
searched, ``bool``
+ :param ignore_markers: Names of files that indicate that a folder should be ignored, ``set``
:returns: A list of relative paths containing package manifest files ``list``
"""
paths = []
real_exclude_paths = [os.path.realpath(p) for p in exclude_paths] if exclude_paths is not None else []
for dirpath, dirnames, filenames in os.walk(basepath, followlinks=True):
- if set(dirnames + filenames) & {'AMENT_IGNORE', 'CATKIN_IGNORE', 'COLCON_IGNORE'} or \
+ if set(dirnames + filenames) & ignore_markers or \
os.path.realpath(dirpath) in real_exclude_paths or \
(exclude_subspaces and '.catkin' in filenames):
del dirnames[:]
return paths
-def find_packages(basepath, exclude_paths=None, exclude_subspaces=False, warnings=None):
+def find_packages(basepath, exclude_paths=None, exclude_subspaces=False, warnings=None, ignore_markers=DEFAULT_IGNORE_MARKERS):
"""
Crawls the filesystem to find package manifest files and parses them.
:param exclude_paths: A list of paths which should not be searched, ``list``
:param exclude_subspaces: The flag is subfolders containing a .catkin file should not be
searched, ``bool``
- :param warnings: Print warnings if None or return them in the given list
+ :param warnings: Print warnings if None or return them in the given list, ``bool``
+ :param ignore_markers: Names of files that indicate that a folder should be ignored, ``set``
:returns: A dict mapping relative paths to ``Package`` objects ``dict``
:raises: :exc:RuntimeError` If multiple packages have the same name
"""
- packages = find_packages_allowing_duplicates(basepath, exclude_paths=exclude_paths, exclude_subspaces=exclude_subspaces, warnings=warnings)
+ packages = find_packages_allowing_duplicates(basepath, exclude_paths=exclude_paths,
+ exclude_subspaces=exclude_subspaces, warnings=warnings,
+ ignore_markers=ignore_markers)
package_paths_by_name = {}
for path, package in packages.items():
if package.name not in package_paths_by_name:
return (path, parsed_package), warnings
-def find_packages_allowing_duplicates(basepath, exclude_paths=None, exclude_subspaces=False, warnings=None):
+def find_packages_allowing_duplicates(basepath, exclude_paths=None, exclude_subspaces=False, warnings=None, ignore_markers=DEFAULT_IGNORE_MARKERS):
"""
Crawls the filesystem to find package manifest files and parses them.
:param exclude_subspaces: The flag is subfolders containing a .catkin file should not be
searched, ``bool``
:param warnings: Print warnings if None or return them in the given list
+ :param ignore_markers: Names of files that indicate that a folder should be ignored, ``set``
:returns: A dict mapping relative paths to ``Package`` objects ``dict``
"""
- package_paths = find_package_paths(basepath, exclude_paths=exclude_paths, exclude_subspaces=exclude_subspaces)
+ package_paths = find_package_paths(basepath, exclude_paths=exclude_paths, exclude_subspaces=exclude_subspaces, ignore_markers=ignore_markers)
xmls = {}
for path in package_paths:
the "url" field.
The "description" is taken from the eponymous tag if it does not
- exceed 200 characters. If it does "description" contains the
- truncated text while "description_long" contains the complete.
+ exceed 200 characters and has no newlines. If it does "description"
+ contains the truncated text while "long_description" contains the
+ complete.
All licenses are merged into the "license" field.
elif package.urls:
data['url'] = package.urls[0].url
- if len(package.description) <= 200:
- data['description'] = package.description
- else:
- data['description'] = package.description[:197] + '...'
- data['long_description'] = package.description
+ description = package.plaintext_description.splitlines()[0]
+ if len(description) > 200:
+ description = description[:197] + '...'
+
+ data['description'] = description
+ if description != package.plaintext_description:
+ data['long_description'] = package.plaintext_description
data['license'] = ', '.join(package.licenses)
:param packages: A dict mapping package name to ``_PackageDecorator`` objects ``dict``
:returns: A list of package names from the input which could not easily be detected as not being part of a cycle.
"""
- assert(packages_orig)
+ assert packages_orig
packages = copy.copy(packages_orig)
last_depended = None
while len(packages) > 0:
def check_0_1_26(content):
assert len(content) == 1
- assert type(content[0]) == BulletList
+ assert type(content[0]) is BulletList
assert len(content[0].bullets) == 3
def check_0_1_25(content):
assert len(content) == 3
- assert type(content[0]) == BulletList
+ assert type(content[0]) is BulletList
assert len(content[0].bullets) == 5
mtext = content[0].bullets[3]
- assert type(mtext) == MixedText
+ assert type(mtext) is MixedText
assert len(mtext.texts) == 2
- assert type(content[1]) == Transition
- assert type(content[2]) == MixedText
+ assert type(content[1]) is Transition
+ assert type(content[2]) is MixedText
def check_0_1_0(content):
assert len(content) == 1
- assert type(content[0]) == MixedText
+ assert type(content[0]) is MixedText
assert len(content[0].texts) == 4
def check_0_0_1(content):
assert len(content) == 1
- assert type(content[0]) == BulletList
+ assert type(content[0]) is BulletList
assert content[0].bullet_type == 'enumerated'
import sys
from flake8.api.legacy import get_style_guide
+import pytest
+@pytest.mark.flake8
+@pytest.mark.linter
def test_flake8():
# Configure flake8 using the .flake8 file in the root of this repository.
style_guide = get_style_guide()
sys.stderr = orig_stderr
-def _validate_metapackage(path, package):
- try:
- validate_metapackage(path, package)
- except Exception:
- # print('on package ' + package.name, file=sys.stderr)
- raise
-
-
class TestMetapackageValidation(unittest.TestCase):
"""Tests the metapackage validator."""
if exc is not None:
if excreg is not None:
with self.assertRaisesRegex(exc, excreg):
- _validate_metapackage(path, package)
+ validate_metapackage(path, package)
else:
with self.assertRaises(exc):
- _validate_metapackage(path, package)
+ validate_metapackage(path, package)
else:
- _validate_metapackage(path, package)
+ validate_metapackage(path, package)
def test_collect_warnings(self):
"""Tests warnings collection."""
# Redirect stderr to stdout to suppress output in tests
import sys
import unittest
+from unittest.mock import Mock
import xml.dom.minidom as dom
+from xml.parsers.expat import ExpatError
from catkin_pkg.package import (
_check_known_attributes,
Person,
)
-from mock import Mock
-
sys.stderr = sys.stdout
test_data_dir = os.path.join(os.path.dirname(__file__), 'data', 'package')
try:
create_node('tag', {'key': 'value'})
- except Exception as e:
+ except ExpatError as e:
self.fail('create_node() raised %s "%s" unexpectedly!' % (type(e), str(e)))
self.assertRaisesRegex(Exception, 'unbound prefix: line 1, column 0', create_node, 'tag', {'ns:key': 'value'})
try:
create_node('tag', {'ns:key': 'value', 'xmlns:ns': 'urn:ns'})
- except Exception as e:
+ except ExpatError as e:
self.fail('create_node() raised %s "%s" unexpectedly!' % (type(e), str(e)))
def check(attrs, known, res=[]):
filename = os.path.join(test_data_dir, 'invalid_package.xml')
self.assertRaises(InvalidPackage, parse_package, filename)
+ def test_parse_package_xhtml_description(self):
+ filename = os.path.join(test_data_dir, 'xhtml_description.xml')
+ expected_plaintext_description = None
+ with open(os.path.join(test_data_dir, 'xhtml_description.txt'), 'r') as f:
+ # Strip the trailing newline from the data file.
+ expected_plaintext_description = f.read().rstrip('\n')
+ package = parse_package(filename)
+ assert package.description
+
+ assert package.plaintext_description == expected_plaintext_description
+
def test_parse_package_string(self):
filename = os.path.join(test_data_dir, 'valid_package.xml')
xml = _get_package_xml(filename)[0]
assert isinstance(xml, bytes)
parse_package_string(xml)
+ xml_string = """
+<package>
+ <name>valid_package</name>
+ <version>0.1.0</version>
+ <description>valid_package description</description>
+ <maintainer email="user@todo.todo>Forgotten end quote</maintainer>
+ <license>BSD</license>
+</package>
+"""
+ self.assertRaises(InvalidPackage, parse_package_string, xml_string)
+
+ xml_string = """
+<package>
+ <name>valid_package</name>
+ <version>0.1.0</version>
+ <description>Invalid < character in description</description>
+ <maintainer email="user@todo.todo">user</maintainer>
+ <license>BSD</license>
+</package>
+"""
+ self.assertRaises(InvalidPackage, parse_package_string, xml_string)
+ xml_string = """
+<package>
+ <name>valid_package</name>
+ <version>0.1.0</version>
+ <description>valid_package description</description>
+ <maintainer email="user@todo.todo">user</maintainer>
+ <license>BSD</license>
+</package><extra>Unwanted junk</extra>
+"""
+ self.assertRaises(InvalidPackage, parse_package_string, xml_string)
+
def test_has_ros_schema_reference_string(self):
self.assertFalse(
has_ros_schema_reference_string(
import shutil
import tempfile
import unittest
+from unittest.mock import Mock
+from catkin_pkg.package_version import _replace_setup_py_version
from catkin_pkg.package_version import _replace_version
from catkin_pkg.package_version import bump_version
from catkin_pkg.package_version import update_changelog_sections
from catkin_pkg.package_version import update_versions
-import mock
-
from .util import in_temporary_directory
self.assertRaises(RuntimeError, _replace_version, '<package></package>', '0.1.1')
self.assertRaises(RuntimeError, _replace_version, '<package><version>0.1.1</version><version>0.1.1</version></package>', '0.1.1')
+ def test_replace_setup_py_version(self):
+ self.assertEqual(
+ 'version="1.0.0",',
+ _replace_setup_py_version('version="0.0.1",', '1.0.0'))
+ self.assertEqual(
+ "version='1.0.0',",
+ _replace_setup_py_version("version='0.0.1',", '1.0.0'))
+ self.assertRaises(
+ RuntimeError,
+ _replace_setup_py_version,
+ '',
+ '1.0.0')
+ self.assertRaises(
+ RuntimeError,
+ _replace_setup_py_version,
+ "version='0.1'",
+ '1.0.0')
+ self.assertRaises(
+ RuntimeError,
+ _replace_setup_py_version,
+ 'version=something,',
+ '1.0.0')
+ self.assertRaises(
+ RuntimeError,
+ _replace_setup_py_version,
+ 'version="0.0.1",version="0.0.1",',
+ '1.0.0')
+
def test_update_versions(self):
try:
root_dir = tempfile.mkdtemp()
with open(os.path.join(sub_dir, 'package.xml'), 'w') as fhand:
fhand.write('<package><version>1.5.4</version></package>')
- update_versions([root_dir, sub_dir], '7.6.5')
+ update_versions({root_dir: Mock(), sub_dir: Mock()}, '7.6.5')
with open(os.path.join(root_dir, 'package.xml'), 'r') as fhand:
contents = fhand.read()
temp_file = os.path.join(directory, 'changelog')
missing_changelogs_but_forthcoming = {}
# Mock the Changelog object from catkin_pkg
- mock_changelog = mock.Mock()
+ mock_changelog = Mock()
# Create a changelog entry with a unicode char.
mock_changelog.rst = ('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n'
'Changelog for package fake_pkg\n'
from .util import in_temporary_directory
+test_data_dir = os.path.join(os.path.dirname(__file__), 'data', 'ignored_packages')
+
+
def _create_pkg_in_dir(path, version='0.1.0'):
path = os.path.abspath(path)
os.makedirs(path)
exception_message = str(e)
assert version in exception_message
assert path in exception_message
+
+
+def test_find_no_ignored_packages():
+ result = find_packages(test_data_dir)
+ assert 'catkin_ignore' not in result
+ assert 'custom_ignore' in result
+
+
+def test_find_no_ignored_packages_with_custom_ignore():
+ custom_result = find_packages(test_data_dir, ignore_markers={'CUSTOM_IGNORE'})
+ assert 'custom_ignore' not in custom_result
+ assert 'catkin_ignore' in custom_result
import shutil
import tempfile
import unittest
+from unittest.mock import MagicMock, Mock
from catkin_pkg.package import Dependency, Export, PACKAGE_MANIFEST_FILENAME, parse_package, Url
from catkin_pkg.package_templates import _create_include_macro, _create_targetlib_args, _safe_write_files, \
create_cmakelists, create_package_files, create_package_xml, PackageTemplate
from catkin_pkg.python_setup import generate_distutils_setup
-from mock import MagicMock, Mock
-
def u(line):
try:
import sys
import unittest
-
-from mock import Mock
+from unittest.mock import Mock
try:
from catkin_pkg.topological_order import topological_order_packages, _PackageDecorator, \
import unittest
try:
- from catkin_pkg.workspaces import ensure_workspace_marker, get_spaces, order_paths,\
+ from catkin_pkg.workspaces import ensure_workspace_marker, get_spaces, order_paths, \
CATKIN_WORKSPACE_MARKER_FILE
except ImportError as e:
raise ImportError('Please adjust your PYTHONPATH before running this test: %s' % str(e))