Package: toppingmaker
toppingmakerPackage to create parameterized QGIS projects and dump it into a YAML structure.Installationpip install toppingmakerStructuretoppingmaker
├── exportsettings.py
├── projecttopping.py
├── target.py
└── utils.pyUser ManualHaving a QGIS Project with some layers:Import the modulesfromqgis.coreimportQgsProject()fromtoppingmakerimportProjectTopping,ExportSettings,TargetCreate aProjectToppingand parse the QGIS Projectproject=QgsProject()project_topping=ProjectTopping()project_topping.parse_project(project)This parses the project, but does not yet write the files (only the style and definition file to a temp folder). The QgsProject object is not used anymore.Create theTargetTo write the files we need to define aTargetobject. The target defines where to store the topping files (YAML, style, definition etc.).target=Target(projectname="freddys_qgis_project",main_dir="/home/fred/repo/",sub_dir="freddys_qgis_topping",pathresover=None)Generate the Filesproject_topping.generate_files(target)The structure looks like this:repo
└── freddys_qgis_topping
    └── projecttopping
        └── freddys_qgis_project.yamlAnd the YAML looks like this:layerorder:[]layertree:-Street:checked:trueexpanded:true-Park:checked:falseexpanded:true-Building:checked:trueexpanded:true-Info Layers:checked:truechild-nodes:-AssetItem:checked:trueexpanded:true-InternalProject:checked:trueexpanded:trueexpanded:truegroup:true-Background:checked:truechild-nodes:-Landeskarten (grau):checked:trueexpanded:trueexpanded:truegroup:trueThe structure is exported. But not any additional files. For that, we need to parse theExportSettingsto theProjectTopping.Create theExportSettings:Layer Tree SettingsWe can decide for every layer (group) if we want to:UseQMLSTYLEfor the export of the qml stylefile.UseDEFINITIONto export the qlr definition file.USESOURCEto store the source in the YAML tree.TheQgsLayerTreeNodeor the layername can be used as key.export_settings=ExportSettings()export_settings.set_setting_values(type=ExportSettings.ToppingType.QMLSTYLE,node=None,name="Street",export=True)export_settings.set_setting_values(type=ExportSettings.ToppingType.SOURCE,node=None,name="Park",export=True)export_settings.set_setting_values(type=ExportSettings.ToppingType.DEFINITION,node=None,name="Info Layers",export=True)export_settings.set_setting_values(type=ExportSettings.ToppingType.SOURCE,node=None,name="Landeskarten (grau)",export=True)Additionally you can pass category flagsQgsMapLayer.StyleCategoriesto define what categories needs to be included in the QML Stylefile:category_flags=QgsMapLayer.StyleCategory.AllStyleCategoriesexport_settings.set_setting_values(type=ExportSettings.ToppingType.QMLSTYLE,node=None,name="Street",export=True,categories=category_flags)Without an additional setting, only the default style is considered. To export the style of multiple style add them as seperate setting entries:# default style (if style_name "default" is added, it makes no difference)export_settings.set_setting_values(type=ExportSettings.ToppingType.QMLSTYLE,node=None,name="Street",export=True))# french style (e.g. french aliases)export_settings.set_setting_values(type=ExportSettings.ToppingType.QMLSTYLE,node=None,name="Street",export=True,categories=category_flags,style_name="french"))# robot style (e.g. technical look)export_settings.set_setting_values(type=ExportSettings.ToppingType.QMLSTYLE,node=None,name="Street",export=True,categories=category_flags,style_name="robot"))Map Themes SettingsSet the names of the map themes that should be considered as a list:export_settings.mapthemes=["Robot Theme","French Theme"]Custom Project Variables SettingsSet the keys of custom variables that should be considered as a list:export_settings.variables=["first_variable","Another_Variable"]Print Layout SettingsSet the names of layouts that should be considered (exported as template files) as a list:export_settings.layouts=["Layout One","Layout Three"]Generate the Files for aProjectToppingcontainingExportSettingWhen parsing the QgsProject we need to pass theExportSettings:project_topping.parse_project(project,export_settings)project_topping.generate_files(target)The structure looks like this:repo
└── freddys_qgis_topping
    ├── layerdefinition
    │   └── freddys_qgis_project_info_layers.qlr
    └── projecttopping
        └── freddys_qgis_project.yaml
    └── layerstyle
        ├── freddys_qgis_project_street.qml
        ├── freddys_qgis_project_street_french.qml
        └── freddys_qgis_project_street_robot.qml
    └── layouttemplate
        ├── freddys_qgis_project_layout_one.qpt
        └── freddys_qgis_project_layout_three.qptAnd the YAML looks like this:layertree:-Street:tablename:streetgeometrycolumn:geometrychecked:trueexpanded:trueqmlstylefile:freddys_qgis_topping/layerstyle/freddys_qgis_project_street.qmlstyles:french:qmlstylefile:freddys_qgis_topping/layerstyle/freddys_qgis_project_street_french.qmlrobot:qmlstylefile:freddys_qgis_topping/layerstyle/freddys_qgis_project_street_robot.qml-Park:tablename:parkgeometrycolumn:geometrychecked:falseexpanded:trueprovider:ogruri:/home/freddy/qgis_projects/bakery/cityandcity.gpkg|layername=park-Building:tablename:building_2geometrycolumn:geometrychecked:trueexpanded:true-Info Layers:checked:truedefinitionfile:freddys_qgis_topping/layerdefinition/freddys_qgis_project_info_layers.qlrexpanded:truegroup:true-Background:checked:trueexpanded:truegroup:truechild-nodes:-Landeskarten (grau):checked:trueexpanded:trueprovider:wmsuri:contextualWMSLegend=0&crs=EPSG:2056&dpiMode=7&featureCount=10&format=image/jpeg&layers=ch.swisstopo.pixelkarte-grau&styles&url=https://wms.geo.admin.ch/?%0ASERVICE%3DWMS%0A%26VERSION%3D1.3.0%0A%26REQUEST%3DGetCapabilitiesmapthemes:"FrenchTheme":Street:style:frenchvisible:trueexpanded:trueBuildings:style:defaultvisible:falseexpanded:true"RobotTheme":Street:style:robotexpanded_items:["{f6c29bf7-af28-4d88-8092-ee9568ac731f}","{fc48a8d7-d774-46c7-97c7-74ecde13a3ec}",]checked_items:["{f6c29bf7-af28-4d88-8092-ee9568ac731f}","{dc726dd5-d0d7-4275-be02-f6916df4fa29}",]Buildings:style:defaultvisible:trueexpanded:falseOther_Layers_Group:group:truechecked:trueexpanded:falseOther_Layers_Group/SubGroup:group:truechecked:trueexpanded:falselayerorder:[]variables:"first_variable":"Thisisatestvalue.""Another_Variable":"2"layouts:"LayoutOne":templatefile:"../layouttemplate/freddys_qgis_project_layout_one.qpt""LayoutThree":templatefile:"../layouttemplate/freddys_qgis_project_layout_three.qpt"Most important functionsprojecttopping.ProjectToppingA project configuration resulting in a YAML file that contains:layertreelayerorderlayer stylesmap themesproject variablesprint layoutsQML style files, QLR layer definition files and the source of a layer can be linked in the YAML file and are exported to the specific folders.parse_project( project: QgsProject, export_settings: ExportSettings = ExportSettings()Parses a project into the ProjectTopping structure. Means the LayerTreeNodes are loaded into the layertree variable and append the ExportSettings to each node. The CustomLayerOrder is loaded into the layerorder. The project is not kept as member variable.generate_files(self, target: Target) -> strGenerates all files according to the passed Target.
The target object containing the paths where to create the files and the path_resolver defining the structure of the link.load_files(self, target: Target)not yet implementedgenerate_project(self, target: Target) -> QgsProjectnot yet implementedtarget.TargetIf there is no subdir it will look like:<maindir>
    ├── projecttopping
    │  └── <projectname>.yaml
    ├── layerstyle
    │  ├── <projectname>_<layername>.qml
    │  └── <projectname>_<layername>.qml
    └── layerdefinition
       └── <projectname>_<layername>.qlrWith subdir:<maindir>
    └── <subdir>
       ├── projecttopping
       │  └── <projectname>.yaml
       ├── layerstyle
       │  ├── <projectname>_<layername>.qml
       │  └── <projectname>_<layername>.qml
       └── layerdefinition
          └── <projectname>_<layername>.qlrThepath_resolvercan be passed as a function. The default implementation lists the created toppingfiles (including the YAML) in the dictTarget.toppingfileinfo_listwith the"path": <relative_filepath>, "type": <filetype>.Target( projectname: str = "project", main_dir: str = None, sub_dir: str = None, path_resolver=None)The constructor of the target class to set up a target.
A member variabletoppingfileinfo_list = []is defined, to store all the information according thepath_resolver.exportsettings.ExportSettingsLayertree SettingsThe requested export settings of each node in the specific dicts:qmlstyle_setting_nodesdefinition_setting_nodessource_setting_nodesThe usual structure is using QgsLayerTreeNode as key and then export True/Falseqmlstyle_nodes={<QgsLayerTreeNode(Node1)>:{export:False}<QgsLayerTreeNode(Node2)>:{export:True}}Alternatively the layername can be used as key. In ProjectTopping it first looks up the node and if not available the name.
Using the node is much more consistent, since one can use layers with the same name, but for nodes you need the project already in advance.
With name you can use prepared settings to pass (before the project exists) e.g. in automated workflows.qmlstyle_nodes={"Node1":{export:False}"Node2":{export:True}}For some settings we have additional info. Like in qmlstyle_nodes <QgsMapLayer.StyleCategories>. These are Flags, and can be constructed manually as well.qmlstyle_nodes={<QgsLayerTreeNode(Node1)>:{export:False}<QgsLayerTreeNode(Node2)>:{export:True,categories:<QgsMapLayer.StyleCategories>}}If styles are used as well we create tuples as key. Mutable objects are not alowed in it, so they would be created with the (layer) name and the style (name):qmlstyle_nodes={<QgsLayerTreeNode(Node1)>:{export:False}<QgsLayerTreeNode(Node2)>:{export:True,categories:<QgsMapLayer.StyleCategories>}("Node2","french"):{export:True,categories:<QgsMapLayer.StyleCategories>},("Node2","robot"):{export:True,categories:<QgsMapLayer.StyleCategories>}}set_setting_values( type: ToppingType, node: Union[QgsLayerTreeLayer, QgsLayerTreeGroup] = None, name: str = None, export=True categories=None, style_name: str = None) -> boolSet the specific types concerning the enumerations:classToppingType(Enum):QMLSTYLE=1DEFINITION=2SOURCE=3Map Themes SettingsThe export setting of the map themes is a simple list of maptheme names:mapthemes = []Custom Project Variables:The export setting of the custom variables is simple list of the keys stored invariables = [].Layouts:The export setting of the print layouts is simple list of the layout names stored inlayouts = [].Infos for DevsCode styleIs enforced with pre-commit. To use, make:pip install pre-commit
pre-commit installAnd to run it over all the files (with infile changes):pre-commit run --color=always --all-file