whitespace-format 0.0.7__py3-none-any.whl → 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: whitespace-format
3
- Version: 0.0.7
3
+ Version: 0.0.8
4
4
  Summary: Linter and formatter for source code files and text files
5
5
  License: MIT
6
6
  Author: David Pal
@@ -27,7 +27,7 @@ Description-Content-Type: text/markdown
27
27
 
28
28
  Linter and formatter for source code files and text files.
29
29
 
30
- The purpose of this tool is to normalize source code files (e.g. Python, Java,
30
+ The purpose of this tool is to normalize source code files (e.g., Python, Java,
31
31
  C/C++, Ruby, Go, JavaScript, etc.) and text files (HTML, JSON, YAML, CSV,
32
32
  MarkDown, LaTeX) before checking them into a version control system.
33
33
 
@@ -94,7 +94,7 @@ The regular expression is evaluated on the path of each file.
94
94
 
95
95
  ### Formatting options
96
96
 
97
- * `--add-new-line-marker-at-end-of-file` -- Add missing new line marker at end of each file.
97
+ * `--add-new-line-marker-at-end-of-file` -- Add missing new line marker at the end of each file.
98
98
  * `--remove-new-line-marker-from-end-of-file` -- Remove all new line marker(s) from the end of each file.
99
99
  This option cannot be used in combination with `--add-new-line-marker-at-end-of-file`.
100
100
  Empty lines at the end of the file are removed, i.e., this option implies `--remove-trailing-empty-lines`
@@ -112,7 +112,7 @@ adding or replacing new line markers. `MARKER` must be one of the following:
112
112
  * `mac` -- Use Mac new line marker `\r`.
113
113
  * `windows` -- Use Windows new line marker `\r\n`.
114
114
  * `--encoding` -- Text encoding for both reading and writing files. Default encoding is `utf-8`.
115
- List of supported encodings can be found at
115
+ The list of supported encodings can be found at
116
116
  https://docs.python.org/3/library/codecs.html#standard-encodings
117
117
 
118
118
  Note that input files can contain an arbitrary mix of new line markers `\n`,
@@ -129,8 +129,8 @@ whitespace-format \
129
129
  --remove-trailing-empty-lines \
130
130
  foo.txt my_project/
131
131
  ```
132
- This should work well for common programming languages (e.g. Python, Java,
133
- C/C++, JavaScript) and common text file formats (e.g. CSV, LaTeX, JSON, YAML,
132
+ This should work well for common programming languages (e.g., Python, Java,
133
+ C/C++, JavaScript) and common text file formats (e.g., CSV, LaTeX, JSON, YAML,
134
134
  HTML, MarkDown).
135
135
 
136
136
  ### Empty files
@@ -149,7 +149,7 @@ where `MODE` is one of the following:
149
149
 
150
150
  Depending on the mode, an empty file or a whitespace-only file will be either
151
151
  ignored, replaced by a zero-byte file, or replaced by a file consisting of
152
- single end of line marker.
152
+ the single new line marker.
153
153
 
154
154
  If `--normalize-whitespace-only-files` is set to `empty`,
155
155
  `--normalize-empty-files setting` set to `empty` as well. In other words,
@@ -212,16 +212,17 @@ command `make delete-environment`.
212
212
 
213
213
  If you make code change, run unit tests and code checks with the command:
214
214
  ```shell
215
- make clean whitespace-format-check isort-check black-check flake8 pydocstyle pylint mypy test coverage
215
+ make clean whitespace-format-check black-check isort-check pydocstyle ruff flake8 pylint mypy test coverage
216
216
  ```
217
217
 
218
218
  Each make target runs different checks:
219
219
  - `clean` deletes temporary files
220
220
  - `whitespace-format-check` runs [whitespace-format](https://github.com/DavidPal/whitespace-format) checker on all files
221
- - `isort-check` runs [isort](https://pycqa.github.io/isort/) checker of imports in `*.py` files
222
221
  - `black-check` runs [black](https://github.com/psf/black/) code format checker on `*.py` files
223
- - `flake8` runs [flake8](https://flake8.pycqa.org/) code style checker on `*.py` files
222
+ - `isort-check` runs [isort](https://pycqa.github.io/isort/) checker of imports in `*.py` files
224
223
  - `pydocstyle` runs [pydocstyle](http://www.pydocstyle.org/) docstring checker on `*.py` files
224
+ - `ruff` runs [ruff](https://docs.astral.sh/ruff/) code checker on `*.py` files
225
+ - `flake8` runs [flake8](https://flake8.pycqa.org/) code style checker on `*.py` files
225
226
  - `pylint` runs [pylint](https://pylint.org/) code checker on `*.py` files
226
227
  - `mypy` runs [mypy](http://mypy-lang.org/) type checker on `*.py` files
227
228
  - `test` runs unit tests
@@ -229,7 +230,7 @@ Each make target runs different checks:
229
230
 
230
231
  You can automatically format code with the command:
231
232
  ```shell
232
- make isort-format black-format whitespace-format
233
+ make whitespace-format isort-format black-format ruff-fix
233
234
  ```
234
235
 
235
236
  ## Modifying dependencies
@@ -0,0 +1,6 @@
1
+ whitespace_format.py,sha256=ClVXr7_0vrte2vk8KK7SC-GP8LldPcQMUkVLy-oqbAU,29302
2
+ whitespace_format-0.0.8.dist-info/LICENSE,sha256=rT6UNfWDYFQc-eo65FioDJRMAyVOndtF95wNCUhkK74,1076
3
+ whitespace_format-0.0.8.dist-info/METADATA,sha256=kzv3a9gkxqs2ik-3JYUrES3Rd2E3FDNBRi3DO1lvJ-Q,10517
4
+ whitespace_format-0.0.8.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
5
+ whitespace_format-0.0.8.dist-info/entry_points.txt,sha256=LbXoevzUZAF5MVbI2foNC9xeDjKS_Woz7VbA1ZNF5CY,60
6
+ whitespace_format-0.0.8.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.0.1
2
+ Generator: poetry-core 2.1.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
whitespace_format.py CHANGED
@@ -3,7 +3,7 @@
3
3
  """Formatter of whitespace in text files.
4
4
 
5
5
  Author: David Pal <davidko.pal@gmail.com>
6
- Date: 2023 - 2024
6
+ Date: 2023 - 2025
7
7
  License: MIT License
8
8
 
9
9
  Usage:
@@ -22,7 +22,7 @@ from enum import Enum
22
22
  from typing import List
23
23
  from typing import Tuple
24
24
 
25
- VERSION = "0.0.7"
25
+ VERSION = "0.0.8"
26
26
 
27
27
  # Regular expression that does NOT match any string.
28
28
  UNMATCHABLE_REGEX = "$."
@@ -83,23 +83,23 @@ ESCAPE_TRANSLATION_TABLE = str.maketrans(
83
83
  TAB: "\\t",
84
84
  VERTICAL_TAB: "\\v",
85
85
  FORM_FEED: "\\f",
86
- }
86
+ },
87
87
  )
88
88
 
89
89
 
90
90
  class ChangeType(Enum):
91
91
  """Type of change that happened to a file."""
92
92
 
93
- # New line marker was added to the end of the file (because it was missing).
93
+ # A new line marker was added to the end of the file (because it was missing).
94
94
  ADDED_NEW_LINE_MARKER_TO_END_OF_FILE = 1
95
95
 
96
- # New line marker was removed from the end of the file.
96
+ # A new line marker was removed from the end of the file.
97
97
  REMOVED_NEW_LINE_MARKER_FROM_END_OF_FILE = 2
98
98
 
99
- # New line marker was replaced by another one.
99
+ # A new line marker was replaced by another one.
100
100
  REPLACED_NEW_LINE_MARKER = 3
101
101
 
102
- # White at the end of a line was removed.
102
+ # Whitespace at the end of a line was removed.
103
103
  REMOVED_TRAILING_WHITESPACE = 4
104
104
 
105
105
  # Empty line(s) at the end of file were removed.
@@ -114,7 +114,7 @@ class ChangeType(Enum):
114
114
  # A file consisting of only whitespace was replaced by a file consisting of single empty line.
115
115
  REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE = 8
116
116
 
117
- # A tab character was replaces by space character(s).
117
+ # A tab character was replaced by space character(s).
118
118
  REPLACED_TAB_WITH_SPACES = 9
119
119
 
120
120
  # A tab character was removed.
@@ -193,7 +193,7 @@ class Change:
193
193
  )
194
194
 
195
195
 
196
- def color_print(message: str, parsed_arguments: argparse.Namespace):
196
+ def color_print(message: str, parsed_arguments: argparse.Namespace) -> None:
197
197
  """Outputs a colored message."""
198
198
  if parsed_arguments.quiet:
199
199
  return
@@ -218,7 +218,7 @@ def string_to_hex(text: str) -> str:
218
218
  return ":".join(f"{ord(character):02x}" for character in text)
219
219
 
220
220
 
221
- def die(error_code: int, message: str = ""):
221
+ def die(error_code: int, message: str = "") -> None:
222
222
  """Exits the script."""
223
223
  if message:
224
224
  print(message)
@@ -240,7 +240,7 @@ def read_file_content(file_name: str, encoding: str) -> str:
240
240
  return ""
241
241
 
242
242
 
243
- def write_file(file_name: str, file_content: str, encoding: str):
243
+ def write_file(file_name: str, file_content: str, encoding: str) -> None:
244
244
  """Writes data to a file."""
245
245
  try:
246
246
  with open(file_name, "w", encoding=encoding) as file:
@@ -251,10 +251,7 @@ def write_file(file_name: str, file_content: str, encoding: str):
251
251
 
252
252
  def is_whitespace_only(text: str) -> bool:
253
253
  """Determines if a string consists of only whitespace characters."""
254
- for char in text:
255
- if char not in WHITESPACE_CHARACTERS:
256
- return False
257
- return True
254
+ return all(char in WHITESPACE_CHARACTERS for char in text)
258
255
 
259
256
 
260
257
  def find_most_common_new_line_marker(text: str) -> str:
@@ -314,14 +311,14 @@ def format_file_content(
314
311
  find_most_common_new_line_marker(file_content),
315
312
  )
316
313
 
317
- # Handle empty file:
314
+ # Handle an empty file.
318
315
  if not file_content:
319
316
  if parsed_arguments.normalize_empty_files in ["ignore", "empty"]:
320
317
  return "", []
321
318
  if parsed_arguments.normalize_empty_files == "one-line":
322
319
  return output_new_line_marker, [Change(ChangeType.REPLACED_EMPTY_FILE_WITH_ONE_LINE, 1)]
323
320
 
324
- # Handle non-empty file consisting of whitespace only.
321
+ # Handle a non-empty file consisting of whitespace only.
325
322
  if is_whitespace_only(file_content):
326
323
  if parsed_arguments.normalize_whitespace_only_files == "empty":
327
324
  return "", [Change(ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_EMPTY_FILE, 1)]
@@ -329,7 +326,7 @@ def format_file_content(
329
326
  if file_content == output_new_line_marker:
330
327
  return file_content, []
331
328
  return output_new_line_marker, [
332
- Change(ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE, 1)
329
+ Change(ChangeType.REPLACED_WHITESPACE_ONLY_FILE_WITH_ONE_LINE, 1),
333
330
  ]
334
331
  if parsed_arguments.normalize_whitespace_only_files == "ignore":
335
332
  return file_content, []
@@ -337,31 +334,31 @@ def format_file_content(
337
334
  # Index into the input buffer.
338
335
  i = 0
339
336
 
340
- # List of changes
337
+ # List of changes.
341
338
  changes: List[Change] = []
342
339
 
343
340
  # Line number. It is incremented every time we encounter a new end of line marker.
344
341
  line_number = 1
345
342
 
346
- # Position one character past the end of last line in the output buffer
343
+ # Index into the output buffer pointing just after the end of the last line,
347
344
  # including the last end of line marker.
348
345
  last_end_of_line_including_eol_marker = 0
349
346
 
350
- # Position one character past the last non-whitespace character in the output buffer.
347
+ # Index into the output buffer pointing just after the last non-whitespace character.
351
348
  last_non_whitespace = 0
352
349
 
353
- # Position one character past the end of last non-empty line in the output buffer
350
+ # Index into the output buffer pointing just after the end of the last non-empty line,
354
351
  # excluding the last end of line marker.
355
352
  last_end_of_non_empty_line_excluding_eol_marker = 0
356
353
 
357
- # Position one character past the end of last non-empty line in the output buffer,
354
+ # Index into the output buffer pointing just after the end of the last non-empty line,
358
355
  # including the last end of line marker.
359
356
  last_end_of_non_empty_line_including_eol_marker = 0
360
357
 
361
358
  # Line number of the last non-empty line.
362
359
  last_non_empty_line_number = 0
363
360
 
364
- # Formatted output
361
+ # Formatted output.
365
362
  output = ""
366
363
 
367
364
  while i < len(file_content):
@@ -378,31 +375,32 @@ def format_file_content(
378
375
  else:
379
376
  new_line_marker = CARRIAGE_RETURN
380
377
 
381
- # Remove trailing whitespace
382
- if parsed_arguments.remove_trailing_whitespace and max(
383
- last_non_whitespace, last_end_of_line_including_eol_marker
384
- ) < len(output):
378
+ # Index into the output buffer pointing just after the last non-whitespace character
379
+ # on the current line. If the current line is empty, it is pointing to the beginning
380
+ # of the current line (i.e., just after the end of the previous line).
381
+ last_non_whitespace_on_current_line = max(
382
+ last_non_whitespace,
383
+ last_end_of_line_including_eol_marker,
384
+ )
385
+
386
+ # Remove trailing whitespace.
387
+ if (
388
+ parsed_arguments.remove_trailing_whitespace
389
+ and last_non_whitespace_on_current_line < len(output)
390
+ ):
385
391
  changes.append(
386
- Change(
387
- ChangeType.REMOVED_TRAILING_WHITESPACE,
388
- line_number,
389
- )
392
+ Change(ChangeType.REMOVED_TRAILING_WHITESPACE, line_number),
390
393
  )
391
- output = output[
392
- : max(
393
- last_non_whitespace,
394
- last_end_of_line_including_eol_marker,
395
- )
396
- ]
397
-
398
- # Determine if the last line is empty
394
+ output = output[:last_non_whitespace_on_current_line]
395
+
396
+ # Determine if the last line is empty.
399
397
  is_empty_line: bool = last_end_of_line_including_eol_marker == len(output)
400
398
 
401
- # Position one character past the end of last line in the output buffer
399
+ # Index into the output buffer pointing just after the end of the last line,
402
400
  # excluding the last end of line marker.
403
401
  last_end_of_line_excluding_eol_marker = len(output)
404
402
 
405
- # Add new line marker
403
+ # Add new line marker.
406
404
  if (
407
405
  parsed_arguments.normalize_new_line_markers
408
406
  and output_new_line_marker != new_line_marker
@@ -413,7 +411,7 @@ def format_file_content(
413
411
  line_number,
414
412
  new_line_marker,
415
413
  output_new_line_marker,
416
- )
414
+ ),
417
415
  )
418
416
  output += output_new_line_marker
419
417
  else:
@@ -457,13 +455,16 @@ def format_file_content(
457
455
  line_number,
458
456
  file_content[i],
459
457
  SPACE,
460
- )
458
+ ),
461
459
  )
462
460
  elif parsed_arguments.normalize_non_standard_whitespace == "remove":
463
461
  changes.append(
464
462
  Change(
465
- ChangeType.REMOVED_NONSTANDARD_WHITESPACE, line_number, file_content[i], ""
466
- )
463
+ ChangeType.REMOVED_NONSTANDARD_WHITESPACE,
464
+ line_number,
465
+ file_content[i],
466
+ "",
467
+ ),
467
468
  )
468
469
  else:
469
470
  raise ValueError("Unknown value of normalize_non_standard_whitespace")
@@ -471,7 +472,7 @@ def format_file_content(
471
472
  output += file_content[i]
472
473
  last_non_whitespace = len(output)
473
474
 
474
- # Move to the next character
475
+ # Move to the next character.
475
476
  i += 1
476
477
 
477
478
  # Remove trailing whitespace from the last line.
@@ -494,7 +495,7 @@ def format_file_content(
494
495
  changes.append(Change(ChangeType.REMOVED_EMPTY_LINES, line_number))
495
496
  output = output[:last_end_of_non_empty_line_including_eol_marker]
496
497
 
497
- # Add new line marker at the end of the file
498
+ # Add new line marker at the end of the file.
498
499
  if (
499
500
  parsed_arguments.add_new_line_marker_at_end_of_file
500
501
  and last_end_of_line_including_eol_marker < len(output)
@@ -504,7 +505,7 @@ def format_file_content(
504
505
  last_end_of_line_including_eol_marker = len(output)
505
506
  line_number += 1
506
507
 
507
- # Remove new line marker(s) from the end of the file
508
+ # Remove new line marker(s) from the end of the file.
508
509
  if (
509
510
  parsed_arguments.remove_new_line_marker_from_end_of_file
510
511
  and last_end_of_line_including_eol_marker == len(output)
@@ -530,7 +531,7 @@ def reformat_file(file_name: str, parsed_arguments: argparse.Namespace) -> bool:
530
531
  file_content = read_file_content(file_name, parsed_arguments.encoding)
531
532
  formatted_file_content, file_changes = format_file_content(file_content, parsed_arguments)
532
533
  if parsed_arguments.verbose:
533
- color_print(f"[WHITE]Processing file [BOLD]{file_name}[RESET_ALL]...", parsed_arguments)
534
+ color_print(f"[WHITE]Processing file [BOLD]{file_name}[RESET_ALL] ...", parsed_arguments)
534
535
  if parsed_arguments.check_only:
535
536
  if file_changes:
536
537
  color_print(
@@ -566,7 +567,7 @@ def reformat_file(file_name: str, parsed_arguments: argparse.Namespace) -> bool:
566
567
  return bool(file_changes)
567
568
 
568
569
 
569
- def reformat_files(file_names: List[str], parsed_arguments: argparse.Namespace):
570
+ def reformat_files(file_names: List[str], parsed_arguments: argparse.Namespace) -> None:
570
571
  """Reformats multiple files."""
571
572
  color_print(f"Processing {len(file_names)} file(s)...", parsed_arguments)
572
573
  num_changed_files = 0
@@ -617,13 +618,14 @@ def find_files_to_process(file_names: List[str], parsed_arguments: argparse.Name
617
618
  """Finds files that need to be processed.
618
619
 
619
620
  The function excludes files that match the regular expression specified
620
- by the --exclude command line option.
621
+ by the "--exclude" command line option.
621
622
  """
622
623
  return [
623
624
  expanded_file_name
624
625
  for file_name in file_names
625
626
  for expanded_file_name in find_all_files_recursively(
626
- file_name, parsed_arguments.follow_symlinks
627
+ file_name,
628
+ parsed_arguments.follow_symlinks,
627
629
  )
628
630
  if not re.search(parsed_arguments.exclude, expanded_file_name)
629
631
  ]
@@ -649,7 +651,7 @@ def parse_command_line() -> argparse.Namespace:
649
651
  "--encoding",
650
652
  help=(
651
653
  "Text encoding for both reading and writing files. Default encoding is utf-8. "
652
- "List of supported encodings can be found at "
654
+ "The list of supported encodings can be found at "
653
655
  "https://docs.python.org/3/library/codecs.html#standard-encodings"
654
656
  ),
655
657
  required=False,
@@ -759,7 +761,7 @@ def parse_command_line() -> argparse.Namespace:
759
761
  group2 = parser.add_mutually_exclusive_group()
760
762
  group2.add_argument(
761
763
  "--add-new-line-marker-at-end-of-file",
762
- help="Add missing new line marker at end of each file.",
764
+ help="Add missing new line marker at the end of each file.",
763
765
  required=False,
764
766
  default=False,
765
767
  action="store_true",
@@ -828,7 +830,7 @@ def parse_command_line() -> argparse.Namespace:
828
830
  return parsed_arguments
829
831
 
830
832
 
831
- def main():
833
+ def main() -> None:
832
834
  """Formats white space in text files."""
833
835
  parsed_arguments = parse_command_line()
834
836
  file_names = find_files_to_process(parsed_arguments.input_files, parsed_arguments)
@@ -1,6 +0,0 @@
1
- whitespace_format.py,sha256=Jl5SqNgDhgG9GixsCtTk2bFwri3Ez6msa8Asrqe99os,28942
2
- whitespace_format-0.0.7.dist-info/LICENSE,sha256=rT6UNfWDYFQc-eo65FioDJRMAyVOndtF95wNCUhkK74,1076
3
- whitespace_format-0.0.7.dist-info/METADATA,sha256=n9Nta0jpn-EVz1gVaMNtU7SuyAN9eECs87N0l3FIcvw,10411
4
- whitespace_format-0.0.7.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
5
- whitespace_format-0.0.7.dist-info/entry_points.txt,sha256=LbXoevzUZAF5MVbI2foNC9xeDjKS_Woz7VbA1ZNF5CY,60
6
- whitespace_format-0.0.7.dist-info/RECORD,,