diff --git a/CMakeLists.txt b/CMakeLists.txt index ef32f33f7..d89a2cabb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,7 +60,6 @@ option(NS3_LINK_WHAT_YOU_USE ) option(NS3_SANITIZE "Build with address, leak and undefined sanitizers" OFF) option(NS3_SANITIZE_MEMORY "Build with memory sanitizer" OFF) -option(NS3_SCAN_PYTHON_BINDINGS "Scan python bindings" OFF) # 3rd-party libraries/programs option(NS3_NETANIM "Build netanim" OFF) @@ -80,7 +79,7 @@ set(NS3_OUTPUT_DIRECTORY "" CACHE STRING "Directory to store built artifacts") option(NS3_PRECOMPILE_HEADERS "Precompile module headers to speed up compilation" ON ) -option(NS3_PYTHON_BINDINGS "Build ns-3 python bindings" OFF) +option(NS3_PYTHON_BINDINGS "Build ns-3 python bindings" ON) option(NS3_REALTIME "Build with realtime support" ON) option(NS3_SQLITE "Build with SQLite support" ON) option(NS3_STATIC "Build a static ns-3 library and link it against executables" @@ -141,7 +140,6 @@ add_subdirectory(utils) write_lock() write_configtable() -write_header_to_modules_map() # Export package targets when installing ns3_cmake_package() diff --git a/bindings/python/_required_pybindgen_version.py b/bindings/python/_required_pybindgen_version.py deleted file mode 100644 index f351b04bb..000000000 --- a/bindings/python/_required_pybindgen_version.py +++ /dev/null @@ -1,9 +0,0 @@ -# Store version information for required pybindgen version, used by -# ns-3-allinone/download.py. -# If specifying a released pybindgen version, specify the required pybindgen -# version as, e.g. '0.21.0' -# If specifying a commit on the development tree, specify it like this based -# on 'git describe --tags' command. Example, if the latest release was 0.21.0, -# and 'git describe --tags' reports "0.21.0-6-g8e7c0a9", then write the -# version string below as '0.21.0.post6+ng8e7c0a9' -__required_pybindgen_version__ = '0.22.1' diff --git a/bindings/python/my_extra_api_definitions.py b/bindings/python/my_extra_api_definitions.py deleted file mode 100644 index e8afeec5c..000000000 --- a/bindings/python/my_extra_api_definitions.py +++ /dev/null @@ -1,13 +0,0 @@ -from pybindgen import Module, FileCodeSink, write_preamble, param, retval - -def register_types(module): - module.add_class('MyClass') - -def register_methods(root_module): - MyClass = root_module['MyClass'] - MyClass.add_constructor([], visibility='public') - MyClass.add_constructor([param('double', 's'), param('double', 'l'), param('double', 'mean')], visibility='public') - -def register_functions(module): - module.add_function('SomeFunction', 'int', [param('int', 'xpto')]) - diff --git a/bindings/python/ns3__init__.py b/bindings/python/ns3__init__.py deleted file mode 100644 index cd1f9ec82..000000000 --- a/bindings/python/ns3__init__.py +++ /dev/null @@ -1,7 +0,0 @@ - -from _ns3 import * - -import atexit -atexit.register(Simulator.Destroy) -del atexit - diff --git a/bindings/python/ns3module_helpers.cc b/bindings/python/ns3module_helpers.cc deleted file mode 100644 index 9951ef80d..000000000 --- a/bindings/python/ns3module_helpers.cc +++ /dev/null @@ -1,336 +0,0 @@ -#include "ns3module.h" -#include "ns3/ref-count-base.h" - - -namespace ns3 { - -void PythonCompleteConstruct (Ptr object, TypeId typeId, const AttributeList &attributes) -{ - object->SetTypeId (typeId); - object->Object::Construct (attributes); -} - -} - - - -class PythonEventImpl : public ns3::EventImpl -{ -private: - PyObject *m_callback; - PyObject *m_args; -public: - PythonEventImpl (PyObject *callback, PyObject *args) - { - m_callback = callback; - Py_INCREF (m_callback); - m_args = args; - Py_INCREF (m_args); - } - virtual ~PythonEventImpl () - { - PyGILState_STATE __py_gil_state; - __py_gil_state = (PyEval_ThreadsInitialized () ? PyGILState_Ensure () : (PyGILState_STATE) 0); - - Py_DECREF (m_callback); - Py_DECREF (m_args); - - if (PyEval_ThreadsInitialized ()) - PyGILState_Release (__py_gil_state); - } - virtual void Notify () - { - PyGILState_STATE __py_gil_state; - __py_gil_state = (PyEval_ThreadsInitialized () ? PyGILState_Ensure () : (PyGILState_STATE) 0); - - PyObject *retval = PyObject_CallObject (m_callback, m_args); - if (retval) { - if (retval != Py_None) { - PyErr_SetString (PyExc_TypeError, "event callback should return None"); - PyErr_Print (); - } - Py_DECREF (retval); - } else { - PyErr_Print (); - } - - if (PyEval_ThreadsInitialized ()) - PyGILState_Release (__py_gil_state); - } -}; - - -PyObject * -_wrap_Simulator_Schedule (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - PyObject *exc_type, *traceback; - PyObject *py_time; - PyObject *py_callback; - PyObject *user_args; - ns3::Ptr py_event_impl; - PyNs3EventId *py_EventId; - - if (kwargs && PyObject_Length (kwargs) > 0) { - PyErr_SetString (PyExc_TypeError, "keyword arguments not supported"); - goto error; - } - - if (PyTuple_GET_SIZE (args) < 2) { - PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 2 arguments"); - goto error; - } - py_time = PyTuple_GET_ITEM (args, 0); - py_callback = PyTuple_GET_ITEM (args, 1); - - if (!PyObject_IsInstance (py_time, (PyObject*) &PyNs3Time_Type)) { - PyErr_SetString (PyExc_TypeError, "Parameter 1 should be a ns3.Time instance"); - goto error; - } - if (!PyCallable_Check (py_callback)) { - PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable"); - goto error; - } - user_args = PyTuple_GetSlice (args, 2, PyTuple_GET_SIZE (args)); - py_event_impl = ns3::Create(py_callback, user_args); - Py_DECREF (user_args); - - py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type); - py_EventId->obj = new ns3::EventId ( - ns3::Simulator::Schedule (*((PyNs3Time *) py_time)->obj, py_event_impl)); - return (PyObject *) py_EventId; - -error: - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; -} - - -PyObject * -_wrap_Simulator_ScheduleNow (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - PyObject *exc_type, *traceback; - PyObject *py_callback; - PyObject *user_args; - ns3::Ptr py_event_impl; - PyNs3EventId *py_EventId; - - if (kwargs && PyObject_Length (kwargs) > 0) { - PyErr_SetString (PyExc_TypeError, "keyword arguments not supported"); - goto error; - } - - if (PyTuple_GET_SIZE (args) < 1) { - PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument"); - goto error; - } - py_callback = PyTuple_GET_ITEM (args, 0); - - if (!PyCallable_Check (py_callback)) { - PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable"); - goto error; - } - user_args = PyTuple_GetSlice (args, 1, PyTuple_GET_SIZE (args)); - py_event_impl = ns3::Create(py_callback, user_args); - Py_DECREF (user_args); - - py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type); - py_EventId->obj = new ns3::EventId (ns3::Simulator::ScheduleNow (py_event_impl)); - return (PyObject *) py_EventId; - -error: - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; -} - - -PyObject * -_wrap_Simulator_ScheduleDestroy (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - PyObject *exc_type, *traceback; - PyObject *py_callback; - PyObject *user_args; - ns3::Ptr py_event_impl; - PyNs3EventId *py_EventId; - - if (kwargs && PyObject_Length (kwargs) > 0) { - PyErr_SetString (PyExc_TypeError, "keyword arguments not supported"); - goto error; - } - - if (PyTuple_GET_SIZE (args) < 1) { - PyErr_SetString (PyExc_TypeError, "ns3.Simulator.Schedule needs at least 1 argument"); - goto error; - } - py_callback = PyTuple_GET_ITEM (args, 0); - - if (!PyCallable_Check (py_callback)) { - PyErr_SetString (PyExc_TypeError, "Parameter 2 should be callable"); - goto error; - } - user_args = PyTuple_GetSlice (args, 1, PyTuple_GET_SIZE (args)); - py_event_impl = ns3::Create(py_callback, user_args); - Py_DECREF (user_args); - - py_EventId = PyObject_New (PyNs3EventId, &PyNs3EventId_Type); - py_EventId->obj = new ns3::EventId (ns3::Simulator::ScheduleDestroy (py_event_impl)); - return (PyObject *) py_EventId; - -error: - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; -} - - -PyObject * -_wrap_TypeId_LookupByNameFailSafe (PyNs3TypeId *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - bool ok; - const char *name; - Py_ssize_t name_len; - ns3::TypeId tid; - PyNs3TypeId *py_tid; - const char *keywords[] = {"name", NULL}; - - if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "s#", (char **) keywords, &name, &name_len)) { - PyObject *exc_type, *traceback; - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; - } - ok = ns3::TypeId::LookupByNameFailSafe (std::string (name, name_len), &tid); - if (!ok) - { - PyErr_Format (PyExc_KeyError, "The ns3 type with name `%s' is not registered", name); - return NULL; - } - - py_tid = PyObject_New (PyNs3TypeId, &PyNs3TypeId_Type); - py_tid->obj = new ns3::TypeId (tid); - PyNs3TypeId_wrapper_registry[(void *) py_tid->obj] = (PyObject *) py_tid; - - return (PyObject *) py_tid; -} - - -class CommandLinePythonValueSetter : public ns3::RefCountBase -{ - PyObject *m_namespace; - std::string m_variable; -public: - CommandLinePythonValueSetter (PyObject *ns, std::string const &variable) { - Py_INCREF (ns); - m_namespace = ns; - m_variable = variable; - } - bool Parse (std::string value) { - PyObject *pyvalue = PyString_FromStringAndSize (value.data (), value.size ()); - PyObject_SetAttrString (m_namespace, (char *) m_variable.c_str (), pyvalue); - if (PyErr_Occurred ()) { - PyErr_Print (); - return false; - } - return true; - } - virtual ~CommandLinePythonValueSetter () { - Py_DECREF (m_namespace); - m_namespace = NULL; - } - -}; - -PyObject * -_wrap_CommandLine_AddValue (PyNs3CommandLine *self, PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - const char *name, *help, *variable = NULL; - PyObject *py_namespace = NULL; - const char *keywords[] = {"name", "help", "variable", "namespace", NULL}; - - if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "ss|sO", (char **) keywords, &name, &help, &variable, &py_namespace)) { - PyObject *exc_type, *traceback; - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; - } - - if (variable == NULL) { - variable = name; - } - if (py_namespace == NULL) { - py_namespace = (PyObject *) self; - } - - ns3::Ptr setter = ns3::Create (py_namespace, variable); - self->obj->AddValue (name, help, ns3::MakeCallback (&CommandLinePythonValueSetter::Parse, setter)); - - Py_INCREF (Py_None); - return Py_None; -} - - -PyObject * -_wrap_Simulator_Run (PyNs3Simulator *PYBINDGEN_UNUSED (dummy), PyObject *args, PyObject *kwargs, - PyObject **return_exception) -{ - const char *keywords[] = {"signal_check_frequency", NULL}; - int signal_check_frequency; - - ns3::Ptr defaultSim = - ns3::DynamicCast (ns3::Simulator::GetImplementation ()); - if (defaultSim) { - signal_check_frequency = 100; - } else { - signal_check_frequency = -1; - } - - if (!PyArg_ParseTupleAndKeywords (args, kwargs, (char *) "|i", (char **) keywords, &signal_check_frequency)) { - PyObject *exc_type, *traceback; - PyErr_Fetch (&exc_type, return_exception, &traceback); - Py_XDECREF (exc_type); - Py_XDECREF (traceback); - return NULL; - } - - PyThreadState *py_thread_state = NULL; - - if (signal_check_frequency == -1) - { - if (PyEval_ThreadsInitialized ()) - py_thread_state = PyEval_SaveThread (); - ns3::Simulator::Run (); - if (py_thread_state) - PyEval_RestoreThread (py_thread_state); - } else { - while (!ns3::Simulator::IsFinished ()) - { - if (PyEval_ThreadsInitialized ()) - py_thread_state = PyEval_SaveThread (); - - for (int n = signal_check_frequency; n > 0 && !ns3::Simulator::IsFinished (); --n) - { - ns3::Simulator::RunOneEvent (); - } - - if (py_thread_state) - PyEval_RestoreThread (py_thread_state); - PyErr_CheckSignals (); - if (PyErr_Occurred ()) - return NULL; - } - } - Py_INCREF (Py_None); - return Py_None; -} - diff --git a/bindings/python/ns3modulegen-modular.py b/bindings/python/ns3modulegen-modular.py deleted file mode 100644 index 9d76f2a8e..000000000 --- a/bindings/python/ns3modulegen-modular.py +++ /dev/null @@ -1,131 +0,0 @@ -from __future__ import print_function -import warnings -import sys -import os -import pybindgen.settings -from pybindgen import Module, FileCodeSink, param, retval, cppclass, typehandlers -from pybindgen.module import MultiSectionFactory -import ns3modulegen_core_customizations - -import logging - -pybindgen.settings.wrapper_registry = pybindgen.settings.StdMapWrapperRegistry - -import traceback - -class ErrorHandler(pybindgen.settings.ErrorHandler): - - def __init__(self, apidefs_file): - self.apidefs_file = apidefs_file - - def handle_error(self, wrapper, exception, traceback_): - stack = getattr(wrapper, 'stack_where_defined', []) - stack.reverse() - for l in stack: - if l[0] == self.apidefs_file: - warnings.warn_explicit("exception %r in wrapper %s" % (exception, wrapper), - Warning, l[0], l[1]) - break - else: - warnings.warn("exception %r in wrapper %s" % (exception, wrapper)) - return True - - -#print >> sys.stderr, ">>>>>>>>>>>>>>>>>>>>>>>>>>>> ", bool(eval(os.environ["GCC_RTTI_ABI_COMPLETE"])) -pybindgen.settings.gcc_rtti_abi_complete = bool(eval(os.environ["GCC_RTTI_ABI_COMPLETE"])) - -class MyMultiSectionFactory(MultiSectionFactory): - def __init__(self, main_file_name): - super(MyMultiSectionFactory, self).__init__() - self.main_file_name = main_file_name - self.main_sink = FileCodeSink(open(main_file_name, "wt")) - self.header_name = "ns3module.h" - header_file_name = os.path.join(os.path.dirname(self.main_file_name), self.header_name) - #print >> sys.stderr, ">>>>>>>>>>>>>>>>>", header_file_name, main_file_name - self.header_sink = FileCodeSink(open(header_file_name, "wt")) - def get_section_code_sink(self, section_name): - return self.main_sink - def get_main_code_sink(self): - return self.main_sink - def get_common_header_code_sink(self): - return self.header_sink - def get_common_header_include(self): - return '"%s"' % self.header_name - def close(self): - self.header_sink.file.close() - self.main_sink.file.close() - - - -def main(argv): - logging.basicConfig() - logging.getLogger("pybindgen.typehandlers").setLevel(logging.DEBUG) - - module_abs_src_path, target, extension_name, output_cc_file_name = argv[1:] - module_name = os.path.basename(module_abs_src_path) - out = MyMultiSectionFactory(output_cc_file_name) - - sys.path.insert(0, os.path.join(module_abs_src_path, "bindings")) - try: - module_apidefs = __import__("modulegen__%s" % target) - del sys.modules["modulegen__%s" % target] - try: - module_customization = __import__("modulegen_customizations") - del sys.modules["modulegen_customizations"] - except ImportError: - module_customization = object() - - try: - from callbacks_list import callback_classes - except ImportError as ex: - print("***************", repr(ex), file=sys.stderr) - callback_classes = [] - else: - print(">>>>>>>>>>>>>>>>", repr(callback_classes), file=sys.stderr) - - finally: - sys.path.pop(0) - - apidefs_file, dummy = os.path.splitext(module_apidefs.__file__) - apidefs_file += '.py' - pybindgen.settings.error_handler = ErrorHandler(apidefs_file) - - root_module = module_apidefs.module_init() - root_module.set_name(extension_name) - root_module.add_include('"ns3/%s-module.h"' % module_name) - - ns3modulegen_core_customizations.add_std_ios_openmode(root_module) - - # ----------- - module_apidefs.register_types(root_module) - - if hasattr(module_customization, 'post_register_types'): - module_customization.post_register_types(root_module) - - # register Callback<...> type handlers - ns3modulegen_core_customizations.register_callback_classes(root_module.after_forward_declarations, - callback_classes) - - # ----------- - module_apidefs.register_methods(root_module) - - if hasattr(module_customization, 'post_register_methods'): - module_customization.post_register_methods(root_module) - - ns3modulegen_core_customizations.Object_customizations(root_module) - ns3modulegen_core_customizations.Attribute_customizations(root_module) - ns3modulegen_core_customizations.generate_callback_classes(root_module, - callback_classes) - - # ----------- - module_apidefs.register_functions(root_module) - - if hasattr(module_customization, 'post_register_functions'): - module_customization.post_register_functions(root_module) - - # ----------- - root_module.generate(out) - -if __name__ == '__main__': - import sys - main(sys.argv) diff --git a/bindings/python/ns3modulegen_core_customizations.py b/bindings/python/ns3modulegen_core_customizations.py deleted file mode 100644 index 087aa361b..000000000 --- a/bindings/python/ns3modulegen_core_customizations.py +++ /dev/null @@ -1,446 +0,0 @@ -from __future__ import print_function -import sys -import re - -from pybindgen.typehandlers import base as typehandlers -from pybindgen import ReturnValue, Parameter -from pybindgen.cppmethod import CustomCppMethodWrapper, CustomCppConstructorWrapper -from pybindgen.typehandlers.codesink import MemoryCodeSink -from pybindgen.typehandlers import ctypeparser -from pybindgen.typehandlers.base import ForwardWrapperBase -from pybindgen import cppclass -import warnings - -from pybindgen.typehandlers.base import CodeGenerationError - -import sys - -class SmartPointerTransformation(typehandlers.TypeTransformation): - """ - This class provides a "type transformation" that tends to support - NS-3 smart pointers. Parameters such as "Ptr foo" are - transformed into something like Parameter.new("Foo*", "foo", - transfer_ownership=False). Return values such as Ptr are - transformed into ReturnValue.new("Foo*", - caller_owns_return=False). Since the underlying objects have - reference counting, PyBindGen does the right thing. - """ - def __init__(self): - super(SmartPointerTransformation, self).__init__() - self.rx = re.compile(r'(ns3::|::ns3::|)Ptr<([^>]+)>\s*$') - print("{0!r}".format(self), file=sys.stderr) - - def _get_untransformed_type_traits(self, name): - m = self.rx.match(name) - is_const = False - if m is None: - print("{0!r} did not match".format(name), file=sys.stderr) - return None, False - else: - name1 = m.group(2).strip() - if name1.startswith('const '): - name1 = name1[len('const '):] - is_const = True - if name1.endswith(' const'): - name1 = name1[:-len(' const')] - is_const = True - new_name = name1+' *' - - if new_name.startswith('::'): - new_name = new_name[2:] - return new_name, is_const - - def get_untransformed_name(self, name): - new_name, dummy_is_const = self._get_untransformed_type_traits(name) - return new_name - - def create_type_handler(self, type_handler, *args, **kwargs): - if issubclass(type_handler, Parameter): - kwargs['transfer_ownership'] = False - elif issubclass(type_handler, ReturnValue): - kwargs['caller_owns_return'] = False - else: - raise AssertionError - - ## fix the ctype, add ns3:: namespace - orig_ctype, is_const = self._get_untransformed_type_traits(args[0]) - if is_const: - correct_ctype = 'ns3::Ptr< {0} const >'.format(orig_ctype[:-2]) - else: - correct_ctype = 'ns3::Ptr< {0} >'.format(orig_ctype[:-2]) - args = tuple([correct_ctype] + list(args[1:])) - - handler = type_handler(*args, **kwargs) - handler.set_transformation(self, orig_ctype) - return handler - - def untransform(self, type_handler, declarations, code_block, expression): - return 'const_cast<%s> (ns3::PeekPointer (%s))' % (type_handler.untransformed_ctype, expression) - - def transform(self, type_handler, declarations, code_block, expression): - assert type_handler.untransformed_ctype[-1] == '*' - return 'ns3::Ptr< %s > (%s)' % (type_handler.untransformed_ctype[:-1], expression) - -## register the type transformation -transf = SmartPointerTransformation() -typehandlers.return_type_matcher.register_transformation(transf) -typehandlers.param_type_matcher.register_transformation(transf) -del transf - - -class CallbackImplProxyMethod(typehandlers.ReverseWrapperBase): - """ - Class that generates a proxy virtual method that calls a similarly named python method. - """ - - def __init__(self, return_value, parameters): - super(CallbackImplProxyMethod, self).__init__(return_value, parameters) - - def generate_python_call(self): - """code to call the python method""" - build_params = self.build_params.get_parameters(force_tuple_creation=True) - if build_params[0][0] == '"': - build_params[0] = '(char *) ' + build_params[0] - args = self.before_call.declare_variable('PyObject*', 'args') - self.before_call.write_code('%s = Py_BuildValue(%s);' - % (args, ', '.join(build_params))) - self.before_call.add_cleanup_code('Py_DECREF(%s);' % args) - self.before_call.write_code('py_retval = PyObject_CallObject(m_callback, %s);' % args) - self.before_call.write_error_check('py_retval == NULL') - self.before_call.add_cleanup_code('Py_DECREF(py_retval);') - - - - -def register_callback_classes(out, callbacks): - for callback_impl_num, template_parameters in enumerate(callbacks): - cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) - #print >> sys.stderr, "***** trying to register callback: %r" % cls_name - class_name = "PythonCallbackImpl%i" % callback_impl_num - - class PythonCallbackParameter(Parameter): - "Class handlers" - CTYPES = [cls_name] - print("***** registering callback handler: %r (%r)" % (ctypeparser.normalize_type_string(cls_name), cls_name), file=sys.stderr) - DIRECTIONS = [Parameter.DIRECTION_IN] - PYTHON_CALLBACK_IMPL_NAME = class_name - TEMPLATE_ARGS = template_parameters - DISABLED = False - - def convert_python_to_c(self, wrapper): - "parses python args to get C++ value" - assert isinstance(wrapper, typehandlers.ForwardWrapperBase) - - if self.DISABLED: - raise CodeGenerationError("wrapper could not be generated") - - if self.default_value is None: - py_callback = wrapper.declarations.declare_variable('PyObject*', self.name) - wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name) - wrapper.before_call.write_error_check( - '!PyCallable_Check(%s)' % py_callback, - 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) - callback_impl = wrapper.declarations.declare_variable( - 'ns3::Ptr<%s>' % self.PYTHON_CALLBACK_IMPL_NAME, - '%s_cb_impl' % self.name) - wrapper.before_call.write_code("%s = ns3::Create<%s> (%s);" - % (callback_impl, self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) - wrapper.call_params.append( - 'ns3::Callback<%s> (%s)' % (', '.join(self.TEMPLATE_ARGS), callback_impl)) - else: - py_callback = wrapper.declarations.declare_variable('PyObject*', self.name, 'NULL') - wrapper.parse_params.add_parameter('O', ['&'+py_callback], self.name, optional=True) - value = wrapper.declarations.declare_variable( - 'ns3::Callback<%s>' % ', '.join(self.TEMPLATE_ARGS), - self.name+'_value', - self.default_value) - - wrapper.before_call.write_code("if (%s) {" % (py_callback,)) - wrapper.before_call.indent() - - wrapper.before_call.write_error_check( - '!PyCallable_Check(%s)' % py_callback, - 'PyErr_SetString(PyExc_TypeError, "parameter \'%s\' must be callbale");' % self.name) - - wrapper.before_call.write_code("%s = ns3::Callback<%s> (ns3::Create<%s> (%s));" - % (value, ', '.join(self.TEMPLATE_ARGS), - self.PYTHON_CALLBACK_IMPL_NAME, py_callback)) - - wrapper.before_call.unindent() - wrapper.before_call.write_code("}") # closes: if (py_callback) { - - wrapper.call_params.append(value) - - - def convert_c_to_python(self, wrapper): - raise typehandlers.NotSupportedError("Reverse wrappers for ns3::Callback<...> types " - "(python using callbacks defined in C++) not implemented.") - - -def generate_callback_classes(module, callbacks): - out = module.after_forward_declarations - for callback_impl_num, template_parameters in enumerate(callbacks): - sink = MemoryCodeSink() - cls_name = "ns3::Callback< %s >" % ', '.join(template_parameters) - #print >> sys.stderr, "***** trying to register callback: %r" % cls_name - class_name = "PythonCallbackImpl%i" % callback_impl_num - sink.writeln(''' -class %s : public ns3::CallbackImpl<%s> -{ -public: - PyObject *m_callback; - %s(PyObject *callback) - { - Py_INCREF(callback); - m_callback = callback; - } - virtual ~%s() - { - PyGILState_STATE __py_gil_state; - __py_gil_state = (PyEval_ThreadsInitialized() ? PyGILState_Ensure() : (PyGILState_STATE) 0); - Py_DECREF(m_callback); - m_callback = NULL; - PyGILState_Release(__py_gil_state); - } - - virtual bool IsEqual(ns3::Ptr other_base) const - { - const %s *other = dynamic_cast (ns3::PeekPointer (other_base)); - if (other != NULL) - return (other->m_callback == m_callback); - else - return false; - } - -''' % (class_name, ', '.join(template_parameters), class_name, class_name, class_name, class_name)) - sink.indent() - callback_return = template_parameters[0] - return_ctype = ctypeparser.parse_type(callback_return) - if ('const' in return_ctype.remove_modifiers()): - kwargs = {'is_const': True} - else: - kwargs = {} - try: - return_type = ReturnValue.new(str(return_ctype), **kwargs) - except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: - warnings.warn("***** Unable to register callback; Return value '%s' error (used in %s): %r" - % (callback_return, cls_name, ex), - Warning) - continue - - arguments = [] - ok = True - callback_parameters = [arg for arg in template_parameters[1:] if arg != 'ns3::empty'] - for arg_num, arg_type in enumerate(callback_parameters): - arg_name = 'arg%i' % (arg_num+1) - - param_ctype = ctypeparser.parse_type(arg_type) - if ('const' in param_ctype.remove_modifiers()): - kwargs = {'is_const': True} - else: - kwargs = {} - try: - param = Parameter.new(str(param_ctype), arg_name, **kwargs) - cpp_class = getattr(param, "cpp_class", None) - if isinstance(cpp_class, cppclass.CppClass): - # check if the "helper class" can be constructed - if cpp_class.helper_class is not None: - cpp_class.helper_class.generate_forward_declarations( - MemoryCodeSink()) - if cpp_class.helper_class.cannot_be_constructed: - cpp_class.helper_class = None - cpp_class.helper_class_disabled = True - arguments.append(param) - except (typehandlers.TypeLookupError, typehandlers.TypeConfigurationError) as ex: - warnings.warn("***** Unable to register callback; parameter '%s %s' error (used in %s): %r" - % (arg_type, arg_name, cls_name, ex), - Warning) - ok = False - if not ok: - try: - typehandlers.return_type_matcher.lookup(cls_name)[0].DISABLED = True - except typehandlers.TypeLookupError: - pass - try: - typehandlers.param_type_matcher.lookup(cls_name)[0].DISABLED = True - except typehandlers.TypeLookupError: - pass - continue - - wrapper = CallbackImplProxyMethod(return_type, arguments) - wrapper.generate(sink, 'operator()', decl_modifiers=[]) - - sink.unindent() - sink.writeln('};\n') - print("Flushing to ", out, file=sys.stderr) - sink.flush_to(out) - - -# def write_preamble(out): -# pybindgen.write_preamble(out) -# out.writeln("#include \"ns3/everything.h\"") - - - -def Simulator_customizations(module): - Simulator = module['ns3::Simulator'] - - ## Simulator::Schedule(delay, callback, ...user..args...) - Simulator.add_custom_method_wrapper("Schedule", "_wrap_Simulator_Schedule", - flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) - - - ## Simulator::ScheduleNow(callback, ...user..args...) - Simulator.add_custom_method_wrapper("ScheduleNow", "_wrap_Simulator_ScheduleNow", - flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) - - - ## Simulator::ScheduleDestroy(callback, ...user..args...) - Simulator.add_custom_method_wrapper("ScheduleDestroy", "_wrap_Simulator_ScheduleDestroy", - flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) - - Simulator.add_custom_method_wrapper("Run", "_wrap_Simulator_Run", - flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) - - -def CommandLine_customizations(module): - CommandLine = module['ns3::CommandLine'] - CommandLine.add_method('Parse', None, [ArgvParam(None, 'argv')], - is_static=False) - CommandLine.add_custom_method_wrapper("AddValue", "_wrap_CommandLine_AddValue", - flags=["METH_VARARGS", "METH_KEYWORDS"]) - - -def Object_customizations(module): - ## --------------------------------------------------------------------- - ## Here we generate custom constructor code for all classes that - ## derive from ns3::Object. The custom constructors are needed in - ## order to support kwargs only and to translate kwargs into ns3 - ## attributes, etc. - ## --------------------------------------------------------------------- - try: - Object = module['ns3::Object'] - except KeyError: - return - - ## add a GetTypeId method to all generatd helper classes - def helper_class_hook(helper_class): - decl = """ -static ns3::TypeId GetTypeId (void) -{ - static ns3::TypeId tid = ns3::TypeId ("%s") - .SetParent< %s > () - ; - return tid; -}""" % (helper_class.name, helper_class.class_.full_name) - - helper_class.add_custom_method(decl) - helper_class.add_post_generation_code( - "NS_OBJECT_ENSURE_REGISTERED (%s);" % helper_class.name) - Object.add_helper_class_hook(helper_class_hook) - - def ns3_object_instance_creation_function(cpp_class, code_block, lvalue, - parameters, construct_type_name): - assert lvalue - assert not lvalue.startswith('None') - if cpp_class.cannot_be_constructed: - raise CodeGenerationError("%s cannot be constructed (%s)" - % cpp_class.full_name) - if cpp_class.incomplete_type: - raise CodeGenerationError("%s cannot be constructed (incomplete type)" - % cpp_class.full_name) - code_block.write_code("%s = new %s(%s);" % (lvalue, construct_type_name, parameters)) - code_block.write_code("%s->Ref ();" % (lvalue)) - - def ns3_object_post_instance_creation_function(cpp_class, code_block, lvalue, - parameters, construct_type_name): - code_block.write_code("ns3::CompleteConstruct(%s);" % (lvalue, )) - - Object.set_instance_creation_function(ns3_object_instance_creation_function) - Object.set_post_instance_creation_function(ns3_object_post_instance_creation_function) - - -def Attribute_customizations(module): - # Fix up for the "const AttributeValue &v = EmptyAttribute()" - # case, as used extensively by helper classes. - - # Here's why we need to do this: pybindgen.gccxmlscanner, when - # scanning parameter default values, is only provided with the - # value as a simple C expression string. (py)gccxml does not - # report the type of the default value. - - # As a workaround, here we iterate over all parameters of all - # methods of all classes and tell pybindgen what is the type of - # the default value for attributes. - - for cls in module.classes: - for meth in cls.get_all_methods(): - for param in meth.parameters: - if isinstance(param, cppclass.CppClassRefParameter): - if param.cpp_class.name == 'AttributeValue' \ - and param.default_value is not None \ - and param.default_value_type is None: - param.default_value_type = 'ns3::EmptyAttributeValue' - - -def TypeId_customizations(module): - TypeId = module['ns3::TypeId'] - TypeId.add_custom_method_wrapper("LookupByNameFailSafe", "_wrap_TypeId_LookupByNameFailSafe", - flags=["METH_VARARGS", "METH_KEYWORDS", "METH_STATIC"]) - - -def add_std_ofstream(module): - module.add_include('') - ostream = module.add_class('ostream', foreign_cpp_namespace='::std') - ostream.set_cannot_be_constructed("abstract base class") - ofstream = module.add_class('ofstream', foreign_cpp_namespace='::std', parent=ostream) - ofstream.add_enum('openmode', [ - ('app', 'std::ios_base::app'), - ('ate', 'std::ios_base::ate'), - ('binary', 'std::ios_base::binary'), - ('in', 'std::ios_base::in'), - ('out', 'std::ios_base::out'), - ('trunc', 'std::ios_base::trunc'), - ]) - ofstream.add_constructor([Parameter.new("const char *", 'filename'), - Parameter.new("::std::ofstream::openmode", 'mode', default_value="std::ios_base::out")]) - ofstream.add_method('close', None, []) - - add_std_ios_openmode(module) - - -class IosOpenmodeParam(Parameter): - - DIRECTIONS = [Parameter.DIRECTION_IN] - CTYPES = ['std::ios_base::openmode', 'std::_Ios_Openmode'] - - def convert_c_to_python(self, wrapper): - assert isinstance(wrapper, ReverseWrapperBase) - wrapper.build_params.add_parameter('i', [self.value]) - - def convert_python_to_c(self, wrapper): - assert isinstance(wrapper, ForwardWrapperBase) - name = wrapper.declarations.declare_variable("std::ios_base::openmode", self.name, self.default_value) - wrapper.parse_params.add_parameter('i', ['&'+name], self.name, optional=bool(self.default_value)) - wrapper.call_params.append(name) - - - -def add_std_ios_openmode(module): - for flag in 'in', 'out', 'ate', 'app', 'trunc', 'binary': - module.after_init.write_code('PyModule_AddIntConstant(m, (char *) "STD_IOS_%s", std::ios::%s);' - % (flag.upper(), flag)) - - - -def add_ipv4_address_tp_hash(module): - module.body.writeln(''' -long -_ns3_Ipv4Address_tp_hash (PyObject *obj) -{ - PyNs3Ipv4Address *addr = reinterpret_cast (obj); - return static_cast (ns3::Ipv4AddressHash () (*addr->obj)); -} -''') - module.header.writeln('long _ns3_Ipv4Address_tp_hash (PyObject *obj);') - module['Ipv4Address'].pytype.slots['tp_hash'] = "_ns3_Ipv4Address_tp_hash" diff --git a/bindings/python/ns3modulescan-modular.py b/bindings/python/ns3modulescan-modular.py deleted file mode 100644 index 673e0a888..000000000 --- a/bindings/python/ns3modulescan-modular.py +++ /dev/null @@ -1,292 +0,0 @@ -#! /usr/bin/env python3 - -import sys -import os.path - -import pybindgen.settings -from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning, find_declaration_from_name -from pybindgen.typehandlers.codesink import FileCodeSink -from pygccxml.declarations import templates -from pygccxml.declarations.enumeration import enumeration_t -from pygccxml.declarations.class_declaration import class_t -from pygccxml.declarations.free_calldef import free_function_t -from pygccxml.declarations.calldef_members import constructor_t, member_function_t -from pygccxml.declarations.calldef import calldef_t - -## we need the smart pointer type transformation to be active even -## during castxml scanning. -import ns3modulegen_core_customizations - - -## silence castxmlparser errors; we only want error handling in the -## generated python script, not while scanning. -class ErrorHandler(pybindgen.settings.ErrorHandler): - def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_): - return True -pybindgen.settings.error_handler = ErrorHandler() -import warnings -warnings.filterwarnings(category=WrapperWarning, action='ignore') - - -import ns3modulescan -type_annotations = ns3modulescan.type_annotations - - -def get_ns3_relative_path(path): - l = [] - head = path - if not path: - return - while head: - new_head, tail = os.path.split(head) - if new_head == head: - raise ValueError - head = new_head - if tail == 'ns3': - return os.path.join(*l) - l.insert(0, tail) - raise AssertionError("is the path %r inside ns3?!" % path) - -class PreScanHook: - - def __init__(self, headers_map, module): - self.headers_map = headers_map - self.module = module - - def __call__(self, module_parser, - pygccxml_definition, - global_annotations, - parameter_annotations): - try: - ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name) - except ValueError: # the header is not from ns3 - return # ignore the definition, it's not ns-3 def. - if not ns3_header: - return - definition_module = self.headers_map[ns3_header] - - ## Note: we don't include line numbers in the comments because - ## those numbers are very likely to change frequently, which would - ## cause needless changes, since the generated python files are - ## kept under version control. - - #global_annotations['pygen_comment'] = "%s:%i: %s" % \ - # (ns3_header, pygccxml_definition.location.line, pygccxml_definition) - global_annotations['pygen_comment'] = "%s (module %r): %s" % \ - (ns3_header, definition_module, pygccxml_definition) - - - ## handle ns3::Object::GetObject (left to its own devices, - ## pybindgen will generate a mangled name containing the template - ## argument type name). - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Object' \ - and pygccxml_definition.name == 'GetObject': - template_args = templates.args(str(pygccxml_definition)) - if template_args == ['ns3::Object']: - global_annotations['template_instance_names'] = 'ns3::Object=>GetObject' - - ## Don't wrap Simulator::Schedule* (manually wrapped) - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Simulator' \ - and pygccxml_definition.name.startswith('Schedule'): - global_annotations['ignore'] = None - - # manually wrapped - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Simulator' \ - and pygccxml_definition.name == 'Run': - global_annotations['ignore'] = True - - ## http://www.gccxml.org/Bug/view.php?id=9915 - if isinstance(pygccxml_definition, calldef_t): - for arg in pygccxml_definition.arguments: - if arg.default_value is None: - continue - elif arg.default_value == "ns3::MilliSeconds( )": - arg.default_value = "ns3::MilliSeconds(0)" - elif arg.default_value == "ns3::Seconds( )": - arg.default_value = "ns3::Seconds(0)" - - ## classes - if isinstance(pygccxml_definition, class_t): - print(pygccxml_definition, file=sys.stderr) - # no need for helper classes to allow subclassing in Python, I think... - #if pygccxml_definition.name.endswith('Helper'): - # global_annotations['allow_subclassing'] = 'false' - - # - # If a class is template instantiation, even if the - # template was defined in some other module, if a template - # argument belongs to this module then the template - # instantiation will belong to this module. - # - if templates.is_instantiation(pygccxml_definition.decl_string): - cls_name, template_parameters = templates.split(pygccxml_definition.name) - template_parameters_decls = [find_declaration_from_name(module_parser.global_ns, templ_param) - for templ_param in template_parameters] - #print >> sys.stderr, "********************", cls_name, repr(template_parameters_decls) - - template_parameters_modules = [] - for templ in template_parameters_decls: - if not hasattr(templ, 'location'): - continue - try: - h = get_ns3_relative_path(templ.location.file_name) - except ValueError: - continue - template_parameters_modules.append(self.headers_map[h]) - - for templ_mod in template_parameters_modules: - if templ_mod == self.module: - definition_module = templ_mod - break - #print >> sys.stderr, "********************", cls_name, repr(template_parameters_modules) - - - if definition_module != self.module: - global_annotations['import_from_module'] = 'ns.%s' % (definition_module.replace('-', '_'),) - - if pygccxml_definition.decl_string.startswith('::ns3::SimpleRefCount<'): - global_annotations['incref_method'] = 'Ref' - global_annotations['decref_method'] = 'Unref' - global_annotations['peekref_method'] = 'GetReferenceCount' - global_annotations['automatic_type_narrowing'] = 'true' - return - - if pygccxml_definition.decl_string.startswith('::ns3::Callback<'): - # manually handled in ns3modulegen_core_customizations.py - global_annotations['ignore'] = None - return - - if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'): - global_annotations['ignore'] = None - return - - if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'): - # handled by pybindgen "type transformation" - global_annotations['ignore'] = None - return - - # table driven class customization - try: - annotations = type_annotations[pygccxml_definition.decl_string] - except KeyError: - pass - else: - global_annotations.update(annotations) - - ## enums - if isinstance(pygccxml_definition, enumeration_t): - if definition_module != self.module: - global_annotations['import_from_module'] = 'ns.%s' % definition_module - - ## free functions - if isinstance(pygccxml_definition, free_function_t): - - if definition_module != self.module: - global_annotations['ignore'] = None - return - - if pygccxml_definition.name == 'PeekPointer': - global_annotations['ignore'] = None - return - - ## table driven methods/constructors/functions customization - if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)): - try: - annotations = type_annotations[str(pygccxml_definition)] - except KeyError: - pass - else: - for key,value in list(annotations.items()): - if key == 'params': - parameter_annotations.update (value) - del annotations['params'] - global_annotations.update(annotations) - - -# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper): -# ## classes -# if isinstance(pybindgen_wrapper, CppClass): -# if pybindgen_wrapper.name.endswith('Checker'): -# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper -# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function) - - -def scan_callback_classes(module_parser, callback_classes_file): - callback_classes_file.write("callback_classes = [\n") - for cls in module_parser.module_namespace.classes(function=module_parser.location_filter, - recursive=False): - if not cls.name.startswith("Callback<"): - continue - assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls - dummy_cls_name, template_parameters = templates.split(cls.decl_string) - callback_classes_file.write(" %r,\n" % template_parameters) - callback_classes_file.write("]\n") - - -def ns3_module_scan(top_builddir, module_name, headers_map, output_file_name, cflags): - module_parser = ModuleParser('ns.%s' % module_name.replace('-', '_'), 'ns3') - module_parser.add_pre_scan_hook(PreScanHook(headers_map, module_name)) - #module_parser.add_post_scan_hook(post_scan_hook) - - castxml_options = dict( - include_paths=[top_builddir, os.path.join(top_builddir, "include")], - define_symbols={ - #'NS3_ASSERT_ENABLE': None, - #'NS3_LOG_ENABLE': None, - }, - cflags=('-std=c++17 %s' % cflags) - ) - - try: - os.unlink(output_file_name) - except OSError: - pass - try: - os.makedirs(os.path.dirname(output_file_name)) - except OSError: - pass - output_file = open(output_file_name, "wt") - output_sink = FileCodeSink(output_file) - - # if there exists a scan-header.h file in src//bindings or contrib//bindings, - # scan it, otherwise scan ns3/xxxx-module.h. - scan_header = os.path.join(os.path.dirname(output_file_name), "scan-header.h") - if not os.path.exists(scan_header): - scan_header = os.path.join(top_builddir, "ns3", "%s-module.h" % module_name) - if not os.path.exists(scan_header): - scan_header = os.path.join(top_builddir, "include", "ns3", "%s-module.h" % module_name) - - module_parser.parse_init([scan_header], - None, whitelist_paths=[top_builddir], - pygen_sink=output_sink, - castxml_options=castxml_options) - module_parser.scan_types() - - callback_classes_file = open(os.path.join(os.path.dirname(output_file_name), "callbacks_list.py"), "wt") - scan_callback_classes(module_parser, callback_classes_file) - callback_classes_file.close() - - - module_parser.scan_methods() - module_parser.scan_functions() - module_parser.parse_finalize() - - output_file.close() - os.chmod(output_file_name, 0o400) - - -if __name__ == '__main__': - if len(sys.argv) != 6: - print("ns3modulescan-modular.py top_builddir module_path module_headers output_file_name cflags") - sys.exit(1) - if os.path.exists(sys.argv[3]): - import json - with open(sys.argv[3], "r") as f: - module_headers = json.load(f) - else: - module_headers = eval(sys.argv[3]) - ns3_module_scan(sys.argv[1], sys.argv[2], module_headers, sys.argv[4], sys.argv[5]) - sys.exit(0) diff --git a/bindings/python/ns3modulescan.py b/bindings/python/ns3modulescan.py deleted file mode 100644 index 7274cbfef..000000000 --- a/bindings/python/ns3modulescan.py +++ /dev/null @@ -1,335 +0,0 @@ -#! /usr/bin/env python3 - -import sys -import os.path - -import pybindgen.settings -from pybindgen.castxmlparser import ModuleParser, PygenClassifier, PygenSection, WrapperWarning -from pybindgen.typehandlers.codesink import FileCodeSink -from pygccxml.declarations import templates -from pygccxml.declarations.class_declaration import class_t -from pygccxml.declarations.free_calldef import free_function_t -from pygccxml.declarations.calldef_members import constructor_t, member_function_t -from pygccxml.declarations.calldef import calldef_t - - -## we need the smart pointer type transformation to be active even -## during gccxml scanning. -import ns3modulegen_core_customizations - - -## silence castxmlparser errors; we only want error handling in the -## generated python script, not while scanning. -class ErrorHandler(pybindgen.settings.ErrorHandler): - def handle_error(self, dummy_wrapper, dummy_exception, dummy_traceback_): - return True -pybindgen.settings.error_handler = ErrorHandler() -import warnings -warnings.filterwarnings(category=WrapperWarning, action='ignore') - -type_annotations = { - '::ns3::AttributeChecker': { - 'automatic_type_narrowing': 'true', - 'allow_subclassing': 'false', - }, - '::ns3::AttributeValue': { - 'automatic_type_narrowing': 'true', - 'allow_subclassing': 'false', - }, - - '::ns3::CommandLine': { - 'allow_subclassing': 'true', # needed so that AddValue is able to set attributes on the object - }, - - '::ns3::NscTcpL4Protocol': { - 'ignore': 'true', # this class is implementation detail - }, - - - 'ns3::RandomVariable::RandomVariable(ns3::RandomVariableBase const & variable) [constructor]': { - 'ignore': None, - }, - 'ns3::RandomVariableBase * ns3::RandomVariable::Peek() const [member function]': { - 'ignore': None, - }, - 'void ns3::RandomVariable::GetSeed(uint32_t * seed) const [member function]': { - 'params': {'seed':{'direction':'out', - 'array_length':'6'}} - }, - 'bool ns3::TypeId::LookupAttributeByName(std::string name, ns3::TypeId::AttributeInformation * info) const [member function]': { - 'params': {'info':{'transfer_ownership': 'false'}} - }, - 'static bool ns3::TypeId::LookupByNameFailSafe(std::string name, ns3::TypeId * tid) [member function]': { - 'ignore': None, # manually wrapped in - }, - 'bool ns3::TraceSourceAccessor::ConnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': { - 'params': {'obj': {'transfer_ownership':'false'}} - }, - 'bool ns3::TraceSourceAccessor::Connect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': { - 'params': {'obj': {'transfer_ownership':'false'}} - }, - 'bool ns3::TraceSourceAccessor::DisconnectWithoutContext(ns3::ObjectBase * obj, ns3::CallbackBase const & cb) const [member function]': { - 'params': {'obj': {'transfer_ownership':'false'}} - }, - 'bool ns3::TraceSourceAccessor::Disconnect(ns3::ObjectBase * obj, std::string context, ns3::CallbackBase const & cb) const [member function]': { - 'params': {'obj': {'transfer_ownership':'false'}} - }, - 'bool ns3::AttributeAccessor::Set(ns3::ObjectBase * object, ns3::AttributeValue const & value) const [member function]': { - 'params': {'object': {'transfer_ownership':'false'}} - }, - 'ns3::EmpiricalVariable::EmpiricalVariable(ns3::RandomVariableBase const & variable) [constructor]': { - 'ignore': None - }, - 'static ns3::AttributeList * ns3::AttributeList::GetGlobal() [member function]': { - 'caller_owns_return': 'false' - }, - 'void ns3::CommandLine::Parse(int argc, char * * argv) const [member function]': { - 'ignore': None # manually wrapped - }, - 'extern void ns3::PythonCompleteConstruct(ns3::Ptr object, ns3::TypeId typeId, ns3::AttributeList const & attributes) [free function]': { - 'ignore': None # used transparently by, should not be wrapped - }, - - 'ns3::Ptr ns3::Ipv4ListRouting::GetRoutingProtocol(uint32_t index, int16_t & priority) const [member function]': { - 'params': {'priority':{'direction':'out'}} - }, - 'ns3::Ipv4RoutingTableEntry * ns3::GlobalRouter::GetInjectedRoute(uint32_t i) [member function]': { - 'params': {'return': { 'caller_owns_return': 'false',}}, - }, - 'ns3::Ipv4RoutingTableEntry * ns3::Ipv4GlobalRouting::GetRoute(uint32_t i) const [member function]': { - 'params': {'return': { 'caller_owns_return': 'false',}}, - }, - - '::ns3::TestCase': { - 'ignore': 'true', # we don't need to write test cases in Python - }, - '::ns3::TestRunner': { - 'ignore': 'true', # we don't need to write test cases in Python - }, - '::ns3::TestSuite': { - 'ignore': 'true', # we don't need to write test cases in Python - }, - - } - -def get_ns3_relative_path(path): - l = [] - head = path - while head: - head, tail = os.path.split(head) - if tail == 'ns3': - return os.path.join(*l) - l.insert(0, tail) - raise AssertionError("is the path %r inside ns3?!" % path) - - -def pre_scan_hook(dummy_module_parser, - pygccxml_definition, - global_annotations, - parameter_annotations): - ns3_header = get_ns3_relative_path(pygccxml_definition.location.file_name) - - ## Note: we don't include line numbers in the comments because - ## those numbers are very likely to change frequently, which would - ## cause needless changes, since the generated python files are - ## kept under version control. - - #global_annotations['pygen_comment'] = "%s:%i: %s" % \ - # (ns3_header, pygccxml_definition.location.line, pygccxml_definition) - global_annotations['pygen_comment'] = "%s: %s" % \ - (ns3_header, pygccxml_definition) - - - ## handle ns3::Object::GetObject (left to its own devices, - ## pybindgen will generate a mangled name containing the template - ## argument type name). - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Object' \ - and pygccxml_definition.name == 'GetObject': - template_args = templates.args(pygccxml_definition.demangled_name) - if template_args == ['ns3::Object']: - global_annotations['template_instance_names'] = 'ns3::Object=>GetObject' - - ## Don't wrap Simulator::Schedule* (manually wrapped) - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Simulator' \ - and pygccxml_definition.name.startswith('Schedule'): - global_annotations['ignore'] = None - - # manually wrapped - if isinstance(pygccxml_definition, member_function_t) \ - and pygccxml_definition.parent.name == 'Simulator' \ - and pygccxml_definition.name == 'Run': - global_annotations['ignore'] = True - - ## http://www.gccxml.org/Bug/view.php?id=9915 - if isinstance(pygccxml_definition, calldef_t): - for arg in pygccxml_definition.arguments: - if arg.default_value is None: - continue - if "ns3::MilliSeconds( )" == arg.default_value: - arg.default_value = "ns3::MilliSeconds(0)" - if "ns3::Seconds( )" == arg.default_value: - arg.default_value = "ns3::Seconds(0)" - - ## classes - if isinstance(pygccxml_definition, class_t): - # no need for helper classes to allow subclassing in Python, I think... - #if pygccxml_definition.name.endswith('Helper'): - # global_annotations['allow_subclassing'] = 'false' - - if pygccxml_definition.decl_string.startswith('::ns3::SimpleRefCount<'): - global_annotations['incref_method'] = 'Ref' - global_annotations['decref_method'] = 'Unref' - global_annotations['peekref_method'] = 'GetReferenceCount' - global_annotations['automatic_type_narrowing'] = 'true' - return - - if pygccxml_definition.decl_string.startswith('::ns3::Callback<'): - # manually handled in ns3modulegen_core_customizations.py - global_annotations['ignore'] = None - return - - if pygccxml_definition.decl_string.startswith('::ns3::TracedCallback<'): - global_annotations['ignore'] = None - return - - if pygccxml_definition.decl_string.startswith('::ns3::Ptr<'): - # handled by pybindgen "type transformation" - global_annotations['ignore'] = None - return - - # table driven class customization - try: - annotations = type_annotations[pygccxml_definition.decl_string] - except KeyError: - pass - else: - global_annotations.update(annotations) - - ## free functions - if isinstance(pygccxml_definition, free_function_t): - if pygccxml_definition.name == 'PeekPointer': - global_annotations['ignore'] = None - return - - ## table driven methods/constructors/functions customization - if isinstance(pygccxml_definition, (free_function_t, member_function_t, constructor_t)): - try: - annotations = type_annotations[str(pygccxml_definition)] - except KeyError: - pass - else: - for key,value in annotations.items(): - if key == 'params': - parameter_annotations.update (value) - del annotations['params'] - global_annotations.update(annotations) - - -# def post_scan_hook(dummy_module_parser, dummy_pygccxml_definition, pybindgen_wrapper): -# ## classes -# if isinstance(pybindgen_wrapper, CppClass): -# if pybindgen_wrapper.name.endswith('Checker'): -# print >> sys.stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", pybindgen_wrapper -# #pybindgen_wrapper.set_instance_creation_function(AttributeChecker_instance_creation_function) - - -def scan_callback_classes(module_parser, callback_classes_file): - callback_classes_file.write("callback_classes = [\n") - for cls in module_parser.module_namespace.classes(function=module_parser.location_filter, - recursive=False): - if not cls.name.startswith("Callback<"): - continue - assert templates.is_instantiation(cls.decl_string), "%s is not a template instantiation" % cls - dummy_cls_name, template_parameters = templates.split(cls.decl_string) - callback_classes_file.write(" %r,\n" % template_parameters) - callback_classes_file.write("]\n") - - -class MyPygenClassifier(PygenClassifier): - def __init__(self, headers_map, section_precendences): - self.headers_map = headers_map - self.section_precendences = section_precendences - - def classify(self, pygccxml_definition): - name = os.path.basename(pygccxml_definition.location.file_name) - try: - return self.headers_map[name] - except KeyError: - return '__main__' - - def get_section_precedence(self, section_name): - if section_name == '__main__': - return -1 - return self.section_precendences[section_name] - - -def ns3_module_scan(top_builddir, pygen_file_name, everything_h, cflags): - - ns3_modules = eval(sys.stdin.readline()) - - ## do a topological sort on the modules graph - from topsort import topsort - graph = [] - module_names = ns3_modules.keys() - module_names.sort() - for ns3_module_name in module_names: - ns3_module_deps = list(ns3_modules[ns3_module_name][0]) - ns3_module_deps.sort() - for dep in ns3_module_deps: - graph.append((dep, ns3_module_name)) - sorted_ns3_modules = topsort(graph) - #print >> sys.stderr, "******* topological sort: ", sorted_ns3_modules - - sections = [PygenSection('__main__', FileCodeSink(open(pygen_file_name, "wt")))] - headers_map = {} # header_name -> section_name - section_precendences = {} # section_name -> precedence - for prec, ns3_module in enumerate(sorted_ns3_modules): - section_name = "ns3_module_%s" % ns3_module.replace('-', '_') - file_name = os.path.join(os.path.dirname(pygen_file_name), "%s.py" % section_name) - sections.append(PygenSection(section_name, FileCodeSink(open(file_name, "wt")), - section_name + "__local")) - for header in ns3_modules[ns3_module][1]: - headers_map[header] = section_name - section_precendences[section_name] = prec - - module_parser = ModuleParser('ns3', 'ns3') - - module_parser.add_pre_scan_hook(pre_scan_hook) - #module_parser.add_post_scan_hook(post_scan_hook) - - gccxml_options = dict( - include_paths=[top_builddir], - define_symbols={ - #'NS3_ASSERT_ENABLE': None, - #'NS3_LOG_ENABLE': None, - }, - cflags=('--gccxml-cxxflags "%s -DPYTHON_SCAN"' % cflags) - ) - - module_parser.parse_init([everything_h], - None, whitelist_paths=[top_builddir, os.path.dirname(everything_h)], - #includes=['"ns3/everything.h"'], - pygen_sink=sections, - pygen_classifier=MyPygenClassifier(headers_map, section_precendences), - gccxml_options=gccxml_options) - module_parser.scan_types() - - callback_classes_file = open(os.path.join(os.path.dirname(pygen_file_name), "callbacks_list.py"), "wt") - scan_callback_classes(module_parser, callback_classes_file) - callback_classes_file.close() - - - module_parser.scan_methods() - module_parser.scan_functions() - module_parser.parse_finalize() - - for section in sections: - section.code_sink.file.close() - - - -if __name__ == '__main__': - ns3_module_scan(sys.argv[1], sys.argv[3], sys.argv[2], sys.argv[4]) - diff --git a/bindings/python/ns__init__.py b/bindings/python/ns__init__.py index 8b1378917..ead3e767f 100644 --- a/bindings/python/ns__init__.py +++ b/bindings/python/ns__init__.py @@ -1 +1,218 @@ +import builtins +import os.path +import sys +import re +def find_ns3_directory(): + # Get the absolute path to this file + path_to_this_init_file = os.path.dirname(os.path.abspath(__file__)) + path_to_lock = path_to_this_init_file + lock_file = (".lock-ns3_%s_build" % sys.platform) + + # Go back and scan each folder until the c4che folder is found + found = False + while not found: + for f in os.listdir(path_to_lock): + # Skip files + if not os.path.isfile(f): + continue + # Search for lock + if lock_file in f: + path_to_lock += os.sep + f + found = True + break + if found: + break + + # Move to the directory above if we haven't found it yet + old_path = path_to_lock + path_to_lock = os.path.dirname(path_to_lock) + + # We give up if we can't move to the directory above + if path_to_lock == old_path: + raise Exception("ns-3 lock file firectory was not found.\n" + "Are you sure %s is inside your ns-3 directory?" % path_to_this_init_file) + return path_to_lock + + +def load_modules(ns3_directory): + # Load NS3_ENABLED_MODULES from _cache.py file inside the build directory + values = {} + + exec(open(find_ns3_directory()).read(), {}, values) + suffix = "-" + values["BUILD_PROFILE"] if values["BUILD_PROFILE"] != "release" else "" + required_modules = [module.replace("ns3-", "") for module in values["NS3_ENABLED_MODULES"]] + ns3_output_directory = values["out_dir"] + libraries = {x.split(".")[0]: x for x in os.listdir(os.path.join(ns3_output_directory, "lib"))} + + import cppyy + + # Enable full logs for debugging + # cppyy.set_debug(True) + + # Register Ptr<> as a smart pointer + import libcppyy + libcppyy.AddSmartPtrType('Ptr') + + # Import ns-3 libraries + cppyy.add_library_path("%s/lib" % ns3_output_directory) + cppyy.add_include_path("%s/include" % ns3_output_directory) + + for module in required_modules: + cppyy.include("ns3/%s-module.h" % module) + + for module in required_modules: + library_name = "libns{version}-{module}{suffix}".format( + version=values["VERSION"], + module=module, + suffix=suffix + ) + if library_name not in libraries: + raise Exception("Missing library %s\n" % library_name, + "Build all modules with './ns3 build'" + ) + cppyy.load_library(libraries[library_name]) + + # We expose cppyy to consumers of this module as ns.cppyy + setattr(cppyy.gbl.ns3, "cppyy", cppyy) + + # To maintain compatibility with pybindgen scripts, + # we set an attribute per module that just redirects to the upper object + for module in required_modules: + setattr(cppyy.gbl.ns3, module.replace("-", "_"), cppyy.gbl.ns3) + + # Setup a few tricks + cppyy.cppdef(""" + using namespace ns3; + bool Time_ge(Time& a, Time& b){ return a >= b;} + bool Time_eq(Time& a, Time& b){ return a == b;} + bool Time_ne(Time& a, Time& b){ return a != b;} + bool Time_le(Time& a, Time& b){ return a <= b;} + bool Time_gt(Time& a, Time& b){ return a > b;} + bool Time_lt(Time& a, Time& b){ return a < b;} + """) + cppyy.gbl.ns3.Time.__ge__ = cppyy.gbl.Time_ge + cppyy.gbl.ns3.Time.__eq__ = cppyy.gbl.Time_eq + cppyy.gbl.ns3.Time.__ne__ = cppyy.gbl.Time_ne + cppyy.gbl.ns3.Time.__le__ = cppyy.gbl.Time_le + cppyy.gbl.ns3.Time.__gt__ = cppyy.gbl.Time_gt + cppyy.gbl.ns3.Time.__lt__ = cppyy.gbl.Time_lt + + # Node::~Node isn't supposed to destroy the object, + # since it gets destroyed at the end of the simulation + # we need to hold the reference until it gets destroyed by C++ + # + # Search for NodeList::Add (this) + cppyy.gbl.ns3.__nodes_pending_deletion = [] + def Nodedel(self: cppyy.gbl.ns3.Node) -> None: + cppyy.gbl.ns3.__nodes_pending_deletion.append(self) + return None + cppyy.gbl.ns3.Node.__del__ = Nodedel + + # Define ns.cppyy.gbl.addressFromIpv4Address and others + cppyy.cppdef("""using namespace ns3; + Address addressFromIpv4Address(Ipv4Address ip){ return Address(ip); }; + Address addressFromInetSocketAddress(InetSocketAddress addr){ return Address(addr); }; + Address addressFromPacketSocketAddress(PacketSocketAddress addr){ return Address(addr); }; + """) + # Expose addressFromIpv4Address as a member of the ns3 namespace (equivalent to ns) + setattr(cppyy.gbl.ns3, "addressFromIpv4Address", cppyy.gbl.addressFromIpv4Address) + setattr(cppyy.gbl.ns3, "addressFromInetSocketAddress", cppyy.gbl.addressFromInetSocketAddress) + setattr(cppyy.gbl.ns3, "addressFromPacketSocketAddress", cppyy.gbl.addressFromPacketSocketAddress) + cppyy.cppdef( + """using namespace ns3; CommandLine& getCommandLine(std::string filename){ static CommandLine g_cmd = CommandLine(filename); return g_cmd; };""") + setattr(cppyy.gbl.ns3, "getCommandLine", cppyy.gbl.getCommandLine) + cppyy.cppdef( + """using namespace ns3; template Callback ns3::MakeNullCallback(void);""") + cppyy.cppdef( + """using namespace ns3; Callback null_callback(){ return MakeNullCallback(); };""") + setattr(cppyy.gbl.ns3, "null_callback", cppyy.gbl.null_callback) + #cppyy.cppdef( + # """using namespace ns3; template Ptr getAggregatedObject(Ptr parentPtr, T param)) + # { + # return parentPtr->GetObject(); + # } + # """ + #) + cppyy.cppdef(""" + using namespace ns3; + std::tuple LookupByNameFailSafe(std::string name) + { + TypeId id; + bool ok = TypeId::LookupByNameFailSafe(name, &id); + return std::make_tuple(ok, id); + } + """) + setattr(cppyy.gbl.ns3, "LookupByNameFailSafe", cppyy.gbl.LookupByNameFailSafe) + def CreateObject(className): + try: + try: + func = "CreateObject%s" % re.sub('[<|>]', '_', className) + return getattr(cppyy.gbl, func)() + except AttributeError: + pass + try: + func = "Create%s" % re.sub('[<|>]', '_', className) + return getattr(cppyy.gbl, func)() + except AttributeError: + pass + raise AttributeError + except AttributeError: + try: + func = "CreateObject%s" % re.sub('[<|>]', '_', className) + cppyy.cppdef(""" + using namespace ns3; + Ptr<%s> %s(){ + Ptr<%s> object = CreateObject<%s>(); + return object; + } + """ % (className, func, className, className) + ) + except Exception as e: + try: + func = "Create%s" % re.sub('[<|>]', '_', className) + cppyy.cppdef(""" + using namespace ns3; + %s %s(){ + %s object = %s(); + return object; + } + """ % (className, func, className, className) + ) + except Exception as e: + exit(-1) + return getattr(cppyy.gbl, func)() + setattr(cppyy.gbl.ns3, "CreateObject", CreateObject) + + def GetObject(parentObject, aggregatedObject): + # Objects have __cpp_name__ attributes, so parentObject + # should not have it while aggregatedObject can + if hasattr(parentObject, "__cpp_name__"): + raise Exception("Class was passed instead of an instance in parentObject") + + aggregatedIsClass = hasattr(aggregatedObject, "__cpp_name__") + aggregatedIsString = type(aggregatedObject) == str + aggregatedIsInstance = not aggregatedIsClass and not aggregatedIsString + + if aggregatedIsClass: + aggregatedType = aggregatedObject.__cpp_name__ + if aggregatedIsInstance: + aggregatedType = aggregatedObject.__class__.__cpp_name__ + if aggregatedIsString: + aggregatedType = aggregatedObject + + cppyy.cppdef( + """using namespace ns3; template <> Ptr<%s> getAggregatedObject<%s>(Ptr parentPtr, %s param) + { + return parentPtr->GetObject<%s>(); + } + """ % (aggregatedType, aggregatedType, aggregatedType, aggregatedType) + ) + return cppyy.gbl.getAggregatedObject(parentObject, aggregatedObject if aggregatedIsClass else aggregatedObject.__class__) + setattr(cppyy.gbl.ns3, "GetObject", GetObject) + return cppyy.gbl.ns3 + + +# Load all modules and make them available via a built-in +ns = load_modules(find_ns3_directory()) # can be imported via 'from ns import ns' +builtins.__dict__['ns'] = ns # or be made widely available with 'from ns import *' diff --git a/bindings/python/rad_util.py b/bindings/python/rad_util.py deleted file mode 100644 index 96aa23a80..000000000 --- a/bindings/python/rad_util.py +++ /dev/null @@ -1,909 +0,0 @@ -# Copyright (c) 2007 RADLogic -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. -"""Provide various handy Python functions. - -Running this script directly will execute the doctests. - -Functions: -int2bin(i, n) -- Convert integer to binary string. -bin2int(bin_string) -- Convert binary string to integer. -reverse(input_string) -- Reverse a string. -transpose(matrix) -- Transpose a list of lists. -polygon_area(points_list) -- Calculate the area of an arbitrary polygon. -timestamp() -- Return string containing current time stamp. -pt2str(point) -- Return prettier string version of point tuple. -gcf(a, b) -- Return the greatest common factor of two numbers. -lcm(a, b) -- Return the least common multiple of two numbers. -permutations(input_list) -- Generate all permutations of a list of items. -reduce_fraction(fraction) -- Reduce fraction (num, denom) to simplest form. -quantile(l, p) -- Return p quantile of list l. E.g. p=0.25 for q1. -trim(l) -- Discard values in list more than 1.5*IQR outside IQR. -nice_units(value) -- Return value converted to human readable units. -uniquify(seq) -- Return sequence with duplicate items in sequence seq removed. -reverse_dict(d) -- Return the dictionary with the items as keys and vice-versa. -lsb(x, n) -- Return the n least significant bits of x. -gray_encode(i) -- Gray encode the given integer. -random_vec(bits, max_value=None) -- Return a random binary vector. -binary_range(bits) -- Return list of all possible binary numbers width=bits. -float_range([start], stop, [step]) -- Return range of floats. -find_common_fixes(s1, s2) -- Find common (prefix, suffix) of two strings. -is_rotated(seq1, seq2) -- Return true if the list is a rotation of other list. -getmodule(obj) -- Return the module that contains the object definition of obj. - (use inspect.getmodule instead, though) -get_args(argv) -- Store command-line args in a dictionary. - -This module requires Python >= 2.2 - -""" -__author__ = 'Tim Wegener ' -__date__ = '$Date: 2007/03/27 03:15:06 $' -__version__ = '$Revision: 0.45 $' -__credits__ = """ - David Chandler, for polygon area algorithm. - (https://web.archive.org/web/20091104151838/http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf) - """ - -import re -import sys -import time -import random - -try: - True, False -except NameError: - True, False = (1==1, 0==1) - - -def int2bin(i, n): - """Convert decimal integer i to n-bit binary number (string). - - >>> int2bin(0, 8) - '00000000' - - >>> int2bin(123, 8) - '01111011' - - >>> int2bin(123L, 8) - '01111011' - - >>> int2bin(15, 2) - Traceback (most recent call last): - ValueError: Value too large for given number of bits. - - """ - hex2bin = {'0': '0000', '1': '0001', '2': '0010', '3': '0011', - '4': '0100', '5': '0101', '6': '0110', '7': '0111', - '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', - 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111'} - # Convert to hex then map each hex digit to binary equivalent. - result = ''.join([hex2bin[x] for x in hex(i).lower().replace('l','')[2:]]) - - # Shrink result to appropriate length. - # Raise an error if the value is changed by the truncation. - if '1' in result[:-n]: - raise ValueError("Value too large for given number of bits.") - result = result[-n:] - # Zero-pad if length longer than mapped result. - result = '0'*(n-len(result)) + result - return result - - -def bin2int(bin_string): - """Convert binary number string to decimal integer. - - Note: Python > v2 has int(bin_string, 2) - - >>> bin2int('1111') - 15 - - >>> bin2int('0101') - 5 - - """ -## result = 0 -## bin_list = list(bin_string) -## if len(filter(lambda x: x in ('1','0'), bin_list)) < len(bin_list): -## raise Exception ("bin2int: Error - not a binary number: %s" -## % bin_string) -## bit_list = map(int, bin_list) -## bit_list.reverse() # Make most significant bit have highest index. -## for bit_place in range(len(bit_list)): -## result = result + ((2**bit_place) * bit_list[bit_place]) -## return result - return int(bin_string, 2) - - -def reverse(input_string): - """Reverse a string. Useful for strings of binary numbers. - - >>> reverse('abc') - 'cba' - - """ - str_list = list(input_string) - str_list.reverse() - return ''.join(str_list) - - -def transpose(matrix): - """Transpose a list of lists. - - >>> transpose([['a', 'b', 'c'], ['d', 'e', 'f'], ['g', 'h', 'i']]) - [['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f', 'i']] - - >>> transpose([['a', 'b', 'c'], ['d', 'e', 'f']]) - [['a', 'd'], ['b', 'e'], ['c', 'f']] - - >>> transpose([['a', 'b'], ['d', 'e'], ['g', 'h']]) - [['a', 'd', 'g'], ['b', 'e', 'h']] - - """ - result = zip(*matrix) - # Convert list of tuples to list of lists. - # map is faster than a list comprehension since it is being used with - # a built-in function as an argument. - result = map(list, result) - return result - - -def polygon_area(points_list, precision=100): - """Calculate area of an arbitrary polygon using an algorithm from the web. - - Return the area of the polygon as a positive float. - - Arguments: - points_list -- list of point tuples [(x0, y0), (x1, y1), (x2, y2), ...] - (Unclosed polygons will be closed automatically. - precision -- Internal arithmetic precision (integer arithmetic). - - >>> polygon_area([(0, 0), (0, 1), (1, 1), (1, 2), (2, 2), (2, 0), (0, 0)]) - 3.0 - - Credits: - Area of a General Polygon by David Chandler - https://web.archive.org/web/20091104151838/http://www.davidchandler.com/AreaOfAGeneralPolygon.pdf - - """ - # Scale up co-ordinates and convert them to integers. - for i in range(len(points_list)): - points_list[i] = (int(points_list[i][0] * precision), - int(points_list[i][1] * precision)) - # Close polygon if not closed. - if points_list[-1] != points_list[0]: - points_list.append(points_list[0]) - # Calculate area. - area = 0 - for i in range(len(points_list)-1): - (x_i, y_i) = points_list[i] - (x_i_plus_1, y_i_plus_1) = points_list[i+1] - area = area + (x_i_plus_1 * y_i) - (y_i_plus_1 * x_i) - area = abs(area / 2) - # Unscale area. - area = float(area)/(precision**2) - return area - - -def timestamp(): - """Return string containing current time stamp. - - Note: In Python 2 onwards can use time.asctime() with no arguments. - - """ - - return time.asctime() - - -def pt2str(point): - """Return prettier string version of point tuple. - - >>> pt2str((1.8, 1.9)) - '(1.8, 1.9)' - - """ - return "(%s, %s)" % (str(point[0]), str(point[1])) - - -def gcf(a, b, epsilon=1e-16): - """Return the greatest common factor of a and b, using Euclidean algorithm. - - Arguments: - a, b -- two numbers - If both numbers are integers return an integer result, - otherwise return a float result. - epsilon -- floats less than this magnitude are considered to be zero - (default: 1e-16) - - Examples: - - >>> gcf(12, 34) - 2 - - >>> gcf(13.5, 4) - 0.5 - - >>> gcf(-2, 4) - 2 - - >>> gcf(5, 0) - 5 - - By (a convenient) definition: - >>> gcf(0, 0) - 0 - - """ - result = max(a, b) - remainder = min(a, b) - while remainder and abs(remainder) > epsilon: - new_remainder = result % remainder - result = remainder - remainder = new_remainder - return abs(result) - -def lcm(a, b, precision=None): - """Return the least common multiple of a and b, using the gcf function. - - Arguments: - a, b -- two numbers. If both are integers return an integer result, - otherwise a return a float result. - precision -- scaling factor if a and/or b are floats. - - >>> lcm(21, 6) - 42 - - >>> lcm(2.5, 3.5) - 17.5 - - >>> str(lcm(1.5e-8, 2.5e-8, precision=1e9)) - '7.5e-08' - - By (an arbitrary) definition: - >>> lcm(0, 0) - 0 - - """ - # Note: Dummy precision argument is for backwards compatibility. - # Do the division first. - # (See https://en.wikipedia.org/wiki/Least_common_multiple ) - denom = gcf(a, b) - if denom == 0: - result = 0 - else: - result = a * (b / denom) - return result - - -def permutations(input_list): - """Return a list containing all permutations of the input list. - - Note: This is a recursive function. - - >>> perms = permutations(['a', 'b', 'c']) - >>> perms.sort() - >>> for perm in perms: - ... print perm - ['a', 'b', 'c'] - ['a', 'c', 'b'] - ['b', 'a', 'c'] - ['b', 'c', 'a'] - ['c', 'a', 'b'] - ['c', 'b', 'a'] - - """ - out_lists = [] - if len(input_list) > 1: - # Extract first item in list. - item = input_list[0] - # Find all permutations of remainder of list. (Recursive call.) - sub_lists = permutations(input_list[1:]) - # For every permutation of the sub list... - for sub_list in sub_lists: - # Insert the extracted first item at every position of the list. - for i in range(len(input_list)): - new_list = sub_list[:] - new_list.insert(i, item) - out_lists.append(new_list) - else: - # Termination condition: only one item in input list. - out_lists = [input_list] - return out_lists - - -def reduce_fraction(fraction): - """Reduce fraction tuple to simplest form. fraction=(num, denom) - - >>> reduce_fraction((14, 7)) - (2, 1) - - >>> reduce_fraction((-2, 4)) - (-1, 2) - - >>> reduce_fraction((0, 4)) - (0, 1) - - >>> reduce_fraction((4, 0)) - (1, 0) - - """ - (numerator, denominator) = fraction - common_factor = abs(gcf(numerator, denominator)) - result = (numerator/common_factor, denominator/common_factor) - return result - - -def quantile(l, p): - """Return p quantile of list l. E.g. p=0.25 for q1. - - See: - https://www.rdocumentation.org/packages/stats/versions/3.6.2/topics/quantile - - """ - l_sort = l[:] - l_sort.sort() - n = len(l) - r = 1 + ((n - 1) * p) - i = int(r) - f = r - i - if i < n: - result = (1-f)*l_sort[i-1] + f*l_sort[i] - else: - result = l_sort[i-1] - return result - - -def trim(l): - """Discard values in list more than 1.5*IQR outside IQR. - - (IQR is inter-quartile-range) - - This function uses rad_util.quantile - - 1.5*IQR -- mild outlier - 3*IQR -- extreme outlier - - See: - http://wind.cc.whecn.edu/~pwildman/statnew/section_7_-_exploratory_data_analysis.htm - - """ - l_sort = l[:] - l_sort.sort() - # Calculate medianscore (based on stats.py lmedianscore by Gary Strangman) - if len(l_sort) % 2 == 0: - # If even number of scores, average middle 2. - index = int(len(l_sort) / 2) # Integer division correct - median = float(l_sort[index] + l_sort[index-1]) / 2 - else: - # int division gives mid value when count from 0 - index = int(len(l_sort) / 2) - median = l_sort[index] - # Calculate IQR. - q1 = quantile(l_sort, 0.25) - q3 = quantile(l_sort, 0.75) - iqr = q3 - q1 - iqr_extra = iqr * 1.5 - def in_interval(x, i=iqr_extra, q1=q1, q3=q3): - return (x >= q1-i and x <= q3+i) - l_trimmed = [x for x in l_sort if in_interval(x)] - return l_trimmed - - -def nice_units(value, dp=0, sigfigs=None, suffix='', space=' ', - use_extra_prefixes=False, use_full_name=False, mode='si'): - """Return value converted to human readable units eg milli, micro, etc. - - Arguments: - value -- number in base units - dp -- number of decimal places to display (rounded) - sigfigs -- number of significant figures to display (rounded) - This overrides dp if set. - suffix -- optional unit suffix to append to unit multiplier - space -- separator between value and unit multiplier (default: ' ') - use_extra_prefixes -- use hecto, deka, deci and centi as well if set. - (default: False) - use_full_name -- use full name for multiplier symbol, - e.g. milli instead of m - (default: False) - mode -- 'si' for SI prefixes, 'bin' for binary multipliers (1024, etc.) - (Default: 'si') - - SI prefixes from: - http://physics.nist.gov/cuu/Units/prefixes.html - (Greek mu changed to u.) - Binary prefixes based on: - http://physics.nist.gov/cuu/Units/binary.html - - >>> nice_units(2e-11) - '20 p' - - >>> nice_units(2e-11, space='') - '20p' - - """ - si_prefixes = {1e24: ('Y', 'yotta'), - 1e21: ('Z', 'zetta'), - 1e18: ('E', 'exa'), - 1e15: ('P', 'peta'), - 1e12: ('T', 'tera'), - 1e9: ('G', 'giga'), - 1e6: ('M', 'mega'), - 1e3: ('k', 'kilo'), - 1e-3: ('m', 'milli'), - 1e-6: ('u', 'micro'), - 1e-9: ('n', 'nano'), - 1e-12: ('p', 'pico'), - 1e-15: ('f', 'femto'), - 1e-18: ('a', 'atto'), - 1e-21: ('z', 'zepto'), - 1e-24: ('y', 'yocto') - } - if use_extra_prefixes: - si_prefixes.update({1e2: ('h', 'hecto'), - 1e1: ('da', 'deka'), - 1e-1: ('d', 'deci'), - 1e-2: ('c', 'centi') - }) - bin_prefixes = {2**10: ('K', 'kilo'), - 2**20: ('M', 'mega'), - 2**30: ('G', 'mega'), - 2**40: ('T', 'tera'), - 2**50: ('P', 'peta'), - 2**60: ('E', 'exa') - } - if mode == 'bin': - prefixes = bin_prefixes - else: - prefixes = si_prefixes - prefixes[1] = ('', '') # Unity. - # Determine appropriate multiplier. - multipliers = prefixes.keys() - multipliers.sort() - mult = None - for i in range(len(multipliers) - 1): - lower_mult = multipliers[i] - upper_mult = multipliers[i+1] - if lower_mult <= value < upper_mult: - mult_i = i - break - if mult is None: - if value < multipliers[0]: - mult_i = 0 - elif value >= multipliers[-1]: - mult_i = len(multipliers) - 1 - mult = multipliers[mult_i] - # Convert value for this multiplier. - new_value = value / mult - # Deal with special case due to rounding. - if sigfigs is None: - if mult_i < (len(multipliers) - 1) and \ - round(new_value, dp) == \ - round((multipliers[mult_i+1] / mult), dp): - mult = multipliers[mult_i + 1] - new_value = value / mult - # Concatenate multiplier symbol. - if use_full_name: - label_type = 1 - else: - label_type = 0 - # Round and truncate to appropriate precision. - if sigfigs is None: - str_value = eval('"%.'+str(dp)+'f" % new_value', locals(), {}) - else: - str_value = eval('"%.'+str(sigfigs)+'g" % new_value', locals(), {}) - return str_value + space + prefixes[mult][label_type] + suffix - - -def uniquify(seq, preserve_order=False): - """Return sequence with duplicate items in sequence seq removed. - - The code is based on usenet post by Tim Peters. - - This code is O(N) if the sequence items are hashable, O(N**2) if not. - - Peter Bengtsson has a blog post with an empirical comparison of other - approaches: - http://www.peterbe.com/plog/uniqifiers-benchmark - - If order is not important and the sequence items are hashable then - list(set(seq)) is readable and efficient. - - If order is important and the sequence items are hashable generator - expressions can be used (in py >= 2.4) (useful for large sequences): - seen = set() - do_something(x for x in seq if x not in seen or seen.add(x)) - - Arguments: - seq -- sequence - preserve_order -- if not set the order will be arbitrary - Using this option will incur a speed penalty. - (default: False) - - Example showing order preservation: - - >>> uniquify(['a', 'aa', 'b', 'b', 'ccc', 'ccc', 'd'], preserve_order=True) - ['a', 'aa', 'b', 'ccc', 'd'] - - Example using a sequence of un-hashable items: - - >>> uniquify([['z'], ['x'], ['y'], ['z']], preserve_order=True) - [['z'], ['x'], ['y']] - - The sorted output or the non-order-preserving approach should equal - that of the sorted order-preserving approach output: - - >>> unordered = uniquify([3, 3, 1, 2], preserve_order=False) - >>> unordered.sort() - >>> ordered = uniquify([3, 3, 1, 2], preserve_order=True) - >>> ordered.sort() - >>> ordered - [1, 2, 3] - >>> int(ordered == unordered) - 1 - - """ - try: - # Attempt fast algorithm. - d = {} - if preserve_order: - # This is based on Dave Kirby's method (f8) noted in the post: - # http://www.peterbe.com/plog/uniqifiers-benchmark - return [x for x in seq if (x not in d) and not d.__setitem__(x, 0)] - else: - for x in seq: - d[x] = 0 - return d.keys() - except TypeError: - # Have an unhashable object, so use slow algorithm. - result = [] - app = result.append - for x in seq: - if x not in result: - app(x) - return result - -# Alias to noun form for backward compatibility. -unique = uniquify - - -def reverse_dict(d): - """Reverse a dictionary so the items become the keys and vice-versa. - - Note: The results will be arbitrary if the items are not unique. - - >>> d = reverse_dict({'a': 1, 'b': 2}) - >>> d_items = d.items() - >>> d_items.sort() - >>> d_items - [(1, 'a'), (2, 'b')] - - """ - result = {} - for key, value in d.items(): - result[value] = key - return result - - -def lsb(x, n): - """Return the n least significant bits of x. - - >>> lsb(13, 3) - 5 - - """ - return x & ((2 ** n) - 1) - - -def gray_encode(i): - """Gray encode the given integer.""" - - return i ^ (i >> 1) - - -def random_vec(bits, max_value=None): - """Generate a random binary vector of length bits and given max value.""" - - vector = "" - for _ in range(int(bits / 10) + 1): - i = int((2**10) * random.random()) - vector += int2bin(i, 10) - - if max_value and (max_value < 2 ** bits - 1): - vector = int2bin((int(vector, 2) / (2 ** bits - 1)) * max_value, bits) - - return vector[0:bits] - - -def binary_range(bits): - """Return a list of all possible binary numbers in order with width=bits. - - It would be nice to extend it to match the - functionality of python's range() built-in function. - - """ - l = [] - v = ['0'] * bits - - toggle = [1] + [0] * bits - - while toggle[bits] != 1: - v_copy = v[:] - v_copy.reverse() - l.append(''.join(v_copy)) - - toggle = [1] + [0]*bits - i = 0 - while i < bits and toggle[i] == 1: - if toggle[i]: - if v[i] == '0': - v[i] = '1' - toggle[i+1] = 0 - else: - v[i] = '0' - toggle[i+1] = 1 - i += 1 - return l - - -def float_range(start, stop=None, step=None): - """Return a list containing an arithmetic progression of floats. - - Return a list of floats between 0.0 (or start) and stop with an - increment of step. - - This is in functionality to python's range() built-in function - but can accept float increments. - - As with range(), stop is omitted from the list. - - """ - if stop is None: - stop = float(start) - start = 0.0 - - if step is None: - step = 1.0 - - cur = float(start) - l = [] - while cur < stop: - l.append(cur) - cur += step - - return l - - -def find_common_fixes(s1, s2): - """Find common (prefix, suffix) of two strings. - - >>> find_common_fixes('abc', 'def') - ('', '') - - >>> find_common_fixes('abcelephantdef', 'abccowdef') - ('abc', 'def') - - >>> find_common_fixes('abcelephantdef', 'abccow') - ('abc', '') - - >>> find_common_fixes('elephantdef', 'abccowdef') - ('', 'def') - - """ - prefix = [] - suffix = [] - - i = 0 - common_len = min(len(s1), len(s2)) - while i < common_len: - if s1[i] != s2[i]: - break - - prefix.append(s1[i]) - i += 1 - - i = 1 - while i < (common_len + 1): - if s1[-i] != s2[-i]: - break - - suffix.append(s1[-i]) - i += 1 - - suffix.reverse() - - prefix = ''.join(prefix) - suffix = ''.join(suffix) - - return (prefix, suffix) - - -def is_rotated(seq1, seq2): - """Return true if the first sequence is a rotation of the second sequence. - - >>> seq1 = ['A', 'B', 'C', 'D'] - >>> seq2 = ['C', 'D', 'A', 'B'] - >>> int(is_rotated(seq1, seq2)) - 1 - - >>> seq2 = ['C', 'D', 'B', 'A'] - >>> int(is_rotated(seq1, seq2)) - 0 - - >>> seq1 = ['A', 'B', 'C', 'A'] - >>> seq2 = ['A', 'A', 'B', 'C'] - >>> int(is_rotated(seq1, seq2)) - 1 - - >>> seq2 = ['A', 'B', 'C', 'A'] - >>> int(is_rotated(seq1, seq2)) - 1 - - >>> seq2 = ['A', 'A', 'C', 'B'] - >>> int(is_rotated(seq1, seq2)) - 0 - - """ - # Do a sanity check. - if len(seq1) != len(seq2): - return False - # Look for occurrences of second sequence head item in first sequence. - start_indexes = [] - head_item = seq2[0] - for index1 in range(len(seq1)): - if seq1[index1] == head_item: - start_indexes.append(index1) - # Check that wrapped sequence matches. - double_seq1 = seq1 + seq1 - for index1 in start_indexes: - if double_seq1[index1:index1+len(seq1)] == seq2: - return True - return False - -def getmodule(obj): - """Return the module that contains the object definition of obj. - - Note: Use inspect.getmodule instead. - - Arguments: - obj -- python obj, generally a class or a function - - Examples: - - A function: - >>> module = getmodule(random.choice) - >>> module.__name__ - 'random' - >>> module is random - 1 - - A class: - >>> module = getmodule(random.Random) - >>> module.__name__ - 'random' - >>> module is random - 1 - - A class inheriting from a class in another module: - (note: The inheriting class must define at least one function.) - >>> class MyRandom(random.Random): - ... def play(self): - ... pass - >>> module = getmodule(MyRandom) - >>> if __name__ == '__main__': - ... name = 'rad_util' - ... else: - ... name = module.__name__ - >>> name - 'rad_util' - >>> module is sys.modules[__name__] - 1 - - Discussion: - This approach is slightly hackish, and won't work in various situations. - However, this was the approach recommended by GvR, so it's as good as - you'll get. - - See GvR's post in this thread: - http://groups.google.com.au/group/comp.lang.python/browse_thread/thread/966a7bdee07e3b34/c3cab3f41ea84236?lnk=st&q=python+determine+class+module&rnum=4&hl=en#c3cab3f41ea84236 - - """ - if hasattr(obj, 'func_globals'): - func = obj - else: - # Handle classes. - func = None - for item in obj.__dict__.values(): - if hasattr(item, 'func_globals'): - func = item - break - if func is None: - raise ValueError("No functions attached to object: %r" % obj) - module_name = func.func_globals['__name__'] - # Get module. - module = sys.modules[module_name] - return module - - -def round_grid(value, grid, mode=0): - """Round off the given value to the given grid size. - - Arguments: - value -- value to be roudne - grid -- result must be a multiple of this - mode -- 0 nearest, 1 up, -1 down - - Examples: - - >>> round_grid(7.5, 5) - 10 - - >>> round_grid(7.5, 5, mode=-1) - 5 - - >>> round_grid(7.3, 5, mode=1) - 10 - - >>> round_grid(7.3, 5.0, mode=1) - 10.0 - - """ - off_grid = value % grid - if mode == 0: - add_one = int(off_grid >= (grid / 2.0)) - elif mode == 1 and off_grid: - add_one = 1 - elif mode == -1 and off_grid: - add_one = 0 - result = ((int(value / grid) + add_one) * grid) - return result - - -def get_args(argv): - """Store command-line args in a dictionary. - - -, -- prefixes are removed - Items not prefixed with - or -- are stored as a list, indexed by 'args' - - For options that take a value use --option=value - - Consider using optparse or getopt (in Python standard library) instead. - - """ - d = {} - args = [] - - for arg in argv: - - if arg.startswith('-'): - parts = re.sub(r'^-+', '', arg).split('=') - if len(parts) == 2: - d[parts[0]] = parts[1] - else: - d[parts[0]] = None - else: - args.append(arg) - - d['args'] = args - - return d - - -if __name__ == '__main__': - import doctest - doctest.testmod(sys.modules['__main__']) - diff --git a/bindings/python/topsort.py b/bindings/python/topsort.py deleted file mode 100644 index 370f39f88..000000000 --- a/bindings/python/topsort.py +++ /dev/null @@ -1,392 +0,0 @@ -# topsort - dependency (topological) sorting and cycle finding functions -# Copyright (C) 2007 RADLogic -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; -# version 2.1 of the License. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# See https://www.fsf.org/licensing/licenses/lgpl.txt for full license text. -"""Provide toplogical sorting (i.e. dependency sorting) functions. - -The topsort function is based on code posted on Usenet by Tim Peters. - -Modifications: -- added doctests -- changed some bits to use current Python idioms - (listcomp instead of filter, +=/-=, inherit from Exception) -- added a topsort_levels version that ports items in each dependency level - into a sub-list -- added find_cycles to aid in cycle debugging - -Run this module directly to run the doctests (unittests). -Make sure they all pass before checking in any modifications. - -Requires Python >= 2.2 -(For Python 2.2 also requires separate sets.py module) - -This requires the rad_util.py module. - -""" - -# Provide support for Python 2.2* -from __future__ import generators - -__version__ = '$Revision: 0.9 $' -__date__ = '$Date: 2007/03/27 04:15:26 $' -__credits__ = '''Tim Peters -- original topsort code -Tim Wegener -- doctesting, updating to current idioms, topsort_levels, - find_cycles -''' - -# Make Python 2.3 sets look like Python 2.4 sets. -try: - set -except NameError: - from sets import Set as set - -from rad_util import is_rotated - - -class CycleError(Exception): - """Cycle Error""" - pass - - -def topsort(pairlist): - """Topologically sort a list of (parent, child) pairs. - - Return a list of the elements in dependency order (parent to child order). - - >>> print topsort( [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)] ) - [1, 2, 3, 5, 4, 6] - - >>> print topsort( [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)] ) - [1, 2, 3, 4, 5, 6] - - >>> print topsort( [(1,2), (2,3), (3,2)] ) - Traceback (most recent call last): - CycleError: ([1], {2: 1, 3: 1}, {2: [3], 3: [2]}) - - """ - num_parents = {} # element -> # of predecessors - children = {} # element -> list of successors - for parent, child in pairlist: - # Make sure every element is a key in num_parents. - if not num_parents.has_key( parent ): - num_parents[parent] = 0 - if not num_parents.has_key( child ): - num_parents[child] = 0 - - # Since child has a parent, increment child's num_parents count. - num_parents[child] += 1 - - # ... and parent gains a child. - children.setdefault(parent, []).append(child) - - # Suck up everything without a parent. - answer = [x for x in num_parents.keys() if num_parents[x] == 0] - - # For everything in answer, knock down the parent count on its children. - # Note that answer grows *in* the loop. - for parent in answer: - del num_parents[parent] - if children.has_key( parent ): - for child in children[parent]: - num_parents[child] -= 1 - if num_parents[child] == 0: - answer.append( child ) - # Following "del" isn't needed; just makes - # CycleError details easier to grasp. - del children[parent] - - if num_parents: - # Everything in num_parents has at least one child -> - # there's a cycle. - raise CycleError(answer, num_parents, children) - return answer - -def topsort_levels(pairlist): - """Topologically sort a list of (parent, child) pairs into depth levels. - - This returns a generator. - Turn this into a an iterator using the iter built-in function. - (if you iterate over the iterator, each element gets generated when - it is asked for, rather than generating the whole list up-front.) - - Each generated element is a list of items at that dependency level. - - >>> dependency_pairs = [(1,2), (3,4), (5,6), (1,3), (1,5), (1,6), (2,5)] - >>> for level in iter(topsort_levels( dependency_pairs )): - ... print level - [1] - [2, 3] - [4, 5] - [6] - - >>> dependency_pairs = [(1,2), (1,3), (2,4), (3,4), (5,6), (4,5)] - >>> for level in iter(topsort_levels( dependency_pairs )): - ... print level - [1] - [2, 3] - [4] - [5] - [6] - - >>> dependency_pairs = [(1,2), (2,3), (3,4), (4, 3)] - >>> try: - ... for level in iter(topsort_levels( dependency_pairs )): - ... print level - ... except CycleError, exc: - ... print 'CycleError:', exc - [1] - [2] - CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]}) - - - The cycle error should look like. - CycleError: ({3: 1, 4: 1}, {3: [4], 4: [3]}) - # todo: Make the doctest more robust (i.e. handle arbitrary dict order). - - """ - num_parents = {} # element -> # of predecessors - children = {} # element -> list of successors - for parent, child in pairlist: - # Make sure every element is a key in num_parents. - if not num_parents.has_key( parent ): - num_parents[parent] = 0 - if not num_parents.has_key( child ): - num_parents[child] = 0 - - # Since child has a parent, increment child's num_parents count. - num_parents[child] += 1 - - # ... and parent gains a child. - children.setdefault(parent, []).append(child) - - return topsort_levels_core(num_parents, children) - -def topsort_levels_core(num_parents, children): - """Topologically sort a bunch of interdependent items based on dependency. - - This returns a generator. - Turn this into a an iterator using the iter built-in function. - (if you iterate over the iterator, each element gets generated when - it is asked for, rather than generating the whole list up-front.) - - Each generated element is a list of items at that dependency level. - - >>> list(topsort_levels_core( - ... {1: 0, 2: 1, 3: 1, 4: 1, 5: 2, 6: 2}, - ... {1: [2, 3, 5, 6], 2: [5], 3: [4], 4: [], 5: [6]})) - [[1], [2, 3], [4, 5], [6]] - - >>> list(topsort_levels_core( - ... {1: 0, 2: 2, 3: 1}, - ... {1: [2], 2: [3], 3: [2]})) - Traceback (most recent call last): - CycleError: ({2: 1, 3: 1}, {2: [3], 3: [2]}) - - This function has a more complicated interface than topsort_levels, - but is useful if the data is easier to generate in this form. - - Arguments: - num_parents -- key: item, value: number of parents (predecessors) - children -- key: item, value: list of children (successors) - - """ - while 1: - # Suck up everything without a predecessor. - level_parents = [x for x in num_parents.keys() if num_parents[x] == 0] - - if not level_parents: - break - - # Offer the next generated item, - # which is a list of the items at this dependency level. - yield level_parents - - # For everything item in this level, - # decrement the parent count, - # since we have accounted for its parent. - for level_parent in level_parents: - - del num_parents[level_parent] - - if children.has_key(level_parent): - for level_parent_child in children[level_parent]: - num_parents[level_parent_child] -= 1 - del children[level_parent] - - if num_parents: - # Everything in num_parents has at least one child -> - # there's a cycle. - raise CycleError(num_parents, children) - else: - # This is the end of the generator. - raise StopIteration - - -def find_cycles(parent_children): - """Yield cycles. Each result is a list of items comprising a cycle. - - Use a 'stack' based approach to find all the cycles. - This is a generator, so yields each cycle as it finds it. - - It is implicit that the last item in each cycle list is a parent of the - first item (thereby forming a cycle). - - Arguments: - parent_children -- parent -> collection of children - - Simplest cycle: - >>> cycles = list(find_cycles({'A': ['B'], 'B': ['A']})) - >>> len(cycles) - 1 - >>> cycle = cycles[0] - >>> cycle.sort() - >>> print cycle - ['A', 'B'] - - Simplest cycle with extra baggage at the start and the end: - >>> cycles = list(find_cycles(parent_children={'A': ['B'], - ... 'B': ['C'], - ... 'C': ['B', 'D'], - ... 'D': [], - ... })) - >>> len(cycles) - 1 - >>> cycle = cycles[0] - >>> cycle.sort() - >>> print cycle - ['B', 'C'] - - Double cycle: - >>> cycles = list(find_cycles(parent_children={'A': ['B'], - ... 'B': ['C1', 'C2'], - ... 'C1': ['D1'], - ... 'D1': ['E1'], - ... 'E1': ['D1'], - ... 'C2': ['D2'], - ... 'D2': ['E2'], - ... 'E2': ['D2'], - ... })) - >>> len(cycles) - 2 - >>> for cycle in cycles: - ... cycle.sort() - >>> cycles.sort() - >>> cycle1 = cycles[0] - >>> cycle1.sort() - >>> print cycle1 - ['D1', 'E1'] - >>> cycle2 = cycles[1] - >>> cycle2.sort() - >>> print cycle2 - ['D2', 'E2'] - - Simple cycle with children not specified for one item: - # todo: Should this barf instead? - >>> cycles = list(find_cycles(parent_children={'A': ['B'], - ... 'B': ['A'], - ... 'C': ['D']})) - >>> len(cycles) - 1 - >>> cycle = cycles[0] - >>> cycle.sort() - >>> print cycle - ['A', 'B'] - - Diamond cycle - >>> cycles = list(find_cycles(parent_children={'A': ['B1', 'B2'], - ... 'B1': ['C'], - ... 'B2': ['C'], - ... 'C': ['A', 'B1']})) - >>> len(cycles) - 3 - >>> sorted_cycles = [] - >>> for cycle in cycles: - ... cycle = list(cycle) - ... cycle.sort() - ... sorted_cycles.append(cycle) - >>> sorted_cycles.sort() - >>> for cycle in sorted_cycles: - ... print cycle - ['A', 'B1', 'C'] - ['A', 'B2', 'C'] - ['B1', 'C'] - - Hairy case (order can matter if something is wrong): - (Note order of B and C in the list.) - >>> cycles = list(find_cycles(parent_children={ - ... 'TD': ['DD'], - ... 'TC': ['DC'], - ... 'DC': ['DQ'], - ... 'C': ['DQ'], - ... 'DQ': ['IA', 'TO'], - ... 'IA': ['A'], - ... 'A': ['B', 'C'], - ... })) - >>> len(cycles) - 1 - >>> cycle = cycles[0] - >>> cycle.sort() - >>> print cycle - ['A', 'C', 'DQ', 'IA'] - - """ - cycles = [] - visited_nodes = set() - - for parent in parent_children: - if parent in visited_nodes: - # This node is part of a path that has already been traversed. - continue - - paths = [[parent]] - while paths: - path = paths.pop() - - parent = path[-1] - - try: - children = parent_children[parent] - except KeyError: - continue - - for child in children: - # Keeping a set of the path nodes, for O(1) lookups at the - # expense of more memory and complexity, actually makes speed - # worse. (Due to construction of sets.) - # This is O(N). - if child in path: - # This is a cycle. - cycle = path[path.index(child):] - # Check that this is not a dup cycle. - is_dup = False - for other_cycle in cycles: - if is_rotated(other_cycle, cycle): - is_dup = True - break - if not is_dup: - cycles.append(cycle) - yield cycle - else: - # Push this new path onto the 'stack'. - # This is probably the most expensive part of the algorithm - # (a list copy). - paths.append(path + [child]) - # Mark the node as visited. - visited_nodes.add(child) - - -if __name__ == '__main__': - # Run the doctest tests. - import sys - import doctest - doctest.testmod(sys.modules['__main__']) diff --git a/build-support/custom-modules/ns3-configtable.cmake b/build-support/custom-modules/ns3-configtable.cmake index cf0a41ab2..2b754ec2a 100644 --- a/build-support/custom-modules/ns3-configtable.cmake +++ b/build-support/custom-modules/ns3-configtable.cmake @@ -160,11 +160,6 @@ macro(write_configtable) string(APPEND out "PyViz visualizer : ") check_on_or_off("${NS3_VISUALIZER}" "${ENABLE_VISUALIZER}") - string(APPEND out "Python API Scanning Support : ") - check_on_or_off( - "${NS3_SCAN_PYTHON_BINDINGS}" "${ENABLE_SCAN_PYTHON_BINDINGS}" - ) - string(APPEND out "Python Bindings : ") check_on_or_off("${NS3_PYTHON_BINDINGS}" "${ENABLE_PYTHON_BINDINGS}") diff --git a/build-support/custom-modules/ns3-lock.cmake b/build-support/custom-modules/ns3-lock.cmake index f8f77a3db..19fdfa122 100644 --- a/build-support/custom-modules/ns3-lock.cmake +++ b/build-support/custom-modules/ns3-lock.cmake @@ -69,9 +69,6 @@ function(write_lock) cache_cmake_flag(NS3_BRITE "ENABLE_BRITE" lock_contents) cache_cmake_flag(NS3_ENABLE_SUDO "ENABLE_SUDO" lock_contents) cache_cmake_flag(NS3_PYTHON_BINDINGS "ENABLE_PYTHON_BINDINGS" lock_contents) - cache_cmake_flag( - NS3_SCAN_PYTHON_BINDINGS "ENABLE_SCAN_PYTHON_BINDINGS" lock_contents - ) string(APPEND lock_contents "EXAMPLE_DIRECTORIES = [") foreach(example_folder ${ns3-example-folders}) diff --git a/build-support/custom-modules/ns3-module-macros.cmake b/build-support/custom-modules/ns3-module-macros.cmake index 3616678a6..272a247e8 100644 --- a/build-support/custom-modules/ns3-module-macros.cmake +++ b/build-support/custom-modules/ns3-module-macros.cmake @@ -276,198 +276,6 @@ function(build_lib) endif() endforeach() - # Get architecture pair for python bindings - if((${CMAKE_SIZEOF_VOID_P} EQUAL 8) AND (NOT APPLE)) - set(arch gcc_LP64) - set(arch_flags -m64) - else() - set(arch gcc_ILP32) - set(arch_flags) - endif() - - # Add target to scan python bindings - if(${ENABLE_SCAN_PYTHON_BINDINGS} - AND (EXISTS ${CMAKE_HEADER_OUTPUT_DIRECTORY}/${BLIB_LIBNAME}-module.h) - AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bindings") - ) - set(bindings_output_folder ${PROJECT_SOURCE_DIR}/${FOLDER}/bindings) - file(MAKE_DIRECTORY ${bindings_output_folder}) - set(module_api_ILP32 ${bindings_output_folder}/modulegen__gcc_ILP32.py) - set(module_api_LP64 ${bindings_output_folder}/modulegen__gcc_LP64.py) - - set(modulescan_modular_command - ${Python3_EXECUTABLE} - ${PROJECT_SOURCE_DIR}/bindings/python/ns3modulescan-modular.py - ) - - set(header_map "") - # We need a python map that takes header.h to module e.g. "ptr.h": "core" - foreach(header ${BLIB_HEADER_FILES}) - # header is a relative path to the current working directory - get_filename_component( - header_name ${CMAKE_CURRENT_SOURCE_DIR}/${header} NAME - ) - string(APPEND header_map "\"${header_name}\":\"${BLIB_LIBNAME}\",") - endforeach() - - set(ns3-headers-to-module-map "${ns3-headers-to-module-map}${header_map}" - CACHE INTERNAL "Map connecting headers to their modules" - ) - - # API scan needs the include directories to find a few headers (e.g. mpi.h) - get_target_includes(${lib${BLIB_LIBNAME}} modulegen_include_dirs) - - set(module_to_generate_api ${module_api_ILP32}) - set(LP64toILP32) - if("${arch}" STREQUAL "gcc_LP64") - set(module_to_generate_api ${module_api_LP64}) - set(LP64toILP32 - ${Python3_EXECUTABLE} - ${PROJECT_SOURCE_DIR}/build-support/pybindings-LP64-to-ILP32.py - ${module_api_LP64} ${module_api_ILP32} - ) - endif() - - add_custom_target( - ${lib${BLIB_LIBNAME}}-apiscan - COMMAND - ${modulescan_modular_command} ${CMAKE_OUTPUT_DIRECTORY} ${BLIB_LIBNAME} - ${PROJECT_BINARY_DIR}/header_map.json ${module_to_generate_api} - \"${arch_flags} ${modulegen_include_dirs}\" 2> - ${bindings_output_folder}/apiscan.log - COMMAND ${LP64toILP32} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - DEPENDS ${lib${BLIB_LIBNAME}} - ) - add_dependencies(apiscan-all ${lib${BLIB_LIBNAME}}-apiscan) - endif() - - # Build pybindings if requested and if bindings subfolder exists in - # NS3/src/BLIB_LIBNAME - if(${ENABLE_PYTHON_BINDINGS} AND (EXISTS - "${CMAKE_CURRENT_SOURCE_DIR}/bindings") - ) - set(bindings_output_folder ${CMAKE_OUTPUT_DIRECTORY}/${FOLDER}/bindings) - file(MAKE_DIRECTORY ${bindings_output_folder}) - set(module_src ${bindings_output_folder}/ns3module.cc) - set(module_hdr ${bindings_output_folder}/ns3module.h) - - string(REPLACE "-" "_" BLIB_LIBNAME_sub ${BLIB_LIBNAME}) # '-' causes - # problems (e.g. - # csma-layout), replace with '_' (e.g. csma_layout) - - # Set prefix of binding to _ if a ${BLIB_LIBNAME}.py exists, and copy the - # ${BLIB_LIBNAME}.py to the output folder - set(prefix) - if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/bindings/${BLIB_LIBNAME}.py) - set(prefix _) - file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/bindings/${BLIB_LIBNAME}.py - DESTINATION ${CMAKE_OUTPUT_DIRECTORY}/bindings/python/ns - ) - endif() - - # Run modulegen-modular to generate the bindings sources - if((NOT EXISTS ${module_hdr}) OR (NOT EXISTS ${module_src})) # OR TRUE) # to - # force - # reprocessing - string(REPLACE ";" "," ENABLED_FEATURES - "${ns3-libs};${BLIB_MODULE_ENABLED_FEATURES}" - ) - set(modulegen_modular_command - GCC_RTTI_ABI_COMPLETE=True NS3_ENABLED_FEATURES="${ENABLED_FEATURES}" - ${Python3_EXECUTABLE} - ${PROJECT_SOURCE_DIR}/bindings/python/ns3modulegen-modular.py - ) - execute_process( - COMMAND - ${CMAKE_COMMAND} -E env - PYTHONPATH=${CMAKE_OUTPUT_DIRECTORY}:$ENV{PYTHONPATH} - ${modulegen_modular_command} ${CMAKE_CURRENT_SOURCE_DIR} ${arch} - ${prefix}${BLIB_LIBNAME_sub} ${module_src} - TIMEOUT 60 - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_FILE ${module_hdr} - ERROR_FILE ${bindings_output_folder}/ns3modulegen.log - RESULT_VARIABLE error_code - ) - if(${error_code} OR NOT (EXISTS ${module_hdr})) - # Delete broken bindings to make sure we will his this error again if - # nothing changed - if(EXISTS ${module_src}) - file(REMOVE ${module_src}) - endif() - if(EXISTS ${module_hdr}) - file(REMOVE ${module_hdr}) - endif() - message( - FATAL_ERROR - "Something went wrong during processing of the python bindings of module ${BLIB_LIBNAME}." - " Make sure you have the latest version of Pybindgen." - ) - endif() - endif() - - # Add core module helper sources - set(python_module_files ${module_hdr} ${module_src}) - file(GLOB custom_python_module_files - ${CMAKE_CURRENT_SOURCE_DIR}/bindings/*.cc - ${CMAKE_CURRENT_SOURCE_DIR}/bindings/*.h - ) - list(APPEND python_module_files ${custom_python_module_files}) - set(bindings-name lib${BLIB_LIBNAME}-bindings) - add_library(${bindings-name} SHARED "${python_module_files}") - target_include_directories( - ${bindings-name} PUBLIC ${Python3_INCLUDE_DIRS} ${bindings_output_folder} - ) - - # If there is any, remove the "lib" prefix of libraries (search for - # "set(lib${BLIB_LIBNAME}") - list(LENGTH ns_libraries_to_link num_libraries) - if(num_libraries GREATER "0") - string(REPLACE ";" "-bindings;" bindings_to_link - "${ns_libraries_to_link};" - ) # add -bindings suffix to all lib${name} - endif() - target_link_libraries( - ${bindings-name} - PUBLIC ${LIB_AS_NEEDED_PRE} ${lib${BLIB_LIBNAME}} "${bindings_to_link}" - "${BLIB_LIBRARIES_TO_LINK}" ${LIB_AS_NEEDED_POST} - PRIVATE ${Python3_LIBRARIES} - ) - target_include_directories( - ${bindings-name} PRIVATE ${PROJECT_SOURCE_DIR}/src/core/bindings - ) - - set(suffix) - if(APPLE) - # Python doesn't like Apple's .dylib and will refuse to load bindings - # unless its an .so - set(suffix SUFFIX .so) - endif() - - # Set binding library name and output folder - set_target_properties( - ${bindings-name} - PROPERTIES OUTPUT_NAME ${prefix}${BLIB_LIBNAME_sub} - PREFIX "" - ${suffix} LIBRARY_OUTPUT_DIRECTORY - ${CMAKE_OUTPUT_DIRECTORY}/bindings/python/ns - ) - - set(ns3-python-bindings-modules - "${bindings-name};${ns3-python-bindings-modules}" - CACHE INTERNAL "list of modules python bindings" - ) - - # Make sure all bindings are built before building the visualizer module - # that makes use of them - if(${ENABLE_VISUALIZER} AND (visualizer IN_LIST libs_to_build)) - if(NOT (${BLIB_LIBNAME} STREQUAL visualizer)) - add_dependencies(${libvisualizer} ${bindings-name}) - endif() - endif() - endif() - # Handle package export install( TARGETS ${lib${BLIB_LIBNAME}} diff --git a/build-support/macros-and-definitions.cmake b/build-support/macros-and-definitions.cmake index 224096de5..aaff4c81e 100644 --- a/build-support/macros-and-definitions.cmake +++ b/build-support/macros-and-definitions.cmake @@ -766,15 +766,15 @@ macro(process_options) if(${NS3_PYTHON_BINDINGS}) if(NOT ${Python3_FOUND}) message( - FATAL_ERROR - "Bindings: python bindings require Python, but it could not be found" + ${HIGHLIGHTED_STATUS} + "Bindings: python bindings require Python, but it could not be found" ) else() - check_python_packages("pybindgen" missing_packages) + check_python_packages("cppyy" missing_packages) if(missing_packages) message( - FATAL_ERROR - "Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}" + ${HIGHLIGHTED_STATUS} + "Bindings: python bindings disabled due to the following missing dependencies: ${missing_packages}" ) else() set(ENABLE_PYTHON_BINDINGS ON) @@ -794,44 +794,6 @@ macro(process_options) add_compile_options(-Wno-potentially-evaluated-expression) endif() - set(ENABLE_SCAN_PYTHON_BINDINGS OFF) - if(${NS3_SCAN_PYTHON_BINDINGS}) - if(NOT ${Python3_FOUND}) - message( - FATAL_ERROR - "Bindings: scanning python bindings require Python, but it could not be found" - ) - else() - # Check if pybindgen, pygccxml, cxxfilt and castxml are installed - check_python_packages( - "pybindgen;pygccxml;cxxfilt;castxml" missing_packages - ) - - # If castxml has not been found via python import, fallback to searching - # the binary - if(castxml IN_LIST missing_packages) - mark_as_advanced(CASTXML) - find_program(CASTXML castxml) - if(NOT ("${CASTXML}" STREQUAL "CASTXML-NOTFOUND")) - list(REMOVE_ITEM missing_packages castxml) - endif() - endif() - - # If packages were not found, print message - if(missing_packages) - message( - FATAL_ERROR - "Bindings: scanning of python bindings disabled due to the following missing dependencies: ${missing_packages}" - ) - else() - set(ENABLE_SCAN_PYTHON_BINDINGS ON) - # empty scan target that will depend on other module scan targets to - # scan all of them - add_custom_target(apiscan-all) - endif() - endif() - endif() - set(ENABLE_VISUALIZER FALSE) if(${NS3_VISUALIZER}) if((NOT ${ENABLE_PYTHON_BINDINGS}) OR (NOT ${Python3_FOUND})) @@ -2079,20 +2041,6 @@ function(find_external_library) endif() endfunction() -function(write_header_to_modules_map) - if(${ENABLE_SCAN_PYTHON_BINDINGS}) - set(header_map ${ns3-headers-to-module-map}) - - # Trim last comma - string(LENGTH "${header_map}" header_map_len) - math(EXPR header_map_len "${header_map_len}-1") - string(SUBSTRING "${header_map}" 0 ${header_map_len} header_map) - - # Then write to header_map.json for consumption of pybindgen - file(WRITE ${PROJECT_BINARY_DIR}/header_map.json "{${header_map}}") - endif() -endfunction() - function(get_target_includes target output) set(include_directories) get_target_property(include_dirs ${target} INCLUDE_DIRECTORIES) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 224711434..1eb795c5c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -13,6 +13,7 @@ if(${ENABLE_EXAMPLES}) CACHE INTERNAL "list of example folders" ) endforeach() + scan_python_examples(${CMAKE_CURRENT_SOURCE_DIR}) endif() scan_python_examples(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/examples/realtime/realtime-udp-echo.py b/examples/realtime/realtime-udp-echo.py index d09f7f5f5..dc094ee1b 100644 --- a/examples/realtime/realtime-udp-echo.py +++ b/examples/realtime/realtime-udp-echo.py @@ -23,11 +23,7 @@ # - DropTail queues # - Tracing of queues and packet receptions to file "udp-echo.tr" -import ns.applications -import ns.core -import ns.csma -import ns.internet -import ns.network +from ns import ns def main(argv): # @@ -89,7 +85,7 @@ def main(argv): packetSize = 1024 maxPacketCount = 500 interPacketInterval = ns.core.Seconds(0.01) - client = ns.applications.UdpEchoClientHelper(i.GetAddress (1), port) + client = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(i.GetAddress (1)), port) client.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount)) client.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval)) client.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize)) @@ -105,6 +101,7 @@ def main(argv): # Now, do the actual simulation. # print ("Run Simulation.") + ns.core.Simulator.Stop(ns.Seconds(10)) ns.core.Simulator.Run() ns.core.Simulator.Destroy() print ("Done.") diff --git a/examples/routing/simple-routing-ping6.py b/examples/routing/simple-routing-ping6.py index cb48d40bc..aa5952e5b 100644 --- a/examples/routing/simple-routing-ping6.py +++ b/examples/routing/simple-routing-ping6.py @@ -27,86 +27,77 @@ # router # -import ns.internet_apps -import ns.core -import ns.csma -import ns.internet -import ns.network +from ns import ns + def main(argv): + cmd = ns.CommandLine() - cmd = ns.core.CommandLine(); - - cmd.Parse(argv); + cmd.Parse(argv) # Create nodes - print ("Create nodes") - n0 = ns.network.Node(); - r = ns.network.Node(); - n1 = ns.network.Node(); + print("Create nodes") - net1 = ns.network.NodeContainer(); - net1.Add(n0); - net1.Add(r); - net2 = ns.network.NodeContainer(); - net2.Add(r); - net2.Add(n1); - all = ns.network.NodeContainer(); - all.Add(n0); - all.Add(r); - all.Add(n1); + all = ns.NodeContainer(3) + net1 = ns.NodeContainer() + net1.Add(all.Get(0)) + net1.Add(all.Get(1)) + net2 = ns.NodeContainer() + net2.Add(all.Get(1)) + net2.Add(all.Get(2)) # Create IPv6 Internet Stack - internetv6 = ns.internet.InternetStackHelper(); - internetv6.Install(all); + internetv6 = ns.InternetStackHelper() + internetv6.Install(all) # Create channels - csma = ns.csma.CsmaHelper(); - csma.SetChannelAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate(5000000))); - csma.SetChannelAttribute("Delay", ns.core.TimeValue(ns.core.MilliSeconds(2))); - d1 = csma.Install(net1); - d2 = csma.Install(net2); + csma = ns.csma.CsmaHelper() + csma.SetChannelAttribute("DataRate", ns.DataRateValue(ns.DataRate(5000000))) + csma.SetChannelAttribute("Delay", ns.TimeValue(ns.MilliSeconds(2))) + d1 = csma.Install(net1) + d2 = csma.Install(net2) # Create networks and assign IPv6 Addresses - print ("Addressing") - ipv6 = ns.internet.Ipv6AddressHelper(); - ipv6.SetBase(ns.network.Ipv6Address("2001:1::"), ns.network.Ipv6Prefix(64)); - i1 = ipv6.Assign(d1); - i1.SetForwarding(1, True); - i1.SetDefaultRouteInAllNodes(1); - ipv6.SetBase(ns.network.Ipv6Address("2001:2::"), ns.network.Ipv6Prefix(64)); - i2 = ipv6.Assign(d2); - i2.SetForwarding(0, True); - i2.SetDefaultRouteInAllNodes(0); + print("Addressing") + ipv6 = ns.Ipv6AddressHelper() + ipv6.SetBase(ns.Ipv6Address("2001:1::"), ns.Ipv6Prefix(64)) + i1 = ipv6.Assign(d1) + i1.SetForwarding(1, True) + i1.SetDefaultRouteInAllNodes(1) + ipv6.SetBase(ns.Ipv6Address("2001:2::"), ns.Ipv6Prefix(64)) + i2 = ipv6.Assign(d2) + i2.SetForwarding(0, True) + i2.SetDefaultRouteInAllNodes(0) # Create a Ping6 application to send ICMPv6 echo request from n0 to n1 via r - print ("Application") - packetSize = 1024; - maxPacketCount = 5; - interPacketInterval = ns.core.Seconds(1.); - ping6 = ns.internet_apps.Ping6Helper(); + print("Application") + packetSize = 1024 + maxPacketCount = 5 + interPacketInterval = ns.Seconds(1.) + ping6 = ns.Ping6Helper() - ping6.SetLocal(i1.GetAddress(0, 1)); - ping6.SetRemote(i2.GetAddress(1, 1)); + ping6.SetLocal(i1.GetAddress(0, 1)) + ping6.SetRemote(i2.GetAddress(1, 1)) - ping6.SetAttribute("MaxPackets", ns.core.UintegerValue(maxPacketCount)); - ping6.SetAttribute("Interval", ns.core.TimeValue(interPacketInterval)); - ping6.SetAttribute("PacketSize", ns.core.UintegerValue(packetSize)); + ping6.SetAttribute("MaxPackets", ns.UintegerValue(maxPacketCount)) + ping6.SetAttribute("Interval", ns.TimeValue(interPacketInterval)) + ping6.SetAttribute("PacketSize", ns.UintegerValue(packetSize)) - apps = ping6.Install(ns.network.NodeContainer(net1.Get(0))); - apps.Start(ns.core.Seconds(2.0)); - apps.Stop(ns.core.Seconds(20.0)); + apps = ping6.Install(ns.NodeContainer(net1.Get(0))) + apps.Start(ns.Seconds(2.0)) + apps.Stop(ns.Seconds(20.0)) - print ("Tracing") - ascii = ns.network.AsciiTraceHelper() + print("Tracing") + ascii = ns.AsciiTraceHelper() csma.EnableAsciiAll(ascii.CreateFileStream("simple-routing-ping6.tr")) csma.EnablePcapAll("simple-routing-ping6", True) # Run Simulation - ns.core.Simulator.Run() - ns.core.Simulator.Destroy() + ns.Simulator.Run() + ns.Simulator.Destroy() + if __name__ == '__main__': import sys - main(sys.argv) + main(sys.argv) diff --git a/examples/tutorial/first.py b/examples/tutorial/first.py index 22dff9e8a..bfa194711 100644 --- a/examples/tutorial/first.py +++ b/examples/tutorial/first.py @@ -13,11 +13,7 @@ # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # */ -import ns.applications -import ns.core -import ns.internet -import ns.network -import ns.point_to_point +from ns import ns # // Default Network Topology # // @@ -53,7 +49,8 @@ serverApps = echoServer.Install(nodes.Get(1)) serverApps.Start(ns.core.Seconds(1.0)) serverApps.Stop(ns.core.Seconds(10.0)) -echoClient = ns.applications.UdpEchoClientHelper(interfaces.GetAddress(1), 9) +address = ns.addressFromIpv4Address(interfaces.GetAddress(1)) +echoClient = ns.applications.UdpEchoClientHelper(address, 9) echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1)) echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds(1.0))) echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024)) diff --git a/examples/tutorial/second.py b/examples/tutorial/second.py index 8d6e7662a..e499efe89 100644 --- a/examples/tutorial/second.py +++ b/examples/tutorial/second.py @@ -16,12 +16,7 @@ # * Ported to Python by Mohit P. Tahiliani # */ -import ns.core -import ns.network -import ns.csma -import ns.internet -import ns.point_to_point -import ns.applications +from ns import ns import sys # // Default Network Topology @@ -31,21 +26,30 @@ import sys # // point-to-point | | | | # // ================ # // LAN 10.1.2.0 +ns.cppyy.cppdef(""" +using namespace ns3; -cmd = ns.core.CommandLine() -cmd.nCsma = 3 -cmd.verbose = "True" -cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices") -cmd.AddValue("verbose", "Tell echo applications to log if true") +CommandLine& GetCommandLine(std::string filename, int& nCsma, bool& verbose) +{ + static CommandLine cmd = CommandLine(filename); + cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", nCsma); + cmd.AddValue("verbose", "Tell echo applications to log if true", verbose); + return cmd; +} +""") +from ctypes import c_int, c_bool +nCsma = c_int(3) +verbose = c_bool(True) +cmd = ns.cppyy.gbl.GetCommandLine(__file__, nCsma, verbose) cmd.Parse(sys.argv) -nCsma = int(cmd.nCsma) -verbose = cmd.verbose +nCsma = nCsma.value +verbose = verbose.value if verbose == "True": ns.core.LogComponentEnable("UdpEchoClientApplication", ns.core.LOG_LEVEL_INFO) ns.core.LogComponentEnable("UdpEchoServerApplication", ns.core.LOG_LEVEL_INFO) -nCsma = 1 if int(nCsma) == 0 else int(nCsma) +nCsma = 1 if nCsma == 0 else nCsma p2pNodes = ns.network.NodeContainer() p2pNodes.Create(2) @@ -83,7 +87,7 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma)) serverApps.Start(ns.core.Seconds(1.0)) serverApps.Stop(ns.core.Seconds(10.0)) -echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma), 9) +echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9) echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1)) echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0))) echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024)) diff --git a/examples/tutorial/third.py b/examples/tutorial/third.py index 4e00ac979..b7e6f7f0b 100644 --- a/examples/tutorial/third.py +++ b/examples/tutorial/third.py @@ -16,14 +16,7 @@ # * Ported to Python by Mohit P. Tahiliani # */ -import ns.core -import ns.network -import ns.point_to_point -import ns.applications -import ns.wifi -import ns.mobility -import ns.csma -import ns.internet +from ns import ns import sys # // Default Network Topology @@ -37,23 +30,21 @@ import sys # // ================ # // LAN 10.1.2.0 -cmd = ns.core.CommandLine() -cmd.nCsma = 3 -cmd.verbose = "True" -cmd.nWifi = 3 -cmd.tracing = "False" +cmd = ns.getCommandLine(__file__) +nCsma ="3" +verbose = "True" +nWifi = "3" +tracing = "False" -cmd.AddValue("nCsma", "Number of \"extra\" CSMA nodes/devices") -cmd.AddValue("nWifi", "Number of wifi STA devices") -cmd.AddValue("verbose", "Tell echo applications to log if true") -cmd.AddValue("tracing", "Enable pcap tracing") +cmd.AddValue("nCsma", "Number of extra CSMA nodes/devices", ns.null_callback(), nCsma) +cmd.AddValue("nWifi", "Number of wifi STA devices", ns.null_callback(), nWifi) +cmd.AddValue("verbose", "Tell echo applications to log if true", ns.null_callback(), verbose) +cmd.AddValue("tracing", "Enable pcap tracing", ns.null_callback(), tracing) cmd.Parse(sys.argv) -nCsma = int(cmd.nCsma) -verbose = cmd.verbose -nWifi = int(cmd.nWifi) -tracing = cmd.tracing +nCsma = int(nCsma) +nWifi = int(nWifi) # The underlying restriction of 18 is due to the grid position # allocator's configuration; the grid layout will exceed the @@ -137,7 +128,7 @@ serverApps = echoServer.Install(csmaNodes.Get(nCsma)) serverApps.Start(ns.core.Seconds(1.0)) serverApps.Stop(ns.core.Seconds(10.0)) -echoClient = ns.applications.UdpEchoClientHelper(csmaInterfaces.GetAddress(nCsma), 9) +echoClient = ns.applications.UdpEchoClientHelper(ns.addressFromIpv4Address(csmaInterfaces.GetAddress(nCsma)), 9) echoClient.SetAttribute("MaxPackets", ns.core.UintegerValue(1)) echoClient.SetAttribute("Interval", ns.core.TimeValue(ns.core.Seconds (1.0))) echoClient.SetAttribute("PacketSize", ns.core.UintegerValue(1024)) diff --git a/examples/wireless/mixed-wired-wireless.py b/examples/wireless/mixed-wired-wireless.py index 85e8f432f..76c4b91bb 100644 --- a/examples/wireless/mixed-wired-wireless.py +++ b/examples/wireless/mixed-wired-wireless.py @@ -51,14 +51,7 @@ # +----------------+ +----------------+ # -import ns.applications -import ns.core -import ns.csma -import ns.internet -import ns.mobility -import ns.network -import ns.olsr -import ns.wifi +from ns import ns # # # # This function will be used below as a trace sink @@ -76,11 +69,11 @@ def main(argv): # simulation parameters. # - cmd = ns.core.CommandLine() - cmd.backboneNodes = 10 - cmd.infraNodes = 2 - cmd.lanNodes = 2 - cmd.stopTime = 20 + cmd = ns.getCommandLine(__file__) + cmd.backboneNodes = "10" + cmd.infraNodes = "2" + cmd.lanNodes = "2" + cmd.stopTime = "20" # # Simulation defaults are typically set next, before command line @@ -95,10 +88,10 @@ def main(argv): # "--backboneNodes=20" # - cmd.AddValue("backboneNodes", "number of backbone nodes") - cmd.AddValue("infraNodes", "number of leaf nodes") - cmd.AddValue("lanNodes", "number of LAN nodes") - cmd.AddValue("stopTime", "simulation stop time(seconds)") + cmd.AddValue("backboneNodes", "number of backbone nodes", ns.null_callback(), cmd.backboneNodes) + cmd.AddValue("infraNodes", "number of leaf nodes", ns.null_callback(), cmd.infraNodes) + cmd.AddValue("lanNodes", "number of LAN nodes", ns.null_callback(), cmd.lanNodes) + cmd.AddValue("stopTime", "simulation stop time(seconds)", ns.null_callback(), cmd.stopTime) # # The system global variables and the local values added to the argument @@ -316,19 +309,26 @@ def main(argv): appSource = ns.network.NodeList.GetNode(backboneNodes) lastNodeIndex = backboneNodes + backboneNodes*(lanNodes - 1) + backboneNodes*(infraNodes - 1) - 1 appSink = ns.network.NodeList.GetNode(lastNodeIndex) - # Let's fetch the IP address of the last node, which is on Ipv4Interface 1 - remoteAddr = appSink.GetObject(ns.internet.Ipv4.GetTypeId()).GetAddress(1,0).GetLocal() - onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", - ns.network.Address(ns.network.InetSocketAddress(remoteAddr, port))) + ns.cppyy.cppdef(""" + Ipv4Address getIpv4AddressFromNode(Ptr node){ + return node->GetObject()->GetAddress(1,0).GetLocal(); + } + """) + # Let's fetch the IP address of the last node, which is on Ipv4Interface 1 + remoteAddr = ns.cppyy.gbl.getIpv4AddressFromNode(appSink) + socketAddr = ns.network.InetSocketAddress(remoteAddr, port) + genericAddress = ns.addressFromInetSocketAddress(socketAddr) + onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", genericAddress) apps = onoff.Install(ns.network.NodeContainer(appSource)) apps.Start(ns.core.Seconds(3)) apps.Stop(ns.core.Seconds(stopTime - 1)) # Create a packet sink to receive these packets sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory", - ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port)) - apps = sink.Install(ns.network.NodeContainer(appSink)) + ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port))) + sinkContainer = ns.network.NodeContainer(appSink) + apps = sink.Install(sinkContainer) apps.Start(ns.core.Seconds(3)) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # / @@ -371,7 +371,6 @@ def main(argv): ns.core.Simulator.Run() ns.core.Simulator.Destroy() - if __name__ == '__main__': import sys main(sys.argv) diff --git a/examples/wireless/wifi-ap.py b/examples/wireless/wifi-ap.py index d2fc7f662..58b4fbb0f 100644 --- a/examples/wireless/wifi-ap.py +++ b/examples/wireless/wifi-ap.py @@ -22,13 +22,7 @@ import sys -import ns.applications -import ns.core -import ns.internet -import ns.mobility -import ns.network -import ns.point_to_point -import ns.wifi +from ns import ns # void # DevTxTrace (std::string context, Ptr p, Mac48Address address) @@ -76,23 +70,17 @@ import ns.wifi # std::cout << " start="< node){ + Ptr mob = node->GetObject(); + Vector pos = mob->GetPosition(); + pos.x += 5.0; + if (pos.x >= 210.0) + return; + mob->SetPosition(pos); + Simulator::Schedule(Seconds(1.0), AdvancePosition, node); + }""") def main(argv): ns.core.CommandLine().Parse(argv) @@ -133,14 +121,15 @@ def main(argv): mobility.Install(stas) mobility.Install(ap) - ns.core.Simulator.Schedule(ns.core.Seconds(1.0), AdvancePosition, ap.Get(0)) + ns.core.Simulator.Schedule(ns.core.Seconds(1.0), ns.cppyy.gbl.AdvancePosition, ap.Get(0)) socket = ns.network.PacketSocketAddress() socket.SetSingleDevice(staDevs.Get(0).GetIfIndex()) socket.SetPhysicalAddress(staDevs.Get(1).GetAddress()) socket.SetProtocol(1) - onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", ns.network.Address(socket)) + genericAddress = ns.addressFromPacketSocketAddress(socket) + onoff = ns.applications.OnOffHelper("ns3::PacketSocketFactory", genericAddress) onoff.SetConstantRate (ns.network.DataRate ("500kb/s")) apps = onoff.Install(ns.network.NodeContainer(stas.Get(0))) diff --git a/src/bridge/examples/csma-bridge.py b/src/bridge/examples/csma-bridge.py index 52b4d3372..f1b51b338 100644 --- a/src/bridge/examples/csma-bridge.py +++ b/src/bridge/examples/csma-bridge.py @@ -33,12 +33,7 @@ # Bridge example connecting two broadcast domains. -import ns.applications -import ns.bridge -import ns.core -import ns.csma -import ns.internet -import ns.network +from ns import ns def main(argv): @@ -100,8 +95,9 @@ def main(argv): #print "Create Applications." port = 9 # Discard port(RFC 863) + inet_sock_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port) onoff = ns.applications.OnOffHelper("ns3::UdpSocketFactory", - ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.2"), port))) + ns.network.Address(ns.addressFromInetSocketAddress(inet_sock_address))) onoff.SetConstantRate (ns.network.DataRate ("500kb/s")) app = onoff.Install(ns.network.NodeContainer(terminals.Get(0))) @@ -110,16 +106,18 @@ def main(argv): app.Stop(ns.core.Seconds(10.0)) # Create an optional packet sink to receive these packets + inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port) sink = ns.applications.PacketSinkHelper("ns3::UdpSocketFactory", - ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), port))) + ns.network.Address(ns.addressFromInetSocketAddress(inet_address))) app = sink.Install(ns.network.NodeContainer(terminals.Get(1))) app.Start(ns.core.Seconds(0.0)) # # Create a similar flow from n3 to n0, starting at time 1.1 seconds # + inet_address = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port) onoff.SetAttribute("Remote", - ns.network.AddressValue(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.1.1.1"), port))) + ns.network.AddressValue(ns.addressFromInetSocketAddress(inet_address))) app = onoff.Install(ns.network.NodeContainer(terminals.Get(3))) app.Start(ns.core.Seconds(1.1)) app.Stop(ns.core.Seconds(10.0)) diff --git a/src/core/examples/sample-rng-plot.py b/src/core/examples/sample-rng-plot.py index 88fcd9616..411b3a706 100644 --- a/src/core/examples/sample-rng-plot.py +++ b/src/core/examples/sample-rng-plot.py @@ -25,14 +25,15 @@ import numpy as np import matplotlib.pyplot as plt -import ns.core +from ns import ns # mu, var = 100, 225 ## Random number generator. -rng = ns.core.NormalRandomVariable() -rng.SetAttribute("Mean", ns.core.DoubleValue(100.0)) -rng.SetAttribute("Variance", ns.core.DoubleValue(225.0)) +rng = ns.CreateObject("NormalRandomVariable") +rng.SetAttribute("Mean", ns.DoubleValue(100.0)) +rng.SetAttribute("Variance", ns.DoubleValue(225.0)) + ## Random number samples. x = [rng.GetValue() for t in range(10000)] @@ -40,14 +41,14 @@ x = [rng.GetValue() for t in range(10000)] ## Make a probability density histogram density = 1 -## Plot color +## Plot color facecolor='g' ## Plot alpha value (transparency) alpha=0.75 # We don't really need the plot results, we're just going to show it later. # n, bins, patches = plt.hist(x, 50, density=1, facecolor='g', alpha=0.75) -plt.hist(x, 50, density=1, facecolor='g', alpha=0.75) +n, bins, patches = plt.hist(x, 50, density=True, facecolor='g', alpha=0.75) plt.title('ns-3 histogram') plt.text(60, .025, r'$\mu=100,\ \sigma=15$') diff --git a/src/core/examples/sample-simulator.py b/src/core/examples/sample-simulator.py index b79611a39..551e87c92 100755 --- a/src/core/examples/sample-simulator.py +++ b/src/core/examples/sample-simulator.py @@ -26,35 +26,11 @@ # Python example program demonstrating use of various Schedule functions. -import ns.core - -class MyModel(object): - """Simple model object to illustrate event handling.""" - - ## \return None. - def Start(self): - """Start model execution by scheduling a HandleEvent.""" - ns.core.Simulator.Schedule(ns.core.Seconds(10.0), self.HandleEvent, ns.core.Simulator.Now().GetSeconds()) - - ## \param [in] self This instance of MyModel - ## \param [in] value Event argument. - ## \return None. - def HandleEvent(self, value): - """Simple event handler.""" - print ("Member method received event at", ns.core.Simulator.Now().GetSeconds(), \ - "s started at", value, "s") - -## Example function - starts MyModel. -## \param [in] model The instance of MyModel -## \return None. -def ExampleFunction(model): - print ("ExampleFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s") - model.Start() +from ns import ns ## Example function - triggered at a random time. -## \param [in] model The instance of MyModel ## \return None. -def RandomFunction(model): +def RandomFunction(): print ("RandomFunction received event at", ns.core.Simulator.Now().GetSeconds(), "s") ## Example function - triggered if an event is canceled (should not be called). @@ -62,19 +38,88 @@ def RandomFunction(model): def CancelledEvent(): print ("I should never be called... ") -def main(dummy_argv): - ns.core.CommandLine().Parse(dummy_argv) +ns.cppyy.cppdef(""" + #include "CPyCppyy/API.h" - model = MyModel() - v = ns.core.UniformRandomVariable() + using namespace ns3; + /** Simple model object to illustrate event handling. */ + class MyModel + { + public: + /** Start model execution by scheduling a HandleEvent. */ + void Start (void); + + private: + /** + * Simple event handler. + * + * \param [in] eventValue Event argument. + */ + void HandleEvent (double eventValue); + }; + + void + MyModel::Start (void) + { + Simulator::Schedule (Seconds (10.0), + &MyModel::HandleEvent, + this, Simulator::Now ().GetSeconds ()); + } + void + MyModel::HandleEvent (double value) + { + std::cout << "Member method received event at " + << Simulator::Now ().GetSeconds () + << "s started at " << value << "s" << std::endl; + } + + void ExampleFunction(MyModel& model){ + std::cout << "ExampleFunction received event at " << Simulator::Now().GetSeconds() << "s" << std::endl; + model.Start(); + }; + + EventImpl* ExampleFunctionEvent(MyModel& model) + { + return MakeEvent(&ExampleFunction, model); + } + + void RandomFunctionCpp(MyModel& model) { + CPyCppyy::Eval("RandomFunction()"); + } + + EventImpl* RandomFunctionEvent(MyModel& model) + { + return MakeEvent(&RandomFunctionCpp, model); + } + + void CancelledFunctionCpp(void) { + CPyCppyy::Eval("CancelledEvent()"); + } + + EventImpl* CancelledFunctionEvent() + { + return MakeEvent(&CancelledFunctionCpp); + } + """) + + +def main(dummy_argv): + cmd = ns.getCommandLine(__file__) + cmd.Parse(dummy_argv) + + model = ns.cppyy.gbl.MyModel() + v = ns.CreateObject("UniformRandomVariable") v.SetAttribute("Min", ns.core.DoubleValue (10)) v.SetAttribute("Max", ns.core.DoubleValue (20)) - ns.core.Simulator.Schedule(ns.core.Seconds(10.0), ExampleFunction, model) + ev = ns.cppyy.gbl.ExampleFunctionEvent(model) + ns.core.Simulator.Schedule(ns.core.Seconds(10.0), ev) - ns.core.Simulator.Schedule(ns.core.Seconds(v.GetValue()), RandomFunction, model) + ev2 = ns.cppyy.gbl.RandomFunctionEvent(model) + ns.core.Simulator.Schedule(ns.core.Seconds(v.GetValue()), ev2) - id = ns.core.Simulator.Schedule(ns.core.Seconds(30.0), CancelledEvent) + ev3 = ns.cppyy.gbl.CancelledFunctionEvent() + id = ns.core.Simulator.Schedule(ns.core.Seconds(30.0), ev3) ns.core.Simulator.Cancel(id) ns.core.Simulator.Run() diff --git a/src/flow-monitor/examples/wifi-olsr-flowmon.py b/src/flow-monitor/examples/wifi-olsr-flowmon.py index f394e48ed..603045b65 100644 --- a/src/flow-monitor/examples/wifi-olsr-flowmon.py +++ b/src/flow-monitor/examples/wifi-olsr-flowmon.py @@ -19,40 +19,39 @@ from __future__ import print_function import sys -import ns.applications -import ns.core -import ns.flow_monitor -import ns.internet -import ns.mobility -import ns.network -import ns.olsr -import ns.wifi -try: - import ns.visualizer -except ImportError: - pass +from ns import ns DISTANCE = 20 # (m) NUM_NODES_SIDE = 3 +ns.cppyy.cppdef(""" +using namespace ns3; + +CommandLine& GetCommandLine(std::string filename, int& NumNodesSide, bool& Plot, std::string Results) +{ + static CommandLine cmd = CommandLine(filename); + cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)", NumNodesSide); + cmd.AddValue("Results", "Write XML results to file", Results); + cmd.AddValue("Plot", "Plot the results using the matplotlib python module", Plot); + return cmd; +} +""") + def main(argv): - cmd = ns.core.CommandLine() - - cmd.NumNodesSide = None - cmd.AddValue("NumNodesSide", "Grid side number of nodes (total number of nodes will be this number squared)") - - cmd.Results = None - cmd.AddValue("Results", "Write XML results to file") - - cmd.Plot = None - cmd.AddValue("Plot", "Plot the results using the matplotlib python module") - + from ctypes import c_int, c_bool + NumNodesSide = c_int(2) + Plot = c_bool(True) + Results = "output.xml" + cmd = ns.cppyy.gbl.GetCommandLine(__file__, NumNodesSide, Plot, Results) cmd.Parse(argv) - wifi = ns.wifi.WifiHelper() - wifiMac = ns.wifi.WifiMacHelper() - wifiPhy = ns.wifi.YansWifiPhyHelper() + Plot = Plot.value + NumNodesSide = NumNodesSide.value + + wifi = ns.CreateObject("WifiHelper") + wifiMac = ns.CreateObject("WifiMacHelper") + wifiPhy = ns.CreateObject("YansWifiPhyHelper") wifiChannel = ns.wifi.YansWifiChannelHelper.Default() wifiPhy.SetChannel(wifiChannel.Create()) ssid = ns.wifi.Ssid("wifi-default") @@ -71,8 +70,9 @@ def main(argv): ipv4Addresses.SetBase(ns.network.Ipv4Address("10.0.0.0"), ns.network.Ipv4Mask("255.255.255.0")) port = 9 # Discard port(RFC 863) + inetAddress = ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port) onOffHelper = ns.applications.OnOffHelper("ns3::UdpSocketFactory", - ns.network.Address(ns.network.InetSocketAddress(ns.network.Ipv4Address("10.0.0.1"), port))) + ns.network.Address(ns.addressFromInetSocketAddress(inetAddress))) onOffHelper.SetAttribute("DataRate", ns.network.DataRateValue(ns.network.DataRate("100kbps"))) onOffHelper.SetAttribute("OnTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=1]")) onOffHelper.SetAttribute("OffTime", ns.core.StringValue ("ns3::ConstantRandomVariable[Constant=0]")) @@ -80,34 +80,39 @@ def main(argv): addresses = [] nodes = [] - if cmd.NumNodesSide is None: + if NumNodesSide is None: num_nodes_side = NUM_NODES_SIDE else: - num_nodes_side = int(cmd.NumNodesSide) + num_nodes_side = NumNodesSide + nodes = ns.NodeContainer(num_nodes_side*num_nodes_side) + accumulator = 0 for xi in range(num_nodes_side): for yi in range(num_nodes_side): - node = ns.network.Node() - nodes.append(node) + node = nodes.Get(accumulator) + accumulator += 1 + container = ns.network.NodeContainer(node) + internet.Install(container) - internet.Install(ns.network.NodeContainer(node)) - - mobility = ns.mobility.ConstantPositionMobilityModel() + mobility = ns.CreateObject("ConstantPositionMobilityModel") mobility.SetPosition(ns.core.Vector(xi*DISTANCE, yi*DISTANCE, 0)) node.AggregateObject(mobility) - devices = wifi.Install(wifiPhy, wifiMac, node) - ipv4_interfaces = ipv4Addresses.Assign(devices) + device = wifi.Install(wifiPhy, wifiMac, node) + ipv4_interfaces = ipv4Addresses.Assign(device) addresses.append(ipv4_interfaces.GetAddress(0)) - for i, node in enumerate(nodes): + for i, node in [(i, nodes.Get(i)) for i in range(nodes.GetN())]: destaddr = addresses[(len(addresses) - 1 - i) % len(addresses)] #print (i, destaddr) - onOffHelper.SetAttribute("Remote", ns.network.AddressValue(ns.network.InetSocketAddress(destaddr, port))) - app = onOffHelper.Install(ns.network.NodeContainer(node)) - urv = ns.core.UniformRandomVariable() - app.Start(ns.core.Seconds(urv.GetValue(20, 30))) + genericAddress = ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(destaddr, port)) + onOffHelper.SetAttribute("Remote", ns.network.AddressValue(genericAddress)) + container = ns.network.NodeContainer(node) + app = onOffHelper.Install(container) + urv = ns.CreateObject("UniformRandomVariable")#ns.cppyy.gbl.get_rng() + startDelay = ns.Seconds(urv.GetValue(20, 30)) + app.Start(startDelay) #internet.EnablePcapAll("wifi-olsr") flowmon_helper = ns.flow_monitor.FlowMonitorHelper() @@ -154,7 +159,7 @@ def main(argv): monitor.CheckForLostPackets() classifier = flowmon_helper.GetClassifier() - if cmd.Results is None: + if Results is None: for flow_id, flow_stats in monitor.GetFlowStats(): t = classifier.FindFlow(flow_id) proto = {6: 'TCP', 17: 'UDP'} [t.protocol] @@ -162,10 +167,10 @@ def main(argv): (flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)) print_stats(sys.stdout, flow_stats) else: - print (monitor.SerializeToXmlFile(cmd.Results, True, True)) + print (monitor.SerializeToXmlFile(Results, True, True)) - if cmd.Plot is not None: + if Plot is not None: import pylab delays = [] for flow_id, flow_stats in monitor.GetFlowStats(): diff --git a/src/tap-bridge/examples/tap-csma-virtual-machine.py b/src/tap-bridge/examples/tap-csma-virtual-machine.py index a55f066dd..b23de3c6a 100644 --- a/src/tap-bridge/examples/tap-csma-virtual-machine.py +++ b/src/tap-bridge/examples/tap-csma-virtual-machine.py @@ -18,11 +18,7 @@ import sys -import ns.core -import ns.csma -import ns.internet -import ns.network -import ns.tap_bridge +from ns import ns def main(argv): @@ -34,7 +30,7 @@ def main(argv): # and take the time to calculate checksums. # ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")) - ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue("true")) + ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True)) # # Create two ghost nodes. The first will represent the virtual machine host @@ -76,7 +72,7 @@ def main(argv): # Run the simulation for ten minutes to give the user time to play around # ns.core.Simulator.Stop (ns.core.Seconds (600)) - ns.core.Simulator.Run(signal_check_frequency = -1) + ns.core.Simulator.Run()#signal_check_frequency = -1 ns.core.Simulator.Destroy() return 0 diff --git a/src/tap-bridge/examples/tap-wifi-virtual-machine.py b/src/tap-bridge/examples/tap-wifi-virtual-machine.py index 239f14cfe..92c6115cb 100644 --- a/src/tap-bridge/examples/tap-wifi-virtual-machine.py +++ b/src/tap-bridge/examples/tap-wifi-virtual-machine.py @@ -17,12 +17,7 @@ # import sys -import ns.core -import ns.internet -import ns.mobility -import ns.network -import ns.tap_bridge -import ns.wifi +from ns import ns def main(argv): @@ -34,7 +29,7 @@ def main(argv): # and take the time to calculate checksums. # ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")) - ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue("true")) + ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue(True)) # # Create two ghost nodes. The first will represent the virtual machine host @@ -105,7 +100,7 @@ def main(argv): # Run the simulation for ten minutes to give the user time to play around # ns.core.Simulator.Stop (ns.core.Seconds (600)); - ns.core.Simulator.Run(signal_check_frequency = -1) + ns.core.Simulator.Run()#signal_check_frequency = -1 ns.core.Simulator.Destroy() return 0 diff --git a/src/visualizer/visualizer/__init__.py b/src/visualizer/visualizer/__init__.py index 1a4d80f89..7829ac513 100644 --- a/src/visualizer/visualizer/__init__.py +++ b/src/visualizer/visualizer/__init__.py @@ -1,3 +1,15 @@ +from ns import * + +# Some useful tricks for visualizer +# we need to check if the node has a mobility model, but we can't pass Ptr to python +ns.cppyy.cppdef("""using namespace ns3; bool hasMobilityModel(Ptr node){ return !(node->GetObject() == 0); };""") +ns.cppyy.cppdef("""using namespace ns3; Vector3D getNodePosition(Ptr node){ return node->GetObject()->GetPosition(); };""") +ns.cppyy.cppdef("""using namespace ns3; Ptr getNodeIpv4(Ptr node){ return node->GetObject(); };""") +ns.cppyy.cppdef("""using namespace ns3; Ptr getNodeIpv6(Ptr node){ return node->GetObject(); };""") +ns.cppyy.cppdef("""using namespace ns3; std::string getMobilityModelName(Ptr node){ return node->GetObject()->GetInstanceTypeId().GetName(); };""") +ns.cppyy.cppdef("""using namespace ns3; bool hasOlsr(Ptr node){ return !(node->GetObject() == 0); };""") +ns.cppyy.cppdef("""using namespace ns3; Ptr getNodeOlsr(Ptr node){ return node->GetObject(); };""") + from .core import start, register_plugin, set_bounds, add_initialization_hook diff --git a/src/visualizer/visualizer/base.py b/src/visualizer/visualizer/base.py index 97d47fdf1..0c06011c2 100644 --- a/src/visualizer/visualizer/base.py +++ b/src/visualizer/visualizer/base.py @@ -1,12 +1,4 @@ from __future__ import print_function -import ns.point_to_point -import ns.csma -import ns.wifi -import ns.bridge -import ns.internet -import ns.mesh -import ns.wimax -import ns.lte from gi.repository import GObject import os.path @@ -58,16 +50,16 @@ class NetDeviceTraits(object): self.is_virtual = is_virtual netdevice_traits = { - ns.point_to_point.PointToPointNetDevice: NetDeviceTraits(is_wireless=False), - ns.csma.CsmaNetDevice: NetDeviceTraits(is_wireless=False), - ns.wifi.WifiNetDevice: NetDeviceTraits(is_wireless=True), - ns.bridge.BridgeNetDevice: NetDeviceTraits(is_virtual=True), - ns.internet.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False), - ns.mesh.MeshPointDevice: NetDeviceTraits(is_virtual=True), - ns.wimax.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True), - ns.wimax.BaseStationNetDevice: NetDeviceTraits(is_wireless=True), - ns.lte.LteUeNetDevice: NetDeviceTraits(is_wireless=True), - ns.lte.LteEnbNetDevice: NetDeviceTraits(is_wireless=True), + ns.PointToPointNetDevice: NetDeviceTraits(is_wireless=False), + ns.CsmaNetDevice: NetDeviceTraits(is_wireless=False), + ns.WifiNetDevice: NetDeviceTraits(is_wireless=True), + ns.BridgeNetDevice: NetDeviceTraits(is_virtual=True), + ns.LoopbackNetDevice: NetDeviceTraits(is_virtual=True, is_wireless=False), + ns.MeshPointDevice: NetDeviceTraits(is_virtual=True), + ns.SubscriberStationNetDevice: NetDeviceTraits(is_wireless=True), + ns.BaseStationNetDevice: NetDeviceTraits(is_wireless=True), + ns.LteUeNetDevice: NetDeviceTraits(is_wireless=True), + ns.LteEnbNetDevice: NetDeviceTraits(is_wireless=True), } def lookup_netdevice_traits(class_type): diff --git a/src/visualizer/visualizer/core.py b/src/visualizer/visualizer/core.py index 4d73e1b4e..487f53be1 100644 --- a/src/visualizer/visualizer/core.py +++ b/src/visualizer/visualizer/core.py @@ -1,6 +1,7 @@ # -*- Mode: python; coding: utf-8 -*- from __future__ import division, print_function #from __future__ import with_statement +from ctypes import c_double LAYOUT_ALGORITHM = 'neato' # ['neato'|'dot'|'twopi'|'circo'|'fdp'|'nop'] REPRESENT_CHANNELS_AS_NODES = 1 @@ -20,13 +21,6 @@ if platform.system() == "Windows": else: SHELL_FONT = "Luxi Mono 10" - -import ns.core -import ns.network -import ns.visualizer -import ns.internet -import ns.mobility - import math import os import sys @@ -50,6 +44,7 @@ try: from gi.repository import GooCanvas import threading from . import hud + #import time try: import svgitem @@ -116,7 +111,7 @@ class Node(PyVizObject): ## information can be appended __gsignals__ = { 'query-extra-tooltip-info': (GObject.SignalFlags.RUN_LAST, None, (object,)), - } + } def __init__(self, visualizer, node_index): """! Initialize function. @@ -231,12 +226,12 @@ class Node(PyVizObject): """ self.visualizer.simulation.lock.acquire() try: - ns3_node = ns.network.NodeList.GetNode(self.node_index) - ipv4 = ns3_node.GetObject(ns.internet.Ipv4.GetTypeId()) - ipv6 = ns3_node.GetObject(ns.internet.Ipv6.GetTypeId()) + ns3_node = ns.NodeList.GetNode(self.node_index) + ipv4 = ns.cppyy.gbl.getNodeIpv4(ns3_node) + ipv6 = ns.cppyy.gbl.getNodeIpv6(ns3_node) name = 'Node %i' % self.node_index - node_name = ns.core.Names.FindName (ns3_node) + node_name = ns.Names.FindName (ns3_node) if len(node_name)!=0: name += ' (' + node_name + ')' @@ -245,15 +240,16 @@ class Node(PyVizObject): self.emit("query-extra-tooltip-info", lines) - mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - if mob is not None: - lines.append(' Mobility Model: %s' % mob.GetInstanceTypeId().GetName()) + mob = ns.cppyy.gbl.hasMobilityModel(ns3_node) + if mob: + mobility_model_name = ns.cppyy.gbl.getMobilityModelName(ns3_node) + lines.append(' Mobility Model: %s' % ns.cppyy.gbl.getMobilityModelName(ns3_node)) for devI in range(ns3_node.GetNDevices()): lines.append('') lines.append(' NetDevice %i:' % devI) dev = ns3_node.GetDevice(devI) - name = ns.core.Names.FindName(dev) + name = ns.Names.FindName(dev) if name: lines.append(' Name: %s' % name) devname = dev.GetInstanceTypeId().GetName() @@ -388,12 +384,12 @@ class Node(PyVizObject): if self._label is not None: if self._label_canvas_item is None: self._label_canvas_item = GooCanvas.CanvasText(visibility_threshold=0.5, - font="Sans Serif 10", - fill_color_rgba=0x808080ff, - alignment=Pango.Alignment.CENTER, - anchor=GooCanvas.CanvasAnchorType.N, - parent=self.visualizer.canvas.get_root_item(), - pointer_events=GooCanvas.CanvasPointerEvents.NONE) + font="Sans Serif 10", + fill_color_rgba=0x808080ff, + alignment=Pango.Alignment.CENTER, + anchor=GooCanvas.CanvasAnchorType.N, + parent=self.visualizer.canvas.get_root_item(), + pointer_events=GooCanvas.CanvasPointerEvents.NONE) self._label_canvas_item.lower(None) self._label_canvas_item.set_properties(visibility=GooCanvas.CanvasItemVisibility.VISIBLE_ABOVE_THRESHOLD, @@ -504,9 +500,8 @@ class Node(PyVizObject): @return modility option """ if self._has_mobility is None: - node = ns.network.NodeList.GetNode(self.node_index) - mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - self._has_mobility = (mobility is not None) + node = ns.NodeList.GetNode(self.node_index) + self._has_mobility = ns.cppyy.gbl.hasMobilityModel(node) return self._has_mobility @@ -528,10 +523,10 @@ class Channel(PyVizObject): """ self.channel = channel self.canvas_item = GooCanvas.CanvasEllipse(radius_x=30, radius_y=30, - fill_color="white", - stroke_color="grey", line_width=2.0, - line_dash=GooCanvas.CanvasLineDash.newv([10.0, 10.0 ]), - visibility=GooCanvas.CanvasItemVisibility.VISIBLE) + fill_color="white", + stroke_color="grey", line_width=2.0, + line_dash=GooCanvas.CanvasLineDash.newv([10.0, 10.0 ]), + visibility=GooCanvas.CanvasItemVisibility.VISIBLE) self.canvas_item.pyviz_object = self self.links = [] @@ -629,7 +624,7 @@ class SimulationThread(threading.Thread): self.go.clear() self.target_time = 0 # in seconds self.quit = False - self.sim_helper = ns.visualizer.PyViz() + self.sim_helper = ns.PyViz() self.pause_messages = [] def set_nodes_of_interest(self, nodes): @@ -664,13 +659,13 @@ class SimulationThread(threading.Thread): self.lock.acquire() try: if 0: - if ns3.core.Simulator.IsFinished(): + if ns3.Simulator.IsFinished(): self.viz.play_button.set_sensitive(False) break #print "sim: Current time is %f; Run until: %f" % (ns3.Simulator.Now ().GetSeconds (), self.target_time) #if ns3.Simulator.Now ().GetSeconds () > self.target_time: # print "skipping, model is ahead of view!" - self.sim_helper.SimulatorRunUntil(ns.core.Seconds(self.target_time)) + self.sim_helper.SimulatorRunUntil(ns.Seconds(self.target_time)) #print "sim: Run until ended at current time: ", ns3.Simulator.Now ().GetSeconds () self.pause_messages.extend(self.sim_helper.GetPauseMessages()) GLib.idle_add(self.viz.update_model, priority=PRIORITY_UPDATE_MODEL) @@ -716,7 +711,7 @@ class Visualizer(GObject.GObject): # signal emitted when it's time to update the view objects 'update-view': (GObject.SignalFlags.RUN_LAST, None, ()), - } + } def __init__(self): """! @@ -776,7 +771,7 @@ class Visualizer(GObject.GObject): assert isinstance(mode, ShowTransmissionsMode) self._show_transmissions_mode = mode if self._show_transmissions_mode == ShowTransmissionsMode.ALL: - self.simulation.set_nodes_of_interest(list(range(ns.network.NodeList.GetNNodes()))) + self.simulation.set_nodes_of_interest(list(range(ns.NodeList.GetNNodes()))) elif self._show_transmissions_mode == ShowTransmissionsMode.NONE: self.simulation.set_nodes_of_interest([]) elif self._show_transmissions_mode == ShowTransmissionsMode.SELECTED: @@ -1050,9 +1045,9 @@ class Visualizer(GObject.GObject): # Screenshot button screenshot_button = GObject.new(Gtk.Button, - label="Snapshot", - relief=Gtk.ReliefStyle.NONE, focus_on_click=False, - visible=True) + label="Snapshot", + relief=Gtk.ReliefStyle.NONE, focus_on_click=False, + visible=True) hbox.pack_start(screenshot_button, False, False, 4) def load_button_icon(button, icon_name): @@ -1071,9 +1066,9 @@ class Visualizer(GObject.GObject): # Shell button if ipython_view is not None: shell_button = GObject.new(Gtk.Button, - label="Shell", - relief=Gtk.ReliefStyle.NONE, focus_on_click=False, - visible=True) + label="Shell", + relief=Gtk.ReliefStyle.NONE, focus_on_click=False, + visible=True) hbox.pack_start(shell_button, False, False, 4) load_button_icon(shell_button, "gnome-terminal") shell_button.connect("clicked", self._start_shell) @@ -1111,22 +1106,22 @@ class Visualizer(GObject.GObject): self.window.show() def scan_topology(self): - print("scanning topology: %i nodes..." % (ns.network.NodeList.GetNNodes(),)) + print("scanning topology: %i nodes..." % (ns.NodeList.GetNNodes(),)) graph = pygraphviz.AGraph() seen_nodes = 0 - for nodeI in range(ns.network.NodeList.GetNNodes()): + for nodeI in range(ns.NodeList.GetNNodes()): seen_nodes += 1 if seen_nodes == 100: - print("scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.network.NodeList.GetNNodes())) + print("scan topology... %i nodes visited (%.1f%%)" % (nodeI, 100*nodeI/ns.NodeList.GetNNodes())) seen_nodes = 0 - node = ns.network.NodeList.GetNode(nodeI) + node = ns.NodeList.GetNode(nodeI) node_name = "Node %i" % nodeI node_view = self.get_node(nodeI) - mobility = node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - if mobility is not None: + mobility = ns.cppyy.gbl.hasMobilityModel(node) + if mobility: node_view.set_color("red") - pos = mobility.GetPosition() + pos = ns.cppyy.gbl.getNodePosition(node) node_view.set_position(*transform_point_simulation_to_canvas(pos.x, pos.y)) #print "node has mobility position -> ", "%f,%f" % (pos.x, pos.y) else: @@ -1213,7 +1208,7 @@ class Visualizer(GObject.GObject): def update_view(self): #print "update_view" - self.time_label.set_text("Time: %f s" % ns.core.Simulator.Now().GetSeconds()) + self.time_label.set_text("Time: %f s" % ns.Simulator.Now().GetSeconds()) self._update_node_positions() @@ -1229,10 +1224,10 @@ class Visualizer(GObject.GObject): def _update_node_positions(self): for node in self.nodes.values(): if node.has_mobility: - ns3_node = ns.network.NodeList.GetNode(node.node_index) - mobility = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - if mobility is not None: - pos = mobility.GetPosition() + ns3_node = ns.NodeList.GetNode(node.node_index) + mobility = ns.cppyy.gbl.hasMobilityModel(ns3_node) + if mobility: + pos = ns.cppyy.gbl.getNodePosition(ns3_node) x, y = transform_point_simulation_to_canvas(pos.x, pos.y) node.set_position(x, y) if node is self.follow_node: @@ -1243,14 +1238,14 @@ class Visualizer(GObject.GObject): vadj.set_value(py - vadj.get_page_size() / 2) def center_on_node(self, node): - if isinstance(node, ns.network.Node): + if isinstance(node, ns.Node): node = self.nodes[node.GetId()] elif isinstance(node, (int, long)): node = self.nodes[node] elif isinstance(node, Node): pass else: - raise TypeError("expected int, viz.Node or ns.network.Node, not %r" % node) + raise TypeError("expected int, viz.Node or ns.Node, not %r" % node) x, y = node.get_position() hadj = self._scrolled_window.get_hadjustment() @@ -1285,10 +1280,14 @@ class Visualizer(GObject.GObject): bounds_x1, bounds_y1 = self.canvas.convert_from_pixels(hadj.get_value(), vadj.get_value()) bounds_x2, bounds_y2 = self.canvas.convert_from_pixels(hadj.get_value() + hadj.get_page_size(), vadj.get_value() + vadj.get_page_size()) - pos1_x, pos1_y, pos2_x, pos2_y = ns.visualizer.PyViz.LineClipping(bounds_x1, bounds_y1, - bounds_x2, bounds_y2, - pos1_x, pos1_y, - pos2_x, pos2_y) + try: + pos1_x, pos1_y, pos2_x, pos2_y = ns.PyViz.LineClipping(bounds_x1, bounds_y1, + bounds_x2, bounds_y2, + pos1_x, pos1_y, + pos2_x, pos2_y) + except: + res = (0,0,0,0) + pos1_x, pos1_y, pos2_x, pos2_y = res return (pos1_x + pos2_x)/2, (pos1_y + pos2_y)/2 def _update_transmissions_view(self): @@ -1349,8 +1348,8 @@ class Visualizer(GObject.GObject): anchor=GooCanvas.CanvasAnchorType.N, x=0, y=line_width/2) M = cairo.Matrix() - lx, ly = self._get_label_over_line_position(pos1_x, pos1_y, - pos2_x, pos2_y) + lx, ly = self._get_label_over_line_position(c_double(pos1_x), c_double(pos1_y), + c_double(pos2_x), c_double(pos2_y)) M.translate(lx, ly) M.rotate(angle) try: @@ -1436,7 +1435,7 @@ class Visualizer(GObject.GObject): self.simulation.pause_messages = [] try: self.update_view() - self.simulation.target_time = ns.core.Simulator.Now ().GetSeconds () + self.sample_period + self.simulation.target_time = ns.Simulator.Now ().GetSeconds () + self.sample_period #print "view: target time set to %f" % self.simulation.target_time finally: self.simulation.lock.release() @@ -1590,13 +1589,13 @@ class Visualizer(GObject.GObject): def begin_node_drag(self, node, event): self.simulation.lock.acquire() try: - ns3_node = ns.network.NodeList.GetNode(node.node_index) - mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - if mob is None: + ns3_node = ns.NodeList.GetNode(node.node_index) + mob = ns.cppyy.gbl.hasMobilityModel(ns3_node) + if not mob: return if self.node_drag_state is not None: return - pos = mob.GetPosition() + pos = ns.cppyy.gbl.getNodePosition(ns3_node) finally: self.simulation.lock.release() devpos = self.canvas.get_window().get_device_position(event.device) @@ -1607,9 +1606,9 @@ class Visualizer(GObject.GObject): def node_drag_motion(self, item, targe_item, event, node): self.simulation.lock.acquire() try: - ns3_node = ns.network.NodeList.GetNode(node.node_index) - mob = ns3_node.GetObject(ns.mobility.MobilityModel.GetTypeId()) - if mob is None: + ns3_node = ns.NodeList.GetNode(node.node_index) + mob = ns.cppyy.gbl.hasMobilityModel(ns3_node) + if not mob: return False if self.node_drag_state is None: return False @@ -1652,14 +1651,14 @@ class Visualizer(GObject.GObject): else: self.simulation.lock.acquire() try: - ns3_node = ns.network.NodeList.GetNode(self.selected_node.node_index) + ns3_node = ns.NodeList.GetNode(self.selected_node.node_index) finally: self.simulation.lock.release() self.ipython.updateNamespace({'selected_node': ns3_node}) def select_node(self, node): - if isinstance(node, ns.network.Node): + if isinstance(node, ns.Node): node = self.nodes[node.GetId()] elif isinstance(node, (int, long)): node = self.nodes[node] @@ -1668,7 +1667,7 @@ class Visualizer(GObject.GObject): elif node is None: pass else: - raise TypeError("expected None, int, viz.Node or ns.network.Node, not %r" % node) + raise TypeError("expected None, int, viz.Node or ns.Node, not %r" % node) if node is self.selected_node: return @@ -1778,11 +1777,11 @@ class Visualizer(GObject.GObject): surface = cairo.SVGSurface(file_name, dest_width, dest_height) else: dialog = Gtk.MessageDialog(parent = self.canvas.get_toplevel(), - flags = Gtk.DialogFlags.DESTROY_WITH_PARENT, - type = Gtk.MessageType.ERROR, - buttons = Gtk.ButtonsType.OK, - message_format = "Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')" - % (extension,)) + flags = Gtk.DialogFlags.DESTROY_WITH_PARENT, + type = Gtk.MessageType.ERROR, + buttons = Gtk.ButtonsType.OK, + message_format = "Unknown extension '%s' (valid extensions are '.eps', '.svg', and '.pdf')" + % (extension,)) dialog.run() dialog.destroy() return @@ -1795,7 +1794,7 @@ class Visualizer(GObject.GObject): surface.finish() def set_follow_node(self, node): - if isinstance(node, ns.network.Node): + if isinstance(node, ns.Node): node = self.nodes[node.GetId()] self.follow_node = node @@ -1856,11 +1855,11 @@ def start(): import sys print("No visualization support (%s)." % (str(_import_error),), file=sys.stderr) - ns.core.Simulator.Run() + ns.Simulator.Run() return load_plugins() viz = Visualizer() for hook, args in initialization_hooks: GLib.idle_add(hook, viz, *args) - ns.network.Packet.EnablePrinting() + ns.Packet.EnablePrinting() viz.start() diff --git a/src/visualizer/visualizer/plugins/interface_statistics.py b/src/visualizer/visualizer/plugins/interface_statistics.py index 9d0346d23..a8162e33a 100644 --- a/src/visualizer/visualizer/plugins/interface_statistics.py +++ b/src/visualizer/visualizer/plugins/interface_statistics.py @@ -1,6 +1,4 @@ from gi.repository import Gtk -import ns.core -import ns.network from visualizer.base import InformationWindow NODE_STATISTICS_MEMORY = 10 @@ -119,7 +117,7 @@ class ShowInterfaceStatistics(InformationWindow): COLUMN_RX_PACKET_RATE, COLUMN_RX_BIT_RATE, - ) = range(9) + ) = range(9) def __init__(self, visualizer, node_index, statistics_collector): """! @@ -182,13 +180,13 @@ class ShowInterfaceStatistics(InformationWindow): @param self this object @return none """ - node = ns.network.NodeList.GetNode(self.node_index) + node = ns.NodeList.GetNode(self.node_index) stats_list = self.statistics_collector.get_interface_statistics(self.node_index) self.table_model.clear() for iface, stats in enumerate(stats_list): tree_iter = self.table_model.append() netdevice = node.GetDevice(iface) - interface_name = ns.core.Names.FindName(netdevice) + interface_name = ns.Names.FindName(netdevice) if not interface_name: interface_name = "(interface %i)" % iface self.table_model.set(tree_iter, diff --git a/src/visualizer/visualizer/plugins/ipv4_routing_table.py b/src/visualizer/visualizer/plugins/ipv4_routing_table.py index a40e8afbc..7f84ef91b 100644 --- a/src/visualizer/visualizer/plugins/ipv4_routing_table.py +++ b/src/visualizer/visualizer/plugins/ipv4_routing_table.py @@ -1,9 +1,5 @@ from gi.repository import Gtk -import ns.core -import ns.network -import ns.internet - from visualizer.base import InformationWindow ## ShowIpv4RoutingTable class @@ -22,7 +18,7 @@ class ShowIpv4RoutingTable(InformationWindow): COLUMN_INTERFACE, COLUMN_TYPE, COLUMN_PRIO - ) = range(5) + ) = range(5) def __init__(self, visualizer, node_index): """! @@ -97,23 +93,23 @@ class ShowIpv4RoutingTable(InformationWindow): @param self this object @return none """ - node = ns.network.NodeList.GetNode(self.node_index) - ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId()) + node = ns.NodeList.GetNode(self.node_index) + ipv4 = ns.cppyy.gbl.getNodeIpv4(node) routing = ipv4.GetRoutingProtocol() if routing is None: return routing_protocols = [] # list of (protocol, type_string, priority) - if isinstance(routing, ns.internet.Ipv4StaticRouting): + if isinstance(routing, ns.Ipv4StaticRouting): ipv4_routing = routing_protocols.append((routing, "static", 0)) - elif isinstance(routing, ns.internet.Ipv4ListRouting): + elif isinstance(routing, ns.Ipv4ListRouting): list_routing = routing for rI in range(list_routing.GetNRoutingProtocols()): routing, prio = list_routing.GetRoutingProtocol(rI) - if isinstance(routing, ns.internet.Ipv4StaticRouting): + if isinstance(routing, ns.Ipv4StaticRouting): routing_protocols.append((routing, "static", prio)) - elif isinstance(routing, ns.internet.Ipv4GlobalRouting): + elif isinstance(routing, ns.Ipv4GlobalRouting): routing_protocols.append((routing, "global", prio)) if not routing_protocols: return @@ -127,7 +123,7 @@ class ShowIpv4RoutingTable(InformationWindow): if netdevice is None: interface_name = 'lo' else: - interface_name = ns.core.Names.FindName(netdevice) + interface_name = ns.Names.FindName(netdevice) if not interface_name: interface_name = "(interface %i)" % route.GetInterface() self.table_model.set(tree_iter, diff --git a/src/visualizer/visualizer/plugins/olsr.py b/src/visualizer/visualizer/plugins/olsr.py index 42d056ddb..802df45ed 100644 --- a/src/visualizer/visualizer/plugins/olsr.py +++ b/src/visualizer/visualizer/plugins/olsr.py @@ -2,11 +2,6 @@ from __future__ import print_function from gi.repository import Gtk from gi.repository import Gdk -import ns.core -import ns.network -import ns.internet -import ns.olsr - from visualizer.base import InformationWindow ## ShowOlsrRoutingTable class @@ -24,7 +19,7 @@ class ShowOlsrRoutingTable(InformationWindow): COLUMN_NEXT_HOP, COLUMN_INTERFACE, COLUMN_NUM_HOPS, - ) = range(4) + ) = range(4) def __init__(self, visualizer, node_index): """! @@ -94,11 +89,12 @@ class ShowOlsrRoutingTable(InformationWindow): @param self this object @return none """ - node = ns.network.NodeList.GetNode(self.node_index) - olsr = node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId()) - ipv4 = node.GetObject(ns.internet.Ipv4.GetTypeId()) - if olsr is None: + node = ns.NodeList.GetNode(self.node_index) + ipv4 = node.GetObject(ns.Ipv4.GetTypeId()) + if not ns.cppyy.gbl.hasOlsr(ns3_node): return + olsr = ns.cppyy.gbl.getNodeOlsr(node) + self.table_model.clear() for route in olsr.GetRoutingTableEntries(): tree_iter = self.table_model.append() @@ -106,7 +102,7 @@ class ShowOlsrRoutingTable(InformationWindow): if netdevice is None: interface_name = 'lo' else: - interface_name = ns.core.Names.FindName(netdevice) + interface_name = ns.Names.FindName(netdevice) if not interface_name: interface_name = "(interface %i)" % route.interface self.table_model.set(tree_iter, @@ -117,9 +113,8 @@ class ShowOlsrRoutingTable(InformationWindow): def populate_node_menu(viz, node, menu): - ns3_node = ns.network.NodeList.GetNode(node.node_index) - olsr = ns3_node.GetObject(ns.olsr.olsr.RoutingProtocol.GetTypeId()) - if olsr is None: + ns3_node = ns.NodeList.GetNode(node.node_index) + if not ns.cppyy.gbl.hasOlsr(ns3_node): print("No OLSR") return diff --git a/src/visualizer/visualizer/plugins/show_last_packets.py b/src/visualizer/visualizer/plugins/show_last_packets.py index 15cef66b9..b48abb0d3 100644 --- a/src/visualizer/visualizer/plugins/show_last_packets.py +++ b/src/visualizer/visualizer/plugins/show_last_packets.py @@ -1,9 +1,7 @@ from gi.repository import GObject from gi.repository import Gtk -import ns.core -import ns.network -import ns.visualizer +from ns import ns from visualizer.base import InformationWindow from kiwi.ui.objectlist import ObjectList, Column diff --git a/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py b/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py index 6371d459b..4504f076d 100644 --- a/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py +++ b/src/visualizer/visualizer/plugins/wifi_intrastructure_link.py @@ -1,6 +1,5 @@ import math -import ns.wifi -import ns.network +from ns import ns from gi.repository import GooCanvas from visualizer.base import Link, transform_distance_canvas_to_simulation diff --git a/utils/python-unit-tests.py b/utils/python-unit-tests.py index d92b1f671..1908d3f52 100644 --- a/utils/python-unit-tests.py +++ b/utils/python-unit-tests.py @@ -19,13 +19,8 @@ # Author: Gustavo J. A. M. Carneiro import unittest -from ns.core import Simulator, Seconds, Config, int64x64_t -import ns.core -import ns.network -import ns.internet -import ns.mobility -import ns.csma -import ns.applications +from ns import ns +import sys UINT32_MAX = 0xFFFFFFFF @@ -46,19 +41,27 @@ class TestSimulator(unittest.TestCase): @param self this object @return none """ - def callback(args): + def callback(args: ns.cppyy.gbl.std.vector) -> None: """! Callback function @param args arguments return none """ - self._args_received = args - self._cb_time = Simulator.Now() - Simulator.Destroy() + import copy + self._args_received = list(map(lambda x: x.decode("utf-8"), args)) + self._cb_time = ns.Simulator.Now() + ns.Simulator.Destroy() self._args_received = None self._cb_time = None - Simulator.ScheduleNow(callback, "args") - Simulator.Run() - self.assertEqual(self._args_received, "args") + ns.cppyy.cppdef(""" + EventImpl* pythonMakeEvent(void (*f)(std::vector), std::vector l) + { + return MakeEvent(f, l); + } + """) + event = ns.cppyy.gbl.pythonMakeEvent(callback, sys.argv) + ns.Simulator.ScheduleNow(event) + ns.Simulator.Run() + self.assertListEqual(self._args_received, sys.argv) self.assertEqual(self._cb_time.GetSeconds(), 0.0) def testSchedule(self): @@ -66,19 +69,26 @@ class TestSimulator(unittest.TestCase): @param self this object @return none """ - def callback(args): + def callback(args: ns.cppyy.gbl.std.vector): """! Callback function @param args arguments @return none """ - self._args_received = args - self._cb_time = Simulator.Now() - Simulator.Destroy() + self._args_received = list(map(lambda x: x.decode("utf-8"), args)) + self._cb_time = ns.Simulator.Now() + ns.Simulator.Destroy() self._args_received = None self._cb_time = None - Simulator.Schedule(Seconds(123), callback, "args") - Simulator.Run() - self.assertEqual(self._args_received, "args") + ns.cppyy.cppdef(""" + EventImpl* pythonMakeEvent2(void (*f)(std::vector), std::vector l) + { + return MakeEvent(f, l); + } + """) + event = ns.cppyy.gbl.pythonMakeEvent2(callback, sys.argv) + ns.Simulator.Schedule(ns.Seconds(123), event) + ns.Simulator.Run() + self.assertListEqual(self._args_received, sys.argv) self.assertEqual(self._cb_time.GetSeconds(), 123.0) def testScheduleDestroy(self): @@ -86,22 +96,29 @@ class TestSimulator(unittest.TestCase): @param self this object @return none """ - def callback(args): + def callback(args: ns.cppyy.gbl.std.vector): """! Callback function @param args @return none """ - self._args_received = args - self._cb_time = Simulator.Now() - Simulator.Destroy() + self._args_received = list(map(lambda x: x.decode("utf-8"), args)) + self._cb_time = ns.Simulator.Now() + ns.Simulator.Destroy() self._args_received = None self._cb_time = None - def null(): pass - Simulator.Schedule(Seconds(123), null) - Simulator.ScheduleDestroy(callback, "args") - Simulator.Run() - Simulator.Destroy() - self.assertEqual(self._args_received, "args") + ns.cppyy.cppdef("void null(){ return; }") + ns.Simulator.Schedule(ns.Seconds(123), ns.cppyy.gbl.null) + ns.cppyy.cppdef(""" + EventImpl* pythonMakeEvent3(void (*f)(std::vector), std::vector l) + { + return MakeEvent(f, l); + } + """) + event = ns.cppyy.gbl.pythonMakeEvent3(callback, sys.argv) + ns.Simulator.ScheduleDestroy(event) + ns.Simulator.Run() + ns.Simulator.Destroy() + self.assertListEqual(self._args_received, sys.argv) self.assertEqual(self._cb_time.GetSeconds(), 123.0) def testScheduleWithContext(self): @@ -109,23 +126,30 @@ class TestSimulator(unittest.TestCase): @param self this object @return none """ - def callback(context, args): + def callback(context, args: ns.cppyy.gbl.std.vector): """! Callback @param context the cntet @param args the arguments @return none """ self._context_received = context - self._args_received = args - self._cb_time = Simulator.Now() - Simulator.Destroy() + self._args_received = list(map(lambda x: x.decode("utf-8"), args)) + self._cb_time = ns.Simulator.Now() + ns.Simulator.Destroy() self._args_received = None self._cb_time = None self._context_received = None - Simulator.ScheduleWithContext(54321, Seconds(123), callback, "args") - Simulator.Run() + ns.cppyy.cppdef(""" + EventImpl* pythonMakeEvent4(void (*f)(uint32_t, std::vector), uint32_t context, std::vector l) + { + return MakeEvent(f, context, l); + } + """) + event = ns.cppyy.gbl.pythonMakeEvent4(callback, 54321, sys.argv) + ns.Simulator.ScheduleWithContext(54321, ns.Seconds(123), event) + ns.Simulator.Run() self.assertEqual(self._context_received, 54321) - self.assertEqual(self._args_received, "args") + self.assertListEqual(self._args_received, sys.argv) self.assertEqual(self._cb_time.GetSeconds(), 123.0) def testTimeComparison(self): @@ -133,29 +157,29 @@ class TestSimulator(unittest.TestCase): @param self this object @return none """ - self.assertTrue(Seconds(123) == Seconds(123)) - self.assertTrue(Seconds(123) >= Seconds(123)) - self.assertTrue(Seconds(123) <= Seconds(123)) - self.assertTrue(Seconds(124) > Seconds(123)) - self.assertTrue(Seconds(123) < Seconds(124)) + self.assertTrue(ns.Seconds(123) == ns.Seconds(123)) + self.assertTrue(ns.Seconds(123) >= ns.Seconds(123)) + self.assertTrue(ns.Seconds(123) <= ns.Seconds(123)) + self.assertTrue(ns.Seconds(124) > ns.Seconds(123)) + self.assertTrue(ns.Seconds(123) < ns.Seconds(124)) def testTimeNumericOperations(self): """! Test numeric operations @param self this object @return none """ - self.assertEqual(Seconds(10) + Seconds(5), Seconds(15)) - self.assertEqual(Seconds(10) - Seconds(5), Seconds(5)) + self.assertEqual(ns.Seconds(10) + ns.Seconds(5), ns.Seconds(15)) + self.assertEqual(ns.Seconds(10) - ns.Seconds(5), ns.Seconds(5)) - v1 = int64x64_t(5.0)*int64x64_t(10) - self.assertEqual(v1, int64x64_t(50)) + v1 = ns.int64x64_t(5.0)*ns.int64x64_t(10) + self.assertEqual(v1, ns.int64x64_t(50)) def testConfig(self): """! Test configuration @param self this object @return none """ - Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123)) + ns.Config.SetDefault("ns3::OnOffApplication::PacketSize", ns.core.UintegerValue(123)) # hm.. no Config.Get? def testSocket(self): @@ -163,27 +187,30 @@ class TestSimulator(unittest.TestCase): @param self @return none """ - node = ns.network.Node() - internet = ns.internet.InternetStackHelper() + nc = ns.NodeContainer(1) + node = nc.Get(0) + internet = ns.CreateObject("InternetStackHelper") internet.Install(node) self._received_packet = None - def rx_callback(socket): - """! Receive Callback - @param socket the socket to receive - @return none - """ - assert self._received_packet is None + def python_rx_callback(socket) -> None: self._received_packet = socket.Recv(maxSize=UINT32_MAX, flags=0) + ns.cppyy.cppdef(""" + Callback > make_rx_callback(void(*func)(Ptr)) + { + return MakeCallback(func); + } + """) + sink = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")) - sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80)) - sink.SetRecvCallback(rx_callback) + sink.Bind(ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 80))) + sink.SetRecvCallback(ns.cppyy.gbl.make_rx_callback(python_rx_callback)) source = ns.network.Socket.CreateSocket(node, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")) - source.SendTo(ns.network.Packet(19), 0, ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80)) + source.SendTo(ns.network.Packet(19), 0, ns.addressFromInetSocketAddress(ns.network.InetSocketAddress(ns.network.Ipv4Address("127.0.0.1"), 80))) - Simulator.Run() + ns.Simulator.Run() self.assertTrue(self._received_packet is not None) self.assertEqual(self._received_packet.GetSize(), 19) @@ -194,7 +221,7 @@ class TestSimulator(unittest.TestCase): @return none """ # Templated class DropTailQueue in C++ - queue = ns.network.DropTailQueue__Ns3Packet() + queue = ns.CreateObject("DropTailQueue") queueSizeValue = ns.network.QueueSizeValue (ns.network.QueueSize ("500p")) queue.SetAttribute("MaxSize", queueSizeValue) @@ -203,66 +230,69 @@ class TestSimulator(unittest.TestCase): self.assertEqual(limit.Get(), ns.network.QueueSize ("500p")) ## -- object pointer values - mobility = ns.mobility.RandomWaypointMobilityModel() - ptr = ns.core.PointerValue() + mobility = ns.CreateObject("RandomWaypointMobilityModel") + ptr = ns.CreateObject("PointerValue") mobility.GetAttribute("PositionAllocator", ptr) - self.assertEqual(ptr.GetObject(), None) + self.assertEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr)) pos = ns.mobility.ListPositionAllocator() - mobility.SetAttribute("PositionAllocator", ns.core.PointerValue(pos)) + ptr.SetObject(pos) + mobility.SetAttribute("PositionAllocator", ptr) - ptr = ns.core.PointerValue() - mobility.GetAttribute("PositionAllocator", ptr) - self.assertTrue(ptr.GetObject() is not None) + ptr2 = ns.CreateObject("PointerValue") + mobility.GetAttribute("PositionAllocator", ptr2) + self.assertNotEqual(ptr.GetObject(), ns.core.Ptr["Object"](ns.cppyy.nullptr)) def testIdentity(self): """! Test identify @param self this object @return none """ - csma = ns.csma.CsmaNetDevice() - channel = ns.csma.CsmaChannel() + csma = ns.CreateObject("CsmaNetDevice") + channel = ns.CreateObject("CsmaChannel") csma.Attach(channel) c1 = csma.GetChannel() c2 = csma.GetChannel() - self.assertTrue(c1 is c2) + self.assertEqual(c1, c2) def testTypeId(self): """! Test type ID @param self this object @return none """ - typeId1 = ns.core.TypeId.LookupByNameFailSafe("ns3::UdpSocketFactory") + ok, typeId1 = ns.LookupByNameFailSafe("ns3::UdpSocketFactory") + self.assertTrue(ok) self.assertEqual(typeId1.GetName (), "ns3::UdpSocketFactory") - self.assertRaises(KeyError, ns.core.TypeId.LookupByNameFailSafe, "__InvalidTypeName__") + ok, typeId1 = ns.LookupByNameFailSafe("ns3::__InvalidTypeName__") + self.assertFalse(ok) - def testCommandLine(self): - """! Test command line - @param self this object - @return none - """ - cmd = ns.core.CommandLine() - cmd.AddValue("Test1", "this is a test option") - cmd.AddValue("Test2", "this is a test option") - cmd.AddValue("Test3", "this is a test option", variable="test_xxx") - cmd.Test1 = None - cmd.Test2 = None - cmd.test_xxx = None - class Foo: - pass - foo = Foo() - foo.test_foo = None - cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo) - - cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"]) - - self.assertEqual(cmd.Test1, "value1") - self.assertEqual(cmd.Test2, "value2") - self.assertEqual(cmd.test_xxx, "123") - self.assertEqual(foo.test_foo, "xpto") +# def testCommandLine(self): +# """! Test command line +# @param self this object +# @return none +# """ +# cmd = ns.core.CommandLine(__file__) +# cmd.AddValue("Test1", "this is a test option") +# cmd.AddValue("Test2", "this is a test option") +# cmd.AddValue("Test3", "this is a test option", variable="test_xxx") +# cmd.Test1 = None +# cmd.Test2 = None +# cmd.test_xxx = None +# class Foo: +# pass +# foo = Foo() +# foo.test_foo = None +# cmd.AddValue("Test4", "this is a test option", variable="test_foo", namespace=foo) +# +# cmd.Parse(["python", "--Test1=value1", "--Test2=value2", "--Test3=123", "--Test4=xpto"]) +# +# self.assertEqual(cmd.Test1, "value1") +# self.assertEqual(cmd.Test2, "value2") +# self.assertEqual(cmd.test_xxx, "123") +# self.assertEqual(foo.test_foo, "xpto") def testSubclass(self): """! Test subclass @@ -271,15 +301,14 @@ class TestSimulator(unittest.TestCase): """ ## MyNode class class MyNode(ns.network.Node): - def __init__(self): - """! Initializer - @param self this object - @return none - """ - super(MyNode, self).__init__() + def GetLocalTime(self) -> ns.Time: + return ns.Seconds(10) node = MyNode() + forced_local_time = node.GetLocalTime() + self.assertEqual(forced_local_time, ns.Seconds(10)) + del node if __name__ == '__main__': - unittest.main() + unittest.main(verbosity=1, failfast=True)