PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const { if (IsAllocated() && key.IsValid()) return PythonObject(PyRefType::Borrowed, PyDict_GetItem(m_py_obj, key.get())); return PythonObject(); }
PythonObject PythonObject::ResolveName(llvm::StringRef name) const { // Resolve the name in the context of the specified object. If, for example, // `this` refers to a PyModule, then this will look for `name` in this // module. If `this` refers to a PyType, then it will resolve `name` as an // attribute of that type. If `this` refers to an instance of an object, // then it will resolve `name` as the value of the specified field. // // This function handles dotted names so that, for example, if `m_py_obj` // refers to the `sys` module, and `name` == "path.append", then it will find // the function `sys.path.append`. size_t dot_pos = name.find('.'); if (dot_pos == llvm::StringRef::npos) { // No dots in the name, we should be able to find the value immediately as // an attribute of `m_py_obj`. return GetAttributeValue(name); } // Look up the first piece of the name, and resolve the rest as a child of // that. PythonObject parent = ResolveName(name.substr(0, dot_pos)); if (!parent.IsAllocated()) return PythonObject(); // Tail recursion.. should be optimized by the compiler return parent.ResolveName(name.substr(dot_pos + 1)); }
void PythonList::AppendItem(const PythonObject &object) { if (IsAllocated() && object.IsValid()) { // `PyList_Append` does *not* steal a reference, so do not call `Py_INCREF` // here like we do with `PyList_SetItem`. PyList_Append(m_py_obj, object.get()); } }
DECLARE_EXPORT int ResourceSkill::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_resource)) { if (!field.check(Resource::metadata)) { PyErr_SetString(PythonDataException, "resourceskill resource must be of type resource"); return -1; } Resource* y = static_cast<Resource*>(static_cast<PyObject*>(field)); setResource(y); } else if (attr.isA(Tags::tag_skill)) { if (!field.check(Skill::metadata)) { PyErr_SetString(PythonDataException, "resourceskill skill must be of type skill"); return -1; } Skill* y = static_cast<Skill*>(static_cast<PyObject*>(field)); setSkill(y); } else if (attr.isA(Tags::tag_priority)) setPriority(field.getInt()); else if (attr.isA(Tags::tag_effective_end)) setEffectiveEnd(field.getDate()); else if (attr.isA(Tags::tag_effective_start)) setEffectiveStart(field.getDate()); else return -1; return 0; }
void PythonTuple::SetItemAtIndex(uint32_t index, const PythonObject &object) { if (IsAllocated() && object.IsValid()) { // PyTuple_SetItem is documented to "steal" a reference, so we need to // convert it to an owned reference by incrementing it. Py_INCREF(object.get()); PyTuple_SetItem(m_py_obj, index, object.get()); } }
StructuredData::ArraySP PythonTuple::CreateStructuredArray() const { StructuredData::ArraySP result(new StructuredData::Array); uint32_t count = GetSize(); for (uint32_t i = 0; i < count; ++i) { PythonObject obj = GetItemAtIndex(i); result->AddItem(obj.CreateStructuredObject()); } return result; }
DECLARE_EXPORT int Solver::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_name)) setName(field.getString()); else if (attr.isA(Tags::tag_loglevel)) setLogLevel(field.getInt()); else return -1; // Error return 0; // OK }
DECLARE_EXPORT int Skill::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_name)) setName(field.getString()); else if (attr.isA(Tags::tag_source)) setSource(field.getString()); else return -1; // Error return 0; // OK }
StructuredData::DictionarySP PythonDictionary::CreateStructuredDictionary() const { StructuredData::DictionarySP result(new StructuredData::Dictionary); PythonList keys(GetKeys()); uint32_t num_keys = keys.GetSize(); for (uint32_t i = 0; i < num_keys; ++i) { PythonObject key = keys.GetItemAtIndex(i); PythonObject value = GetItemForKey(key); StructuredData::ObjectSP structured_value = value.CreateStructuredObject(); result->AddItem(key.Str().GetString(), structured_value); } return result; }
DECLARE_EXPORT int SolverMRP::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_constraints)) setConstraints(field.getInt()); else if (attr.isA(Tags::tag_autocommit)) setAutocommit(field.getBool()); else if (attr.isA(Tags::tag_userexit_flow)) setUserExitFlow(field); else if (attr.isA(Tags::tag_userexit_demand)) setUserExitDemand(field); else if (attr.isA(Tags::tag_userexit_buffer)) setUserExitBuffer(field); else if (attr.isA(Tags::tag_userexit_resource)) setUserExitResource(field); else if (attr.isA(Tags::tag_userexit_operation)) setUserExitOperation(field); else if (attr.isA(Tags::tag_plantype)) setPlanType(field.getInt()); // Less common parameters else if (attr.isA(tag_iterationthreshold)) setIterationThreshold(field.getDouble()); else if (attr.isA(tag_iterationaccuracy)) setIterationAccuracy(field.getDouble()); else if (attr.isA(tag_lazydelay)) setLazyDelay(field.getTimeperiod()); else if (attr.isA(tag_allowsplits)) setAllowSplits(field.getBool()); else if (attr.isA(tag_planSafetyStockFirst)) setPlanSafetyStockFirst(field.getBool()); // Default parameters else return Solver::setattro(attr, field); return 0; }
PythonObject PythonObject::ResolveNameWithDictionary(llvm::StringRef name, const PythonDictionary &dict) { size_t dot_pos = name.find('.'); llvm::StringRef piece = name.substr(0, dot_pos); PythonObject result = dict.GetItemForKey(PythonString(piece)); if (dot_pos == llvm::StringRef::npos) { // There was no dot, we're done. return result; } // There was a dot. The remaining portion of the name should be looked up in // the context of the object that was found in the dictionary. return result.ResolveName(name.substr(dot_pos + 1)); }
DECLARE_EXPORT int SetupMatrix::Rule::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_priority)) setPriority(field.getInt()); else if (attr.isA(Tags::tag_fromsetup)) setFromSetup(field.getString()); else if (attr.isA(Tags::tag_tosetup)) setToSetup(field.getString()); else if (attr.isA(Tags::tag_duration)) setDuration(field.getTimeperiod()); else if (attr.isA(Tags::tag_cost)) setCost(field.getDouble()); else return -1; // Error return 0; // OK }
TEST_F(PythonDataObjectsTest, TestPythonCallableInvoke) { auto list = m_builtins_module.ResolveName("list").AsType<PythonCallable>(); PythonInteger one(1); PythonString two("two"); PythonTuple three = {one, two}; PythonTuple tuple_to_convert = {one, two, three}; PythonObject result = list({tuple_to_convert}); EXPECT_TRUE(PythonList::Check(result.get())); auto list_result = result.AsType<PythonList>(); EXPECT_EQ(3U, list_result.GetSize()); EXPECT_EQ(one.get(), list_result.GetItemAtIndex(0).get()); EXPECT_EQ(two.get(), list_result.GetItemAtIndex(1).get()); EXPECT_EQ(three.get(), list_result.GetItemAtIndex(2).get()); }
PythonObject callFunctionWithArgs( PythonObject function, const std::vector<PythonObject>& args, const std::vector<std::pair<std::string, PythonObject>>& kwargs) { if (!PyCallable_Check(function.get())) { throw WrappyError("Wrappy: Supplied object isn't callable."); } // Build tuple size_t sz = args.size(); PythonObject tuple(PythonObject::owning {}, PyTuple_New(sz)); if (!tuple) { PyErr_Print(); throw WrappyError("Wrappy: Couldn't create python typle."); } for (size_t i = 0; i < sz; ++i) { PyObject* arg = args.at(i).get(); Py_XINCREF(arg); // PyTuple_SetItem steals a reference PyTuple_SetItem(tuple.get(), i, arg); } // Build kwargs dict PythonObject dict(PythonObject::owning {}, PyDict_New()); if (!dict) { PyErr_Print(); throw WrappyError("Wrappy: Couldn't create python dictionary."); } for (const auto& kv : kwargs) { PyDict_SetItemString(dict.get(), kv.first.c_str(), kv.second.get()); } PythonObject res(PythonObject::owning{}, PyObject_Call(function.get(), tuple.get(), dict.get())); if (!res) { PyErr_Print(); throw WrappyError("Wrappy: Error calling function"); } return res; }
DECLARE_EXPORT int Item::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_name)) setName(field.getString()); else if (attr.isA(Tags::tag_description)) setDescription(field.getString()); else if (attr.isA(Tags::tag_category)) setCategory(field.getString()); else if (attr.isA(Tags::tag_subcategory)) setSubCategory(field.getString()); else if (attr.isA(Tags::tag_price)) setPrice(field.getDouble()); else if (attr.isA(Tags::tag_owner)) { if (!field.check(Item::metadata)) { PyErr_SetString(PythonDataException, "item owner must be of type item"); return -1; } Item* y = static_cast<Item*>(static_cast<PyObject*>(field)); setOwner(y); } else if (attr.isA(Tags::tag_operation)) { if (!field.check(Operation::metadata)) { PyErr_SetString(PythonDataException, "item operation must be of type operation"); return -1; } Operation* y = static_cast<Operation*>(static_cast<PyObject*>(field)); setOperation(y); } else if (attr.isA(Tags::tag_hidden)) setHidden(field.getBool()); else return -1; return 0; }
DECLARE_EXPORT int Location::setattro(const Attribute& attr, const PythonObject& field) { if (attr.isA(Tags::tag_name)) setName(field.getString()); else if (attr.isA(Tags::tag_description)) setDescription(field.getString()); else if (attr.isA(Tags::tag_category)) setCategory(field.getString()); else if (attr.isA(Tags::tag_subcategory)) setSubCategory(field.getString()); else if (attr.isA(Tags::tag_owner)) { if (!field.check(Location::metadata)) { PyErr_SetString(PythonDataException, "location owner must be of type location"); return -1; } Location* y = static_cast<Location*>(static_cast<PyObject*>(field)); setOwner(y); } else if (attr.isA(Tags::tag_available)) { if (!field.check(CalendarDouble::metadata)) { PyErr_SetString(PythonDataException, "location availability must be of type double calendar"); return -1; } CalendarDouble* y = static_cast<CalendarDouble*>(static_cast<PyObject*>(field)); setAvailable(y); } else if (attr.isA(Tags::tag_hidden)) setHidden(field.getBool()); else return -1; return 0; }
PythonInteger::PythonInteger (const PythonObject &object) : PythonObject() { Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a integer type }
PythonString::PythonString (const PythonObject &object) : PythonObject() { Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a string }
void PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object) { if (m_py_obj && object) PyList_SetItem(m_py_obj, index, object.GetPythonObject()); }
PythonList::PythonList (const PythonObject &object) : PythonObject() { Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a list }
void PythonDictionary::SetItemForKey(const PythonObject &key, const PythonObject &value) { if (IsAllocated() && key.IsValid() && value.IsValid()) PyDict_SetItem(m_py_obj, key.get(), value.get()); }
void PythonList::AppendItem (const PythonObject &object) { if (m_py_obj && object) PyList_Append(m_py_obj, object.GetPythonObject()); }
PythonDictionary::PythonDictionary (const PythonObject &object) : PythonObject() { Reset(object.GetPythonObject()); // Use "Reset()" to ensure that py_obj is a dictionary }
void PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value) { if (m_py_obj && key && value) PyDict_SetItem(m_py_obj, key.GetPythonObject(), value.GetPythonObject()); }
DECLARE_EXPORT void SolverMRP::solve(const Flow* fl, void* v) // @todo implement search mode { // Note: This method is only called for consuming flows and for the leading // flow of an alternate group. See SolverMRP::checkOperation SolverMRPdata* data = static_cast<SolverMRPdata*>(v); if (fl->hasAlternates()) { // CASE I: It is an alternate flow. // We ask each alternate flow in order of priority till we find a flow // that has a non-zero reply. // 1) collect a list of alternates list<const Flow*> thealternates; const Flow *x = fl->hasAlternates() ? fl : fl->getAlternate(); for (Operation::flowlist::const_iterator i = fl->getOperation()->getFlows().begin(); i != fl->getOperation()->getFlows().end(); ++i) if ((i->getAlternate() == x || &*i == x) && i->getEffective().within(data->state->q_flowplan->getDate())) thealternates.push_front(&*i); // 2) Sort the list thealternates.sort(sortFlow); // 3) Control the planning mode bool originalPlanningMode = data->constrainedPlanning; data->constrainedPlanning = true; const Flow *firstAlternate = NULL; double firstQuantity = 0.0; // Remember the top constraint bool originalLogConstraints = data->logConstraints; //Problem* topConstraint = data->planningDemand->getConstraints().top(); // 4) Loop through the alternates till we find a non-zero reply Date min_next_date(Date::infiniteFuture); double ask_qty; FlowPlan *flplan = data->state->q_flowplan; for (list<const Flow*>::const_iterator i = thealternates.begin(); i != thealternates.end();) { const Flow *curflow = *i; data->state->q_flowplan = flplan; // because q_flowplan can change // 4a) Switch to this flow if (data->state->q_flowplan->getFlow() != curflow) data->state->q_flowplan->setFlow(curflow); // 4b) Call the Python user exit if there is one if (userexit_flow) { PythonObject result = userexit_flow.call(data->state->q_flowplan, PythonObject(data->constrainedPlanning)); if (!result.getBool()) { // Return value is false, alternate rejected if (data->getSolver()->getLogLevel()>1) logger << indent(curflow->getOperation()->getLevel()) << " User exit disallows consumption from '" << (*i)->getBuffer()->getName() << "'" << endl; // Move to the next alternate if (++i != thealternates.end() && data->getSolver()->getLogLevel()>1) logger << indent(curflow->getOperation()->getLevel()) << " Alternate flow switches from '" << curflow->getBuffer()->getName() << "' to '" << (*i)->getBuffer()->getName() << "'" << endl; continue; } } // Remember the first alternate if (!firstAlternate) { firstAlternate = *i; firstQuantity = data->state->q_flowplan->getQuantity(); } // Constraint tracking if (*i != firstAlternate) // Only enabled on first alternate data->logConstraints = false; else // Keep track of constraints, if enabled data->logConstraints = originalLogConstraints; // 4c) Ask the buffer data->state->q_qty = ask_qty = - data->state->q_flowplan->getQuantity(); data->state->q_date = data->state->q_flowplan->getDate(); CommandManager::Bookmark* topcommand = data->setBookmark(); curflow->getBuffer()->solve(*this,data); // 4d) A positive reply: exit the loop if (data->state->a_qty > ROUNDING_ERROR) { // Update the opplan, which is required to (1) update the flowplans // and to (2) take care of lot sizing constraints of this operation. if (data->state->a_qty < ask_qty - ROUNDING_ERROR) { flplan->setQuantity(-data->state->a_qty, true); data->state->a_qty = -flplan->getQuantity(); } if (data->state->a_qty > ROUNDING_ERROR) { data->constrainedPlanning = originalPlanningMode; data->logConstraints = originalLogConstraints; return; } } // 4e) Undo the plan on the alternate data->rollback(topcommand); // 4f) Prepare for the next alternate if (data->state->a_date < min_next_date) min_next_date = data->state->a_date; if (++i != thealternates.end() && data->getSolver()->getLogLevel()>1) logger << indent(curflow->getOperation()->getLevel()) << " Alternate flow switches from '" << curflow->getBuffer()->getName() << "' to '" << (*i)->getBuffer()->getName() << "'" << endl; } // 5) No reply found, all alternates are infeasible if (!originalPlanningMode) { assert(firstAlternate); // Unconstrained plan: Plan on the primary alternate // Switch to this flow if (flplan->getFlow() != firstAlternate) flplan->setFlow(firstAlternate); // Message if (data->getSolver()->getLogLevel()>1) logger << indent(fl->getOperation()->getLevel()) << " Alternate flow plans unconstrained on alternate '" << firstAlternate->getBuffer()->getName() << "'" << endl; // Plan unconstrained data->constrainedPlanning = false; data->state->q_flowplan = flplan; // because q_flowplan can change flplan->setQuantity(firstQuantity, true); data->state->q_qty = ask_qty = - flplan->getQuantity(); data->state->q_date = flplan->getDate(); firstAlternate->getBuffer()->solve(*this,data); data->state->a_qty = -flplan->getQuantity(); // Restore original planning mode data->constrainedPlanning = originalPlanningMode; } else { // Constrained plan: Return 0 data->state->a_date = min_next_date; data->state->a_qty = 0; if (data->getSolver()->getLogLevel()>1) logger << indent(fl->getOperation()->getLevel()) << " Alternate flow doesn't find supply on any alternate : " << data->state->a_qty << " " << data->state->a_date << endl; } } else { // CASE II: Not an alternate flow. // In this case, this method is passing control on to the buffer. data->state->q_qty = - data->state->q_flowplan->getQuantity(); data->state->q_date = data->state->q_flowplan->getDate(); if (data->state->q_qty != 0.0) { fl->getBuffer()->solve(*this,data); if (data->state->a_date > fl->getEffective().getEnd()) { // The reply date must be less than the effectivity end date: after // that date the flow in question won't consume any material any more. if (data->getSolver()->getLogLevel()>1 && data->state->a_qty < ROUNDING_ERROR) logger << indent(fl->getBuffer()->getLevel()) << " Buffer '" << fl->getBuffer()->getName() << "' answer date is adjusted to " << fl->getEffective().getEnd() << " because of a date effective flow" << endl; data->state->a_date = fl->getEffective().getEnd(); } } else { // It's a zero quantity flowplan. // E.g. because it is not effective. data->state->a_date = data->state->q_date; data->state->a_qty = 0.0; } } }