Skip to content

Commit ac724f2

Browse files
committed
docs: adding docstrings in the whole project, removing unused wich file (replacing him with an existing func)
1 parent 7683ada commit ac724f2

File tree

8 files changed

+802
-135
lines changed

8 files changed

+802
-135
lines changed

language_tool_python/__main__.py

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@
1313

1414
try:
1515
__version__ = version("language_tool_python")
16-
except PackageNotFoundError:
16+
except PackageNotFoundError: # If the package is not installed in the environment, read the version from pyproject.toml
1717
with open("pyproject.toml", "rb") as f:
1818
__version__ = toml.loads(f.read().decode('utf-8'))["project"]["version"]
1919

2020

2121
def parse_args() -> argparse.Namespace:
22+
"""
23+
Parse command line arguments.
24+
25+
:return: parsed arguments
26+
:rtype: argparse.Namespace
27+
"""
2228
parser = argparse.ArgumentParser(
2329
description=__doc__.strip() if __doc__ else None,
2430
prog='language_tool_python')
@@ -70,22 +76,71 @@ def parse_args() -> argparse.Namespace:
7076

7177

7278
class RulesAction(argparse.Action):
73-
def __call__(self, parser: argparse.ArgumentParser, namespace: Any, values: Any, option_string: Optional[str] = None) -> str:
79+
"""
80+
Custom argparse action to update a set of rules in the namespace.
81+
This action is used to modify the set of rules stored in the argparse
82+
namespace when the action is triggered. It updates the attribute specified
83+
by 'self.dest' with the provided values.
84+
85+
Attributes:
86+
dest (str): the destination attribute to update
87+
"""
88+
def __call__(self, parser: argparse.ArgumentParser, namespace: Any, values: Any, option_string: Optional[str] = None):
89+
"""
90+
This method is called when the action is triggered. It updates the set of rules
91+
in the namespace with the provided values. The method is invoked automatically
92+
by argparse when the corresponding command-line argument is encountered.
93+
94+
:param parser: The ArgumentParser object which contains this action.
95+
:type parser: argparse.ArgumentParser
96+
:param namespace: The namespace object that will be returned by parse_args().
97+
:type namespace: Any
98+
:param values: The argument values associated with the action.
99+
:type values: Any
100+
:param option_string: The option string that was used to invoke this action.
101+
:type option_string: Optional[str]
102+
"""
74103
getattr(namespace, self.dest).update(values)
75104

76105

77106
def get_rules(rules: str) -> Set[str]:
107+
"""
108+
Parse a string of rules and return a set of rule IDs.
109+
110+
:param rules: A string containing rule IDs separated by non-word characters.
111+
:type rules: str
112+
:return: A set of rule IDs.
113+
:rtype: Set[str]
114+
"""
78115
return {rule.upper() for rule in re.findall(r"[\w\-]+", rules)}
79116

80117

81118
def get_text(filename: Union[str, int], encoding: Optional[str], ignore: Optional[str]) -> str:
119+
"""
120+
Read the content of a file and return it as a string, optionally ignoring lines that match a regular expression.
121+
122+
:param filename: The name of the file to read or file descriptor.
123+
:type filename: Union[str, int]
124+
:param encoding: The encoding to use for reading the file.
125+
:type encoding: Optional[str]
126+
:param ignore: A regular expression pattern to match lines that should be ignored.
127+
:type ignore: Optional[str]
128+
:return: The content of the file as a string.
129+
:rtype: str
130+
"""
82131
with open(filename, encoding=encoding) as f:
83132
text = ''.join('\n' if (ignore and re.match(ignore, line)) else line
84133
for line in f.readlines())
85134
return text
86135

87136

88137
def main() -> int:
138+
"""
139+
Main function to parse arguments, process files, and check text using LanguageTool.
140+
141+
:return: Exit status code
142+
:rtype: int
143+
"""
89144
args = parse_args()
90145

91146
status = 0

language_tool_python/config_file.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import os
55
import tempfile
66

7+
# Allowed configuration keys for LanguageTool.
78
ALLOWED_CONFIG_KEYS = {
89
'maxTextLength', 'maxTextHardLength', 'maxCheckTimeMillis', 'maxErrorsPerWordRate',
910
'maxSpellingSuggestions', 'maxCheckThreads', 'cacheSize', 'cacheTTLSeconds', 'requestLimit',
@@ -12,10 +13,25 @@
1213
'blockedReferrers', 'premiumOnly', 'disabledRuleIds', 'pipelineCaching', 'maxPipelinePoolSize',
1314
'pipelineExpireTimeInSeconds', 'pipelinePrewarming'
1415
}
16+
1517
class LanguageToolConfig:
18+
"""
19+
Configuration class for LanguageTool.
20+
21+
:param config: Dictionary containing configuration keys and values.
22+
:type config: Dict[str, Any]
23+
24+
Attributes:
25+
config (Dict[str, Any]): Dictionary containing configuration keys and values.
26+
path (str): Path to the temporary file storing the configuration.
27+
"""
1628
config: Dict[str, Any]
1729
path: str
30+
1831
def __init__(self, config: Dict[str, Any]):
32+
"""
33+
Initialize the LanguageToolConfig object.
34+
"""
1935
assert set(config.keys()) <= ALLOWED_CONFIG_KEYS, f"unexpected keys in config: {set(config.keys()) - ALLOWED_CONFIG_KEYS}"
2036
assert len(config), "config cannot be empty"
2137
self.config = config
@@ -31,9 +47,15 @@ def __init__(self, config: Dict[str, Any]):
3147
self.path = self._create_temp_file()
3248

3349
def _create_temp_file(self) -> str:
50+
"""
51+
Create a temporary file to store the configuration.
52+
53+
:return: Path to the temporary file.
54+
:rtype: str
55+
"""
3456
tmp_file = tempfile.NamedTemporaryFile(delete=False)
3557

36-
# WRite key=value entries as lines in temporary file.
58+
# Write key=value entries as lines in temporary file.
3759
for key, value in self.config.items():
3860
next_line = f'{key}={value}\n'
3961
tmp_file.write(next_line.encode())

language_tool_python/download_lt.py

Lines changed: 70 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import re
44
import requests
55
import subprocess
6-
import sys
76
import tempfile
87
import tqdm
98
from typing import IO, Dict, Optional, Tuple
@@ -39,21 +38,18 @@
3938
re.MULTILINE)
4039

4140
def parse_java_version(version_text: str) -> Tuple[int, int]:
42-
"""Return Java version (major1, major2).
43-
44-
>>> parse_java_version('''java version "1.6.0_65"
45-
... Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609)
46-
... Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode))
47-
... ''')
48-
(1, 6)
41+
"""
42+
Parse the Java version from a given version text.
4943
50-
>>> parse_java_version('''
51-
... openjdk version "1.8.0_60"
52-
... OpenJDK Runtime Environment (build 1.8.0_60-b27)
53-
... OpenJDK 64-Bit Server VM (build 25.60-b23, mixed mode))
54-
... ''')
55-
(1, 8)
44+
This function attempts to extract the major version numbers from the provided
45+
Java version string using regular expressions. It supports two different
46+
version formats defined by JAVA_VERSION_REGEX and JAVA_VERSION_REGEX_UPDATED.
5647
48+
:param version_text: The Java version string to parse.
49+
:type version_text: str
50+
:return: A tuple containing the major version numbers.
51+
:rtype: Tuple[int, int]
52+
:raises SystemExit: If the version string cannot be parsed.
5753
"""
5854
match = (
5955
re.search(JAVA_VERSION_REGEX, version_text)
@@ -67,7 +63,17 @@ def parse_java_version(version_text: str) -> Tuple[int, int]:
6763

6864

6965
def confirm_java_compatibility() -> bool:
70-
""" Confirms Java major version >= 8. """
66+
"""
67+
Confirms if the installed Java version is compatible with language-tool-python.
68+
This function checks if Java is installed and verifies that the major version is at least 8.
69+
It raises an error if Java is not installed or if the version is incompatible.
70+
71+
:raises ModuleNotFoundError: If no Java installation is detected.
72+
:raises SystemError: If the detected Java version is less than 8.
73+
:return: True if the Java version is compatible.
74+
:rtype: bool
75+
"""
76+
7177
java_path = which('java')
7278
if not java_path:
7379
raise ModuleNotFoundError(
@@ -94,15 +100,32 @@ def confirm_java_compatibility() -> bool:
94100

95101

96102
def get_common_prefix(z: zipfile.ZipFile) -> Optional[str]:
97-
"""Get common directory in a zip file if any."""
103+
"""
104+
Determine the common prefix of all file names in a zip archive.
105+
106+
:param z: A ZipFile object representing the zip archive.
107+
:type z: zipfile.ZipFile
108+
:return: The common prefix of all file names in the zip archive, or None if there is no common prefix.
109+
:rtype: Optional[str]
110+
"""
111+
98112
name_list = z.namelist()
99113
if name_list and all(n.startswith(name_list[0]) for n in name_list[1:]):
100114
return name_list[0]
101115
return None
102116

103117

104118
def http_get(url: str, out_file: IO[bytes], proxies: Optional[Dict[str, str]] = None) -> None:
105-
""" Get contents of a URL and save to a file.
119+
"""
120+
Downloads a file from a given URL and writes it to the specified output file.
121+
122+
:param url: The URL to download the file from.
123+
:type url: str
124+
:param out_file: The file object to write the downloaded content to.
125+
:type out_file: IO[bytes]
126+
:param proxies: Optional dictionary of proxies to use for the request.
127+
:type proxies: Optional[Dict[str, str]]
128+
:raises Exception: If the file could not be found at the given URL (HTTP 403).
106129
"""
107130
req = requests.get(url, stream=True, proxies=proxies)
108131
content_length = req.headers.get('Content-Length')
@@ -120,14 +143,29 @@ def http_get(url: str, out_file: IO[bytes], proxies: Optional[Dict[str, str]] =
120143

121144

122145
def unzip_file(temp_file: str, directory_to_extract_to: str) -> None:
123-
""" Unzips a .zip file to folder path. """
146+
"""
147+
Unzips a zip file to a specified directory.
148+
149+
:param temp_file: A temporary file object representing the zip file to be extracted.
150+
:type temp_file: str
151+
:param directory_to_extract_to: The directory where the contents of the zip file will be extracted.
152+
:type directory_to_extract_to: str
153+
"""
154+
124155
logger.info(f'Unzipping {temp_file.name} to {directory_to_extract_to}.')
125156
with zipfile.ZipFile(temp_file.name, 'r') as zip_ref:
126157
zip_ref.extractall(directory_to_extract_to)
127158

128159

129160
def download_zip(url: str, directory: str) -> None:
130-
""" Downloads and unzips zip file from `url` to `directory`. """
161+
"""
162+
Downloads a ZIP file from the given URL and extracts it to the specified directory.
163+
164+
:param url: The URL of the ZIP file to download.
165+
:type url: str
166+
:param directory: The directory where the ZIP file should be extracted.
167+
:type directory: str
168+
"""
131169
# Download file.
132170
downloaded_file = tempfile.NamedTemporaryFile(suffix='.zip', delete=False)
133171
http_get(url, downloaded_file)
@@ -142,6 +180,19 @@ def download_zip(url: str, directory: str) -> None:
142180

143181

144182
def download_lt(language_tool_version: Optional[str] = LTP_DOWNLOAD_VERSION) -> None:
183+
"""
184+
Downloads and extracts the specified version of LanguageTool.
185+
This function checks for Java compatibility, creates the necessary download
186+
directory if it does not exist, and downloads the specified version of
187+
LanguageTool if it is not already present.
188+
189+
:param language_tool_version: The version of LanguageTool to download. If not
190+
specified, the default version defined by
191+
LTP_DOWNLOAD_VERSION is used.
192+
:type language_tool_version: Optional[str]
193+
:raises AssertionError: If the download folder is not a directory.
194+
"""
195+
145196
confirm_java_compatibility()
146197

147198
download_folder = get_language_tool_download_path()

language_tool_python/language_tag.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,80 @@
44

55
@total_ordering
66
class LanguageTag:
7-
"""Language tag supported by LanguageTool."""
7+
"""
8+
A class to represent and normalize language tags.
9+
10+
:param tag: The language tag.
11+
:type tag: str
12+
:param languages: An iterable of supported language tags.
13+
:type languages: Iterable[str]
14+
15+
Attributes:
16+
tag (str): The language tag to be normalized.
17+
languages (Iterable[str]): An iterable of supported language tags.
18+
normalized_tag (str): The normalized language tag.
19+
_LANGUAGE_RE (re.Pattern): A regular expression to match language tags.
20+
"""
821
_LANGUAGE_RE = re.compile(r"^([a-z]{2,3})(?:[_-]([a-z]{2}))?$", re.I)
922

1023
def __init__(self, tag: str, languages: Iterable[str]) -> None:
24+
"""
25+
Initialize a LanguageTag instance.
26+
"""
1127
self.tag = tag
1228
self.languages = languages
1329
self.normalized_tag = self._normalize(tag)
1430

1531
def __eq__(self, other: Any) -> bool:
16-
return self.normalized_tag == self._normalize(other_tag)
32+
"""
33+
Compare this LanguageTag object with another for equality.
34+
35+
:param other: The other object to compare with.
36+
:type other: Any
37+
:return: True if the normalized tags are equal, False otherwise.
38+
:rtype: bool
39+
"""
40+
return self.normalized_tag == self._normalize(other)
1741

1842
def __lt__(self, other: Any) -> bool:
43+
"""
44+
Compare this object with another for less-than ordering.
45+
46+
:param other: The object to compare with.
47+
:type other: Any
48+
:return: True if this object is less than the other, False otherwise.
49+
:rtype: bool
50+
"""
1951
return str(self) < self._normalize(other)
2052

2153
def __str__(self) -> str:
54+
"""
55+
Returns the string representation of the object.
56+
57+
:return: The normalized tag as a string.
58+
:rtype: str
59+
"""
2260
return self.normalized_tag
2361

2462
def __repr__(self) -> str:
63+
"""
64+
Return a string representation of the LanguageTag instance.
65+
66+
:return: A string in the format '<LanguageTag "language_tag_string">'
67+
:rtype: str
68+
"""
2569
return f'<LanguageTag "{str(self)}">'
2670

2771
def _normalize(self, tag: str) -> str:
72+
"""
73+
Normalize a language tag to a standard format.
74+
75+
:param tag: The language tag to normalize.
76+
:type tag: str
77+
:raises ValueError: If the tag is empty or unsupported.
78+
:return: The normalized language tag.
79+
:rtype: str
80+
"""
2881
if not tag:
2982
raise ValueError('empty language tag')
3083
languages = {language.lower().replace('-', '_'): language

0 commit comments

Comments
 (0)