cyphesis/rulesets/python/CyPy_Operation.cpp
2018-07-29 19:53:43 +02:00

406 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 "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 typeArg = args.front();
if (!typeArg.isString()) {
throw Py::TypeError("First argument must be string.");
}
Root r = Atlas::Objects::Factories::instance()->createObject(Py::String(typeArg).as_string());
m_value = Atlas::Objects::smart_dynamic_cast<RootOperation>(r);
if (!m_value) {
// PyErr_SetString(PyExc_TypeError, "Operation() unknown operation type requested");
// return -1;
m_value = Generic();
m_value->setParent(Py::String(typeArg).as_string());
}
if (kwds.size()) {
if (kwds.hasKey("from_")) {
auto fromObj = kwds.getItem("from_");
if (fromObj.isString()) {
m_value->setFrom(fromObj.as_string());
} else if (fromObj.hasAttr("id") && fromObj.getAttr("id").isString()) {
m_value->setFrom(fromObj.getAttr("id").as_string());
} else {
throw Py::TypeError("from is not a string and has no id");
}
}
if (kwds.hasKey("to")) {
auto toObj = kwds.getItem("to");
if (toObj.isString()) {
m_value->setTo(toObj.as_string());
} else if (toObj.hasAttr("id") && toObj.getAttr("id").isString()) {
m_value->setTo(toObj.getAttr("id").as_string());
} else {
throw Py::TypeError("to is not a string and has no id");
}
}
}
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 (CyPy_Element::check(arg)) {
Py::PythonClassObject<CyPy_Element> obj(arg);
auto& o = obj.getCxxObject()->m_value;
if (o.isMap()) {
args.push_back(Atlas::Objects::Factories::instance()->createObject(o.asMap()));
} else {
throw Py::TypeError("Operation arg is not a map");
}
} else if (CyPy_Operation::check(arg)) {
Py::PythonClassObject<CyPy_Operation> obj(arg);
args.push_back(obj.getCxxObject()->m_value);
} else if (CyPy_RootEntity::check(arg)) {
Py::PythonClassObject<CyPy_RootEntity> obj(arg);
args.push_back(obj.getCxxObject()->m_value);
} 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(setSerialno, setSerialno, "");
PYCXX_ADD_VARARGS_METHOD(setRefno, setRefno, "");
PYCXX_ADD_VARARGS_METHOD(setFrom, setFrom, "");
PYCXX_ADD_VARARGS_METHOD(setTo, setTo, "");
PYCXX_ADD_VARARGS_METHOD(setSeconds, setSeconds, "");
PYCXX_ADD_VARARGS_METHOD(setFutureSeconds, setFutureSeconds, "");
PYCXX_ADD_VARARGS_METHOD(setName, setName, "");
PYCXX_ADD_VARARGS_METHOD(setArgs, setArgs, "");
PYCXX_ADD_NOARGS_METHOD(getSerialno, getSerialno, "");
PYCXX_ADD_NOARGS_METHOD(isDefaultSerialno, isDefaultSerialno, "");
PYCXX_ADD_NOARGS_METHOD(getRefno, getRefno, "");
PYCXX_ADD_NOARGS_METHOD(getFrom, getFrom, "");
PYCXX_ADD_NOARGS_METHOD(getTo, getTo, "");
PYCXX_ADD_NOARGS_METHOD(getSeconds, getSeconds, "");
PYCXX_ADD_NOARGS_METHOD(getFutureSeconds, getFutureSeconds, "");
PYCXX_ADD_NOARGS_METHOD(getName, getName, "");
PYCXX_ADD_NOARGS_METHOD(getArgs, getArgs, "");
PYCXX_ADD_NOARGS_METHOD(get_name, get_name, "");
behaviors().readyType();
}
Py::Object CyPy_Operation::setSerialno(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isLong()) {
throw Py::TypeError("Must submit long.");
}
m_value->setSerialno(Py::Long(arg));
return Py::None();
}
Py::Object CyPy_Operation::setRefno(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isLong()) {
throw Py::TypeError("Must submit long.");
}
m_value->setRefno(Py::Long(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setFrom(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isString()) {
throw Py::TypeError("Must submit string.");
}
m_value->setFrom(Py::String(args.front()).as_string());
return Py::None();
}
Py::Object CyPy_Operation::setTo(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isString()) {
throw Py::TypeError("Must submit string.");
}
m_value->setTo(Py::String(args.front()).as_string());
return Py::None();
}
Py::Object CyPy_Operation::setSeconds(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isNumeric()) {
throw Py::TypeError("Must submit numeric.");
}
m_value->setSeconds(Py::Float(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setFutureSeconds(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isNumeric()) {
throw Py::TypeError("Must submit numeric.");
}
m_value->setFutureSeconds(Py::Float(args.front()));
return Py::None();
}
Py::Object CyPy_Operation::setName(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isString()) {
throw Py::TypeError("Must submit string.");
}
m_value->setName(Py::String(args.front()).as_string());
return Py::None();
}
Py::Object CyPy_Operation::setArgs(const Py::Tuple& args)
{
args.verify_length(1);
auto arg = args.front();
if (!arg.isList()) {
throw Py::TypeError("Must submit list.");
}
Py::List argsAsList(args.front());
std::vector<Root> argslist;
for (auto item : argsAsList) {
if (CyPy_Operation::check(item)) {
argslist.push_back(Py::PythonClassObject<CyPy_Operation>(item).getCxxObject()->m_value);
} else if (CyPy_Element::check(item)) {
auto& e = CyPy_Element::value(item);
if (!e.isMap()) {
throw Py::TypeError("args contains non map");
}
argslist.push_back(Factories::instance()->createObject(e.Map()));
} else if (CyPy_RootEntity::check(item)) {
argslist.push_back(Py::PythonClassObject<CyPy_RootEntity>(item).getCxxObject()->m_value);
} else {
//std::cout << "o: " << i << item->ob_type->tp_name << std::endl << std::flush;
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.isValid()) {
return CyPy_Operation::wrap(std::move(op));
}
RootEntity ent = Atlas::Objects::smart_dynamic_cast<RootEntity>(arg);
if (ent.isValid()) {
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());
}
return PythonExtensionBase::getattro(name);
}
int CyPy_Operation::setattro(const Py::String& name, const Py::Object& attr)
{
auto nameStr = name.as_string();
//TODO: Original code looked for an attribute "id" in the submitted "attr" object.
//We've kept this, but it's not clear exactly why it's this way. Perhaps look into changing it?
if (nameStr == "from_") {
if (attr.hasAttr("id")) {
auto inner = attr.getAttr("id");
if (inner.isString()) {
m_value->setFrom(Py::String(inner));
return 0;
}
}
throw Py::TypeError("invalid from_");
}
if (nameStr == "to") {
if (attr.hasAttr("id")) {
auto inner = attr.getAttr("id");
if (inner.isString()) {
m_value->setTo(Py::String(inner));
return 0;
}
}
throw Py::TypeError("invalid to_");
}
throw Py::AttributeError("unknown attribute");
}