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
Feature/local extensions #1240
Feature/local extensions #1240
Conversation
I totally missed your PR, @mwesterhof, when quickly scanning the open PRs today for exactly this feature. While not being finally decided whether I like an implicit (silent) loading of local extensions or your more explicit approach via dedicated keyword, I definitely like your context-manager approach for prepending |
Thanks, it was a bit of a challenge to find the right way to implement this. I'd be very interested in this feature, though. When you decide on the way you want this to work, feel free to let me know. I'd be happy to make some changes |
@mwesterhof @croesnick thank you for contribution. |
d8bb40f
to
e950ef9
Compare
@insspb @croesnick |
I'm sorry, it seems I've implemented a very similar thing in #1340 but at least mine is more documented than the other duplicate in #944 😅 For completeness I want to mention the issues, I know of, that have requested something like that #1211 and #547 so that people don't re-implement it again. Btw. may I ask, why not just add the extension directory to the path. It will only stay there, as long as the interpreter process running cookiecutter lives, so it will not influence anything else. You don't even have to check of its existence as python ignores non-existent dirs on I'd gravitate toward the more simple solution that involves less code. For the same reason I'd also vote for using the If anything, make the folder name just |
Love this PR @mwesterhof! I was thinking about how to tackle the I had one idea that I thought might improve this implementation. I haven't fully thought it through, but I wanted to get your take: As a What about instead of having users create a full-blown extension like: class FoobarExtension(Extension):
def __init__(self, environment):
super(FoobarExtension, self).__init__(environment)
def foobar():
return "foobar"
environment.filters['foobar'] = foobar we had them create a module def foo():
return "bar"
def baz():
return "qux" and we could do something like: import inspect
import filters
functions = inspect.getmembers(filters, inspect.isfunction)
for function in functions:
register_function_as_filter(function) Thoughts on this? |
it's an interesting take, @grahamalama I'm no expert on jinja, but i think we're ignoring a lot of the power of template filters by simplifying it this much. I'd propose a compromise: @simple_filter
def foo():
return 'stuff'
it actually mimics some ideas in the django framework regarding template filters and template tags, and it's an approach that i'm a big fan of. Any opinions? I'd be happy to implement this behavior in my branch |
I still maintain, that just adding the extensions directory to the path and letting the user do whatever is the best, smallest, most simple and most generic solution. I don't know what the extra Either way, the |
@con-f-use i would agree. importing the decorator as an additional helper from cookiecutter.utils is exactly what i had in mind. As far as separating the local extensions from the "regular" ones goes... i'm sure this is somewhat of a personal thing, but I'm personally a fan of having a clear distinction between "extensions bundled with the template" and "installed extensions". That's just my view on it, but i'd be happy to change that. I'm not entirely sure who makes that call, but please let me know |
@insspb @croesnick @con-f-use @grahamalama |
any news about this? |
@@ -414,6 +414,19 @@ def test_echo_unknown_extension_error(tmpdir, cli_runner): | |||
assert 'Unable to load extension: ' in result.output | |||
|
|||
|
|||
def test_local_extension(tmpdir, cli_runner): |
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.
Would it be good to include tests for non-happy path? I can think of two cases, but maybe there are more:
- I include a filter in my template, but didn't include the extension in the
_local_extensions
list - I include a filter in my template and extension in the
_local_extensions
list, but haven't defined that extension (or it's somehow not available to be imported)- It looks like there's a similar test for built-in Jinja extensions
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.
that's a good idea. i'll pick that up ASAP
This example assumes that a ``local_extensions`` folder (python module) exists in the template root. | ||
It will contain a ``main.py`` file, containing the following (for instance): |
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 I only need one or two extensions and they're not that complicated, I can just define them directly in a module local_extensions.py
, correct? Maybe instead of having the documentation suggest a more-complicated package setup, it could suggest simply that you have a module local_extensions
available in the template root with extensions defined, with no reference to a folder or main.py
. That would leave it up to the user to use a standalone module or a package structure depending on their needs.
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.
that seems fair. i'll make the change
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.
From what I gather reading the code you are adding the path of the local directory. So in effect you could create a folder that is named extensions
that contains an __init__.py
file. In that file you'll have the extensions and you'd refer to that in the cookiecutter.json file as 'extensions.MyExtension'
and it should all work.
I was looking for exactly this. I'm glad that this in the works. My preference, would be to not introduce new naming such as the |
I like the |
sorry guys, i've been quite sick recently and haven't gotten around to any work. I'll start working on this again though, so expect to see changes soon 💪 |
Can we please get this in the 2.0 release? |
Hello, is there any update for this feature? Thank you |
@audreyfeldroy Pretty please? 😁 |
2 days ago I've opened up an issue requesting to use some sort of custom .py script or function while generating the cookiecutter project to set a value in the cookiecutter.json, I believe this feature is exactly what I'm looking for! (In my case I need to read out the git config file to grab the name of the user) Is there any update on this? This is the one feature needed to automate all the things with cookiecutter 😛 |
Yeah, please merge this asap, I'd prefer not to wait another 2.5 years. It would be incredibly useful! |
Hi, I hope the best for @insspb but unfortunately, there is no Github activities for his account since December 2021. Could we review/merge this PR without him? Thank you, |
I was planning to merge it but I wanted to see the CI result first. |
@ssbarnea it seems that black linting was added somewhere along the line. I accounted for that, and it looks like everything passes now |
I'm overjoyed 😁 Thanks ssabernea! 🥇 When can we expect that to be released? Edit: |
Awesome, can't wait to use it cause this will really make things a lot more extensive! Same question as @con-f-use, is there a planned release date(with updated Docs as well?). |
I'm eager make use of this feature too! Thanks. |
} | ||
|
||
This example assumes that a ``local_extensions`` folder (python module) exists in the template root. | ||
It will contain a ``main.py`` file, containing the following (for instance): |
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.
main.py
must be __init__.py
@con-f-use looks like it made it into this release. |
this is a proposed change to add a "_local_extensions" feature.
It will enable the use of an additional "_local_extensions" element in the cookiecutter.json file. This will have the exact same functionality as the "_extensions" element, except that it can be used to load jinja2 template extensions straight from the project template.
I'm not certain if this is the best approach to achieve this, but I'm happy to have some feedback, of course.