-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
config: Skip copyright substitution for copyright notices declared as constant values #12519
config: Skip copyright substitution for copyright notices declared as constant values #12519
Conversation
…ared using ``ast.Constant`` assignments.
…ng entirely-constant elements to be constants.
I don't have any further changes planned here, but I'm not 100% confident about the changeset either. This code handles detection of simple constant assignments, but the functionality as-is can falsely give the impression that certain variables are literal constants, when in fact they're later appended-to, re-assigned-to, etc. It wouldn't be much fun to have to continually evolve and adjust this code to handle edge cases. |
Tangential idea, available from Py3.11 onwards: perhaps we could add a type-hint in the templated Sites could still remove or adjust that, but it might encourage usage of configuration of copyright notices using constants. |
…not configured and `copyright` is a constant.
…opyright settings.
Since there is some careful logic required to handle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are too many cases where someone can (for debugging purposes) redeclare a configuration variable and thus the detection algorithm must be improved. One could just ignore when a variable is being redeclared but that's probably too harsh since this could be tricky to debug.
I know that @AA-Turner wasn't in favor of having an additional configuration variable but to tackle the reproducbility issue, I think it's needed. However, what I can suggest is a configuration variable which is simply a format string and we will just use datetime.datetime.today().strftime(copyright_format)
as is.
On the other hand, a way to make it much simpler is... to create an event so that users can just return whatever strings they want. It's yet another event but maybe it could done.
@@ -278,9 +280,17 @@ class Config: | |||
def __init__(self, config: dict[str, Any] | None = None, | |||
overrides: dict[str, Any] | None = None) -> None: | |||
raw_config: dict[str, Any] = config or {} | |||
constants = raw_config.pop('__constants__', None) or frozenset() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If someone is using this name for something else, it's a bad idea to actually change it IMO.
# when empty, config.epub_copyright inherits from config.copyright, so | ||
# treat it as constant if the latter is | ||
if 'epub_copyright' not in raw_config and 'copyright' in constants: | ||
constants |= frozenset(['epub_copyright']) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, I would say that you should explicitly hardcode the allowed constants in a global variable (outside the Config class).
) | ||
for name in constant_assignments | ||
)) | ||
except Exception: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tree = ast.parse(code_py)
can never fail since compiled the code above.
In addition, if someone writes
x = 1
x = get_x()
and
x = get_x()
x = 1
Then the first one is dynamic while the second can be considered constant. Your filter unfortunately doesn't consider those cases. As such, I think this approach is too complex.
I'm not too keen on continuing along paths where we support dynamic replacement of values, because generally I think that a static/constant declaration is near-optimal for various reasons. I do admit that some groups will want to ensure that their build output contains the current year in copyright notices; I think that's better achieved by adding a post-build validation step, amenable to automation. The changes suggested here don't require or enforce any of that, but they are intended to encourage use of literal/constant assignments for the copyright config setting(s). |
Perhaps:
I am really wary of the complexity here, and oftentimes the import of A |
I'd vote for What do we think about applying that logic to the existing |
Sure. Though we need to be clear that this is strftime-inspired, and only supports %Y and %y.
This was my intent, yes. A |
@picnixz do you also find this plan acceptable? I'd ideally like at least two supporters with some experience of the copyright functionality before closing this and #12516 and commencing work on it. |
I'm back to business here Jay (really sorry for just contributing to CPython and forgetting about Sphinx). I like this plan because:
|
No problem! Thank you for taking your time and considering the suggested approach. Answering the third point first because I think it is the most important:
tl;dr - that condition approximates: "only apply substitutions for notice lines where the project itself specifies a dynamically-evaluated end-year" My thinking about this has changed since writing the bugreport (#12451), however I'll use the same example to explain:
I had a sense that there was something odd/wrong about updating both of these lines, because they have different end years, so I wrote the bugreport suggesting that the expected output was that only the most recent author's line should be updated. That expectation was from some kind of probabilisic (and definitely not always true) sense that contributors listed towards the end of the copyright notice tend to be the more recently-active contributors -- and also that sometimes copyright transfer means that the latest-listed holder is effectively the only remaining contributor (again, not always true). While thinking about disambiguation of active/inactive contributors, I gradually decided that contributor self-interest is likely to motivate them to keep their own copyright notice lines up-to-date and accurate. So in fact we could assume that Based on that, the remaining requirement is to continue to substitute any dynamically computed years, because we don't want to break those, and that's where the In the latter case, the lines where (in this case perhaps a third author added Your other observations:
To confirm points one and two: yep, this provides a minimal method for dynamic copyright notices, where the output is always year-based and deterministic (at least for a fixed build time and timezone, strictly speaking). Projects that use static/constant copyright notices would be unaffected, by definition. |
Closing this as the detection-of-constants approach seems complex, and also since we are gaining agreement that we can use a simplified template string format instead. |
Feature or Bugfix
Purpose
SOURCE_DATE_EPOCH
reproducible build timestamp is configured, I do not think that Sphinx should attempt automated substitution of constantly-declared copyright notice lines.Detail
conf.py
file, also parse it using Python's built-in AST parser, and keep a note of config key names that were declared at the module-level and values that are parsed asast.Constant
. Skip the substitution logic for any copyright keys configured using these identified constants.Relates