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

Adopt PEP 621 Conventions #1219

Merged
merged 9 commits into from
Apr 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/1203.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Briefcase will now honor PEP-621 project fields where they map to Briefcase configuration items.
27 changes: 27 additions & 0 deletions docs/reference/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,30 @@ look for ``resource/round-icon-42.png``, ``resource/square-icon-42.png``,
-------

A URL for help related to the document format.

PEP621 compatibility
====================

Many of the keys that exist in Briefcase's configuration have analogous settings
in `PEP621 project metadata
<https://packaging.python.org/en/latest/specifications/declaring-project-metadata>`__.
If your ``pyproject.toml`` defines a ``[project]`` section, Briefcase will honor
those settings as a top level definition. Any ``[tool.briefcase]`` definitions
will override those in the ``[project]`` section.

The following PEP621 project metadata keys will be used by Briefcase if they are
available:

* ``version`` maps to the same key in Briefcase.
* ``authors`` The ``email`` and ``name`` keys of the first value in the
``authors`` setting map to ``author`` and ``author_email``.
* ``dependencies`` maps to the Briefcase ``requires`` setting. This is a
cumulative setting; any packages defined in the ``requires`` setting at the
``[tool.briefcase]`` level will be appended to the packages defined with
``dependencies`` at the ``[project]`` level.
* ``description`` maps to the same key in Briefcase.
* ``test`` in an ``[project.optional-dependencies]`` section maps to
``test_requires``., As with ``dependencies``/``requires``, this is a
cumulative setting.
* ``text`` in a ``[project.license]`` section will be mapped to ``license``.
* ``homepage`` in a ``[project.urls]`` section will be mapped to ``url``.
65 changes: 63 additions & 2 deletions src/briefcase/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,60 @@ def merge_config(config, data):
config.update(data)


def merge_pep621_config(global_config, pep621_config):
"""Merge a PEP621 configuration into a Briefcase configuration."""

def maybe_update(field, *project_fields):
# If there's an existing key in the Briefcase config, it takes priority.
if field in global_config:
return

# Traverse the fields in the pep621 config; if the config exists, set it
# in the Briefcase config.
datum = pep621_config
try:
for key in project_fields:
datum = datum[key]
except KeyError:
pass
else:
global_config[field] = datum

# Keys that map direclty
maybe_update("description", "description")
maybe_update("license", "license", "text")
maybe_update("url", "urls", "Homepage")
maybe_update("version", "version")

# Use the details of the first author as the Briefcase author.
if "author" not in global_config:
try:
global_config["author"] = pep621_config["authors"][0]["name"]
except (KeyError, IndexError):
pass
if "author_email" not in global_config:
try:
global_config["author_email"] = pep621_config["authors"][0]["email"]
except (KeyError, IndexError):
pass

# Briefcase requires is cumulative over PEP621 dependencies
try:
pep621_dependencies = pep621_config["dependencies"]
requires = global_config.get("requires", [])
global_config["requires"] = pep621_dependencies + requires
except KeyError:
pass

# Briefcase test_requires is cumulative over PEP621 optional test dependencies
try:
pep621_test_dependencies = pep621_config["optional-dependencies"]["test"]
test_requires = global_config.get("test_requires", [])
global_config["test_requires"] = pep621_test_dependencies + test_requires
except KeyError:
pass


def parse_config(config_file, platform, output_format):
"""Parse the briefcase section of the pyproject.toml configuration file.

Expand Down Expand Up @@ -521,13 +575,20 @@ def parse_config(config_file, platform, output_format):
"""
try:
pyproject = tomllib.load(config_file)

global_config = pyproject["tool"]["briefcase"]
except tomllib.TOMLDecodeError as e:
raise BriefcaseConfigError(f"Invalid pyproject.toml: {e}") from e

try:
global_config = pyproject["tool"]["briefcase"]
except KeyError as e:
raise BriefcaseConfigError("No tool.briefcase section in pyproject.toml") from e

# Merge the PEP621 configuration (if it exists)
try:
merge_pep621_config(global_config, pyproject["project"])
except KeyError:
pass

# For consistent results, sort the platforms and formats
all_platforms = sorted(get_platforms().keys())
all_formats = sorted(get_output_formats(platform).keys())
Expand Down
Loading