<p>Jenkins2 <strong>merged</strong> this change.</p><p><a href="https://gerrit.asterisk.org/8641">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  George Joseph: Looks good to me, but someone else must approve
  Kevin Harwell: Looks good to me, approved
  Jenkins2: Approved for Submit

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Build System: Enable python3 compatibility.<br><br>* Consistently use spaces in rest-api-templates/asterisk_processor.py.<br>* Exclude third-party from docs/full-en_US.xml.<br>* Add docs/full-en_US.xml to .gitignore.<br>* Use list() to convert python3 view.<br>* Use python3 print function.<br>* Replace cmp() with equivalent equation.<br>* Replace reference to out of scope subtype variable with name<br>  parameter.<br>* Use unescaping triple bracket notation in mustache templates where<br>  needed.  This causes behavior of Python2 to be maintained when using<br>  Python3.<br>* Fix references to has_websocket / is_websocket in<br>  res_ari_resource.c.mustache.<br>* Update calculation of has_websocket to use any().<br>* Use unicode mode for writing output file in transform.py.<br>* Replace 'from swagger_model import *' with explicit import of required<br>  symbols.<br><br>I have not tested spandspflow2pcap.py or voicemailpwcheck.py, only the<br>print syntax has been fixed.<br><br>Change-Id: If5c5b556a2800d41a3e2cfef080ac2e151178c33<br>---<br>M Makefile<br>M contrib/scripts/refcounter.py<br>M contrib/scripts/spandspflow2pcap.py<br>M contrib/scripts/voicemailpwcheck.py<br>M doc/.gitignore<br>M rest-api-templates/api.wiki.mustache<br>M rest-api-templates/ari_resource.h.mustache<br>M rest-api-templates/asterisk_processor.py<br>M rest-api-templates/make_ari_stubs.py<br>M rest-api-templates/res_ari_resource.c.mustache<br>M rest-api-templates/swagger_model.py<br>M rest-api-templates/transform.py<br>12 files changed, 49 insertions(+), 44 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/Makefile b/Makefile<br>index 2c10dc4..1cd9665 100644<br>--- a/Makefile<br>+++ b/Makefile<br>@@ -511,7 +511,7 @@<br>       @echo "<!DOCTYPE docs SYSTEM \"appdocsxml.dtd\">" >> $@<br>       @echo "<?xml-stylesheet type=\"text/xsl\" href=\"appdocsxml.xslt\"?>" >> $@<br>         @echo "<docs xmlns:xi=\"http://www.w3.org/2001/XInclude\">" >> $@<br>-    @for x in $(MOD_SUBDIRS); do \<br>+       @for x in $(filter-out third-party,$(MOD_SUBDIRS)); do \<br>              printf "$$x " ; \<br>           for i in `find $$x -name '*.c'`; do \<br>                         $(PYTHON) build_tools/get_documentation.py < $$i >> $@ ; \<br>diff --git a/contrib/scripts/refcounter.py b/contrib/scripts/refcounter.py<br>index 1f4b375..de3cda0 100755<br>--- a/contrib/scripts/refcounter.py<br>+++ b/contrib/scripts/refcounter.py<br>@@ -18,6 +18,7 @@<br>  Matt Jordan <mjordan@digium.com><br> """<br> <br>+from __future__ import print_function<br> import sys<br> import os<br> <br>@@ -35,8 +36,8 @@<br>     """<br>     tokens = line.strip().split(',', 7)<br>     if len(tokens) < 8:<br>-        print "ERROR: ref debug line '%s' contains fewer tokens than " \<br>-              "expected: %d" % (line.strip(), len(tokens))<br>+        print("ERROR: ref debug line '%s' contains fewer tokens than "<br>+              "expected: %d" % (line.strip(), len(tokens)))<br>         return None<br> <br>     processed_line = {'addr': tokens[0],<br>@@ -142,7 +143,7 @@<br>                 del current_objects[obj]<br> <br>     if options.leaks:<br>-        for key, lines in current_objects.iteritems():<br>+        for (key, lines) in current_objects.items():<br>             leaked_objects.append((key, lines))<br>     return (finished_objects, invalid_objects, leaked_objects, skewed_objects)<br> <br>@@ -156,13 +157,13 @@<br>             this object<br>     """<br> <br>-    print "======== %s Objects ========" % prefix<br>-    print "\n"<br>+    print("======== %s Objects ========" % prefix)<br>+    print("\n")<br>     for obj in objects:<br>-        print "==== %s Object %s history ====" % (prefix, obj[0])<br>+        print("==== %s Object %s history ====" % (prefix, obj[0]))<br>         for line in obj[1]['log']:<br>-            print line<br>-        print "\n"<br>+            print(line)<br>+        print("\n")<br> <br> <br> def main(argv=None):<br>@@ -198,11 +199,11 @@<br> <br>     if not options.invalid and not options.leaks and not options.normal \<br>             and not options.skewed:<br>-        print >>sys.stderr, "All options disabled"<br>+        print("All options disabled", file=sys.stderr)<br>         return -1<br> <br>     if not os.path.isfile(options.filepath):<br>-        print >>sys.stderr, "File not found: %s" % options.filepath<br>+        print("File not found: %s" % options.filepath, file=sys.stderr)<br>         return -1<br> <br>     try:<br>@@ -227,7 +228,7 @@<br>             print_objects(finished_objects, "Finalized")<br> <br>     except (KeyboardInterrupt, SystemExit, IOError):<br>-        print >>sys.stderr, "File processing cancelled"<br>+        print("File processing cancelled", file=sys.stderr)<br>         return -1<br> <br>     return ret_code<br>diff --git a/contrib/scripts/spandspflow2pcap.py b/contrib/scripts/spandspflow2pcap.py<br>index a6546b6..7c403f1 100755<br>--- a/contrib/scripts/spandspflow2pcap.py<br>+++ b/contrib/scripts/spandspflow2pcap.py<br>@@ -119,7 +119,7 @@<br>         else:<br>             self.date += timedelta(microseconds=9000)<br> <br>-        print seqno, '\t', self.date + self.dateoff<br>+        print(seqno, '\t', self.date + self.dateoff)<br> <br>         # Make packet.<br>         packet, prev_data = self.data2packet(self.date + self.dateoff,<br>diff --git a/contrib/scripts/voicemailpwcheck.py b/contrib/scripts/voicemailpwcheck.py<br>index d7a66d4..452255c 100755<br>--- a/contrib/scripts/voicemailpwcheck.py<br>+++ b/contrib/scripts/voicemailpwcheck.py<br>@@ -46,20 +46,20 @@<br> <br> # Enforce a password length of at least 6 characters<br> if len(new_pw) < REQUIRED_LENGTH:<br>-    print "INVALID: Password is too short (%d) - must be at least %d" % \<br>-            (len(new_pw), REQUIRED_LENGTH)<br>+    print("INVALID: Password is too short (%d) - must be at least %d" % \<br>+            (len(new_pw), REQUIRED_LENGTH))<br>     sys.exit(0)<br> <br> for regex, error in REGEX_BLACKLIST:<br>     if re.search(regex, new_pw):<br>-        print "INVALID: %s" % error<br>+        print("INVALID: %s" % error)<br>         sys.exit(0)<br> <br> for pw in PW_BLACKLIST:<br>     if new_pw.find(pw) != -1:<br>-        print "INVALID: %s is forbidden in a password" % pw<br>+        print("INVALID: %s is forbidden in a password" % pw)<br>         sys.exit(0)<br> <br>-print "VALID"<br>+print("VALID")<br> <br> sys.exit(0)<br>diff --git a/doc/.gitignore b/doc/.gitignore<br>index 3461c58..49bfe42 100644<br>--- a/doc/.gitignore<br>+++ b/doc/.gitignore<br>@@ -1,4 +1,5 @@<br> core-en_US.xml<br>+full-en_US.xml<br> rest-api<br> api<br> asterisk-ng-doxygen<br>diff --git a/rest-api-templates/api.wiki.mustache b/rest-api-templates/api.wiki.mustache<br>index ad12bb6..a51c3e6 100644<br>--- a/rest-api-templates/api.wiki.mustache<br>+++ b/rest-api-templates/api.wiki.mustache<br>@@ -5,7 +5,7 @@<br> <br> {{#apis}}<br> {{#operations}}<br>-| {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{summary}} |<br>+| {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{{summary}}} |<br> {{/operations}}<br> {{/apis}}<br> {{#apis}}<br>diff --git a/rest-api-templates/ari_resource.h.mustache b/rest-api-templates/ari_resource.h.mustache<br>index df075af..c1d880d 100644<br>--- a/rest-api-templates/ari_resource.h.mustache<br>+++ b/rest-api-templates/ari_resource.h.mustache<br>@@ -76,7 +76,7 @@<br> <br> {{/parse_body}}<br> /*!<br>- * \brief {{summary}}<br>+ * \brief {{{summary}}}<br> {{#notes}}<br>  *<br>  * {{{notes}}}<br>@@ -99,7 +99,7 @@<br> {{#is_websocket}}<br> <br> /*!<br>- * \brief {{summary}}<br>+ * \brief {{{summary}}}<br> {{#notes}}<br>  *<br>  * {{{notes}}}<br>@@ -111,7 +111,7 @@<br> int ast_ari_websocket_{{c_name}}_{{c_nickname}}_init(void);<br> <br> /*!<br>- * \brief {{summary}}<br>+ * \brief {{{summary}}}<br> {{#notes}}<br>  *<br>  * {{{notes}}}<br>diff --git a/rest-api-templates/asterisk_processor.py b/rest-api-templates/asterisk_processor.py<br>index 9812946..5f8dbb5 100644<br>--- a/rest-api-templates/asterisk_processor.py<br>+++ b/rest-api-templates/asterisk_processor.py<br>@@ -23,7 +23,7 @@<br> import os<br> import re<br> <br>-from swagger_model import *<br>+from swagger_model import Stringify, SwaggerError, SwaggerPostProcessor<br> <br> try:<br>     from collections import OrderedDict<br>@@ -183,7 +183,7 @@<br>                 raise SwaggerError(<br>                     "Should not mix resources in one API declaration", context)<br>             # root_path isn't needed any more<br>-            resource_api.root_path = resource_api.root_path.children()[0]<br>+            resource_api.root_path = list(resource_api.root_path.children())[0]<br>             if resource_api.name != resource_api.root_path.name:<br>                 raise SwaggerError(<br>                     "API declaration name should match", context)<br>@@ -206,10 +206,10 @@<br> <br>     def process_parameter(self, parameter, context):<br>         if parameter.param_type == 'body':<br>-     parameter.is_body_parameter = True;<br>+            parameter.is_body_parameter = True;<br>             parameter.c_data_type = 'struct ast_json *'<br>         else:<br>-      parameter.is_body_parameter = False;<br>+            parameter.is_body_parameter = False;<br>             if not parameter.data_type in self.type_mapping:<br>                 raise SwaggerError(<br>                     "Invalid parameter type %s" % parameter.data_type, context)<br>diff --git a/rest-api-templates/make_ari_stubs.py b/rest-api-templates/make_ari_stubs.py<br>index 0aba06d..a25773d 100755<br>--- a/rest-api-templates/make_ari_stubs.py<br>+++ b/rest-api-templates/make_ari_stubs.py<br>@@ -16,19 +16,20 @@<br> # at the top of the source tree.<br> #<br> <br>+from __future__ import print_function<br> import sys<br> <br> try:<br>     import pystache<br> except ImportError:<br>-    print >> sys.stderr, "Pystache required. Please sudo pip install pystache."<br>+    print("Pystache required. Please sudo pip install pystache.", file=sys.stderr)<br>     sys.exit(1)<br> <br> import os.path<br> <br> from asterisk_processor import AsteriskProcessor<br> from optparse import OptionParser<br>-from swagger_model import *<br>+from swagger_model import ResourceListing<br> from transform import Transform<br> <br> TOPDIR = os.path.dirname(os.path.abspath(__file__))<br>diff --git a/rest-api-templates/res_ari_resource.c.mustache b/rest-api-templates/res_ari_resource.c.mustache<br>index 67a04d8..85948fb 100644<br>--- a/rest-api-templates/res_ari_resource.c.mustache<br>+++ b/rest-api-templates/res_ari_resource.c.mustache<br>@@ -55,7 +55,7 @@<br> #if defined(AST_DEVMODE)<br> #include "ari/ari_model_validators.h"<br> #endif<br>-{{^has_websocket}}<br>+{{#has_websocket}}<br> {{! Only include http_websocket if necessary. Otherwise we'll do a lot of<br>  *  unnecessary optional_api intialization, which makes optional_api harder<br>  *  to debug<br>@@ -278,7 +278,7 @@<br> <br> {{#apis}}<br> {{#operations}}<br>-{{#has_websocket}}<br>+{{#is_websocket}}<br>         struct ast_websocket_protocol *protocol;<br> <br>   if (ast_ari_websocket_{{c_name}}_{{c_nickname}}_init() == -1) {<br>@@ -300,8 +300,6 @@<br>  }<br>     protocol->session_attempted = ast_ari_{{c_name}}_{{c_nickname}}_ws_attempted_cb;<br>   protocol->session_established = ast_ari_{{c_name}}_{{c_nickname}}_ws_established_cb;<br>-{{/has_websocket}}<br>-{{#is_websocket}}<br>      res |= ast_websocket_server_add_protocol2({{full_name}}.ws_server, protocol);<br> {{/is_websocket}}<br> {{/operations}}<br>diff --git a/rest-api-templates/swagger_model.py b/rest-api-templates/swagger_model.py<br>index 3f729d8..50c5fb0 100644<br>--- a/rest-api-templates/swagger_model.py<br>+++ b/rest-api-templates/swagger_model.py<br>@@ -26,6 +26,7 @@<br> See https://github.com/wordnik/swagger-core/wiki/API-Declaration for the spec.<br> """<br> <br>+from __future__ import print_function<br> import json<br> import os.path<br> import pprint<br>@@ -75,7 +76,7 @@<br>     '''<br>     lhs = [int(v) for v in lhs.split('.')]<br>     rhs = [int(v) for v in rhs.split('.')]<br>-    return cmp(lhs, rhs)<br>+    return (lhs > rhs) - (lhs < rhs)<br> <br> <br> class ParsingContext(object):<br>@@ -444,8 +445,7 @@<br>         op_json = api_json.get('operations')<br>         self.operations = [<br>             Operation().load(j, processor, context) for j in op_json]<br>-        self.has_websocket = \<br>-            filter(lambda op: op.is_websocket, self.operations) != []<br>+        self.has_websocket = any(op.is_websocket for op in self.operations)<br>         processor.process_api(self, context)<br>         return self<br> <br>@@ -611,7 +611,7 @@<br>         except SwaggerError:<br>             raise<br>         except Exception as e:<br>-            print >> sys.stderr, "Error: ", traceback.format_exc()<br>+            print("Error: ", traceback.format_exc(), file=sys.stderr)<br>             raise SwaggerError(<br>                 "Error loading %s" % api_declaration_file, context, e)<br> <br>@@ -624,8 +624,8 @@<br>             .replace(".json", ".{format}")<br> <br>         if self.resource_path != expected_resource_path:<br>-            print >> sys.stderr, \<br>-                "%s != %s" % (self.resource_path, expected_resource_path)<br>+            print("%s != %s" % (self.resource_path, expected_resource_path),<br>+                file=sys.stderr)<br>             raise SwaggerError("resourcePath has incorrect value", context)<br> <br>         return self<br>@@ -656,8 +656,7 @@<br>             if api.path in paths:<br>                 raise SwaggerError("API with duplicated path: %s" % api.path, context)<br>             paths.add(api.path)<br>-        self.has_websocket = filter(lambda api: api.has_websocket,<br>-                                    self.apis) == []<br>+        self.has_websocket = any(api.has_websocket for api in self.apis)<br>         models = api_decl_json.get('models').items() or []<br>         self.models = [Model().load(id, json, processor, context)<br>                        for (id, json) in models]<br>@@ -666,7 +665,7 @@<br>         model_dict = dict((m.id, m) for m in self.models)<br>         for m in self.models:<br>             def link_subtype(name):<br>-                res = model_dict.get(subtype)<br>+                res = model_dict.get(name)<br>                 if not res:<br>                     raise SwaggerError("%s has non-existing subtype %s",<br>                                        m.id, name)<br>@@ -725,7 +724,7 @@<br>         except SwaggerError:<br>             raise<br>         except Exception as e:<br>-            print >> sys.stderr, "Error: ", traceback.format_exc()<br>+            print("Error: ", traceback.format_exc(), file=sys.stderr)<br>             raise SwaggerError(<br>                 "Error loading %s" % resource_file, context, e)<br> <br>diff --git a/rest-api-templates/transform.py b/rest-api-templates/transform.py<br>index c3a0300..88f7d2e 100644<br>--- a/rest-api-templates/transform.py<br>+++ b/rest-api-templates/transform.py<br>@@ -21,6 +21,11 @@<br> import pystache<br> import shutil<br> import tempfile<br>+import sys<br>+<br>+if sys.version_info[0] == 3:<br>+    def unicode(v):<br>+        return str(v)<br> <br> <br> class Transform(object):<br>@@ -52,10 +57,10 @@<br>         dest_exists = os.path.exists(dest_file)<br>         if dest_exists and not self.overwrite:<br>             return<br>-        with tempfile.NamedTemporaryFile() as out:<br>+        with tempfile.NamedTemporaryFile(mode='w+') as out:<br>             out.write(renderer.render(self.template, model))<br>             out.flush()<br> <br>             if not dest_exists or not filecmp.cmp(out.name, dest_file):<br>-                print "Writing %s" % dest_file<br>+                print("Writing %s" % dest_file)<br>                 shutil.copyfile(out.name, dest_file)<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/8641">change 8641</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/8641"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: If5c5b556a2800d41a3e2cfef080ac2e151178c33 </div>
<div style="display:none"> Gerrit-Change-Number: 8641 </div>
<div style="display:none"> Gerrit-PatchSet: 4 </div>
<div style="display:none"> Gerrit-Owner: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: Alexander Traud <pabstraud@compuserve.com> </div>
<div style="display:none"> Gerrit-Reviewer: Corey Farrell <git@cfware.com> </div>
<div style="display:none"> Gerrit-Reviewer: George Joseph <gjoseph@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins2 </div>
<div style="display:none"> Gerrit-Reviewer: Kevin Harwell <kharwell@digium.com> </div>
<div style="display:none"> Gerrit-Reviewer: Tzafrir Cohen <tzafrir.cohen@xorcom.com> </div>