1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/pxr.h"
26 
27 #include "pxr/base/tf/pyArg.h"
28 #include "pxr/base/tf/pyUtils.h"
29 #include "pxr/base/tf/stringUtils.h"
30 
31 #include <boost/python/extract.hpp>
32 #include <boost/python/list.hpp>
33 #include <boost/python/slice.hpp>
34 #include <boost/python/stl_iterator.hpp>
35 
36 using std::string;
37 using std::vector;
38 
39 using namespace boost::python;
40 
41 PXR_NAMESPACE_OPEN_SCOPE
42 
43 static bool
_ArgumentIsNamed(const std::string & name,const TfPyArg & arg)44 _ArgumentIsNamed(const std::string& name, const TfPyArg& arg)
45 {
46     return arg.GetName() == name;
47 }
48 
49 std::pair<tuple, dict>
TfPyProcessOptionalArgs(const tuple & args,const dict & kwargs,const TfPyArgs & expectedArgs,bool allowExtraArgs)50 TfPyProcessOptionalArgs(
51     const tuple& args, const dict& kwargs,
52     const TfPyArgs& expectedArgs,
53     bool allowExtraArgs)
54 {
55     std::pair<tuple, dict> rval;
56 
57     const unsigned int numArgs = static_cast<unsigned int>(len(args));
58     const unsigned int numExpectedArgs = static_cast<unsigned int>(expectedArgs.size());
59 
60     if (!allowExtraArgs) {
61         if (numArgs > numExpectedArgs) {
62             TfPyThrowTypeError("Too many arguments for function");
63         }
64 
65         const list keys = kwargs.keys();
66 
67         typedef stl_input_iterator<string> KeyIterator;
68         for (KeyIterator it(keys), it_end; it != it_end; ++it) {
69             if (std::find_if(expectedArgs.begin(), expectedArgs.end(),
70                              std::bind(_ArgumentIsNamed, *it,
71                                        std::placeholders::_1))
72                 == expectedArgs.end()) {
73 
74                 TfPyThrowTypeError("Unexpected keyword argument '%s'");
75             }
76         }
77     }
78 
79     rval.second = kwargs;
80 
81     for (unsigned int i = 0; i < std::min(numArgs, numExpectedArgs); ++i) {
82         const string& argName = expectedArgs[i].GetName();
83         if (rval.second.has_key(argName)) {
84             TfPyThrowTypeError(
85                 TfStringPrintf("Multiple values for keyword argument '%s'",
86                                argName.c_str()));
87         }
88 
89         rval.second[argName] = args[i];
90     }
91 
92     if (numArgs > numExpectedArgs) {
93         rval.first = tuple(args[slice(numExpectedArgs, numArgs)]);
94     }
95 
96     return rval;
97 }
98 
99 static void
_AddArgAndTypeDocStrings(const TfPyArg & arg,vector<string> * argStrs,vector<string> * typeStrs)100 _AddArgAndTypeDocStrings(
101     const TfPyArg& arg, vector<string>* argStrs, vector<string>* typeStrs)
102 {
103     argStrs->push_back(arg.GetName());
104     if (!arg.GetDefaultValueDoc().empty()) {
105         argStrs->back() +=
106             TfStringPrintf(" = %s", arg.GetDefaultValueDoc().c_str());
107     }
108 
109     typeStrs->push_back(
110         TfStringPrintf("%s : %s",
111                        arg.GetName().c_str(), arg.GetTypeDoc().c_str()));
112 }
113 
114 string
TfPyCreateFunctionDocString(const string & functionName,const TfPyArgs & requiredArgs,const TfPyArgs & optionalArgs,const string & description)115 TfPyCreateFunctionDocString(
116     const string& functionName,
117     const TfPyArgs& requiredArgs,
118     const TfPyArgs& optionalArgs,
119     const string& description)
120 {
121     string rval = functionName + "(";
122 
123     vector<string> argStrs;
124     vector<string> typeStrs;
125 
126     for (size_t i = 0; i < requiredArgs.size(); ++i) {
127         _AddArgAndTypeDocStrings(requiredArgs[i], &argStrs, &typeStrs);
128     }
129 
130     for (size_t i = 0; i < optionalArgs.size(); ++i) {
131         _AddArgAndTypeDocStrings(optionalArgs[i], &argStrs, &typeStrs);
132     }
133 
134     rval += TfStringJoin(argStrs.begin(), argStrs.end(), ", ");
135     rval += ")";
136 
137     if (!typeStrs.empty()) {
138         rval += "\n";
139         rval += TfStringJoin(typeStrs.begin(), typeStrs.end(), "\n");
140     }
141 
142     if (!description.empty()) {
143         rval += "\n\n";
144         rval += description;
145     }
146 
147     return rval;
148 }
149 
150 PXR_NAMESPACE_CLOSE_SCOPE
151