Skip to content
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

Allow custom escape #1386

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Allow custom escape #1386

wants to merge 1 commit into from

Conversation

CarliJoy
Copy link

@CarliJoy CarliJoy commented Apr 5, 2021

Checklist:

  • Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
  • Add or update relevant docs, in the docs folder and in code.
  • Add an entry in CHANGES.rst summarizing the change and linking to the issue.
  • Add .. versionchanged:: entries in any relevant code docs.
  • Run pre-commit hooks and fix any issues.
  • Run pytest and tox, no tests failed.
  • Check all left TODOs
    • Make sure that the left Markup() calls do not overwrite custom escapes with HTML escapes
    • if possible create yet some more test for some changes (see TODOs as well)
  • add some more changed version documention, but IMO low prio
  • add a test that uses files that have includes / extends templates that have different endings (configured to different auto escapern)

@CarliJoy CarliJoy changed the title WIP: Allow custom escape Allow custom escape Apr 7, 2021
@CarliJoy CarliJoy marked this pull request as ready for review April 7, 2021 00:27
src/jinja2/filters.py Outdated Show resolved Hide resolved
src/jinja2/filters.py Outdated Show resolved Hide resolved
src/jinja2/filters.py Outdated Show resolved Hide resolved
@@ -273,7 +316,11 @@ def do_xmlattr(
rv = " " + rv

if eval_ctx.autoescape:
rv = Markup(rv)
# We don't assume that using this filter we will use a custom
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# We don't assume that using this filter we will use a custom
# We don't assume that using this filter will use a custom

Maybe this way? Sentence made no sense to me.

src/jinja2/filters.py Outdated Show resolved Hide resolved
src/jinja2/nodes.py Outdated Show resolved Hide resolved
Comment on lines 84 to 92
# We need to keep Markup Class if existing as autoescape can be
# overwritten by {% autoescape %} environment.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this sentence.

src/jinja2/runtime.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
docs/api.rst Outdated
)


Note that for `.world` files the `{{ var|e }}` and `{{ var | escape }}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all this should use double backticks (assuming you want the equivalent to single-backtick highlighting on github)

docs/api.rst Outdated
template = env.get_template("message_to_the.world")
# the content of the template is simply assumed to by
"""
<h1>My Message to the world<h1>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<h1>My Message to the world<h1>
<h1>My Message to the world</h1>

docs/api.rst Show resolved Hide resolved
src/jinja2/compiler.py Outdated Show resolved Hide resolved
src/jinja2/compiler.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Show resolved Hide resolved
@@ -203,7 +201,6 @@ class InternationalizationExtension(Extension):

tags = {"trans"}

# TODO: the i18n extension is currently reevaluating values in a few
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removing that line probably wasn't intended...

src/jinja2/filters.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
Copy link

@jugmac00 jugmac00 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @CarliJoy,

I suggested some improvements regarding spelling and phrasing. Take my suggestions with a grain of salt as I am neither a Flask maintainer nor a native English speaker.

As I found many typos, I strongly suggest that you consider installing a spell checker for your IDE or editor.

If that is not possible, please give me a ping after your merged /considered my suggestions, then I will download your branch and review it locally - I just went through the PR in the GitHub UI.

That said - wow, what a massive PR - hats off!

src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/filters.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Outdated Show resolved Hide resolved
each file type.

.. versionchanged:: 3.0
if `autoescape` function returns not True or False but a Callable
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if `autoescape` function returns not True or False but a Callable
if the `autoescape` function does not return True or False but a Callable

src/jinja2/environment.py Outdated Show resolved Hide resolved
@CarliJoy
Copy link
Author

CarliJoy commented Apr 9, 2021

Hi guys,

thanks for your efforts, will work you comments in tomorrow or the days after tomorrow.
Actually PyCharm has Spell Check enabled but especially for grammar stuff it's not that good yet.
Probably I also have to change some settings as I guess I just missed some spell underlines 🤷🏻 🤦🏻
As I wrote in #1377, I am bit of (maybe not only a bit ;-) ) dyslexic, even in my native language (the one I probably share with @jugmac00).

So thanks for taking the effort in checking and correcting -> much appreciated!

Also is the first time for me that an PR in github actually got reviewed, so I also need to get started on this slowly :)
And please be forgiveful for my mistakes :-)

Comment on lines 646 to 669
for key, func in sorted(
special_extensions.items(), key=lambda x: len(x[0]), reverse=True
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The commend above is overly verbose IMO. Something like "Lookup autoescape function using the longest matching suffix" explains it just as well.

That aside, do we really need this complexity? The only file type where double extensions are somewhat common are archives (.tar.{gz,xz,bz2}). So I'd rather just match using the actual extension (as determined by os.path.splitext) instaed of making this more complex than necessary.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I can imagine end users that want a custom escape function for .special.html and also i.dont.like.spaces.but.points.html

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the use case for this? I get .html vs .tex, but anything .html should probably use the standard HTML escaper...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

People could (arguably maybe misuse) use the escape function to escape all bad words like "fuck" from endusers.
Or people use a javascript framework that replaces a specific part of the HTML, so the end users should never be allow to write this special string.

IMO libraries should be enablers and if I see a potential bug/edge case I rather fix it right away as frustrate an end user/library user in the end.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arguably maybe misuse

indeed, which is why I'm -1 on this

Or people use a javascript framework that replaces a specific part of the HTML, so the end users should never be allow to write this special string.
IMO libraries should be enablers and if I see a potential bug/edge case I rather fix it right away as frustrate an end user/library user in the end.

I get your point, but when people go into that kind of obscure territory they should probably provide their own select_autoescape implementation... In the end, libraries/framework should do their main jobs well, and if someone wants to do obscure things they can do that by subclassing/overriding things (or in this case providing their own autoescape function)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure but honestly I don't know any better solution 💫.
Using splitext simply feels wrong for me:

from os.path import splitext
splitext('foobar.ver1.html')
('foobar.ver1', '.html')
splitext('foobar.gz.html')
('foobar.gz', '.html')
splitext('foobar.tar.gz')
('foobar.tar', '.gz')

So please provide a change request with your preferred solution . Already spend much more time on this PR then intended and really would not like to invest time implementing something that feels like implementing a 🐞 bug for me. 🧘

src/jinja2/environment.py Outdated Show resolved Hide resolved
src/jinja2/environment.py Outdated Show resolved Hide resolved
@CarliJoy
Copy link
Author

@davidism is okay for your to take care of the conflict in docs/api.rst that was introduced through: #1391?

@CarliJoy
Copy link
Author

CarliJoy commented Apr 13, 2021

the moment when you worked 4hours to resolve a merge conflict and you realise that in the meanwhile the next PR was merged that causes the next merge conflict 😭

@CarliJoy
Copy link
Author

@ThiefMaster I fixed everything so far. Documentation is up to date, tests are as well. Currently no Merge Conflicts.
How likely is that you will give your ok for the PR? Because I rather would not to spend any more work into something that goes into the bin.

Also because this change touches code on so many places, that other PR most likely will introduce other Merge Conflicts.

@ThiefMaster
Copy link
Member

Because I rather would not to spend any more work into something that goes into the bin.

Don't worry about that. If we believed this was something we don't want we'd have told you from the beginning.

However, this is a large and complex PR, and while I will have another look, I don't think I'm going to be the one that will take the final decision on it and merge it; I'll leave that up to @davidism once he has the time for it.

I wouldn't worry too much about merge conflicts - most of them can probably be resolved right before merging.

docs/api.rst Show resolved Hide resolved
@CarliJoy
Copy link
Author

@davidism once you check the code, have a lock especially on the async stuff. I have no experience with async coding what so ever, so my changes are more like an educated guess.
I still tried to write some tests but not sure if I covered all the cases.
Maybe you also find a way make EvalContext known to the async Macros....

@CarliJoy
Copy link
Author

CarliJoy commented May 8, 2021

@davidism can I support/help you in any way with the review?

@davidism
Copy link
Member

davidism commented May 8, 2021

We won't have time to review something of this magnitude before release, so we're marking this for 3.1. I'm currently adding type annotations to the entire code base, so this is likely to need a rebase after that. Rebasing in general to squash commits would also be helpful, as 71 is too many to review.

@CarliJoy
Copy link
Author

CarliJoy commented May 8, 2021

Sorry I am not yet that experienced with rebasing.
What would be the workflow in an existing PR like this?
I would assume:

  1. After your added the Type Annotations create a new branch like custom_escape_squashed base on main
  2. Merge squash the existing custom_escape in the new branch
  3. Create a new PR based on the squashed branch and close this PR

Would that work/help? Or what else do you mean?

@jugmac00
Copy link

jugmac00 commented May 8, 2021

I think @davidism meant, that you should squash (https://levelup.gitconnected.com/how-to-squash-git-commits-9a095c1bc1fc) your 71 commits into one (and maybe force push the result to this branch).

After @davidism applied the type annotations, and merged them into master/main, you can rebase onto master/main - but only this one commit (https://stackoverflow.com/questions/7929369) - which makes it much easier.

Finally, force-push to this branch.

So, it is neither required to create a new branch or a new PR.

@davidism
Copy link
Member

davidism commented May 8, 2021

Hold off on squashing until I merge the type annotations. It might actually be easier to recreate after the fact instead of trying to resolve the merge conflicts, which will be significant.

@CarliJoy
Copy link
Author

CarliJoy commented May 8, 2021

@davidism just tell me once you finished the merge of the type annotations...

@CarliJoy
Copy link
Author

CarliJoy commented May 8, 2021

I think @davidism meant, that you should squash (https://levelup.gitconnected.com/how-to-squash-git-commits-9a095c1bc1fc) your 71 commits into one (and maybe force push the result to this branch).

After @davidism applied the type annotations, and merged them into master/main, you can rebase onto master/main - but only this one commit (https://stackoverflow.com/questions/7929369) - which makes it much easier.

Finally, force-push to this branch.

So, it is neither required to create a new branch or a new PR.

Thanks for the detailed answer

@davidism
Copy link
Member

davidism commented May 8, 2021

They're merged

@CarliJoy
Copy link
Author

CarliJoy commented May 17, 2021

@davidism Did the rebase and combination as requested.
One thing: When are you planning to release 3.0?
Are you following SemVer?
Because if you do it would be good not only to deprecate Markup but directly make people aware of the functions that will return the correct Markdown class?
Otherwise there will be one braking change between 3.0 and 3.1.

My suggestion would be to create a small PR that only provides the functions to get the (then only hardcoded) Markdown and escape functions.

Is this understandable?
What do you think?
Okay just realized that you release 3.0 already, well then there will be a braking change between 3.0 and 3.1...

@davidism
Copy link
Member

We don't follow semver.

I don't understand what the breaking change is, the only thing this PR should be doing is adding customization capabilities, not changing existing behavior.

@CarliJoy
Copy link
Author

First of all. Sorry I missed that release. Big thing, updating all libraries at once. Congratulations 🎉

We don't follow semver.
Good to know.

I don't understand what the breaking change is, the only thing this PR should be doing is adding customization capabilities, not changing existing behavior.

Braking change is for all creators of custom extensions and people that use Markdown directly in normal Python code to define a string as safe.
If they combine it with custom escape it could lead to unexpected behaviour (i.e. when using the % operator).
Tried to explain that in the documentation of the PR as good as possible.

@davidism
Copy link
Member

davidism commented May 17, 2021

That's not a breaking change though, that use case will continue to work, but they'll need to update if they want to take advantage / make correct use of customization that this enables. That's what a good changelog message and docs are for, so if you've addressed that there, that's good.

src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/utils.py Outdated Show resolved Hide resolved
src/jinja2/runtime.py Outdated Show resolved Hide resolved
@davidism davidism added this to the 3.1.0 milestone May 17, 2021
CHANGES.rst Outdated Show resolved Hide resolved
@CarliJoy
Copy link
Author

@davidism I changed things as requested. If there are still any issues, let me know.

@CarliJoy CarliJoy force-pushed the custom_escape branch 2 times, most recently from 0fc2b15 to ee08594 Compare May 29, 2021 22:48
@CarliJoy CarliJoy requested a review from davidism May 29, 2021 22:50
@CarliJoy
Copy link
Author

@davidism and @ThiefMaster will this ever be merged?

@davidism
Copy link
Member

davidism commented Jan 13, 2022

Yes, I do plan to eventually merge this. It is a huge set of changes, and I just have not been able to sit down and properly review it.

@davidism davidism modified the milestones: 3.1.0, 3.2.0 Mar 12, 2022
@CarliJoy
Copy link
Author

@davidism just another ping. Anything I can do to support you on this MR?

@CarliJoy
Copy link
Author

CarliJoy commented Jul 9, 2023

@davidism And here the yearly ping again 😉 . Anything I could do to finally finally get this merged?

@CarliJoy
Copy link
Author

CarliJoy commented May 21, 2024

Happy 3rd birthday MR :-)

@davidism I know this is a huge MR, due to the way how autoescape is handled currently.

In the meanwhile I gained a lot more experience, also with async. I could review the MR again, rebase it and see if I am able to maybe reduce the number of changes lines.

But I would only invest this time if there are resources on pallets side to review and merge the MR. Otherwise I will check in a year again.

Feel free to reach out to me with tasks and questions related to this MR 🤗

@davidism davidism removed this from the 3.2.0 milestone Dec 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow custom autoescape functions as result of the autoescape function parameter for the Environment
4 participants