Skip to content

Commit

Permalink
Fix inconsistent encoding in config files, among different functions …
Browse files Browse the repository at this point in the history
…and OSs.

On Windows the default Python text encoding is "cp1252", while on Unix is "utf-8".
This affects open(), pathlib.Path().read_text() and pathlib.Path().write_text().
This explicitly sets the encoding on all read/write operations on text files.
Before some function calls had an explicit encoding, other not.
  • Loading branch information
feddg committed Aug 15, 2024
1 parent 7c8dbbc commit c3a64cd
Show file tree
Hide file tree
Showing 46 changed files with 581 additions and 361 deletions.
2 changes: 1 addition & 1 deletion scripts/generate_coverage_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

def main():
coverage_report = ROOT / 'coverage.xml'
root = etree.fromstring(coverage_report.read_text()) # nosec B320 # noqa: S320
root = etree.fromstring(coverage_report.read_text(encoding='utf-8')) # nosec B320 # noqa: S320

raw_package_data = defaultdict(lambda: {'hits': 0, 'misses': 0})
for package in root.find('packages'):
Expand Down
8 changes: 4 additions & 4 deletions src/hatch/cli/fmt/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def write_config_file(self, *, preview: bool) -> None:
return

self.internal_config_file.parent.ensure_dir_exists()
self.internal_config_file.write_text(config_contents)
self.internal_config_file.write_text(config_contents, encoding='utf-8')

# TODO: remove everything below once this is fixed https://github.com/astral-sh/ruff/issues/8737
if self.internal_user_config_file is None:
Expand All @@ -93,7 +93,7 @@ def write_config_file(self, *, preview: bool) -> None:
if self.user_config_file is None:
return

old_contents = self.user_config_file.read_text()
old_contents = self.user_config_file.read_text(encoding='utf-8')
config_path = str(self.internal_config_file).replace('\\', '\\\\')
if self.user_config_file.name == 'pyproject.toml':
lines = old_contents.splitlines()
Expand All @@ -112,7 +112,7 @@ def write_config_file(self, *, preview: bool) -> None:
else:
contents = f'extend = "{config_path}"\n{old_contents}'

self.internal_user_config_file.write_text(contents)
self.internal_user_config_file.write_text(contents, encoding='utf-8')

@cached_property
def internal_user_config_file(self) -> Path | None:
Expand All @@ -137,7 +137,7 @@ def user_config(self) -> dict[str, Any]:

from hatch.utils.toml import load_toml_data

return load_toml_data(self.user_config_file.read_text())
return load_toml_data(self.user_config_file.read_text(encoding='utf-8'))

@cached_property
def linter_preview(self) -> bool:
Expand Down
2 changes: 1 addition & 1 deletion src/hatch/cli/run/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def run(ctx: click.Context, args: tuple[str, ...]):
script = script.resolve()

try:
metadata = parse_inline_script_metadata(script.read_text())
metadata = parse_inline_script_metadata(script.read_text(encoding='utf-8'))
except ValueError as e:
app.abort(f'{e}, {first_arg}')

Expand Down
6 changes: 3 additions & 3 deletions src/hatch/cli/test/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def write_config_file(self) -> None:
from configparser import ConfigParser

cfg = ConfigParser()
cfg.read(str(self.user_config_path))
cfg.read(str(self.user_config_path), encoding='utf-8')

if 'run' not in cfg:
cfg['run'] = {'parallel': 'true'}
Expand All @@ -47,9 +47,9 @@ def write_config_file(self) -> None:

from hatch.utils.toml import load_toml_data

project_data = load_toml_data(self.user_config_path.read_text())
project_data = load_toml_data(self.user_config_path.read_text(encoding='utf-8'))
project_data.setdefault('tool', {}).setdefault('coverage', {}).setdefault('run', {})['parallel'] = True
self.internal_config_path.write_text(tomli_w.dumps(project_data))
self.internal_config_path.write_text(tomli_w.dumps(project_data), encoding='utf-8')

def _write_ini(self, cfg: ConfigParser) -> None:
with self.internal_config_path.open('w', encoding='utf-8') as f:
Expand Down
3 changes: 2 additions & 1 deletion src/hatch/env/virtual.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ def create(self):
"""\
# This file was automatically created by Hatch
*
"""
""",
encoding='utf-8',
)

with self.expose_uv():
Expand Down
4 changes: 2 additions & 2 deletions src/hatch/project/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,14 +398,14 @@ def _read(self, environment: EnvironmentInterface) -> dict[str, Any]:
if not metadata_file.is_file():
return {}

return json.loads(metadata_file.read_text())
return json.loads(metadata_file.read_text(encoding='utf-8'))

def _write(self, environment: EnvironmentInterface, metadata: dict[str, Any]) -> None:
import json

metadata_file = self._metadata_file(environment)
metadata_file.parent.ensure_dir_exists()
metadata_file.write_text(json.dumps(metadata))
metadata_file.write_text(json.dumps(metadata), encoding='utf-8')

def _metadata_file(self, environment: EnvironmentInterface) -> Path:
from hatch.env.internal import is_isolated_environment
Expand Down
26 changes: 13 additions & 13 deletions src/hatch/project/frontend/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def build_sdist(self, directory: Path) -> Path:

script_context = fs_context.join('build_sdist.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -45,7 +45,7 @@ def build_sdist(self, directory: Path) -> Path:
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output = json.loads(output_path.read_text())
output = json.loads(output_path.read_text(encoding='utf-8'))

work_dir = output_context.local_path / 'work'
artifact_path = Path(work_dir / output['return_val'])
Expand All @@ -60,7 +60,7 @@ def build_wheel(self, directory: Path) -> Path:

script_context = fs_context.join('build_wheel.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -69,7 +69,7 @@ def build_wheel(self, directory: Path) -> Path:
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output = json.loads(output_path.read_text())
output = json.loads(output_path.read_text(encoding='utf-8'))

work_dir = output_context.local_path / 'work'
artifact_path = Path(work_dir / output['return_val'])
Expand All @@ -86,7 +86,7 @@ def get_requires(self, build: Literal['sdist', 'wheel', 'editable']) -> list[str

script_context = fs_context.join(f'get_requires_{build}.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -95,7 +95,7 @@ def get_requires(self, build: Literal['sdist', 'wheel', 'editable']) -> list[str
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output = json.loads(output_path.read_text())
output = json.loads(output_path.read_text(encoding='utf-8'))
return output['return_val']

def get_core_metadata(self, *, editable: bool = False) -> dict[str, Any]:
Expand All @@ -110,7 +110,7 @@ def get_core_metadata(self, *, editable: bool = False) -> dict[str, Any]:

script_context = fs_context.join('get_core_metadata.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -119,11 +119,11 @@ def get_core_metadata(self, *, editable: bool = False) -> dict[str, Any]:
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output = json.loads(output_path.read_text())
output = json.loads(output_path.read_text(encoding='utf-8'))

work_dir = output_context.local_path / 'work'
metadata_file = Path(work_dir) / output['return_val'] / 'METADATA'
return project_metadata_from_core_metadata(metadata_file.read_text())
return project_metadata_from_core_metadata(metadata_file.read_text(encoding='utf-8'))


class HatchBuildFrontend:
Expand All @@ -146,7 +146,7 @@ def get_build_deps(self, targets: list[str]) -> list[str]:

script_context = fs_context.join(f'get_build_deps_{"_".join(targets)}.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -155,7 +155,7 @@ def get_build_deps(self, targets: list[str]) -> list[str]:
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output: list[str] = json.loads(output_path.read_text())
output: list[str] = json.loads(output_path.read_text(encoding='utf-8'))
return output

def get_core_metadata(self) -> dict[str, Any]:
Expand All @@ -168,7 +168,7 @@ def get_core_metadata(self) -> dict[str, Any]:

script_context = fs_context.join('get_core_metadata.py')
script_context.local_path.parent.ensure_dir_exists()
script_context.local_path.write_text(script)
script_context.local_path.write_text(script, encoding='utf-8')
script_context.sync_env()

context = ExecutionContext(self.__env)
Expand All @@ -177,7 +177,7 @@ def get_core_metadata(self) -> dict[str, Any]:
output_context.sync_local()

output_path = output_context.local_path / 'output.json'
output: dict[str, Any] = json.loads(output_path.read_text())
output: dict[str, Any] = json.loads(output_path.read_text(encoding='utf-8'))
return output

def get_required_build_deps(self, targets: list[str]) -> list[str]:
Expand Down
6 changes: 3 additions & 3 deletions src/hatch/publish/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def __get_username(self) -> str:

def _read_previous_working_user_data(self) -> str | None:
if self._pwu_path.is_file():
contents = self._pwu_path.read_text()
contents = self._pwu_path.read_text(encoding='utf-8')
if contents:
import json

Expand All @@ -85,7 +85,7 @@ def _read_pypirc(self) -> str | None:
import configparser

pypirc = configparser.ConfigParser()
pypirc.read(Path.home() / '.pypirc')
pypirc.read(Path.home() / '.pypirc', encoding='utf-8')
repo = self._repo or 'pypi'

if pypirc.has_section(repo):
Expand All @@ -106,7 +106,7 @@ def write_updated_data(self):

self.__pwu_data[self._repo] = self.__username
self._pwu_path.ensure_parent_dir_exists()
self._pwu_path.write_text(json.dumps(self.__pwu_data))
self._pwu_path.write_text(json.dumps(self.__pwu_data), encoding='utf-8')

if self.__password_was_read:
import keyring
Expand Down
4 changes: 2 additions & 2 deletions src/hatch/python/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def get_installed(self) -> dict[str, InstalledDistribution]:
if not metadata_file.is_file():
continue

metadata = json.loads(metadata_file.read_text())
metadata = json.loads(metadata_file.read_text(encoding='utf-8'))
distribution = get_distribution(path.name, source=metadata.get('source', ''))
if not (path / distribution.python_path).is_file():
continue
Expand Down Expand Up @@ -117,7 +117,7 @@ def install(self, identifier: str) -> InstalledDistribution:

metadata = {'source': dist.source, 'python_path': dist.python_path}
metadata_file = path / InstalledDistribution.metadata_filename()
metadata_file.write_text(json.dumps(metadata, indent=2))
metadata_file.write_text(json.dumps(metadata, indent=2), encoding='utf-8')

return InstalledDistribution(path, dist, metadata)

Expand Down
9 changes: 6 additions & 3 deletions tests/backend/builders/hooks/test_custom.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class CustomHook(BuildHookInterface):
def foo(self):
return self.PLUGIN_NAME, self.root
"""
)
),
encoding='utf-8',
)

with temp_dir.as_cwd():
Expand All @@ -63,7 +64,8 @@ class CustomHook(BuildHookInterface):
def foo(self):
return self.PLUGIN_NAME, self.root
"""
)
),
encoding='utf-8',
)

with temp_dir.as_cwd():
Expand All @@ -88,7 +90,8 @@ def test_no_subclass(temp_dir, helpers):
class CustomHook:
pass
"""
)
),
encoding='utf-8',
)

with pytest.raises(
Expand Down
Loading

0 comments on commit c3a64cd

Please sign in to comment.