Code forensics  0.1
Generate historical information about code changes
python_interop.hpp
Go to the documentation of this file.
1 
4 #ifndef PYTHON_INTEROP_HPP
5 #define PYTHON_INTEROP_HPP
6 
7 #include "common.hpp"
8 #include "logging.hpp"
9 
10 
11 #include <boost/python.hpp>
12 
13 // Python datetime header file
14 #include <datetime.h>
15 
16 namespace py = boost::python;
17 
18 class PyForensics {
19  py::object path_predicate;
22  py::object sample_predicate;
23  py::object post_analyze;
24  SPtr<Logger> logger;
25 
26  public:
27  void set_logger(SPtr<Logger> log) { logger = log; }
28 
30  void log_info(CR<Str> text) { LOG_I(logger) << text; }
32  void log_warning(CR<Str> text) { LOG_W(logger) << text; }
34  void log_trace(CR<Str> text) { LOG_T(logger) << text; }
36  void log_debug(CR<Str> text) { LOG_D(logger) << text; }
38  void log_error(CR<Str> text) { LOG_E(logger) << text; }
40  void log_fatal(CR<Str> text) { LOG_F(logger) << text; }
41 
42 
44  void set_post_analyze(py::object post) { post_analyze = post; }
45 
47  void set_path_predicate(py::object predicate) {
48  path_predicate = predicate;
49  }
50 
52  void set_commit_period_mapping(py::object mapping) {
53  commit_period_mapping = mapping;
54  }
55 
57  void set_sample_period_mapping(py::object mapping) {
58  sample_period_mapping = mapping;
59  }
60 
62  void set_sample_predicate(py::object predicate) {
63  sample_predicate = predicate;
64  }
65 
66 
69  bool allow_path(CR<Str> path) const {
70  if (path_predicate) {
71  return py::extract<bool>(path_predicate(path));
72  } else {
73  return true;
74  }
75  }
76 
78  int get_commit_period(CR<PTime> date) const {
80  return py::extract<int>(commit_period_mapping(date));
81  } else {
82  return 0;
83  }
84  }
85 
86 
88  int get_sample_period(CR<PTime> date) const {
90  return py::extract<int>(sample_period_mapping(date));
91  } else {
92  return 0;
93  }
94  }
95 
98  bool allow_sample_at_date(CR<PTime> date, CR<Str> author, CR<Str> id)
99  const {
100  if (sample_predicate) {
101  return py::extract<bool>(sample_predicate(date, author, id));
102  } else {
103  return true;
104  }
105  }
106 
107  void run_post_analyze() const {
108  if (post_analyze) { post_analyze(); }
109  }
110 };
111 
112 
115 template <typename T>
117  static PyObject* convert(T const&);
118 };
119 
120 template <typename T>
123  py::converter::registry::push_back(
124  convertible, construct, py::type_id<T>());
125  }
126 
127  static void* convertible(PyObject* obj);
128 
129  static void construct(
130  PyObject* obj,
131  py::converter::rvalue_from_python_stage1_data* data);
132 };
133 
136 template <>
137 PyObject* type_into_python<PTime>::convert(CR<PTime> t) {
138  auto d = t.date();
139  auto tod = t.time_of_day();
140  auto usec = tod.total_microseconds() % 1000000;
141  return PyDateTime_FromDateAndTime(
142  d.year(),
143  d.month(),
144  d.day(),
145  tod.hours(),
146  tod.minutes(),
147  tod.seconds(),
148  usec);
149 }
150 
151 template <>
153  return PyDateTime_Check(obj) ? obj : nullptr;
154 }
155 
156 template <>
158  PyObject* obj,
159  py::converter::rvalue_from_python_stage1_data* data) {
160  auto storage = reinterpret_cast<
161  py::converter::rvalue_from_python_storage<PTime>*>(
162  data)
163  ->storage.bytes;
164  Date date_only(
165  PyDateTime_GET_YEAR(obj),
166  PyDateTime_GET_MONTH(obj),
167  PyDateTime_GET_DAY(obj));
168  TimeDuration time_of_day(
169  PyDateTime_DATE_GET_HOUR(obj),
170  PyDateTime_DATE_GET_MINUTE(obj),
171  PyDateTime_DATE_GET_SECOND(obj));
172  time_of_day += boost::posix_time::microsec(
173  PyDateTime_DATE_GET_MICROSECOND(obj));
174  new (storage) PTime(date_only, time_of_day);
175  data->convertible = storage;
176 }
178 
179 template <>
181  return PyDate_FromDate(d.year(), d.month(), d.day());
182 }
183 
184 template <>
186  return PyDate_Check(obj) ? obj : nullptr;
187 }
188 
189 template <>
191  PyObject* obj,
192  py::converter::rvalue_from_python_stage1_data* data) {
193  auto storage = reinterpret_cast<
194  py::converter::rvalue_from_python_storage<Date>*>(
195  data)
196  ->storage.bytes;
197  new (storage) Date(
198  PyDateTime_GET_YEAR(obj),
199  PyDateTime_GET_MONTH(obj),
200  PyDateTime_GET_DAY(obj));
201  data->convertible = storage;
202 }
203 
204 
206  PyDateTime_IMPORT;
207 
208  py::to_python_converter<PTime, type_into_python<PTime>>();
210 
211  py::to_python_converter<Date, type_into_python<Date>>();
213 
214  py::object class_creator =
215  //
216  py::class_<PyForensics>("Forensics") //
217  .def("log_info", &PyForensics::log_info, py::args("text"))
218  .def(
219  "log_warning", &PyForensics::log_warning, py::args("text"))
220  .def("log_trace", &PyForensics::log_trace, py::args("text"))
221  .def("log_debug", &PyForensics::log_debug, py::args("text"))
222  .def("log_error", &PyForensics::log_error, py::args("text"))
223  .def("log_fatal", &PyForensics::log_fatal, py::args("text"))
224  .def(
225  "set_post_analyze",
227  py::arg("post"))
228  .def(
229  "set_path_predicate",
231  py::args("predicate"))
232  .def(
233  "set_commit_period_mapping",
235  py::args("mapping"))
236  .def(
237  "set_sample_period_mapping",
239  py::args("mapping"))
240  .def(
241  "set_sample_predicate",
243  py::args("predicate"));
244 
245  py::object module_level_object = class_creator();
246  py::scope().attr("config") = module_level_object;
247 }
248 
249 #endif // PYTHON_INTEROP_HPP
PyForensics::post_analyze
py::object post_analyze
Definition: python_interop.hpp:23
type_from_python
Definition: python_interop.hpp:121
PyForensics::log_warning
void log_warning(CR< Str > text)
write text as a warning-level log record
Definition: python_interop.hpp:32
BOOST_PYTHON_MODULE
BOOST_PYTHON_MODULE(forensics)
Definition: python_interop.hpp:205
PyForensics::sample_predicate
py::object sample_predicate
Definition: python_interop.hpp:22
LOG_F
#define LOG_F(state)
Definition: logging.hpp:158
PyForensics::get_sample_period
int get_sample_period(CR< PTime > date) const
Get period number from the specified commit date.
Definition: python_interop.hpp:88
PyForensics::allow_sample_at_date
bool allow_sample_at_date(CR< PTime > date, CR< Str > author, CR< Str > id) const
Check whether commit by.
Definition: python_interop.hpp:98
PyForensics::get_commit_period
int get_commit_period(CR< PTime > date) const
Get period number from the specified commit date.
Definition: python_interop.hpp:78
PyForensics::set_logger
void set_logger(SPtr< Logger > log)
Definition: python_interop.hpp:27
PyForensics::logger
SPtr< Logger > logger
Definition: python_interop.hpp:24
LOG_W
#define LOG_W(state)
Definition: logging.hpp:154
LOG_D
#define LOG_D(state)
Definition: logging.hpp:150
PTime
boost::posix_time::ptime PTime
Definition: program_state.hpp:25
logging.hpp
PyForensics::set_sample_predicate
void set_sample_predicate(py::object predicate)
set sample predicate callback for the allow_sample_at_date predicate
Definition: python_interop.hpp:62
PyForensics::set_commit_period_mapping
void set_commit_period_mapping(py::object mapping)
set period mapping callback for the get_commit_period
Definition: python_interop.hpp:52
PyForensics::log_fatal
void log_fatal(CR< Str > text)
write text as a fatal-level log record
Definition: python_interop.hpp:40
PyForensics::sample_period_mapping
py::object sample_period_mapping
Definition: python_interop.hpp:21
PyForensics::set_post_analyze
void set_post_analyze(py::object post)
set post-analyze hook implementation
Definition: python_interop.hpp:44
type_into_python
helper type to aid conversion from input type T to the python object
Definition: python_interop.hpp:116
PyForensics
Definition: python_interop.hpp:18
type_from_python::construct
static void construct(PyObject *obj, py::converter::rvalue_from_python_stage1_data *data)
type_into_python::convert
static PyObject * convert(T const &)
PyForensics::set_path_predicate
void set_path_predicate(py::object predicate)
set path filtering predicate for the allow_path predicate
Definition: python_interop.hpp:47
PyForensics::log_info
void log_info(CR< Str > text)
write text as a info-level log record
Definition: python_interop.hpp:30
LOG_E
#define LOG_E(state)
Definition: logging.hpp:156
PyForensics::path_predicate
py::object path_predicate
Definition: python_interop.hpp:19
type_from_python::type_from_python
type_from_python()
Definition: python_interop.hpp:122
PyForensics::commit_period_mapping
py::object commit_period_mapping
Definition: python_interop.hpp:20
PyForensics::allow_path
bool allow_path(CR< Str > path) const
Check whether provided path should be processed for the 'blame' information.
Definition: python_interop.hpp:69
LOG_I
#define LOG_I(state)
Definition: logging.hpp:152
PyForensics::log_debug
void log_debug(CR< Str > text)
write text as a debug-level log record
Definition: python_interop.hpp:36
PyForensics::run_post_analyze
void run_post_analyze() const
Definition: python_interop.hpp:107
Date
boost::gregorian::date Date
Definition: program_state.hpp:24
type_from_python::convertible
static void * convertible(PyObject *obj)
PyForensics::log_error
void log_error(CR< Str > text)
write text as a error-level log record
Definition: python_interop.hpp:38
TimeDuration
boost::posix_time::time_duration TimeDuration
Definition: program_state.hpp:26
PyForensics::log_trace
void log_trace(CR< Str > text)
write text as a trace-level log record
Definition: python_interop.hpp:34
PyForensics::set_sample_period_mapping
void set_sample_period_mapping(py::object mapping)
set period mapping callback for the get_sample_period
Definition: python_interop.hpp:57
LOG_T
#define LOG_T(state)
Definition: logging.hpp:148