classification
Title: run_setup() behavior differs from cli invocation of setup.py
Type: behavior Stage: resolved
Components: Distutils Versions:
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: eric.araujo Nosy List: eric.araujo, l, steve.dower, tarek
Priority: normal Keywords: patch

Created on 2013-09-08 13:36 by l, last changed 2021-02-03 18:30 by steve.dower. This issue is now closed.

Files
File name Uploaded Description Edit
run_setup-py32-py33-py34.diff l, 2013-09-08 13:36 review
run_setup-py31.diff l, 2013-09-08 13:37 review
run_setup-py27.diff l, 2013-09-08 13:37 review
run_setup-py26.diff l, 2013-09-08 13:38 review
Messages (3)
msg197259 - (view) Author: Lukas Wunner (l) Date: 2013-09-08 13:36
The principle of least surprise suggests that run_setup() should behave equivalently to a command line invocation of setup.py. However there are currently (at least) two issues preventing this:


(a) When calling exec(), both a globals and a locals dict is passed.

According to the documentation: "If exec gets two separate objects as globals and locals, the code will be executed as if it were embedded in a class definition." [1] Consequence: "The scope of names defined in a class block is limited to the class block; it does not extend to the code blocks of methods". [2]

One example where this is relevant is the "MarkupSafe" PyPI package [3]: Its setup.py defines a class BuildFailed which is used in other methods defined in setup.py. Calling run_setup() with this setup.py will therefore fail. Calling setup.py from the command line works.

Solution: Only pass a globals dict to exec().


(b) The globals dict does not contain '__name__':'__main__'.

Many setup.py scripts use the idiomatic 'conditional script' stanza "if __name__ == '__main__'". An example is the "PyYAML" PyPI package. [4] In these cases, run_setup() will raise a RuntimeError exception ("'distutils.core.setup()' was never called").

Solution: Add '__name__':'__main__' to the globals dict.


Attached are patches to fix these issues in Python 2.6 to 3.4.


[1] http://docs.python.org/3/library/functions.html#exec
[2] http://docs.python.org/reference/executionmodel.html#naming-and-binding
[3] https://pypi.python.org/pypi/MarkupSafe
[4] https://pypi.python.org/pypi/PyYAML
msg213225 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2014-03-12 09:11
> The principle of least surprise suggests that run_setup() should behave equivalently
> to a command line invocation of setup.py.

That’s debatable: distutils.core.setup corresponds to a command-line invocation of setup.py, but run_setup is documented as something else: http://docs.python.org/3.4/distutils/apiref#distutils.core.run_setup

In general, distutils lends itself poorly to programmatic usage.  Can you tell more about your use case for calling run_setup directly?

> Many setup.py scripts use the idiomatic 'conditional script' stanza
> "if __name__ == '__main__'".

That’s surprising to me: setup.py scripts are not modules-that-also-work-as-scripts, only scripts.
msg386421 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2021-02-03 18:30
Distutils is now deprecated (see PEP 632) and all tagged issues are being closed. From now until removal, only release blocking issues will be considered for distutils.

If this issue does not relate to distutils, please remove the component and reopen it. If you believe it still requires a fix, most likely the issue should be re-reported at https://github.com/pypa/setuptools
History
Date User Action Args
2021-02-03 18:30:33steve.dowersetstatus: open -> closed

nosy: + steve.dower
messages: + msg386421

resolution: out of date
stage: resolved
2014-03-12 09:11:02eric.araujosetmessages: + msg213225
versions: - Python 2.6, Python 3.1, Python 2.7, Python 3.2, Python 3.3, Python 3.4
2013-09-08 13:38:06lsetfiles: + run_setup-py26.diff
2013-09-08 13:37:48lsetfiles: + run_setup-py27.diff
2013-09-08 13:37:23lsetfiles: + run_setup-py31.diff
2013-09-08 13:36:31lcreate