Template.yml per-project includes

I’m just toying with the idea of having a single shared pipeline config for the studio that is able to reference a templates.yml stored in each project folder for per-project overrides (eg client delivery templates). It would be great to be able to do this as it lessens the likelyhood of requiring a unique pipeline config for every project which introduces quite an overhead in terms of keeping them all up to date.

I tried adding an include using an env var, but I’m coming to realise that templates.yml is being parsed prior to any engine_init or tank_init hook being processed where one might be able to place the project path in an env var:

- {PATH_TO_PROJECT}/config/templates.yml

Am I going down a path to madness with this idea? Is it even possible?

Thanks in advance for your tuppenceworths.


Ah, I’ve just remembered about the " example_template_hook.py" core hook which I think would cover my use-case for what I’m trying to do.

I’m still interested to hear other thoughts on the above though!

Actually, on second look, that template hook is only for app settings. I don’t think it would allow me to evaluate a template via hook at runtime via tk.templates[‘some_dynamic_template’] method.

So, the question remains, how to define templates outside templates.yml?

It looks like the “pipeline_configuration_init.py” core hook initialises prior to templates.yml, so that might be a place where I can define the env var pointing to the project path.
The problem is I can’t see where I can find what project is being loaded.
There is the TANK_CURRENT_PC environment variable which has the project id as part of the PC path…
The only argument passed to the hook is kwargs which is empty.
Is there any way to find the project path from this hook?

Hey Patrick -

I added this line to templates.yml and it worked:

include: "${INCLUDE_PATH}/test.yml"

so we definitely do support env vars in template includes.

As for when to set the env var, pipeline_configuration_init is the right place, and it looks like you can get to the project name via self.parent.

Here’s where the project is getting set and the pipeline_configuration_init core hook is getting executed (conveniently adjacent to one another :slight_smile: ). You can see that the core hook is getting called with parent=self (looks like the snippet got cut off – click through to see that line):

So, I just tested referring to self.parent._project_name in the core hook and it worked.

Hope that helps!


Oh, and as for an example of using includes in templates.yml, you can see one here:

(Does it hurt my eyes that in the line foo_bar_in_master: "@sequence_root/@foo_bar" the two @ symbols perform two different functions? Yes, yes it does. Grateful we have a working solution though!)


Thanks Tanaz,
So I have the project name, is, etc. I don’t unfortunately have the roots.
There’s a self._storage_roots but it’s not got a value. I assume because I’m using distributed configs? Are the roots available from this point in the process?


1 Like

Hi Patrick – I’m not sure what you’d want the storage roots for – is your intention to store the included files in the same location as your production files?

It actually leads me to a few other questions: if you’re using distributed configs, where would these included files live? Where are you including from? Can you tell me more about your plans for these different files?

Having said that, I did get a value for self._storage_roots, but I have a centralized config. I didn’t get a chance to test today with a distributed one, but I’ll give it a go tomorrow and let you know what I find.

1 Like

Yes that’s right.
I’m looking to be able to have a single pipeline configuration for the entire studio, but where the studio defaults need adjusted on a per-project basis, instead of having a seperate pipeline config, I would impliment overrides in files within the project folder. I appreciate that this aim is perhaps counter to the design philosophy of SG, but I think it’s a goal worth investigating.
For example, most projects are identical in requirements. One area that definitely does change per-project is naming convention for client delivery of media. In this case, one might override the default template for client deliveries. I would do this by including a project_templates.yml that redefines a single template. I think this would be a pretty powerful pattern.
As it is, we can do this for hooks (eg for changing the format of reviewsubmission transcodes per project by pointing the hook to the project based hook using an env var in the template path), but being able to actually override templates in the same manner is not currently possible.
I’m attempting do this with a hardcoded “include” in the pipeline config templates.yml, but I imagine another approach might be for SG to add a hook which could be used to intercept template resolution. This is a feature when templates are defined in app configs, but this, as far as I can see, is not applicable to api calls to templates; eg tk.templates[‘some_template’]

As I say, this is fairly anti-pattern behaviour and carries certain risks (eg where a template no longer matches the schema) but the benefits of having a truly studio-wide config that can be selectively adapted on a per-project basis are clear; maintanance overheads spiral out of control where you end up with a custom pipeline config per-project would be avoided.


Hi Patrick,

Couldn’t you use the same configuration every where and set the values you want to customize per project in environment variables?

1 Like

Possibly. I’ve not tried instantating new templates from strings on the fly before though.

I can probably do something along those lines but as a point of principle I’d prefer to keep all my path resolution within sg templates.

Thanks for the suggestion anyway!


Hey Patrick – That all makes sense. And you’re not alone in wanting this functionality; @kporangehat asks pretty much the exact same question in this post.

And I hear what you’re saying about the risks – perfectly coordinating the schema and templates is always a challenge; this definitely complicates it further, and makes me wonder if there’s not a better way to manage both in one go.

Having said all that, I did try this with a distributed config, and it worked fine for me. Here are the details of my case:

  • My distributed config is brand new, based on tk-config-default2, and identical to it, save for the modified pipeline_configuration_init.py file.
  • The contents of roots.yml (cached to ~/Library/Caches/Shotgun/tannaz/p272c319.basic.desktop/cfg/config/core/):
  default: true
  linux_path: /sgtk/projects
  mac_path: /sgtk/projects
  shotgun_storage_id: 2
  windows_path: G:\blahlbah
  • What I’m logging in pipeline_configuration_init.py (cached to ~/Library/Caches/Shotgun/bundle_cache/sg/tannaz/v1385/core/hooks/)

log.warning("STORAGE ROOT PATH: %s" % self.parent._storage_roots.default_path)

  • And the value I’m getting in the log:

STORAGE ROOT PATH: <Path win:'G:\blahlbah', linux:'/sgtk/projects', macosx:'/sgtk/projects'>

So… it should work – I’m not sure what the difference is between my case and yours, but maybe this information jogs something for you?

As a side note, I’m going to make a note to the product team about this desired functionality – the fact that it’s come up twice in a matter of days makes me think it’ll come up even more.

L:et me know if you make any progress or have any follow-up questions!


2 posts were split to a new topic: Hierarchical includes in environment config files