To me that just seems like a static value of what is allowed or not - it doesn’t look like something customizable to the studio. Which to me sounds like what you and @robert were asking for?
Yul
12 April 2024 16:03
22
The static check rules are better than nothing.
But yes, having it customizable would be better (for studios that prefer uppercase, or lowercase, or force the first character to be a letter, etc…).
.
Also, if we can’t have it when an entity is created, we could have it later when Anatomy comes into play, using this very nice future feature :
opened 09:51PM - 09 Oct 23 UTC
type: enhancement
community contribution
### Is there an existing issue for this?
- [X] I have searched the existing i… ssues.
### Please describe the feature you have in mind and explain what the current shortcomings are?
It might be worth using a custom formatter in OpenPype so we don't need all the keys like Task task, TASK etc. in the data and can actually explicitly state what we want to have done with the value.
It would allow explicitly forcing lowercase, uppercase or whatever we want as custom formatting. 🙂
Plus, you'd just need to just extend the anatomy formatting class and don't need to actually wrangle all data. It'd then automatically work for all data formatted with anatomy.
Simpler. (And faster potentially since the formatting would only occur when requested instead of preparing the data beforehand).
So uppercase task would e.g. be {task:upper} or {task!u} or whatever we want to use as format specifier or solution.
### How would you imagine the implementation of the feature?
#### Custom value conversions
An example of specifying custom conversion specs for formatting can be found [here](https://stackoverflow.com/a/46160537) which shows how to add e.g. `{myvar!u}` to uppercase a string or `{myvar!l}` to lowercase a string.
Here's an example of that:
```python
from string import Formatter
class ExtendedFormatter(Formatter):
"""An extended format string formatter
Formatter with extended conversion symbol
"""
def convert_field(self, value, conversion):
""" Extend conversion symbol
Conversions:
* l: convert to string and low case
* u: convert to string and up case
"""
if conversion == "u":
return str(value).upper()
elif conversion == "l":
return str(value).lower()
# Do the default conversion or raise error if no matching conversion found
return super(ExtendedFormatter, self).convert_field(value, conversion)
# Example
template = "{task!u}/{asset!l}/v{version:03d}"
data = {
"task": "anim",
"asset": "char_SuperHero",
"version": 1
}
formatter = ExtendedFormatter()
output = formatter.format(template, **data)
print(output)
# ANIM/char_superhero/v001
```
This requires the conversion character to start with `!` and the conversion can only be a single character.
#### Custom field format specifiers
However, it's also possible to define custom field conversions - where we can use the format spec to implement the same but allowing e.g. longer readable specs like `:lower` and `:upper`
```python
from string import Formatter
class MyFormatter(Formatter):
def format_field(self, value, format_spec):
if format_spec == "upper":
return str(value).upper()
elif format_spec == "lower":
return str(value).lower()
return super(MyFormatter, self).format_field(value, format_spec)
# Example
template_str = "{task:upper}/{asset:lower}/{subset:lower}/v{version:03d}"
data = {
"task": "anim",
"asset": "char_SuperHero",
"subset": "helloWorld",
"version": 1
}
myformatter = MyFormatter()
output = myformatter.format(template_str, **data)
print(output)
# ANIM/char_superhero/helloworld/v001
```
_Maybe `low` and `up` are nicer because they are shorter maybe?_
These could be implemented on the `StringTemplate` class when formatting.
#### Custom field format specifiers - uppercase only first character
We currently also support `{Task}` to only uppercase the first character - we can take that same logic and implement it as well:
```python
from string import Formatter
class MyFormatter(Formatter):
def format_field(self, value, format_spec):
if format_spec == "upper":
return str(value).upper()
elif format_spec == "lower":
return str(value).lower()
elif format_spec == "upperfirst":
value = str(value)
if value:
# Uppercase first character, leave rest as is
return "".join([value[0].upper(), value[1:]])
else:
return value
return super(MyFormatter, self).format_field(value, format_spec)
# Example
template_str = "{task:upper}/{asset:lower}/{family}{task:upperfirst}{variant:upperfirst}/v{version:03d}"
data = {
"task": "anim",
"asset": "char_SuperHero",
"family": "render",
"variant": "main",
"version": 1
}
myformatter = MyFormatter()
output = myformatter.format(template_str, **data)
print(output)
# ANIM/char_superhero/renderAnimMain/v001
```
### Are there any labels you wish to add?
- [X] I have added the relevant labels to the enhancement request.
### Describe alternatives you've considered:
The alternative is basically the hassle we've been riding with currently where all data needs to be prepared with: `{task}`, `{Task}`, `{TASK}`, etc.
It would mean we'd need to preformat all data, which can be slow due to the fact that we're likely formatting a lot of versions that we don't end up using in the data. Also with these keys it's unclear what e.g. would be a key for force lowercase formatting.
### Additional context:
Originally proposed on [Discord](https://discord.com/channels/517362899170230292/563751989075378201/1159903871494258779)
[cuID:[OP-7100](https://app.clickup.com/t/86bw4gg4k)]