Codebase list ros-dynamic-reconfigure / upstream/1.6.0
New upstream version 1.6.0 Jochen Sprickerhof 5 years ago
14 changed file(s) with 184 addition(s) and 142 deletion(s). Raw diff Collapse all Expand all
00 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11 Changelog for package dynamic_reconfigure
22 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3
4 1.6.0 (2018-10-02)
5 ------------------
6 * fix check preventing range for string and bool parameters (`#122 <https://github.com/ros/dynamic_reconfigure/issues/122>`_)
7 * Fix build issue on Windows (`#114 <https://github.com/ros/dynamic_reconfigure/issues/114>`_)
8 * Contributors: Johnson Shih, Mikael Arguedas
9
10 1.5.50 (2018-10-02)
11 -------------------
12 * final-keyword (`#113 <https://github.com/ros/dynamic_reconfigure/issues/113>`_)
13 * Add final keyword to child class since parent has virtual methods and grand parent doesn't have a virtual destructor. This allows the code to be compiled by clang version 6.0 and above.
14 * [indentation fixups]
15 * Use textwrap dedent for multiline strings
16 * Remove extra indentation in wikidoc
17 * Use textwrap.dedent to form the error message
18 * [test fix] call shutdown to prevent test from hanging (`#119 <https://github.com/ros/dynamic_reconfigure/issues/119>`_)
19 * Modernize Python code (`#102 <https://github.com/ros/dynamic_reconfigure/issues/102>`_)
20 * Use new-style classes
21 * Use with statement to ensure files are closed
22 * Python 3 compatibility (`#105 <https://github.com/ros/dynamic_reconfigure/issues/105>`_)
23 * some randon python cleanup
24 * remove iter* method for their 2/3 compatible equivalent
25 * Contributors: Eric Wieser, Jason Mercer, Mikael Arguedas
326
427 1.5.49 (2017-07-27)
528 -------------------
3030 # since it might contain dynamic_reconfigure or Python code of the current package
3131 set("_CUSTOM_PYTHONPATH_ENV")
3232 if(EXISTS "${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_PYTHON_DESTINATION}")
33 configure_file(
34 "${dynamic_reconfigure_BASE_DIR}/cmake/setup_custom_pythonpath.sh.in"
35 "setup_custom_pythonpath.sh"
36 @ONLY
37 )
38 set("_CUSTOM_PYTHONPATH_ENV" "${CMAKE_CURRENT_BINARY_DIR}/setup_custom_pythonpath.sh")
33 if(WIN32)
34 configure_file(
35 "${dynamic_reconfigure_BASE_DIR}/cmake/setup_custom_pythonpath.bat.in"
36 "setup_custom_pythonpath.bat"
37 @ONLY
38 )
39 set("_CUSTOM_PYTHONPATH_ENV" "${CMAKE_CURRENT_BINARY_DIR}/setup_custom_pythonpath.bat")
40 else()
41 configure_file(
42 "${dynamic_reconfigure_BASE_DIR}/cmake/setup_custom_pythonpath.sh.in"
43 "setup_custom_pythonpath.sh"
44 @ONLY
45 )
46 set("_CUSTOM_PYTHONPATH_ENV" "${CMAKE_CURRENT_BINARY_DIR}/setup_custom_pythonpath.sh")
47 endif()
3948 endif()
4049
4150 assert(CATKIN_ENV)
0 REM generated from dynamic_reconfigure/cmake/setup_custom_pythonpath.bat.in
1
2 set PYTHONPATH=@CATKIN_DEVEL_PREFIX@/@CATKIN_GLOBAL_PYTHON_DESTINATION@;%PYTHONPATH%
3 call python %*
22
33 #include <boost/thread/mutex.hpp>
44
5 #include <ros/macros.h>
6
7 // Import/export for windows dll's and visibility for gcc shared libraries.
8
9 #ifdef ROS_BUILD_SHARED_LIBS // ros is being built around shared libraries
10 #ifdef dynamic_reconfigure_config_init_mutex_EXPORTS // we are building a shared lib/dll
11 #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL ROS_HELPER_EXPORT
12 #else // we are using shared lib/dll
13 #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL ROS_HELPER_IMPORT
14 #endif
15 #else // ros is being built around static libraries
16 #define DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL
17 #endif
18
519 namespace dynamic_reconfigure
620 {
7 extern boost::mutex __init_mutex__;
21 extern DYNAMIC_RECONFIGURE_CONFIG_INIT_MUTEX_DECL boost::mutex __init_mutex__;
822 }
923
1024 #endif
11 <?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
22 <package format="2">
33 <name>dynamic_reconfigure</name>
4 <version>1.5.49</version>
4 <version>1.6.0</version>
55 <description>
66 This unary stack contains the dynamic_reconfigure package which provides a means to change
77 node parameters at any time without having to restart the node.
2020
2121 <buildtool_depend version_gte="0.5.87">catkin</buildtool_depend>
2222
23 <build_depend>cpp_common</build_depend>
2324 <build_depend>message_generation</build_depend>
2425 <build_depend>roscpp_serialization</build_depend>
2526 <build_depend>rostest</build_depend>
3535 """
3636
3737 import roslib
38 import os
3938
4039
4140 class DynamicReconfigureException(Exception):
3838
3939 try:
4040 import roslib; roslib.load_manifest('dynamic_reconfigure')
41 except:
41 except Exception:
4242 pass
4343 import rospy
4444 import sys
3131
3232 try:
3333 import roslib; roslib.load_manifest('dynamic_reconfigure')
34 except:
34 except Exception:
3535 pass
3636 import copy
3737 import sys
7474
7575 def __deepcopy__(self, memo):
7676 c = type(self)({})
77 for key, value in self.iteritems():
77 for key, value in self.items():
7878 c[copy.deepcopy(key)] = copy.deepcopy(value)
7979
8080 return c
127127 if flat is True:
128128 def flatten(g):
129129 groups = []
130 for name, group in g['groups'].items():
130 for _name, group in g['groups'].items():
131131 groups.extend(flatten(group))
132132 groups.append(GroupState(group['name'], group['state'], group['id'], group['parent']))
133133 return groups
276276 def add_params(group, descr):
277277 for param in descr['parameters']:
278278 group['parameters'][param['name']] = d[param['name']]
279 for n, g in group['groups'].items():
279 for _n, g in group['groups'].items():
280280 for dr in descr['groups']:
281281 if dr['name'] == g['name']:
282282 add_params(g, dr)
303303 for param in descr['parameters']:
304304 if param['name'] in d.keys():
305305 group[param['name']] = d[param['name']]
306 for n, g in group['groups'].items():
307 for nr, dr in descr['groups'].items():
306 for _n, g in group['groups'].items():
307 for _nr, dr in descr['groups'].items():
308308 if dr['name'] == g['name']:
309309 add_params(g, dr)
310310
317317 params = []
318318 params.extend(group['parameters'])
319319 try:
320 for n, g in group['groups'].items():
320 for _n, g in group['groups'].items():
321321 params.extend(extract_params(g))
322322 except AttributeError:
323323 for g in group['groups']:
3737 # classes to allow runtime reconfiguration. Documentation of a node's
3838 # parameters is a handy byproduct.
3939
40 ## @todo
40 # @todo
4141 # Need to check types of min max and default
4242 # Need to put sane error on exceptions
4343
4444 from __future__ import print_function
4545
46 import inspect
47 import os
48 import re
4649 from string import Template
47 import os
48 import inspect
49 import string
5050 import sys
51 import re
51 import textwrap
5252
5353 # LINEDEBUG="#line"
5454 LINEDEBUG = "//#line"
7575 raise Exception("The name of field \'%s\' does not follow the ROS naming conventions, see http://wiki.ros.org/ROS/Patterns/Conventions" % name)
7676
7777
78 class ParameterGenerator:
78 class ParameterGenerator(object):
7979 minval = {
8080 'int': -0x80000000, # 'INT_MIN',
8181 'double': '-std::numeric_limits<double>::infinity()',
9797 'bool': False,
9898 }
9999
100 class Group:
100 class Group(object):
101101 instances = {}
102102
103103 def __init__(self, gen, name, type, state, id, parent):
138138 'srcfile': inspect.getsourcefile(inspect.currentframe().f_back.f_code),
139139 'edit_method': edit_method,
140140 }
141 if type == str_t and (max is not None or min is not None):
142 raise Exception("Max or min specified for %s, which is of string type" % name)
141 if (paramtype == str_t or paramtype == bool_t) and (max is not None or min is not None):
142 raise Exception(
143 "Max or min specified for %s, which is of '%s' type" % (name, paramtype))
143144 check_name(name)
144145 self.gen.fill_type(newparam)
145146 self.gen.check_type_fill_default(newparam, 'default', self.gen.defval[paramtype])
245246 id = 1
246247 self.constants = []
247248 if len(sys.argv) < 5:
248 msg = """
249 ahhhh! Unexpected command line syntax!
250
251 Are you trying to call a dynamic_reconfigure configuration generation script
252 directly? When you are using dynamic_reconfigure with python, you don't ever
253 need to invoke the configuration generator script yourself; it loads
254 automatically. If you are using dynamic_reconfigure from C++, you need to
255 add a call to generate_dynamic_reconfigure_options() in your CMakeLists.txt
256
257 For an example, see http://wiki.ros.org/dynamic_reconfigure/Tutorials
258
259 Have a nice day
260 """
261 print(msg)
262 sys.exit(1)
249 raise SystemExit(textwrap.dedent("""\
250 ahhhh! Unexpected command line syntax!
251
252 Are you trying to call a dynamic_reconfigure configuration generation script
253 directly? When you are using dynamic_reconfigure with python, you don't ever
254 need to invoke the configuration generator script yourself; it loads
255 automatically. If you are using dynamic_reconfigure from C++, you need to
256 add a call to generate_dynamic_reconfigure_options() in your CMakeLists.txt
257
258 For an example, see http://wiki.ros.org/dynamic_reconfigure/Tutorials
259
260 Have a nice day
261 """))
263262 self.dynconfpath = sys.argv[1] # FIXME this is awful
264263 self.binary_dir = sys.argv[2]
265264 self.cpp_gen_dir = sys.argv[3]
316315 # causes imports of dynamic_reconfigure.msg to fail from at
317316 # least some .cfg files. (Not sure why)
318317 return
319 except:
318 except Exception:
320319 pass
321320 try:
322321 self.pkgname = pkgname
343342
344343 def generatewikidoc(self):
345344 self.mkdirabs(os.path.join(self.binary_dir, "docs"))
346 f = open(os.path.join(self.binary_dir, "docs", self.msgname + ".wikidoc"), 'w')
347 print(
348 """# Autogenerated param section. Do not hand edit.
349 param {
350 group.0 {
351 name=Dynamically Reconfigurable Parameters
352 desc=See the [[dynamic_reconfigure]] package for details on dynamically reconfigurable parameters.""", file=f)
353 i = -1
354 for param in self.group.get_parameters():
355 i = i + 1
356 range = ""
357 try:
358 enum = eval(param['edit_method'])['enum']
359 range = ", ".join(Template("$name ($value): $description").substitute(const) for const in enum)
360 range = "Possible values are: " + range
361 except:
362 if param['type'] == int_t or param['type'] == double_t:
363 range = Template("Range: $min to $max").substitute(param)
364 print(Template(
365 """$i.name= ~$name
366 $i.default= $default
367 $i.type= $type
368 $i.desc=$description $range"""
369 ).substitute(param, range=range, i=i), file=f)
370 print("}\n}\n# End of autogenerated section. You may edit below.", file=f)
371 f.close()
372
373 def generateusage(self):
374 self.mkdirabs("docs")
375 f = open(os.path.join(self.binary_dir, "docs", self.msgname + "-usage.dox"), 'w')
376 # print("/**", file=f)
377 print("\\subsubsection usage Usage", file=f)
378 print('\\verbatim', file=f)
379 print(Template('<node name="$nodename" pkg="$pkgname" type="$nodename">').substitute(
380 pkgname=self.pkgname, nodename=self.nodename), file=f)
381 for param in self.group.get_parameters():
382 print(Template(' <param name="$name" type="$type" value="$default" />').substitute(param), file=f)
383 print('</node>', file=f)
384 print('\\endverbatim', file=f)
385 print('', file=f)
386 # print("*/", file=f)
387 f.close()
345 with open(os.path.join(self.binary_dir, "docs", self.msgname + ".wikidoc"), 'w') as f:
346 print(textwrap.dedent("""\
347 # Autogenerated param section. Do not hand edit.
348 param {
349 group.0 {
350 name=Dynamically Reconfigurable Parameters
351 desc=See the [[dynamic_reconfigure]] package for details on dynamically reconfigurable parameters."""
352 ), file=f)
353 i = -1
354 for param in self.group.get_parameters():
355 i = i + 1
356 range = ""
357 try:
358 enum = eval(param['edit_method'])['enum']
359 range = ", ".join(Template("$name ($value): $description").substitute(const) for const in enum)
360 range = "Possible values are: " + range
361 except Exception:
362 if param['type'] == int_t or param['type'] == double_t:
363 range = Template("Range: $min to $max").substitute(param)
364 print(Template(textwrap.dedent("""\
365 $i.name= ~$name
366 $i.default= $default
367 $i.type= $type
368 $i.desc=$description $range"""
369 )).substitute(param, range=range, i=i), file=f)
370 print("}\n}\n# End of autogenerated section. You may edit below.", file=f)
388371
389372 def generatedoc(self):
390373 self.mkdirabs("docs")
391374 dir_path = os.path.join(self.binary_dir, "docs")
392375 self.mkdirabs(dir_path)
393 f = open(os.path.join(dir_path, self.msgname + ".dox"), 'w')
394 # print("/**", file=f)
395 print("\\subsubsection parameters ROS parameters", file=f)
396 print("", file=f)
397 print("Reads and maintains the following parameters on the ROS server", file=f)
398 print("", file=f)
399 for param in self.group.get_parameters():
400 print(Template("- \\b \"~$name\" : \\b [$type] $description min: $min, default: $default, max: $max").substitute(param), file=f)
401 print("", file=f)
402 # print("*/", file=f)
403 f.close()
376 with open(os.path.join(dir_path, self.msgname + ".dox"), 'w') as f:
377 # print("/**", file=f)
378 print("\\subsubsection parameters ROS parameters", file=f)
379 print("", file=f)
380 print("Reads and maintains the following parameters on the ROS server", file=f)
381 print("", file=f)
382 for param in self.group.get_parameters():
383 print(Template("- \\b \"~$name\" : \\b [$type] $description min: $min, default: $default, max: $max").substitute(param), file=f)
384 print("", file=f)
385 # print("*/", file=f)
404386
405387 def generateusage(self):
406388 self.mkdirabs("docs")
407 f = open(os.path.join(self.binary_dir, "docs", self.msgname + "-usage.dox"), 'w')
408 # print("/**", file=f)
409 print("\\subsubsection usage Usage", file=f)
410 print('\\verbatim', file=f)
411 print(Template('<node name="$nodename" pkg="$pkgname" type="$nodename">').substitute(
412 pkgname=self.pkgname, nodename=self.nodename), file=f)
413 for param in self.group.get_parameters():
414 print(Template(' <param name="$name" type="$type" value="$default" />').substitute(param), file=f)
415 print('</node>', file=f)
416 print('\\endverbatim', file=f)
417 print("", file=f)
418 # print("*/", file=f)
419 f.close()
389 with open(os.path.join(self.binary_dir, "docs", self.msgname + "-usage.dox"), 'w') as f:
390 # print("/**", file=f)
391 print("\\subsubsection usage Usage", file=f)
392 print('\\verbatim', file=f)
393 print(Template('<node name="$nodename" pkg="$pkgname" type="$nodename">').substitute(
394 pkgname=self.pkgname, nodename=self.nodename), file=f)
395 for param in self.group.get_parameters():
396 print(Template(' <param name="$name" type="$type" value="$default" />').substitute(param), file=f)
397 print('</node>', file=f)
398 print('\\endverbatim', file=f)
399 print("", file=f)
400 # print("*/", file=f)
420401
421402 def crepr(self, param, val):
422403 type = param["type"]
469450 templatelines = []
470451 templatefilesafe = templatefile.replace('\\', '\\\\') # line directive does backslash expansion.
471452 curline = 1
472 f = open(templatefile)
473 for line in f:
474 curline = curline + 1
475 templatelines.append(Template(line).safe_substitute(linenum=curline, filename=templatefilesafe))
476 f.close()
453 with open(templatefile) as f:
454 for line in f:
455 curline = curline + 1
456 templatelines.append(Template(line).safe_substitute(linenum=curline, filename=templatefilesafe))
457
477458 template = ''.join(templatelines)
478459
479460 # Write the configuration manipulator.
480461 self.mkdirabs(self.cpp_gen_dir)
481 f = open(os.path.join(self.cpp_gen_dir, self.name + "Config.h"), 'w')
482462 paramdescr = []
483463 groups = []
484464 members = []
523503 members = '\n'.join(members)
524504 constants = '\n'.join(constants)
525505 groups = '\n'.join(groups)
526 f.write(Template(template).substitute(
527 uname=self.name.upper(),
528 configname=self.name, pkgname=self.pkgname, paramdescr=paramdescr,
529 members=members, groups=groups, doline=LINEDEBUG, constants=constants))
530 f.close()
506 with open(os.path.join(self.cpp_gen_dir, self.name + "Config.h"), 'w') as f:
507 f.write(Template(template).substitute(
508 uname=self.name.upper(),
509 configname=self.name, pkgname=self.pkgname, paramdescr=paramdescr,
510 members=members, groups=groups, doline=LINEDEBUG, constants=constants))
531511 print("Wrote header file in " + os.path.join(self.cpp_gen_dir, self.name + "Config.h"))
532512
533513 # def deleteoneobsolete(self, file):
601581 def generatepy(self):
602582 # Read the configuration manipulator template and insert line numbers and file name into template.
603583 templatefile = os.path.join(self.dynconfpath, "templates", "ConfigType.py.template")
604 f = open(templatefile)
605 template = f.read()
606 f.close()
584 with open(templatefile) as f:
585 template = f.read()
607586
608587 # Write the configuration manipulator.
609588 self.mkdirabs(os.path.join(self.py_gen_dir, "cfg"))
610 f = open(os.path.join(self.py_gen_dir, "cfg", self.name + "Config.py"), 'w')
611 pycfgdata = self.replace_infinity(self.group.to_dict())
612 f.write(Template(template).substitute(
613 name=self.name,
614 pkgname=self.pkgname, pycfgdata=pycfgdata))
615 for const in self.constants:
616 f.write(Template("${configname}_${name} = $v\n").substitute(
617 const, v=repr(const['value']),
618 configname=self.name))
619 f.close()
620
621 f = open(os.path.join(self.py_gen_dir, "cfg", "__init__.py"), 'a')
622 f.close()
589 with open(os.path.join(self.py_gen_dir, "cfg", self.name + "Config.py"), 'w') as f:
590 pycfgdata = self.replace_infinity(self.group.to_dict())
591 f.write(Template(template).substitute(
592 name=self.name,
593 pkgname=self.pkgname, pycfgdata=pycfgdata))
594 for const in self.constants:
595 f.write(Template("${configname}_${name} = $v\n").substitute(
596 const, v=repr(const['value']),
597 configname=self.name))
598
599 with open(os.path.join(self.py_gen_dir, "cfg", "__init__.py"), 'a'):
600 pass
3838
3939 try:
4040 import roslib; roslib.load_manifest('dynamic_reconfigure')
41 except:
41 except Exception:
4242 pass
4343 import rospy
4444 import threading
99 #ifndef __${pkgname}__${uname}CONFIG_H__
1010 #define __${pkgname}__${uname}CONFIG_H__
1111
12 #if __cplusplus >= 201103L
13 #define DYNAMIC_RECONFIGURE_FINAL final
14 #else
15 #define DYNAMIC_RECONFIGURE_FINAL
16 #endif
17
1218 #include <dynamic_reconfigure/config_tools.h>
1319 #include <limits>
1420 #include <ros/node_handle.h>
5056 typedef boost::shared_ptr<AbstractParamDescription> AbstractParamDescriptionPtr;
5157 typedef boost::shared_ptr<const AbstractParamDescription> AbstractParamDescriptionConstPtr;
5258
59 // Final keyword added to class because it has virtual methods and inherits
60 // from a class with a non-virtual destructor.
5361 template <class T>
54 class ParamDescription : public AbstractParamDescription
62 class ParamDescription DYNAMIC_RECONFIGURE_FINAL : public AbstractParamDescription
5563 {
5664 public:
5765 ParamDescription(std::string a_name, std::string a_type, uint32_t a_level,
136144 typedef boost::shared_ptr<AbstractGroupDescription> AbstractGroupDescriptionPtr;
137145 typedef boost::shared_ptr<const AbstractGroupDescription> AbstractGroupDescriptionConstPtr;
138146
147 // Final keyword added to class because it has virtual methods and inherits
148 // from a class with a non-virtual destructor.
139149 template<class T, class PT>
140 class GroupDescription : public AbstractGroupDescription
150 class GroupDescription DYNAMIC_RECONFIGURE_FINAL : public AbstractGroupDescription
141151 {
142152 public:
143153 GroupDescription(std::string a_name, std::string a_type, int a_parent, int a_id, bool a_s, T PT::* a_f) : AbstractGroupDescription(a_name, a_type, a_parent, a_id, a_s), field(a_f)
429439 ${constants}
430440 }
431441
442 #undef DYNAMIC_RECONFIGURE_FINAL
443
432444 #endif // __${uname}RECONFIGURATOR_H__
00 add_executable(dynamic_reconfigure-ref_server EXCLUDE_FROM_ALL ref_server.cpp)
11 add_dependencies(dynamic_reconfigure-ref_server ${PROJECT_NAME}_gencfg ${PROJECT_NAME}_generate_messages_cpp ${PROJECT_NAME}_generate_messages_py)
2 target_link_libraries(dynamic_reconfigure-ref_server pthread dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES})
2 target_link_libraries(dynamic_reconfigure-ref_server dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES})
33
44 add_dependencies(tests dynamic_reconfigure-ref_server)
55
66 add_rostest_gtest(dynamic_reconfigure-test_client test_cpp_simple_client.launch test_client.cpp)
77 add_dependencies(dynamic_reconfigure-test_client ${PROJECT_NAME}_gencfg ${PROJECT_NAME}_generate_messages_py)
8 target_link_libraries(dynamic_reconfigure-test_client pthread dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES})
8 target_link_libraries(dynamic_reconfigure-test_client dynamic_reconfigure_config_init_mutex ${catkin_LIBRARIES})
99
1010 add_dependencies(tests dynamic_reconfigure-test_client)
1111
139139 testing::InitGoogleTest(&argc, argv);
140140 ros::AsyncSpinner spinner(2);
141141 spinner.start();
142 return RUN_ALL_TESTS();
142 int res = RUN_ALL_TESTS();
143 ros::shutdown();
144 return res;
143145 }
5353
5454
5555 def print_config(config):
56 for k, v in config.iteritems():
56 for k, v in config.items():
5757 print(k, ":", v)
5858 print('')
5959