cyphesis/rules/python/CyPy_Operation.cpp
Erik Ogenvik e1ab2f5f85 Handle native Python types instead of Message.
When handling properties and attributes in the Python code we now use
native types, together with ElementMap and ElementList.
2018-12-16 17:31:35 +01:00

401 lines
12 KiB
C++

/*
Copyright (C) 2018 Erik Ogenvik
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "CyPy_Operation.h"
#include "CyPy_Element.h"
#include "CyPy_RootEntity.h"
#include "rules/entityfilter/python/CyPy_EntityFilter.h"
#include "CyPy_Oplist.h"
#include <Atlas/Objects/Generic.h>
#include <Atlas/Objects/Entity.h>
#include <common/log.h>
using Atlas::Message::Element;
using Atlas::Message::ListType;
using Atlas::Objects::Root;
using Atlas::Objects::Factories;
using Atlas::Objects::Operation::RootOperation;
using Atlas::Objects::Operation::Generic;
using Atlas::Objects::Entity::RootEntity;
CyPy_Operation::CyPy_Operation(Py::PythonClassInstance* self, Py::Tuple& args, Py::Dict& kwds)
: WrapperBase(self, args, kwds)
{
if (args.size() == 0) {
throw Py::TypeError("Must submit argument for operation type.");
}
auto parent = verifyString(args.front());
Root r = Atlas::Objects::Factories::instance()->createObject(parent);
m_value = Atlas::Objects::smart_dynamic_cast<RootOperation>(r);
if (!m_value) {
m_value = Generic();
m_value->setParent(parent);
}
for (auto entry : kwds) {
if (entry.first.isString()) {
setattro(entry.first.as_string(), entry.second);
}
}
if (args.size() > 1) {
auto& args_list = m_value->modifyArgs();
for (PyCxx_ssize_t i = 1; i < args.size(); ++i) {
addToArgs(args_list, args[i]);
}
}
}
CyPy_Operation::CyPy_Operation(Py::PythonClassInstance* self, Atlas::Objects::Operation::RootOperation value)
: WrapperBase(self, std::move(value))
{
}
void CyPy_Operation::addToArgs(std::vector<Root>& args, const Py::Object& arg)
{
if (arg.isDict()) {
args.push_back(Atlas::Objects::Factories::instance()->createObject(CyPy_Element::dictAsElement(Py::Dict(arg))));
} else if (CyPy_ElementMap::check(arg)) {
args.push_back(Atlas::Objects::Factories::instance()->createObject(CyPy_ElementMap::value(arg)));
} else if (CyPy_Operation::check(arg)) {
args.push_back(CyPy_Operation::value(arg));
} else if (CyPy_RootEntity::check(arg)) {
args.push_back(CyPy_RootEntity::value(arg));
} else {
throw Py::TypeError("Operation arg is of unknown type");
}
}
void CyPy_Operation::init_type()
{
behaviors().name("Operation");
behaviors().doc("");
behaviors().supportNumberType(Py::PythonType::support_number_add);
behaviors().supportSequenceType(Py::PythonType::support_sequence_length
| Py::PythonType::support_sequence_item);
PYCXX_ADD_VARARGS_METHOD(set_serialno, setSerialno, "");
PYCXX_ADD_VARARGS_METHOD(set_refno, setRefno, "");
PYCXX_ADD_VARARGS_METHOD(set_from, setFrom, "");
PYCXX_ADD_VARARGS_METHOD(set_to, setTo, "");
PYCXX_ADD_VARARGS_METHOD(set_seconds, setSeconds, "");
PYCXX_ADD_VARARGS_METHOD(set_future_seconds, setFutureSeconds, "");
PYCXX_ADD_VARARGS_METHOD(set_name, setName, "");
PYCXX_ADD_VARARGS_METHOD(set_args, setArgs, "");
PYCXX_ADD_NOARGS_METHOD(get_serialno, getSerialno, "");
PYCXX_ADD_NOARGS_METHOD(is_default_serialno, isDefaultSerialno, "");
PYCXX_ADD_NOARGS_METHOD(get_refno, getRefno, "");
PYCXX_ADD_NOARGS_METHOD(get_from, getFrom, "");
PYCXX_ADD_NOARGS_METHOD(get_to, getTo, "");
PYCXX_ADD_NOARGS_METHOD(get_seconds, getSeconds, "");
PYCXX_ADD_NOARGS_METHOD(get_future_seconds, getFutureSeconds, "");
PYCXX_ADD_NOARGS_METHOD(get_args, getArgs, "");
PYCXX_ADD_NOARGS_METHOD(get_name, get_name, "");
behaviors().readyType();
}
Py::Object CyPy_Operation::setSerialno(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setSerialno(verifyLong(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setRefno(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setRefno(verifyLong(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setFrom(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setFrom(verifyString(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setTo(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setTo(verifyString(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setSeconds(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setSeconds(verifyFloat(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setFutureSeconds(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setFutureSeconds(verifyFloat(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setName(const Py::Tuple& args)
{
args.verify_length(1);
m_value->setName(verifyString(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setArgs(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isSequence()) {
throw Py::TypeError("Must submit sequence.");
}
Py::Sequence argsAsSequence(args.front());
std::vector<Root> argslist;
for (auto item : argsAsSequence) {
if (CyPy_Operation::check(item)) {
argslist.push_back(CyPy_Operation::value(item));
} else if (item.isDict()) {
argslist.push_back(Factories::instance()->createObject(CyPy_Element::dictAsElement(Py::Dict(item))));
} else if (CyPy_ElementMap::check(item)) {
argslist.push_back(Factories::instance()->createObject(CyPy_ElementMap::value(item)));
} else if (CyPy_RootEntity::check(item)) {
argslist.push_back(CyPy_RootEntity::value(item));
} else {
throw Py::TypeError("args contains non Atlas Object");
}
}
m_value->setArgs(argslist);
return Py::None();
}
Py::Object CyPy_Operation::getSerialno()
{
return Py::Long(m_value->getSerialno());
}
Py::Object CyPy_Operation::isDefaultSerialno()
{
return Py::Boolean(m_value->isDefaultSerialno());
}
Py::Object CyPy_Operation::getRefno()
{
return Py::Long(m_value->getRefno());
}
Py::Object CyPy_Operation::getFrom()
{
return Py::String(m_value->getFrom());
}
Py::Object CyPy_Operation::getTo()
{
return Py::String(m_value->getTo());
}
Py::Object CyPy_Operation::getSeconds()
{
return Py::Float(m_value->getSeconds());
}
Py::Object CyPy_Operation::getFutureSeconds()
{
return Py::Float(m_value->getFutureSeconds());
}
Py::Object CyPy_Operation::getName()
{
return Py::String(m_value->getName());
}
Py::Object CyPy_Operation::getArgs()
{
auto args_list = m_value->getArgs();
Py::List list;
for (auto& arg : args_list) {
auto elementObj = CyPy_Element::wrap(arg->asMessage());
list.append(elementObj);
}
return list;
}
Py::Object CyPy_Operation::get_name()
{
return Py::String("op");
}
PyCxx_ssize_t CyPy_Operation::sequence_length()
{
return Py::Long(m_value->getArgs().size());
}
Py::Object CyPy_Operation::sequence_item(Py_ssize_t item)
{
auto& args = m_value->getArgs();
if (item < 0 || item >= (Py_ssize_t) args.size()) {
throw Py::IndexError("Operation.[]: Not enough op arguments");
}
const Root& arg = args[item];
RootOperation op = Atlas::Objects::smart_dynamic_cast<RootOperation>(arg);
if (op) {
return CyPy_Operation::wrap(std::move(op));
}
RootEntity ent = Atlas::Objects::smart_dynamic_cast<RootEntity>(arg);
if (ent) {
return CyPy_RootEntity::wrap(std::move(ent));
}
//log(WARNING, "Non operation or entity being returned as arg of operation");
return CyPy_Element::wrap(arg->asMessage());
}
Py::Object CyPy_Operation::number_add(const Py::Object& other)
{
//It's not clear what use this is...
if (other.isNone()) {
return self();
}
if (CyPy_Oplist::check(other)) {
auto list = CyPy_Oplist::value(other);
list.push_back(m_value);
return CyPy_Oplist::wrap(list);
}
if (CyPy_Operation::check(other)) {
std::vector<Atlas::Objects::Operation::RootOperation> oplist;
oplist.push_back(m_value);
oplist.push_back(CyPy_Operation::value(other));
return CyPy_Oplist::wrap(oplist);
}
throw Py::TypeError("Unknown other in Operation.num_add");
}
Py::Object CyPy_Operation::getattro(const Py::String& name)
{
auto nameStr = name.as_string();
if (nameStr == "from_") {
return Py::String(m_value->getFrom());
}
if (nameStr == "to") {
return Py::String(m_value->getTo());
}
//Why should "id" return the parent?
if (nameStr == "id") {
return Py::String(m_value->getParent());
}
if (nameStr == "future_seconds") {
return getFutureSeconds();
}
if (nameStr == "name") {
return getName();
}
if (nameStr == "serialno") {
return getSerialno();
}
if (nameStr == "refno") {
return getRefno();
}
if (nameStr == "args") {
return getArgs();
}
return PythonExtensionBase::getattro(name);
}
int CyPy_Operation::setattro(const Py::String& name, const Py::Object& attr)
{
auto nameStr = name.as_string();
if (nameStr == "from_") {
if (attr.isString()) {
m_value->setFrom(attr.as_string());
return 0;
} else if (attr.hasAttr("id") && attr.getAttr("id").isString()) {
m_value->setFrom(attr.getAttr("id").as_string());
return 0;
} else if (attr.isDict()) {
Py::Dict dict(attr);
if (dict.hasKey("id")) {
auto value = dict.getItem("id");
if (value.isString()) {
m_value->setFrom(value.as_string());
return 0;
}
}
}
throw Py::TypeError("from_ is neither a string nor an object with an 'id' attribute");
}
if (nameStr == "to") {
if (attr.isString()) {
m_value->setTo(attr.as_string());
return 0;
} else if (attr.hasAttr("id") && attr.getAttr("id").isString()) {
m_value->setTo(attr.getAttr("id").as_string());
return 0;
} else if (attr.isDict()) {
Py::Dict dict(attr);
if (dict.hasKey("id")) {
auto value = dict.getItem("id");
if (value.isString()) {
m_value->setTo(value.as_string());
return 0;
}
}
}
throw Py::TypeError("to is neither a string nor an object with an 'id' attribute");
}
if (nameStr == "future_seconds") {
m_value->setFutureSeconds(verifyFloat(attr));
return 0;
}
if (nameStr == "name") {
m_value->setName(verifyString(attr));
return 0;
}
if (nameStr == "serialno") {
m_value->setSerialno(verifyLong(attr));
return 0;
}
if (nameStr == "refno") {
m_value->setRefno(verifyLong(attr));
return 0;
}
if (nameStr == "args") {
setArgs(Py::Tuple(attr));
return 0;
}
throw Py::AttributeError("unknown attribute");
}