· 6 years ago · Jan 29, 2020, 12:28 AM
1class FacebookRequest:
2 """
3 Represents an API request
4 """
5
6 def __init__(
7 self,
8 node_id,
9 method,
10 endpoint,
11 api=None,
12 param_checker=TypeChecker({}, {}),
13 target_class=None,
14 api_type=None,
15 allow_file_upload=False,
16 response_parser=None,
17 include_summary=True,
18 api_version=None,
19 ):
20 """
21 Args:
22 node_id: The node id to perform the api call.
23 method: The HTTP method of the call.
24 endpoint: The edge of the api call.
25 api (optional): The FacebookAdsApi object.
26 param_checker (optional): Parameter checker.
27 target_class (optional): The return class of the api call.
28 api_type (optional): NODE or EDGE type of the call.
29 allow_file_upload (optional): Whether the call allows upload.
30 response_parser (optional): An ObjectParser to parse response.
31 include_summary (optional): Include "summary".
32 api_version (optional): API version.
33 """
34 self._api = api or FacebookAdsApi.get_default_api()
35 self._node_id = node_id
36 self._method = method
37 self._endpoint = endpoint.replace('/', '')
38 self._path = (node_id, endpoint.replace('/', ''))
39 self._param_checker = param_checker
40 self._target_class = target_class
41 self._api_type = api_type
42 self._allow_file_upload = allow_file_upload
43 self._response_parser = response_parser
44 self._include_summary = include_summary
45 self._api_version = api_version
46 self._params = {}
47 self._fields = []
48 self._file_params = {}
49 self._file_counter = 0
50 self._accepted_fields = []
51 if target_class is not None:
52 self._accepted_fields = target_class.Field.__dict__.values()
53
54 def add_file(self, file_path):
55 if not self._allow_file_upload:
56 api_utils.warning('Endpoint ' + self._endpoint + ' cannot upload files')
57 file_key = 'source' + str(self._file_counter)
58 if os.path.isfile(file_path):
59 self._file_params[file_key] = file_path
60 self._file_counter += 1
61 else:
62 raise FacebookBadParameterError(
63 'Cannot find file ' + file_path + '!',
64 )
65 return self
66
67 def add_files(self, files):
68 if files is None:
69 return self
70 for file_path in files:
71 self.add_file(file_path)
72 return self
73
74 def add_field(self, field):
75 if field not in self._fields:
76 self._fields.append(field)
77 if field not in self._accepted_fields:
78 api_utils.warning(self._endpoint + ' does not allow field ' + field)
79 return self
80
81 def add_fields(self, fields):
82 if fields is None:
83 return self
84 for field in fields:
85 self.add_field(field)
86 return self
87
88 def add_param(self, key, value):
89 if not self._param_checker.is_valid_pair(key, value):
90 api_utils.warning('value of ' + key + ' might not be compatible. ' +
91 ' Expect ' + self._param_checker.get_type(key) + '; ' +
92 ' got ' + str(type(value)))
93 if self._param_checker.is_file_param(key):
94 self._file_params[key] = value
95 else:
96 self._params[key] = self._extract_value(value)
97 return self
98
99 def add_params(self, params):
100 if params is None:
101 return self
102 for key in params.keys():
103 self.add_param(key, params[key])
104 return self
105
106 def get_fields(self):
107 return list(self._fields)
108
109 def get_params(self):
110 return copy.deepcopy(self._params)
111
112 def execute(self):
113 params = copy.deepcopy(self._params)
114 if self._api_type == "EDGE" and self._method == "GET":
115 cursor = Cursor(
116 target_objects_class=self._target_class,
117 params=params,
118 fields=self._fields,
119 include_summary=self._include_summary,
120 api=self._api,
121 node_id=self._node_id,
122 endpoint=self._endpoint,
123 )
124 cursor.load_next_page()
125 return cursor
126 if self._fields:
127 params['fields'] = ','.join(self._fields)
128 with open_files(self._file_params) as files:
129 response = self._api.call(
130 method=self._method,
131 path=(self._path),
132 params=params,
133 files=files,
134 api_version=self._api_version,
135 )
136 if response.error():
137 raise response.error()
138 if self._response_parser:
139 return self._response_parser.parse_single(response.json())
140 else:
141 return response
142
143 def add_to_batch(self, batch, success=None, failure=None):
144 batch.add_request(self, success, failure)
145
146 def _extract_value(self, value):
147 if hasattr(value, 'export_all_data'):
148 return value.export_all_data()
149 elif isinstance(value, list):
150 return [self._extract_value(item) for item in value]
151 elif isinstance(value, dict):
152 return dict((self._extract_value(k), self._extract_value(v))
153 for (k, v) in value.items())
154 else:
155 return value