Repository: huggingface/transformers
Pull request: Add explicit utf-8 encoding to CircleCI scripts for Windows compatibility

# What does this PR do?

Adds explicit `encoding="utf-8"` to `open()` calls in `.circleci/create_circleci_config.py` and `.circleci/parse_test_outputs.py`.

## The Problem
On Windows, `open()` defaults to the system encoding (often `cp1252`). This causes a `UnicodeDecodeError` when the scripts attempt to read files containing non-ASCII characters (e.g., emojis or symbols in test logs).

## The Fix
Enforces `utf-8` encoding for file I/O in these CI scripts to ensure cross-platform compatibility.

## Verification
This change purely adds `encoding="utf-8"` to existing `open()` calls. It has no effect on Linux/macOS systems (where UTF-8 is already the default) and fixes the crash on Windows.

## Before submitting
- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
- [x] Did you read the [contributor guideline](https://github.com/huggingface/transformers/blob/main/CONTRIBUTING.md#create-a-pull-request),
      Pull Request section?
- [ ] Was this discussed/approved via a Github issue or the [forum](https://discuss.huggingface.co/)? Please add a link
      to it if that's the case.
- [ ] Did you make sure to update the documentation with your changes? Here are the
      [documentation guidelines](https://github.com/huggingface/transformers/tree/main/docs), and
      [here are tips on formatting docstrings](https://github.com/huggingface/transformers/tree/main/docs#writing-source-documentation).
- [ ] Did you write any new necessary tests?


## Who can review?

@ydshieh
@ArthurZucker

Changed files:
filename: .circleci/create_circleci_config.py
patch: @@ -121,7 +121,7 @@ def __post_init__(self):
             test_file = os.path.join("test_preparation" , f"{self.job_name}_test_list.txt")
             print("Looking for ", test_file)
             if os.path.exists(test_file):
-                with open(test_file) as f:
+                with open(test_file, encoding="utf-8") as f:
                     expanded_tests = f.read().strip().split("\n")
                 self.tests_to_run = expanded_tests
                 print("Found:", expanded_tests)
@@ -399,7 +399,7 @@ def create_circleci_config(folder=None):
     else:
         # For public repo. (e.g. `transformers`)
         config["workflows"] = {"version": 2, "run_tests": {"jobs": [j.job_name for j in jobs]}}
-    with open(os.path.join(folder, "generated_config.yml"), "w") as f:
+    with open(os.path.join(folder, "generated_config.yml"), "w", encoding="utf-8") as f:
         f.write(yaml.dump(config, sort_keys=False, default_flow_style=False).replace("' << pipeline", " << pipeline").replace(">> '", " >>"))
 
 

filename: .circleci/parse_test_outputs.py
patch: @@ -5,7 +5,7 @@
 def parse_pytest_output(file_path):
     skipped_tests = {}
     skipped_count = 0
-    with open(file_path, 'r') as file:
+    with open(file_path, 'r', encoding='utf-8') as file:
         for line in file:
             match = re.match(r'^SKIPPED \[(\d+)\] (tests/.*): (.*)$', line)
             if match:
@@ -19,7 +19,7 @@ def parse_pytest_output(file_path):
 def parse_pytest_failure_output(file_path):
     failed_tests = {}
     failed_count = 0
-    with open(file_path, 'r') as file:
+    with open(file_path, 'r', encoding='utf-8') as file:
         for line in file:
             match = re.match(r'^FAILED (tests/.*) - (.*): (.*)$', line)
             if match:
@@ -36,7 +36,7 @@ def parse_pytest_errors_output(file_path):
     print(file_path)
     error_tests = {}
     error_count = 0
-    with open(file_path, 'r') as file:
+    with open(file_path, 'r', encoding='utf-8') as file:
         for line in file:
             match = re.match(r'^ERROR (tests/.*) - (.*): (.*)$', line)
             if match: