-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #24622 from Dr15Jones/pluginValidation
User plugin ParameterSet validation
- Loading branch information
Showing
9 changed files
with
647 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** \class edmtest::PluginUsingProducer | ||
\author Chris Jones, created 21 September 2018 | ||
*/ | ||
|
||
#include "FWCore/Framework/interface/global/EDProducer.h" | ||
#include "FWCore/Framework/interface/Event.h" | ||
#include "FWCore/ParameterSet/interface/ParameterSet.h" | ||
#include "FWCore/Framework/interface/MakerMacros.h" | ||
#include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h" | ||
#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" | ||
#include "FWCore/ParameterSet/interface/PluginDescription.h" | ||
#include "FWCore/ParameterSet/interface/ValidatedPluginMacros.h" | ||
#include "FWCore/ParameterSet/interface/ValidatedPluginFactoryMacros.h" | ||
|
||
#include <vector> | ||
|
||
namespace edm { | ||
class EventSetup; | ||
} | ||
|
||
namespace edmtest { | ||
struct IntMakerBase { | ||
virtual ~IntMakerBase() = default; | ||
virtual int value() const = 0; | ||
}; | ||
|
||
using IntFactory = edmplugin::PluginFactory<IntMakerBase*(edm::ParameterSet const&)>; | ||
} | ||
EDM_REGISTER_VALIDATED_PLUGINFACTORY(edmtest::IntFactory, "edmtestIntFactory"); | ||
|
||
namespace edmtest { | ||
|
||
struct OneMaker : public IntMakerBase { | ||
explicit OneMaker(edm::ParameterSet const&) {} | ||
int value() const final { return 1;}; | ||
|
||
static void fillPSetDescription(edm::ParameterSetDescription&) { | ||
} | ||
}; | ||
|
||
struct ValueMaker : public IntMakerBase { | ||
explicit ValueMaker(edm::ParameterSet const& iPSet) : | ||
value_{iPSet.getParameter<int>("value") } {} | ||
int value() const final { return value_;}; | ||
|
||
static void fillPSetDescription(edm::ParameterSetDescription& iDesc) { | ||
iDesc.add<int>("value",5); | ||
} | ||
|
||
int value_; | ||
}; | ||
|
||
|
||
class PluginUsingProducer : public edm::global::EDProducer<> { | ||
public: | ||
|
||
explicit PluginUsingProducer(edm::ParameterSet const&); | ||
|
||
void produce(edm::StreamID, edm::Event&, edm::EventSetup const&) const override; | ||
|
||
static void fillDescriptions(edm::ConfigurationDescriptions& iConf) { | ||
edm::ParameterSetDescription pluginDesc; | ||
pluginDesc.addNode( edm::PluginDescription<IntFactory>("type", "edmtestValueMaker", true)); | ||
|
||
edm::ParameterSetDescription top; | ||
top.add<edm::ParameterSetDescription>("plugin",pluginDesc); | ||
|
||
iConf.addWithDefaultLabel(top); | ||
} | ||
private: | ||
std::unique_ptr<IntMakerBase> maker_; | ||
edm::EDPutTokenT<int> putToken_; | ||
}; | ||
|
||
PluginUsingProducer::PluginUsingProducer(edm::ParameterSet const& pset): | ||
putToken_{produces<int>()} | ||
{ | ||
auto pluginPSet = pset.getParameter<edm::ParameterSet>("plugin"); | ||
maker_.reset( IntFactory::get()->create(pluginPSet.getParameter<std::string>("type"), pset)); | ||
} | ||
|
||
void PluginUsingProducer::produce(edm::StreamID, edm::Event& event, edm::EventSetup const&) const{ | ||
event.emplace(putToken_, maker_->value()); | ||
} | ||
} | ||
using edmtest::PluginUsingProducer; | ||
DEFINE_FWK_MODULE(PluginUsingProducer); | ||
|
||
|
||
DEFINE_EDM_VALIDATED_PLUGIN(edmtest::IntFactory,edmtest::OneMaker,"edmtestOneMaker"); | ||
DEFINE_EDM_VALIDATED_PLUGIN(edmtest::IntFactory,edmtest::ValueMaker,"edmtestValueMaker"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
#ifndef FWCore_ParameterSet_PluginDescription_h | ||
#define FWCore_ParameterSet_PluginDescription_h | ||
// -*- C++ -*- | ||
// | ||
// Package: FWCore/ParameterSet | ||
// Class : PluginDescription | ||
// | ||
/**\class PluginDescription PluginDescription.h "PluginDescription.h" | ||
Description: Use to describe how to validate a plugin that will be loaded | ||
Usage: | ||
User defined plugins which are constructed by passing a edm::ParameterSet can | ||
have their parameters validated using the \c edm::PluginDescription. For this to | ||
work, one must | ||
1) Plugin configuration | ||
All the parameters used by the Plugin must be contained within one PSet, this | ||
also includes an cms.string parameter containing the name of the actual plugin | ||
type to be loaded. E.g. if a module \c FooProd loaded a plugin of specific type | ||
\c BarHelper and \c BarHelper uses the parameter named \c value : | ||
\code{.py} | ||
foo = cms.EDProducer("FooProd", | ||
pluginDescription = cms.PSet(type = cms.string("BarHelper"), | ||
value = cms.int32(5) ) ) | ||
\endcode | ||
2) Plugin fillPSetDescription | ||
Each user plugin must define a static member function: | ||
\code{.cpp} | ||
static void fillPSetDescription(edm::ParameterSetDescription const&); | ||
\endcode | ||
The function fills the \c edm::ParameterSetDescription with the descriptions of | ||
the parameters necessary for that particular plugin. Note that the parameter | ||
used by the module to find the type of the plugin should NOT be declared in | ||
the \c edm::ParameterSetDescription since it will be added by the | ||
\c edm::PluginDescription itself. E.g. | ||
\code{.cpp} | ||
void BarHelper::fillPSetDescription(edm::ParameterSetDescription& iPSD) { | ||
iPSD.add<int>("value", 5); | ||
} | ||
\endcode | ||
3) Module's fillDescriptions | ||
The module which uses the plugins must use the \c edm::PluginDescription within its | ||
\c fillDescriptions static member function. | ||
The \c edm::PluginDescription object is attached to the \c edm::ParameterSetDescription | ||
object which is being used to represent the PSet for the plugin. In turn, that | ||
\c edm::ParamterSetDescription is attached to the module's top level \edm::ParameterSetDescription. | ||
This exactly mimics what would be done if the plugin's parameters were directly known to | ||
the module. | ||
\code{.cpp} | ||
void FooProd::fillDescriptions(ConfigurationDescriptions& oDesc) { | ||
//specify how to get the plugin validation | ||
ParameterSetDescription pluginDesc; | ||
//'type' is the label to the string containing which plugin to load | ||
pluginDesc.addNode(edm::PluginDescription<HelperFactory>("type") ); | ||
ParameterSetDescription desc; | ||
desc.add<ParameterSetDescription>("pluginDescription", pluginDesc); | ||
oDesc.addDefault(desc); | ||
} | ||
\endcode | ||
4) Factory registration | ||
Use \c EDM_REGISTER_VALIDATED_PLUGINFACTORY rather than | ||
\c EDM_REGISTER_PLUGINFACTORY. This new macro can be found in | ||
FWCore/ParameterSet/interface/ValidatedPluginFactoryMacros.h | ||
5) Plugin registration | ||
Use \c DEFINE_EDM_VALIDATED_PLUGIN rather than \c DEFINE_EDM_PLUGIN. | ||
This new macro can be found in FWCore/Framework/interface/ValidatedPluginMacros.h | ||
*/ | ||
// | ||
// Original Author: Chris Jones | ||
// Created: Wed, 19 Sep 2018 19:23:27 GMT | ||
// | ||
|
||
// system include files | ||
#include "FWCore/ParameterSet/interface/ParameterDescriptionNode.h" | ||
#include "FWCore/ParameterSet/interface/PluginDescriptionAdaptorBase.h" | ||
#include "FWCore/PluginManager/interface/PluginFactory.h" | ||
#include "FWCore/PluginManager/interface/PluginManager.h" | ||
#include "FWCore/PluginManager/interface/standard.h" | ||
|
||
// user include files | ||
#include <string> | ||
|
||
// forward declarations | ||
namespace edm { | ||
template< typename T> | ||
class PluginDescription : public ParameterDescriptionNode | ||
{ | ||
public: | ||
/**Constructor without a default for typeLabel | ||
@param[in] typeLabel the label for the std::string parameter which holds the plugin type to be loaded | ||
@param[in] typeLabelIsTracked 'true' if the parameter `typeLabel` is tracked, else should be false | ||
*/ | ||
PluginDescription(std::string typeLabel, bool typeLabelIsTracked): | ||
typeLabel_{std::move(typeLabel)}, | ||
typeLabelIsTracked_{typeLabelIsTracked} {} | ||
|
||
/**Constructor with a default for typeLabel | ||
@param[in] typeLabel the label for the std::string parameter which holds the plugin type to be loaded | ||
@param[in] defaultType the default plugin type that should be loaded if no type is given | ||
@param[in] typeLabelIsTracked 'true' if the parameter `typeLabel` is tracked, else should be false | ||
*/ | ||
PluginDescription(std::string typeLabel, std::string defaultType, bool typeLabelIsTracked): | ||
typeLabel_{std::move(typeLabel)}, | ||
defaultType_{std::move(defaultType)}, | ||
typeLabelIsTracked_{typeLabelIsTracked} {} | ||
|
||
// ---------- const member functions --------------------- | ||
ParameterDescriptionNode* clone() const final { | ||
return new PluginDescription<T>(*this); | ||
} | ||
|
||
protected: | ||
|
||
void checkAndGetLabelsAndTypes_(std::set<std::string>& usedLabels, | ||
std::set<ParameterTypes>& parameterTypes, | ||
std::set<ParameterTypes>& wildcardTypes) const final { | ||
|
||
} | ||
|
||
|
||
|
||
void validate_(ParameterSet& pset, | ||
std::set<std::string>& validatedLabels, | ||
bool optional) const final { | ||
loadPlugin(findType(pset)); | ||
cache_->validate(pset); | ||
//all names are good | ||
auto n =pset.getParameterNames(); | ||
validatedLabels.insert(n.begin(),n.end()); | ||
} | ||
|
||
void writeCfi_(std::ostream& os, | ||
bool& startWithComma, | ||
int indentation, | ||
bool& wroteSomething) const final { | ||
if(not defaultType_.empty()) { | ||
edmplugin::PluginManager::configure(edmplugin::standard::config()); | ||
|
||
loadPlugin(defaultType_); | ||
|
||
cache_->writeCfi(os,startWithComma,indentation); | ||
wroteSomething = true; | ||
} | ||
} | ||
|
||
bool hasNestedContent_() const final { | ||
return true; | ||
} | ||
|
||
void printNestedContent_(std::ostream& os, | ||
bool /*optional*/, | ||
DocFormatHelper& dfh) const final { | ||
int indentation = dfh.indentation(); | ||
|
||
using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>; | ||
using Factory = edmplugin::PluginFactory<CreatedType*()>; | ||
|
||
std::stringstream ss; | ||
ss << dfh.section() << "." << dfh.counter(); | ||
std::string newSection = ss.str(); | ||
|
||
printSpaces(os, indentation); | ||
os << "Section " << newSection | ||
<< " " << Factory::get()->category() << " Plugins description:\n"; | ||
if(!dfh.brief()) os << "\n"; | ||
|
||
DocFormatHelper new_dfh(dfh); | ||
new_dfh.init(); | ||
new_dfh.setSection(newSection); | ||
|
||
//loop over all possible plugins | ||
unsigned int pluginCount = 0; | ||
for(auto const& info: edmplugin::PluginManager::get()->categoryToInfos().find(Factory::get()->category())->second) { | ||
|
||
|
||
std::stringstream ss; | ||
ss << dfh.section() << "." << dfh.counter(); | ||
std::string newSection = ss.str(); | ||
printSpaces(os, indentation); | ||
os << "Section " << newSection <<"."<< ++pluginCount | ||
<< " " << info.name_ << " Plugin description:\n"; | ||
if(!dfh.brief()) os << "\n"; | ||
|
||
DocFormatHelper new_dfh(dfh); | ||
new_dfh.init(); | ||
new_dfh.setSection(newSection); | ||
|
||
loadDescription(info.name_)->print(os,new_dfh); | ||
} | ||
} | ||
|
||
bool exists_(ParameterSet const& pset) const final { | ||
return pset.existsAs<std::string>(typeLabel_, typeLabelIsTracked_); | ||
} | ||
|
||
bool partiallyExists_(ParameterSet const& pset) const final { | ||
return exists_(pset); | ||
} | ||
|
||
int howManyXORSubNodesExist_(ParameterSet const& pset) const final { | ||
return exists(pset) ? 1 : 0; | ||
} | ||
|
||
private: | ||
std::string findType(edm::ParameterSet const& iPSet) const { | ||
if(typeLabelIsTracked_) { | ||
if(defaultType_.empty()) { | ||
return iPSet.getParameter<std::string>(typeLabel_); | ||
} | ||
if(not iPSet.existsAs<std::string>(typeLabel_) ) { | ||
return defaultType_; | ||
} | ||
} | ||
if(defaultType_.empty()) { | ||
return iPSet.getUntrackedParameter<std::string>(typeLabel_); | ||
} | ||
return iPSet.getUntrackedParameter<std::string>(typeLabel_,defaultType_); | ||
} | ||
|
||
void loadPlugin(std::string const& iName) const { | ||
if(not cache_) { | ||
cache_ = loadDescription(iName); | ||
} | ||
} | ||
|
||
std::shared_ptr<ParameterSetDescription> | ||
loadDescription(std::string const& iName) const { | ||
using CreatedType = PluginDescriptionAdaptorBase<typename T::CreatedType>; | ||
std::unique_ptr<CreatedType> a(edmplugin::PluginFactory<CreatedType*()>::get()->create(iName)); | ||
|
||
std::shared_ptr<ParameterSetDescription> desc = std::make_shared<ParameterSetDescription>(a->description()); | ||
|
||
//There is no way to check to see if a node already wants a label | ||
if(typeLabelIsTracked_) { | ||
if(defaultType_.empty()) { | ||
desc->add<std::string>(typeLabel_); | ||
} else { | ||
desc->add<std::string>(typeLabel_,defaultType_); | ||
} | ||
} else { | ||
if(defaultType_.empty()) { | ||
desc->addUntracked<std::string>(typeLabel_); | ||
} else { | ||
desc->addUntracked<std::string>(typeLabel_,defaultType_); | ||
} | ||
} | ||
return desc; | ||
} | ||
|
||
// ---------- member data -------------------------------- | ||
mutable std::shared_ptr<ParameterSetDescription> cache_; | ||
std::string typeLabel_; | ||
std::string defaultType_; | ||
bool typeLabelIsTracked_; | ||
|
||
}; | ||
} | ||
|
||
#endif |
Oops, something went wrong.