Open abn opened 4 years ago
a question unrelated to my proposal, how would you accomplish to drop the file extension here?
[tool.poetry.scripts]
my-script = {path = "bin/my-script.sh"}
i'm assuming that you propose to install that file as my-script
.
@funkyfuture yes, this is how it will be installed. The name of the installed script in this instance will be "my-script".
poetry
shouldn't establish concepts that blur distinct, existing ones. it should treat equal concepts equally. setuptools
entrypoints can be used versatile and poetry shouldn't insinuate assumptions on their use by using specific usage-related terms. a generalized approach on entrypoints allows to canonically handle their optionality that stems from required extras. that lack is a show-stopper for adopting poetry by projects that rely on this feature.
poetry
, today, allows for the handling of console_script
and other entrypoints which are defined in two different namespaces within the tool.poetry
namespace of a pyproject.toml
(plugins
& scripts
). setuptools
' pkg_resources
module offers interfaces to canonically query entrypoints, regardless their function.
in contrast to the PyPA's entrypoints specification poetry
's expects console_scripts
- for which beside gui_scripts
an extended, afaik non-standardized handling exists - in another namespace than all other entrypoint groups. at the same time all other entrypoint grouposs are lumped together under the term plugins
.
other than entrypoints which always point to a member within the package, scripts
(as defined by this keyword to setuptools.setup
) can point to any file within the distributed package source, but it doesn't necessarily need to be Python code or depend on the package itself. if it was a Python code file, the shebang could point to any Python interpreter and there's no way to control that it would point the one that is used for the package installation. in some cases it is used to install further (non-Python) dependencies or data that is required to make use of the package. another difference between console_scripts
entrypoints and scripts
is that the former can lead to installations of various executables that execute callables within the same module.
let's take this setuptools
setup as an example:
setup(
entry_points={
"console_scripts": ["theclitool = a_package.cli:a_function"],
"a_frameworks.serializers": ["a_format = a_package.serializers:a_format_serializer"],
"a_frameworks.data_sources": ["that_catalogue = a_package.data:DataLoader.ingest"],
"a_frameworks.locale_strings": ["it-IT = a_package.locales.it:strings"]
},
scripts=["bin/download-catalogue.sh"]
)
@abn's proposal continues to separate out the console_scripts
entrypoints from others and specifies different notation of entrypoints as tables and inline tables:
[tool.poetry.scripts]
"download-catalogue.sh" = {path = "bin/download-catalogue.sh"}
theclitool = {entrypoint = "a_package.cli:a_function"}
[tool.poetry.plugins."a_frameworks.serializers"]
a_format = "a_package.serializers:a_format_serializer"
[tool.poetry.plugins."a_frameworks.data_sources"]
that_catalogue = "a_package.data:DataLoader.ingest"
[tool.poetry.plugins."a_frameworks.locale_strings"]
it-IT = "a_package.locales.it:strings"
while both plugins
and scripts
are no hard terms, the underlying mechanics actually allow uses that don't fit them. in the example that would be the locale example, which wouldn't match the connotation of a functional enhancement that one may have with plugins. the console_scripts
entrypoints could be a standalone server or a complex tool like poetry which most wouldn't recognize as scripts. hence, actually, the term commands
might be better suited than console_scripts
. while it might an option to use that better term by translating it to setuptools.setup
, that would make that name unusable as group name and could hinder the adoption of poetry by projects that may use it.
my proposal is to stick with the well-established and versatile namespacing of setuptools
:
[tool.poetry.scripts]
paths = ["bin/download-catalogue.sh"]
[tool.poetry.entrypoints.console_scripts]
theclitool = "a_package.cli:a_function"
[tool.poetry.entrypoints."a_frameworks.serializers"]
a_format = "a_package.serializers:a_format_serializer"
[tool.poetry.entrypoints."a_frameworks.data_sources"]
that_catalogue = "a_package.data:DataLoader.ingest"
[tool.poetry.entrypoints."a_frameworks.locale_strings"]
it-IT = "a_package.locales.it:strings"
alternatively, poetry
may allow nested tables to define entrypoint groups and flatten these:
[tool.poetry.entrypoints.a_frameworks.serializers]
a_format = "a_package.serializers:a_format_serializer"
also, src
may be clearer as keyword in the tools.poetry.scripts
instead of paths
.
another important, yet completely missing aspect from poetry
that unifies all entrypoints and sets them apart from setuptools
scripts is their optionality that depends on the specification of extras. with the above clear distinction and (re-)unification in place, any tools.poetry.entrypoints
table's entry could alternatively take an inline table as value to define dependencies on one or more extras. The extras
value could either be a string or a list of such that need to point to keys that are defined in the tools.poetry.extras
table:
[tool.poetry.extras]
cliframework = ["cleo"]
https-transport = ["requests"]
xml-parser = ["lxml"]
[tool.poetry.entrypoints.console_scripts]
theclitool = {entrypoint = "a_package.cli:a_function", extras = "cliframework"}
[tool.poetry.entrypoints."a_frameworks.data_sources"]
that_catalogue = {
entrypoint = "a_package.data:DataLoader.ingest",
extras = ["https-transport", "xml-parser"]
}
since a new table entrypoints
is used, it should be easy to convert definitions from the plugins
table while this is still supported as deprecated feature. the intended use of specifications from the scripts
table seems to be distinguishable by heuristics, but i haven't thought deeply about that yet, there might be edge cases.
(yes, i know poetry doesn't want to be setuptools, but i see no advancement in this regard on its side and effectively it's still a setuptools wrapper, isn't it?)
@funkyfuture thank you for taking the time to provide feedback. However, this conversation has already been had across the linked related issues. As you have mentioned, poetry is not setuptools. While setuptools uses the entry_points
argument to configure all three use cases, this can, in the end, be one of the more confusing aspects of the setup.py
file. And this is not something that we should repeat just because it is what is already done. PyPA's interoperability specification exists "to allow build tools other than setuptools to publish pkg_resources compatible entry point metadata, and runtime libraries other than pkg_resources to portably read published entry point metadata (potentially with different caching and conflict resolution strategies)" [1]. It does not dictate or recommend how build tools expose these features to end users in their respective configurations. Any build artifacts produced by Poetry will be interoperable as per the recommended specification.
The scope of this issue is limited to improve script file support, by allowing poetry users to specify a file to be used. To that effect, we do not wish to replace the "plugin" section or duplicate its functionality in another section. The current proposal has been made with future extensibility in mind. I have updated the title to reflect this clearly.
An extension to this could include support for extras
and also for distinguishing between console
and gui
quite easily. For example;
[tool.poetry.scripts]
my-script = {path = "bin/my-script.sh", extras=["foo"]}
my-python-script = {entrypoint = "package.module:function", type="console", extras=["cli"]}
my-python-script = {entrypoint = "package.module.gui:function", type="gui"}
However, this conversation has already been had across the linked related issues.
sorry, but no. in #658 the discussion is mainly @brycedrennan explaining what scripts in the scope of packaging are not.
in #1023 it's @grabear, @tedmiston and me expressing concerns about the confusing design.
in #1504 @peterdeme is proposing to keep scripts
distinct from console_scripts
. which is then again followed by people talking about task runners.
none of my points of critique regarding ambiguity, clear distinction, consistency and adequate naming of configuration keys i tried to elaborate above is discussed there in a way that deserves to be called that way (including posts by me).
While setuptools uses the entry_points argument to configure all three use cases
what would be the three use-cases? my argument is, that there is only one general use-case, to group and to name entrypoints, in order to facilitate infinite concrete use-cases.
this can, in the end, be one of the more confusing aspects of the setup.py
could you please elaborate on the potential confusion of entrypoints?
And this is not something that we should repeat just because it is what is already done.
i did not argue that it should be repeated b/c it's already done, but b/c it's done well and simple. i do not see an improvement with the current state, your proposal, or any argument in your rationale that would explain why it would be.
The scope of this issue is limited to improve script file support
that i see, but i could hardly leave the broader picture out of the scope, because, as you write, the console_scripts end up in the same metadata fields as "plugins" with the same properties, and imo should hence be configured by the user equally to avoid confusion from the start and down the road.
one thing i forgot to mention in my previous response; i would expect users to ask for the use of extras
in conjunction of executable files with the schema you propose.
Hey guys @funkyfuture and @abn ! Just want to preface with, I love to use poetry! And I'm assuming you guys do too, especially since you're both willing to put so much time into the development process.
I'm out of the loop on this and haven't developed with poetry in about 4-5 months. But I will say this.. The current implementation can be confusing it doesn't document the different script strategies used throughout the python universe (including poetry).
My suggestion would be to encapsulate any previously existing strategies using the same syntax to avoid confusion https://github.com/python-poetry/poetry/issues/1023#issuecomment-481043154:
It's also not super clear in the documentation what the difference is between 'plugins' and 'scripts'. Based on the original comment:
- poetry's scripts == setuptools' entrypoint/console_script
- setuptools' scripts keyword != poetry (is not represented by poetry)
And new information:
- poetry's plugins == setuptools' entrypoint/dynamic-discovery-of-services-and-plugins
By changing the link in the 'plugins' documentation to the one supplied above, I think that would also help clear things up:
From this (main page of setuptools) to this (the actual article).
And then if you want to create a new poetry specific strategies for deploying scripts, then make sure it's well documented and distinguished from the alternatives (setuptools entrypoint, setuptools console_scirpts, setuptools scripts)
If you think that the old setuptools strategies for accomplishing this are dumb, then don't include them. The reason that there are so many issues regarding this is that: A) Setuptools is confusing B) Poetry is confusing C) Poetry has made itself and Setuptools more confusing
Anyways, I hope this helps!
I agree with @funkyfuture, certain concept are imporant and not discussed.
People (like me) are trying for a while to move from setuptools to something else. Poetry is a more valid tool which is really promising, but lacks features. In addition, some feature are really confusing and seem to have been not well-though. This is a a show-stopper for many of us.
@funkyfuture gave a very well presentation on what's needed
To be honest, I want to see a tool that is extendible and powerful. All the talking I see in many places for this project are about to implement a very limited set of narrowed-down features with a limited use.
Does poetry as a project have a statement on what it wants to achieve? It's ok if it's "help simple projects to be built". But it means it's not many people who needs advanced tools. Too bad for those people, they'll stay longer with setuptools.
But, as.I hope, the objetive is to built a powerful extensible tool, then please, listen also to what @funkyfuture says (I would have written something similar, but they did a great work articulating the issues)
It's also ok to have a plan which is big, and implementing part of it, step by step. I do not mean to insult anyone, but it feels silly not to take advantege of the great potentiality of this project and design things properly.
Hello,
In addition, some feature are really confusing and seem to have been not well-though.
I suggest to open a new issue about the the things you find confusing, so that we can keep the focus of the discussion here to the suggestions made by @abn . I guess most of the confusing are due to the behavior one knows from other tools and expects to find the same behavior in poetry, which isn't necessarily the case.
To be honest, I want to see a tool that is extendible and powerful.
The extensibility is near. With poetry 1.1 there will be a plugin system (https://github.com/python-poetry/poetry/issues/1856)
fin swimmer
If you think that the old setuptools strategies for accomplishing this are dumb, then don't include them.
To be clear, the project team does not consider the setuptools configuration layout for handling this is in anyway shape or form incorrect or "dumb". We simply feel that it does not fit well as is for poetry.
My suggestion would be to encapsulate any previously existing strategies using the same syntax to avoid confusion
In order to use the same configuration syntax/layout as setuptools temporarily, it would mean implementing new configuration mechanisms within poetry. This is not something that the project team would like to do, we prefer to avoid creating multiple ways to do the same thing. Additionally, this also pollutes the configuration namespace unnecessarily, especially since we know we do not want to keep the setuptools layout for this configuration. A lot has changed since the original implementation for script/plugin support was added to poetry. The documentation, as it stands today, has gaps when detailing the concepts and how they map to entry points/plugins as described by setuptools.
At the end of the day, the objective is to enable a poetry user to specify the installation of a script when their package is installed. In our opinion, there is no real advantage in following the exact syntax/layout used by setuptools here. Poetry has to cater to users having varied levels of understanding about Python's packaging. As part of this implementation however, I would expect the documentation to be updated and also provide examples for users that are more familiar with setuptools.
I have, based on the above discussions, updated the description to include additional details as well as use new properties to better map to the PyPA specification data model.
@abn I haven't checked the repo to read any updates. So I'm not sure what you guys have done to the documentation with respect to this issue..
But when you implement the new docs could you explicitly compare poetry's strategies vs setuptools? That way it is clear to the veteran, and novice users.
@grabear in the issue description under "Comparison with setuptools" I have added configuration comparisons for now, which should get incorporated in the documentation when this is implemented. If you are talking about the documentation in the broader context, I would suggest opening a new issue specifying what areas (outside of console scripts) require these comparisions.
Also, feel free to contribute any such changes. Happy to review.
Implemented file scripts https://github.com/python-poetry/poetry-core/pull/40 Please review it. Thanks.
I assume once https://github.com/python-poetry/poetry-core/pull/40, this will need to be applied to the EditableBuilder
here too.
In that case, it'd be great if we could leverage distlib.scripts
because that can also create Windows executables for console_scripts
-style launchers, rather than the current batch-file generation, which can lead to issues like #2030 (although #2030 itself is a problem in get-poetry.py)
@TBBle we should be able to reuse the logic if done right; for editable installs.
As for the use of distlib
, I need to check what the latest in the packaging community is regarding this. Last I checked there were some differences of opinions in what is "official" and what is not. :(
The get-poetry
issues need to be revisited seperately. We need to revisit how poetry itself is distributed. We might end up doing something more standardised later on.
Certainly the parsing logic in https://github.com/python-poetry/poetry-core/pull/40 should be reusable in EditableBuilder
, but as far as I understand, the Builder
s in poetry-core
will never be responsible for creating the (current) batch or (future) executable for the console_scripts
, they just bundle the relevant python file into the sdist/wheel package, and the install-time handler is the one that performs that logic in those cases, because it's install-platform specific.
If distlib
itself is a concern, setuptools
also exposes a mechanism for configuring exe-runners for console_scripts
and gui_scripts
. I personally prefer the bundled-exe approach (distlib
) to the stock-exe-that-uses-argv[0] (setuptools
), but it's only a preference. (pip install -e
actually uses the latter, because it delegates such installs entirely to setuptools
, but I assume we don't want that).
However, with setuptools
, you need to make the determination yourself of whether it's a console_script
/gui_script
, or (copied) script
, in which case implementing the current feature is agnostic to fixing #2030-style issues by replacing the .cmd/.bat wrappers for console_scripts
.
Hello, I'm a new poetry user trying to transition from a project using setuptools. It seems python-poetry/poetry-core#40 is implemented but, from the master docs here, this change is not being implemented in v1.2?
Please may you advise if and when this feature will be implemented?
It seems python-poetry/poetry-core#40 is implemented but, from the master docs here, this change is not being implemented in v1.2?
Also curious about this!
Any updates on this?
Any updates? Seems like a pretty bad move to override setuptools scripts
but actually implement entry points instead
This is mostly implemented in core, but poetry run
is currently broken with this variant of scripts, and it is undocumented. PRs documenting it are welcome!
I have a question for the current specification.
Why to have different field for each type? Since we have the discriminator type
, I don't see a very good reasons to write source
and reference
depends on the type.
My point is, why not to call everything source
or everything reference
?
For instance:
[tool.poetry.scripts]
console-script = {source = "package.module:function", type = "console"}
gui-script = {source = "package.module:function", type = "gui"}
file-script = {source = "bin/script.sh", type= "file"}
By the way, if you stick to reference
, any chance to shorten to ref
? :slightly_smiling_face:
As far as I can tell, this doesn't work as described. There also appears to be no documentation about what the intended behavior is, if it is something different than the original proposal. I filed https://github.com/python-poetry/poetry/issues/7925 asking whether this feature was actually implemented, and if so, how it is intended to be used, but I was told that that question should be asked in this thread instead.
So, the question: is there any working example of this feature? I have been unable to construct one - see https://github.com/python-poetry/poetry/issues/7925#issuecomment-1550550415 for an unsuccessful attempt - and was eventually forced to remove Poetry from my project.
What I expect is that I can install an executable script as part of my Python package, so that it will be added to $PATH
like native Python entry points. This does not seem possible with Poetry, although the discussion in this issue and numerous linked issues suggests that it should be. Have I missed something?
Repeating what I said in the other: that poetry-core MR does not do what you think it does (I don't know what part of the discussion has misled you). There is an open issue - this one! - wishing for the job to be finished.
The linked example should work if a distribution is generated (i.e. an sdist or wheel is output) and installed using pip
or other installation tool. The missing thing is just that poetry install
specifically doesn't yet know how to handle such scripts, which is why this ticket is still open.
As a workaround, you could use something like https://github.com/nat-n/poethepoet to make those scripts easily running in a poetry install
-created environment if you need them during development as well as for end-users.
I don't know what part of the discussion has misled you
One possible piece of confusion is that the original description of that PR included poetry run scriptname
as an example, which I don't believe works currently, because that relies on the scripts being installed into the Poetry-managed venv's bin/
folder.
Unless I'm confused, and that is working?
Ah, I see. Thank for you the explanation. It never would have occurred to me that this only worked specifically when installing the package with Pip and not with Poetry directly. Indeed, with the following pyproject.toml
:
And an executable script foo.bash
and an empty file called poetry_repro/__init__.py
, running pip3 install .
finally creates a file foo.bash
in the bin
subdirectory of the virtualenv. I read this thread and numerous linked discussions but was unable to determine that this was the right combination of parameters to get things working.
As a workaround, you could use something like https://github.com/nat-n/poethepoet
Thanks for sharing, Poe — this looks like what I wanted Poetry scripts to do this whole time. I'll be sure to try that one on my next project.
Still have trouble understanding how this currently works ^^
the docs say:
[tool.poetry.scripts]
devtest = { reference = "mypackage:test.run_tests", extras = ["test"], type = "console" }
but to me it seems like this works:
[tool.poetry.scripts]
devtest = { callable= "mypackage:test.run_tests", extras = ["test"] }
or am I misunderstanding something?
@zeratax yeah the docs don't even mention where all those fields come from or how they are used
The docs are correct, but do not yet describe the new "type" added to support this feature (i.e. this ticket), so they only list the already-existing type = "console"
for PyPA console_scripts
entry points scripts. If console_scripts
is all you want, then the docs are fine. The callable=
syntax is the old syntax, so it works, but is not documented as it has been replaced by the currently-documented syntax for a few years now.
This appears to be all you're after, @zeratax, based on your example. @arielnmz if you think the docs need more details on those fields, I'd suggest opening a new ticket for that, as this ticket is about a new feature, not the existing documented feature, and it'll get lost in the noise here.
The JSON schema documents the fields with more detail, but that includes the field values used by this ticket's new feature. The feature from this ticket (PyPA wheel-packaged executable scripts) is not yet documented. This is probably because until poetry install
understands this feature (i.e. when this ticket is resolved), then it's likely been shown to lead to confusion from users if they use it, because it works for pip install
but not yet for poetry install
.
so, I just tried type="gui"
and it doesn't allow it. Wasn't this supposed to be supported? I just want the script to be launched using pythonw.exe on windows.
Wasn't this supposed to be supported?
Yes, maybe, or not. But definitely not before this issue is closed, which it is not.
Wasn't this supposed to be supported?
Yes, maybe, or not. But definitely not before this issue is closed, which it is not.
My mistake, I thought the issue was to support the syntax, including the various types.
console-script = {reference = "package.module:function", type = "console"}
Since the syntax is now supported, it seems that the issue is at least half-completed.
As-of-today, poetry-core only supports two type values, file
and console
.
If gui
support is added, it won't cause this issue to be closed, as this issue is tracking not just the underlying support in poetry-core, but also integration with poetry, e.g., poetry install
, which does not support script types other than console
. Adding the new type (or types) to the documentation is probably also required to close this ticket, which of course comes after the code actually works.
file-script = {source = "bin/script.sh", type= "file"}
I want to say +1 for this and share you one additional use case.
There is https://xon.sh shell (Python package) that is based on Python. Xonsh syntax is based on Python and allows to distribute apps using PyPi. But to run xonsh script it's needed to run script using xonsh. Real life examples you can find in xonsh-awesome-cli-app.
This all means this use case:
#!/usr/bin/env xonsh
echo Hello from @("Xonsh")
pyproject.toml
that includes: xonsh dependency, myapp
xonsh script.file-script = {source = "bin/myapp", type= "file"}
Then I want to just do:
pip install myapp
# After this: xonsh dependency installed, myapp now in ~/.local/bin.
myapp hello
# Because of myapp has xonsh shebang it was executed under xonsh.
# Everything is working out of the box.
So I'm +1 for ability to put raw script files into the package.
poetry already has the ability to put raw script files into the package, the state of this issue is per https://github.com/python-poetry/poetry/issues/2310#issuecomment-1560869506
(thumbs up on your own comments don't count!)
I'm pretty confused..
This doesn't work:
[tool.poetry.scripts]
start-web = { reference = "scripts/start-web-app.sh", type = "file" }
But if I move the file, this works:
[tool.poetry.scripts]
start-web = { reference = "start-web-app.sh", type = "file" }
but the expected start-web
executable instead uses the reference and it can only be executed by running start-web-app.sh
, that's the only script that appears in bin/
after installing with pip (or in the poetry venv).
Is this a bug? I would expect the key (start-web
) to be the name of the executable that ends up in bin/
and for reference
s inside subdirectories to work.
Yeah, that does look like a bug. A quick glance at the code shows that the script entry-name is lost, and only the filename is used. That might be deliberate (but is definitely not what I would have expected) but either way it should have found it by relative path compared to the pyproject.toml, looking at the same code. (There's a test-case that covers this code and includes checking relative paths but the failure may be happening in code later than the test-case covers.)
I'd suggest opening a new bug for those issues.
I would like to add details about the behavior of poetry when installing a script file. In fact, the following lines seem to work:
[tool.poetry.scripts]
my_script = { reference = "script-files/sample_script.sh", type= "file" }
But, to run 'samplescript', you must use: not samplescript
, not script-files/sample_script.sh
(this is not possible), but sample_script.sh
.
This works like that because the reference script is just moved into the bin folder of the target environment. The script is not renamed.
For me, this aspect was not really clear, this is why I wanted to clarify it here.
I would like to propose two things.
The first one is to give the possibility to rename the script with a particular option, e.g. target_filename, keeping the current behavior as default one if the option is not given. Here an example:
[tool.poetry.scripts]
my_script = { reference = "script-files/sample_script.sh", type= "file", target_filename="my_script.sh" }
This way, we can run the script with the command "my_script.sh". We can imagine using only "my_script" or whatever we want.
My second suggestion is to document the script feature. For now, poetry documentation just explains how to configure a python script, giving a package path and a function to run. It could be great to have more details to avoid people to search for solutions. Also, it would be great to precise that, as the scripts are copied into the bin, you'll need to use 'pip install .' again each time you modify the script and you want to run it.
Improve script support
Rationale & Background
Python packaging supports the distribution and installation of executable scripts by specifying one or more of the following.
console_scripts
gui_scripts
The PyPA Entry points specification details the implementation requirement for handling (1) and (2). As for (3), refer to PEP 427.
Poetry, today, allows for the handling of console_scripts as documented here. Non-script entry points (plugins) are also already supported by Poetry as documented here and is considered a separate feature within the context of Poetry.
As part of the requested enhancement, we want to expand the current support distributing scripts with Poetry managed projects to include both entry point scripts as well as file sourced scripts.
Configuration Specification
In order to achieve this, we need to expand the capabilities offered by the scripts section of the poetry configuration. Today, we expect
console_scripts
to be configured as follows.This should be extended to support various configurations as shown here.
Entry point script configuration
importable.module
,importable.module:object.attr
console
. Allowed values for reference sourced scripts areconsole
andgui
.File sourced script configuration
file
for file sourced scripts.While it is possible to detect if a given value is a method or script, the team feels that using an in-line table here will allow for future enhancements to this feature. And furthermore, it allows us to be explicit rather than implicit with respect to the intention.
An implementation of this feature should ensure the following.
console_scripts
andgui_scripts
sections of theentry_point.txt
file as described by PyPA specifications.pyproject.toml
files.Support for extras
Use of
extras
for an entry point will not be supported by poetry. As per PyPA specifications, these are discouraged for new publishers is discouraged and will not be supported by poetry at this time.If in the future, this recommendation changes, adding support for this would be as trivial as adding an additional property
extras
in the script configuration.Backwards compatibility
To ensure older configuration will still work, string values must also be accepted as a script value. This will default to treating it as an entry point console script. The following will be equivalent.
Comparison with setuptools
While these concepts are familiar for users that have used
setuptools
, the intention here is not copy the configuration interface one-to-one, but rather provide an intuitive and objective driven configuration interface within the context of a Poetry managed project.To understand better the differences based on the above specification, here are
setuptools
configurations compared with Poetry configuration achieving the same objective.Entry point script (console)
setup.py
:pyproject.toml
:Entry point script (gui)
setup.py
:pyproject.toml
:File sourced script
setup.py
:pyproject.toml
:Related Issues
241
1023
1504