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

Add support for scripts #241

Closed
ojii opened this issue Jun 20, 2018 · 73 comments · Fixed by python-poetry/poetry-core#40
Closed

Add support for scripts #241

ojii opened this issue Jun 20, 2018 · 73 comments · Fixed by python-poetry/poetry-core#40
Labels
kind/feature Feature requests/implementations

Comments

@ojii
Copy link
Contributor

ojii commented Jun 20, 2018

It would be nice if poetry supported the scripts feature of setuptools (note: this is not the same as entry points).

I tried using a custom build script but it seems to be ignored by poetry when building wheels.

@cauebs
Copy link
Contributor

cauebs commented Jun 20, 2018

So, this already works:

[tool.poetry.scripts]
funniest-joke = "funniest.command_line:main"

Maybe we could support this as well:

[tool.poetry.scripts]
funniest-joke = { path = "bin/funniest-joke" }

...analogous to how we can specify dependencies.
@sdispater what do you think?

@ojii
Copy link
Contributor Author

ojii commented Jun 20, 2018

Thanks for the info, I tried a scripts key under [tool.poetry]. I either missed that in the docs or it isn't there (if that's the case, I'll try to open a PR tomorrow).

@cauebs
Copy link
Contributor

cauebs commented Jun 20, 2018

It's documented here: https://poetry.eustace.io/docs/pyproject/#scripts
But I often miss these things as well :P

@ojii
Copy link
Contributor Author

ojii commented Jun 20, 2018

Ah I misread your initial comments. What's called "scripts" in poetry is called "entry points/console scripts" in setuptools. What I'm referring to is the "scripts" keyword to setup(...) which lets you specify things files as scripts (as opposed to python modules + functions). So it's the second example in your first comment I'm interested in.

If at all possible, if those scripts could be somehow selected per-platform, that would be amazing (maybe only for platform-specific wheels?)

@ojii
Copy link
Contributor Author

ojii commented Jun 21, 2018

For those interested, I'm working on this at https://github.com/ojii/poetry/tree/non-python-scripts

@cauebs
Copy link
Contributor

cauebs commented Jun 24, 2018

@ojii I was just testing you fork and it appears to be working, but I think the syntax I proposed is misleading unless you rename the script, which is something setuptools doesn't do.

Say I have this in my pyproject.toml

[tool.poetry.scripts]
cli = { path = "foo/bar" }

I might expect to be able to run cli, but only bar will work.
You could either rename the script to whatever is specified, to maintain the same syntax, or we can change the syntax, but I can't think of anything.

@ojii
Copy link
Contributor Author

ojii commented Jun 25, 2018

You could either rename the script to whatever is specified, to maintain the same syntax, or we can change the syntax, but I can't think of anything.

I think it's reasonable to just reject those scripts if the filename does not match the key. (In setuptools, it's a list, not a mapping).

@markovendelin
Copy link
Contributor

I think it's reasonable to just reject those scripts if the filename does not match the key. (In setuptools, it's a list, not a mapping).

Not sure that such rejection would be reasonable. As a user, I would expect either a list of scripts (for plain copy) or mapping with renaming. Having to enter mapping with the same data entered twice (key and part of the value) does seem to be just a source for errors on user's side.

@ojii
Copy link
Contributor Author

ojii commented Jul 13, 2018

@cauebs @markovendelin I've updated my branch to re-name the scripts according to the users configuration. Should I open a PR or are there other blocking issues with this?

@cauebs
Copy link
Contributor

cauebs commented Jul 13, 2018

Pretty cool! Worthy of a PR, in my opinion.

@ojii ojii mentioned this issue Jul 14, 2018
2 tasks
de3sw2aq1 added a commit to de3sw2aq1/fiction-scraper that referenced this issue Aug 7, 2018
Probably waiting on python-poetry/poetry#241
to easily use a "script" entrypoint for a package.
@rcisterna
Copy link

rcisterna commented Aug 13, 2018

Are there plans to merge #304 any time soon? I've been recommending poetry in the company I work for, but sadly, this feature is a must have :(

Edit: Maybe there is a workaround that @cauebs or @sdispater can recommend for this in the meanwhile.

@Kamforka
Copy link

Is the script section able to execute commands that can help you integrate developer tasks into poetry?

I imagine it like this:

[tool.poetry.scripts]
test = "pytest tests/ --verbose"

It would be a nice feature to have, what do you think?

@cw-andrews
Copy link

cw-andrews commented Oct 20, 2018

Is the script section able to execute commands that can help you integrate developer tasks into poetry?

I imagine it like this:

[tool.poetry.scripts]
test = "pytest tests/ --verbose"

It would be a nice feature to have, what do you think?

I definitely agree. I am trying to do the same thing to run a molten app via gunicorn and it would be much easier to do it this way then write a script for a custom gunicorn application.

@purificant
Copy link

I'd like to be able to type poetry test and have that run a longer script with test configuration, similar to poetry build. poetry lint would be nice too, this could be done through 'scripts' if they were similar to https://docs.npmjs.com/misc/scripts where you can define arbitrary script names which perform context aware commands.

@michaeldel michaeldel mentioned this issue Nov 2, 2018
2 tasks
@mattyclarkson
Copy link

I'm keen for something similary to NPM scripts. I would like to use poetry as my full workflow tool so:

poetry format
poetry lint
poetry build
poetry test
poetry coverage

@germn
Copy link
Contributor

germn commented Dec 8, 2018

Just wanted to share messy workaround I ended up with.

pyproject.toml

[tool.poetry.scripts]
pytest = 'scripts:pytest'

You'll need to create file scripts.py to delegate stuff:

scripts.py

import sys
import subprocess


def __getattr__(name):  # python 3.7+, otherwise define each script manually
    name = name.replace('_', '-')
    subprocess.run(
        ['python', '-u', '-m', name] + sys.argv[1:]
    )  # run whatever you like based on 'name'

Then run something, for example:

poetry run pytest --help

It works :)

@mm-matthias
Copy link

I'd also like to see a feature like this, currently I am doing

[tool.poetry.scripts]
generate-code="codegen:generate_code"

But this will also create the generate-code script when installing the package in non-dev mode.

To run scripts only in dev mode I propose this:

[tool.poetry.dev-scripts]
generate-code="codegen:generate_code"

This is analogous to tool.poetry.dependencies/ tool.poetry.dev-dependencies.

@brycedrennan
Copy link
Contributor

brycedrennan commented Mar 6, 2019

@mm-matthias @germn @cw-andrews @Kamforka @purificant

It looks like there is a desire for developer/project specific helper scripts, but that's not what [tool.poetry.scripts] is for. As mentioned, scripts are entrypoints into a python packages. This section's purpose is for libraries to install useful command line tools. Libraries like pytest, poetry, and the aws cli would use this scripts section so you can call their tool from the command line.

Scripts in this section will be globally available in any python environment that installs that package. For example, if someone were to install a package that had

[tool.poetry.scripts]
pytest = 'scripts:pytest'

in its pyproject.toml, that would be overriding the pytest command everywhere in the environment.

For a lot of what is being described, which is project specific developer scripts, a Makefile sounds more appropriate. Makefiles have the advantage of being language independent and already installed on most systems. This means for example, your makefile could have a script that setup a installed poetry and used it to create a virtual environment.

Here is a simple example of a Makefile. Here is a more fleshed out one from one of my projects.

test:  ## Run the tests in current environment
	pytest

help: ## Show this help message.
	@## https://gist.github.com/prwhite/8168133#gistcomment-1716694
	@echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" | sort

In your project you could then run make test or make help.

I'd rather not have poetry turn into yet another way to run scripts for developers.

@brycedrennan
Copy link
Contributor

brycedrennan commented Mar 6, 2019

Also you can see an example Makefile in the poetry codebase itself:
https://github.com/sdispater/poetry/blob/master/Makefile

@jgirardet
Copy link
Contributor

I'm waiting the plugin system to see if something like could'nt be added outside of poetry "core". Make file style command would be very usefull inside the pyproject.toml

@brycedrennan
Copy link
Contributor

Looks like a similar feature is being added:
#591

@Kamforka
Copy link

Kamforka commented Mar 6, 2019

@brycedrennan I see your point, but I still feel like this feature has a direct place inside the poetry ecosystem.

Also for those who've got used to setuptools like entry_points it's a bit confusing to use a section like scripts for the same purpose.

It makes it even more confusing for those who are somehow related to npm projects where the scripts section is used to declare tasks.

But as far as I know the dev-scripts section is already under construction to achieve similar functionality as npm-scripts.

@brycedrennan
Copy link
Contributor

Naming aside, we shouldn't overload a section to handle both entrypoints and dev-scripts. And certainly not in a way that would hose the environments of people who installed our packages with global overrides of pytest or test.

I'll still have to have a Makefile to handle installing the proper python version (via pyenv) and poetry itself. That's why this just feels like unnecessary fragmentation. It also doesn't help for projects that use multiple languages. Makefile works for everything.

I concede there is demand for it though.

@Kamforka
Copy link

Kamforka commented Mar 6, 2019

I didn't say we should overload, rather I was talking about a section that could handle task running.

I understand that basically anything can be achieved using makefiles, but honestly I never had a Makefile inside any of my Python projects neither seen one in projects I use as dependencies.

Also I think that the main ambition behind poetry is to make a proper solution to manage, build and package Python projects, so I think multi-language support is not a top priority here.
However if one needs to support multi-language projects then makefiles are a nice fallback to rely on.

@brycedrennan
Copy link
Contributor

I thought using the already existing scripts section to support developer tasks was what was proposed here. Based on what you're saying now, I'll interpret that previous comment to mean you wanted entrypoints to be moved to a different section.

Makefiles can be pretty messy in some projects and thus its common to find them intimidating. Here are makefiles from libraries you use:

@abn abn closed this as completed May 6, 2021
@euberdeveloper
Copy link

I don't think python-poetry/poetry-core#40 is related to this issue

@abn
Copy link
Member

abn commented May 7, 2021

@euberdeveloper as per the OP, this issue is talking about "scripts" similar to how setuptools does it. I think the issue(s) you are looking for are #591 #2496.

@euberdeveloper
Copy link

euberdeveloper commented May 7, 2021

Ok, I read them and it was written that the owner of poetry won't implement it but there is a third party plugin that works pretty well, thank you

@keattang
Copy link

This is the only thing holding us back from rolling poetry out across our entire company. The posted solutions are workable but it's less than ideal to have to type run + <runner> + <cmd> when a lot of other tools let you run scripts directly.

To help mitigate this I've just created the poetry-exec-plugin, ready and waiting for poetry 1.2 to be released with its plugin system. It works just like npm or pipenv and can be installed with pip install poetry-exec-plugin. You then configure your scripts like this in your pyproject.toml:

[tool.poetry-exec-plugin.commands]
lint = "flake8 && black --check . && mypy ."
test = "pytest"

Then your scripts can be run with poetry exec <cmd> (e.g. poetry exec lint , poetry exec test).

Hopefully this is helpful to others 😄

@miigotu
Copy link

miigotu commented Nov 9, 2021

This is the only thing holding us back from rolling poetry out across our entire company. The posted solutions are workable but it's less than ideal to have to type run + <runner> + <cmd> when a lot of other tools let you run scripts directly.

To help mitigate this I've just created the poetry-exec-plugin, ready and waiting for poetry 1.2 to be released with its plugin system. It works just like npm or pipenv and can be installed with pip install poetry-exec-plugin. You then configure your scripts like this in your pyproject.toml:

[tool.poetry-exec-plugin.commands]
lint = "flake8 && black --check . && mypy ."
test = "pytest"

Then your scripts can be run with poetry exec <cmd> (e.g. poetry exec lint , poetry exec test).

Hopefully this is helpful to others 😄

https://pypi.org/project/poethepoet/

@bluebrown
Copy link

bluebrown commented Jan 21, 2022

Why is this not built in? It's pretty much a must-have. Installing an extra plugin is strange.

@purificant
Copy link

Why is this not built in? Its pretty much a must have. Installing an extra plugin is strage.

From what I understand the team behind poetry has made a decision not to support this kind of user experience in the core codebase. Other similar teams in different communities / programming languages have made different decisions and this thread reflects that.

dimbleby referenced this issue in dimbleby/poetry Apr 21, 2022
Resolves: python-poetry#241
dimbleby referenced this issue in dimbleby/poetry Apr 21, 2022
This change refactors implementation and tests relating to script file
specifications.

Relates-to: python-poetry#40
Relates-to: python-poetry#241
@arielnmz
Copy link

Re @hg-zt
Still no way of making this work?

[tool.poetry.scripts]
# other entry points
my_shell_command = { path = "bin/my_shell_command.sh" }

I just want to package a .sh with my library

@TBBle
Copy link
Contributor

TBBle commented May 10, 2022

Per the poetry-core ticket that closed this issue, the syntax is

[tool.poetry.scripts]
my_shell_command = {reference = "bin/my_shell_command.sh", type = "file"}

and it only works with poetry-core 1.1.0a5 or later (which will need to be specified in the build-system table in your pyproject.toml), and hence Poetry 1.2.0a1 or later, and poetry install won't set up the scripts as the feature is not yet implemented in the EditableBuilder in Poetry itself (See #2310 for the ticket tracking that).

But given the above caveats, it should package the desired scripts into the sdist and wheels, and then they will be installed by the installer (i.e. pip) as expected. You can see some examples in the poetry-core test suite.

@shubb30
Copy link

shubb30 commented Jun 23, 2022

Hi @TBBle,

Can you confirm the syntax is still correct?
I am using versions poetry==1.2.0a1 poetry-core==1.1.0a5 and when I run check, get the errors:


poetry check -vv

  Stack trace:

  8  .venv/lib/python3.8/site-packages/cleo/application.py:329 in run
       exit_code = self._run(io)

  7  .venv/lib/python3.8/site-packages/poetry/console/application.py:167 in _run
       return super()._run(io)

  6  .venv/lib/python3.8/site-packages/cleo/application.py:423 in _run
       exit_code = self._run_command(command, io)

  5  .venv/lib/python3.8/site-packages/cleo/application.py:465 in _run_command
       raise error

  4  .venv/lib/python3.8/site-packages/cleo/application.py:449 in _run_command
       exit_code = command.run(io)

  3  .venv/lib/python3.8/site-packages/cleo/commands/base_command.py:119 in run
       status_code = self.execute(io)

  2  .venv/lib/python3.8/site-packages/cleo/commands/command.py:83 in execute
       return self.handle()

  1  .venv/lib/python3.8/site-packages/poetry/console/commands/check.py:18 in handle
       check_result = Factory.validate(config, strict=True)

  KeyError

  'extras'

  at .venv/lib/python3.8/site-packages/poetry/core/factory.py:372 in validate
      368│                 for name, script in scripts.items():
      369│                     if not isinstance(script, dict):
      370│                         continue
      371│ 
    → 372│                     extras = script["extras"]
      373│                     for extra in extras:
      374│                         if extra not in config["extras"]:
      375│                             result["errors"].append(
      376│                                 'Script "{}" requires extra "{}" which is not defined.'.format(

To test, I changed the section to be

[tool.poetry.scripts]
my_script = {reference = "bin/my_script.py", type = "file", extras = []}

And then the check worked, and the package was correctly built, and included the script.

@TBBle
Copy link
Contributor

TBBle commented Jun 24, 2022

That looks like a bug in poetry-core, so I'd report it separately.

I guess extras support was added later and accidentally broke the case of no extras by failing to default to []. (Edit: Nope, it's always been that way. Weird, must be a code-path that the test suite isn't actually testing) The line that failed probably should be

extras = script.get("extras", [])

and so should the use of "extras" a few lines down. Every other usage in this file of "extras" is protected like that.

That said, the example in the poetry-core test suite hasn't changed, so I'm not sure why it doesn't reproduce there. Either way, worth a new bug report since this ticket is closed and your issue won't get the attention it needs here.

Edit: Turns out there's already a fix in progress: python-poetry/poetry-core#404, as this issue was reported at #4665 (including by you, I see now).

@miigotu
Copy link

miigotu commented Jun 25, 2022

Hi @TBBle,

Can you confirm the syntax is still correct?
I am using versions poetry==1.2.0a1 poetry-core==1.1.0a5 and when I run check, get the errors:


poetry check -vv

  Stack trace:

  8  .venv/lib/python3.8/site-packages/cleo/application.py:329 in run
       exit_code = self._run(io)

  7  .venv/lib/python3.8/site-packages/poetry/console/application.py:167 in _run
       return super()._run(io)

  6  .venv/lib/python3.8/site-packages/cleo/application.py:423 in _run
       exit_code = self._run_command(command, io)

  5  .venv/lib/python3.8/site-packages/cleo/application.py:465 in _run_command
       raise error

  4  .venv/lib/python3.8/site-packages/cleo/application.py:449 in _run_command
       exit_code = command.run(io)

  3  .venv/lib/python3.8/site-packages/cleo/commands/base_command.py:119 in run
       status_code = self.execute(io)

  2  .venv/lib/python3.8/site-packages/cleo/commands/command.py:83 in execute
       return self.handle()

  1  .venv/lib/python3.8/site-packages/poetry/console/commands/check.py:18 in handle
       check_result = Factory.validate(config, strict=True)

  KeyError

  'extras'

  at .venv/lib/python3.8/site-packages/poetry/core/factory.py:372 in validate
      368│                 for name, script in scripts.items():
      369│                     if not isinstance(script, dict):
      370│                         continue
      371│ 
    → 372│                     extras = script["extras"]
      373│                     for extra in extras:
      374│                         if extra not in config["extras"]:
      375│                             result["errors"].append(
      376│                                 'Script "{}" requires extra "{}" which is not defined.'.format(

To test, I changed the section to be

[tool.poetry.scripts]
my_script = {reference = "bin/my_script.py", type = "file", extras = []}

And then the check worked, and the package was correctly built, and included the script.

1.2.0a2 is behind the release version, I had to use the regular release rather than the alpha.

@TBBle
Copy link
Contributor

TBBle commented Jun 25, 2022

What version do you mean by "regular release"? There's no non-pre-release version of 1.2 series Poetry (the latest is 1.2.0b2), and the current release versions of Poetry (1.1 series) do not have this feature. Poetry 1.1.x only supports what setuptools calls "console_scripts entry point", not what setuptools calls "scripts". (Both are different kinds of "scripts" in Poetry's terminology, and the latter is what this issue was requesting, and has now been implemented for Poetry 1.2).

@rosaLux161
Copy link

Any updates here?

@TBBle
Copy link
Contributor

TBBle commented Mar 8, 2023

See #2310 for where updates will appear, since this issue has been closed after the underlying support in poetry-core was delivered, so it works for package creation, but apparently not poetry install or poetry run of the package containing the script itself. #2310 (comment) appears to be the most-recent status for the poetry side of this.

As noted in #2310, it's also missing from the docs still, although maybe that's because of the current non-working cases.

@django-djack
Copy link

Any updates here ?

@django-djack
Copy link

It's been almost 5 years lol

@TBBle
Copy link
Contributor

TBBle commented Oct 5, 2023

Nope, no updates here, and there won't be any, as this issue has been closed, and the support for scripts was shipped in Poetry 1.2.0 (technically Poetry Core 1.1.0, which is the matching Poetry Core release) over a year ago. See #241 (comment) for updates relating to scripts support in poetry install and poetry run, and (presumably) full documentation of this feature.

Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 29, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
kind/feature Feature requests/implementations
Projects
None yet
Development

Successfully merging a pull request may close this issue.