python-negar 1.2.15__tar.gz → 1.4__tar.gz
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.
- {python_negar-1.2.15 → python_negar-1.4}/Changelog.txt +6 -0
- {python_negar-1.2.15 → python_negar-1.4}/PKG-INFO +6 -6
- {python_negar-1.2.15 → python_negar-1.4}/README.md +4 -4
- {python_negar-1.2.15 → python_negar-1.4}/negar/constants.py +1 -1
- {python_negar-1.2.15 → python_negar-1.4}/negar/data/immutable.words +5 -0
- {python_negar-1.2.15 → python_negar-1.4}/negar/virastar.py +44 -31
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/PKG-INFO +6 -6
- {python_negar-1.2.15 → python_negar-1.4}/setup.py +1 -2
- {python_negar-1.2.15 → python_negar-1.4}/tests/test_unittest.py +11 -5
- {python_negar-1.2.15 → python_negar-1.4}/AUTHORS +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/LICENSE +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/MANIFEST.in +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/negar/__init__.py +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/negar/gui.py +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/SOURCES.txt +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/dependency_links.txt +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/entry_points.txt +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/requires.txt +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/python_negar.egg-info/top_level.txt +0 -0
- {python_negar-1.2.15 → python_negar-1.4}/setup.cfg +0 -0
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
1.4 - 2025-01-05
|
|
2
|
+
-- Added a new feature to ignore text after #> as a comment trigger.
|
|
3
|
+
|
|
4
|
+
1.3 - 2025-01-01
|
|
5
|
+
-- Enhanced the handling of immutable words to achieve greater accuracy in results.
|
|
6
|
+
|
|
1
7
|
1.2.15 - 2024-12-31
|
|
2
8
|
-- Fixed issue #24 and added several new immutable words.
|
|
3
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-negar
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4
|
|
4
4
|
Summary: Negar is a spell corrector and Persian text editor
|
|
5
5
|
Home-page: http://github.com/shahinism/python-negar
|
|
6
6
|
Author: Shahin Azad
|
|
@@ -13,7 +13,7 @@ Classifier: Environment :: Console
|
|
|
13
13
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Requires-Python: >=3.
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
License-File: AUTHORS
|
|
@@ -42,7 +42,7 @@ Installation
|
|
|
42
42
|
|
|
43
43
|
## Git
|
|
44
44
|
|
|
45
|
-
You can get latest stable changes from
|
|
45
|
+
You can get the latest stable changes from the GitHub server:
|
|
46
46
|
|
|
47
47
|
$ git clone https://github.com/shahinism/python-negar.git
|
|
48
48
|
$ cd python-negar
|
|
@@ -62,11 +62,11 @@ Get the latest tarball & install:
|
|
|
62
62
|
|
|
63
63
|
### Windows
|
|
64
64
|
|
|
65
|
-
Download latest zip archive.
|
|
65
|
+
Download the latest zip archive.
|
|
66
66
|
|
|
67
67
|
https://github.com/shahinism/python-negar/archive/master.zip
|
|
68
68
|
|
|
69
|
-
Decompress it, and run the following command in root directory of `python-negar`
|
|
69
|
+
Decompress it, and run the following command in the root directory of `python-negar`
|
|
70
70
|
|
|
71
71
|
$ python setup.py install
|
|
72
72
|
|
|
@@ -85,7 +85,7 @@ Calling by default options:
|
|
|
85
85
|
* جایگزینی
|
|
86
86
|
+ خط تیره های پیاپی نظیر (--) و (---) با معادل های استاندارد شان
|
|
87
87
|
+ سه نقطه ی پیاپی (...) با کاراکتر استانداردش در زبان فارسی
|
|
88
|
-
+ علایمی نظیر
|
|
88
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه ؛ 'نگار'
|
|
89
89
|
+ اعداد عربی '١٢٣٤٥٦٧٨٩٠' و انگلیسی '1234567890' با معادل فارسی
|
|
90
90
|
+ کاراکتر های غیر فارسی نظیر ',;%يةك' با معادل های فارسی
|
|
91
91
|
|
|
@@ -21,7 +21,7 @@ Installation
|
|
|
21
21
|
|
|
22
22
|
## Git
|
|
23
23
|
|
|
24
|
-
You can get latest stable changes from
|
|
24
|
+
You can get the latest stable changes from the GitHub server:
|
|
25
25
|
|
|
26
26
|
$ git clone https://github.com/shahinism/python-negar.git
|
|
27
27
|
$ cd python-negar
|
|
@@ -41,11 +41,11 @@ Get the latest tarball & install:
|
|
|
41
41
|
|
|
42
42
|
### Windows
|
|
43
43
|
|
|
44
|
-
Download latest zip archive.
|
|
44
|
+
Download the latest zip archive.
|
|
45
45
|
|
|
46
46
|
https://github.com/shahinism/python-negar/archive/master.zip
|
|
47
47
|
|
|
48
|
-
Decompress it, and run the following command in root directory of `python-negar`
|
|
48
|
+
Decompress it, and run the following command in the root directory of `python-negar`
|
|
49
49
|
|
|
50
50
|
$ python setup.py install
|
|
51
51
|
|
|
@@ -64,7 +64,7 @@ Calling by default options:
|
|
|
64
64
|
* جایگزینی
|
|
65
65
|
+ خط تیره های پیاپی نظیر (--) و (---) با معادل های استاندارد شان
|
|
66
66
|
+ سه نقطه ی پیاپی (...) با کاراکتر استانداردش در زبان فارسی
|
|
67
|
-
+ علایمی نظیر
|
|
67
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه ؛ 'نگار'
|
|
68
68
|
+ اعداد عربی '١٢٣٤٥٦٧٨٩٠' و انگلیسی '1234567890' با معادل فارسی
|
|
69
69
|
+ کاراکتر های غیر فارسی نظیر ',;%يةك' با معادل های فارسی
|
|
70
70
|
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
الشان
|
|
93
93
|
الکتر
|
|
94
94
|
الکترومتر
|
|
95
|
+
الکترومتری
|
|
95
96
|
الکتری
|
|
96
97
|
الماسنشان
|
|
97
98
|
المان
|
|
@@ -331,6 +332,7 @@
|
|
|
331
332
|
بیایی
|
|
332
333
|
بیایید
|
|
333
334
|
بیاییم
|
|
335
|
+
بیاییم
|
|
334
336
|
بیبسکو
|
|
335
337
|
بیبل
|
|
336
338
|
بیبها
|
|
@@ -1169,6 +1171,7 @@
|
|
|
1169
1171
|
کودکستان
|
|
1170
1172
|
کوهستان
|
|
1171
1173
|
کیلومتر
|
|
1174
|
+
کیلومتری
|
|
1172
1175
|
کیها
|
|
1173
1176
|
گالوانومتر
|
|
1174
1177
|
گانگستر
|
|
@@ -1200,6 +1203,8 @@
|
|
|
1200
1203
|
لیموعمان
|
|
1201
1204
|
ماتریس
|
|
1202
1205
|
متان
|
|
1206
|
+
متر
|
|
1207
|
+
متری
|
|
1203
1208
|
متشابها
|
|
1204
1209
|
متکلمان
|
|
1205
1210
|
متها
|
|
@@ -57,7 +57,8 @@ class PersianEditor:
|
|
|
57
57
|
self.cleanup()
|
|
58
58
|
|
|
59
59
|
def cleanup(self):
|
|
60
|
-
self.
|
|
60
|
+
self.__handle_comments__(State.save)
|
|
61
|
+
self.__handle_urls__(State.save)
|
|
61
62
|
# fix punctuation spaces at first
|
|
62
63
|
# : ; , ! ? and their Persian counterparts should have one space after and no space before
|
|
63
64
|
# An exception is triple dots, which should be handled first
|
|
@@ -77,10 +78,12 @@ class PersianEditor:
|
|
|
77
78
|
self.char_validator() if self._fix_misc_non_persian_chars else None
|
|
78
79
|
self.fix_arabic_numbers() if self._fix_arabic_numbers else None
|
|
79
80
|
self.fix_english_numbers() if self._fix_english_numbers else None
|
|
81
|
+
self.__handle_immutable_words__(State.save)
|
|
80
82
|
self.fix_prefix_spacing() if self._fix_prefix_spacing else None
|
|
81
83
|
self.fix_prefix_separate() if self._fix_prefix_separate else None
|
|
82
84
|
self.fix_suffix_spacing() if self._fix_suffix_spacing else None
|
|
83
85
|
self.fix_suffix_separate() if self._fix_suffix_separate else None
|
|
86
|
+
self.__handle_immutable_words__(State.restore)
|
|
84
87
|
self.fix_spacing_for_braces_and_quotes() \
|
|
85
88
|
if self._fix_spacing_for_braces_and_quotes else None
|
|
86
89
|
self.cleanup_redundant_zwnj()
|
|
@@ -92,7 +95,8 @@ class PersianEditor:
|
|
|
92
95
|
)
|
|
93
96
|
if self._trim_leading_trailing_whitespaces:
|
|
94
97
|
self.text = "\n".join([line.strip() for line in self.text.split("\n")])
|
|
95
|
-
self.
|
|
98
|
+
self.__handle_urls__(State.restore)
|
|
99
|
+
self.__handle_comments__(State.restore)
|
|
96
100
|
return self.text
|
|
97
101
|
|
|
98
102
|
def __repr__(self):
|
|
@@ -100,8 +104,19 @@ class PersianEditor:
|
|
|
100
104
|
|
|
101
105
|
__str__ = __repr__
|
|
102
106
|
|
|
103
|
-
def
|
|
104
|
-
"""
|
|
107
|
+
def __handle_comments__(self, state):
|
|
108
|
+
"""Extract comments, process the content, and reinsert the comments at the end."""
|
|
109
|
+
if state == State.save:
|
|
110
|
+
self.comments = list(set(re.findall(r"#>.*$", self.text, re.I | re.M)))
|
|
111
|
+
self.comments.sort(key=lambda x: len(x), reverse=True)
|
|
112
|
+
for i, comment in enumerate(self.comments):
|
|
113
|
+
self.text = regex.sub(rf"{re.escape(comment)}", rf"__COMMENT__#{i}__", self.text)
|
|
114
|
+
if state == State.restore:
|
|
115
|
+
for i, comment in enumerate(self.comments):
|
|
116
|
+
self.text = re.sub(f"__COMMENT__#{i}__", comment, self.text)
|
|
117
|
+
|
|
118
|
+
def __handle_urls__(self, state):
|
|
119
|
+
"""Remove URLs temporarily and reinsert them at the end of the process."""
|
|
105
120
|
if state == State.save:
|
|
106
121
|
self.urls = list(set(re.findall(URLREGX, self.text, re.M | re.I | re.X)))
|
|
107
122
|
self.urls.sort(key=lambda x: len(x), reverse=True)
|
|
@@ -111,6 +126,19 @@ class PersianEditor:
|
|
|
111
126
|
for i, url in enumerate(self.urls):
|
|
112
127
|
self.text = re.sub(f"__URL__#{i}__", url, self.text)
|
|
113
128
|
|
|
129
|
+
def __handle_immutable_words__(self, state):
|
|
130
|
+
"""Remove immutable words temporarily and reapply them at the end of the process."""
|
|
131
|
+
if state == State.save:
|
|
132
|
+
self.immutable_words = {}
|
|
133
|
+
words = self.text.split()
|
|
134
|
+
for i, word in enumerate(words):
|
|
135
|
+
if (word := word.strip()) in ImmutableWords.get():
|
|
136
|
+
self.immutable_words[i] = word
|
|
137
|
+
self.text = regex.sub(rf"\b{word}\b", rf"__IMM__#{i}__", self.text)
|
|
138
|
+
if state == State.restore:
|
|
139
|
+
for imm_key, imm_word in self.immutable_words.items():
|
|
140
|
+
self.text = re.sub(f"__IMM__#{imm_key}__", imm_word, self.text)
|
|
141
|
+
|
|
114
142
|
def fix_dashes(self):
|
|
115
143
|
"""Replace double and triple dashes with `ndash` and `mdash`, respectively."""
|
|
116
144
|
self.text = re.sub(r"-{3}", r"—", self.text)
|
|
@@ -193,24 +221,8 @@ class PersianEditor:
|
|
|
193
221
|
""",
|
|
194
222
|
re.VERBOSE,
|
|
195
223
|
) # \b for words like سهمیه
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
text = self.text.replace("\\", "PN__BACKSLASH__PN")
|
|
199
|
-
wlist = text.split()
|
|
200
|
-
for word in wlist:
|
|
201
|
-
if word.strip() in ImmutableWords.get():
|
|
202
|
-
continue
|
|
203
|
-
regx_iter = regx.finditer(word)
|
|
204
|
-
for p in regx_iter:
|
|
205
|
-
# Checks that the prefix (mi* nemi* bi*) is part a a word or not, like میلاد.
|
|
206
|
-
if p.group() not in ImmutableWords.get():
|
|
207
|
-
text = re.sub(
|
|
208
|
-
re.escape(p.group()),
|
|
209
|
-
p.group(1) + "\u200c" + p.group(2),
|
|
210
|
-
text,
|
|
211
|
-
)
|
|
212
|
-
# Restore the original backslashes
|
|
213
|
-
self.text = text.replace("PN__BACKSLASH__PN", "\\")
|
|
224
|
+
# Checks that the prefix (mi*, nemi*, and bi*) is part a a word or not, like میلاد.
|
|
225
|
+
self.__immutability_check__(regx)
|
|
214
226
|
|
|
215
227
|
def fix_suffix_spacing(self):
|
|
216
228
|
"""Put ZWNJ between a word and its suffix (*ha[ye] *tar[in])."""
|
|
@@ -258,21 +270,22 @@ class PersianEditor:
|
|
|
258
270
|
)\b""",
|
|
259
271
|
re.VERBOSE,
|
|
260
272
|
)
|
|
273
|
+
# Checks that the suffix (tar*, haye*) is part of a word or not, like بهتر.
|
|
274
|
+
self.__immutability_check__(regx)
|
|
275
|
+
|
|
276
|
+
def __immutability_check__(self, regx: re.Pattern):
|
|
261
277
|
# Replace backslashes with a temporary placeholder
|
|
262
278
|
text = self.text.replace("\\", "PN__BACKSLASH__PN")
|
|
263
279
|
wlist = text.split()
|
|
264
280
|
for word in wlist:
|
|
265
|
-
if word.strip() in ImmutableWords.get():
|
|
266
|
-
continue
|
|
267
281
|
regx_iter = regx.finditer(word)
|
|
268
282
|
for p in regx_iter:
|
|
269
|
-
#
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
)
|
|
283
|
+
# if p.group() not in ImmutableWords.get():
|
|
284
|
+
text = re.sub(
|
|
285
|
+
rf"\b{re.escape(p.group())}\b",
|
|
286
|
+
p.group(1) + "\u200c" + p.group(2),
|
|
287
|
+
text,
|
|
288
|
+
)
|
|
276
289
|
# Restore the original backslashes
|
|
277
290
|
self.text = text.replace("PN__BACKSLASH__PN", "\\")
|
|
278
291
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-negar
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4
|
|
4
4
|
Summary: Negar is a spell corrector and Persian text editor
|
|
5
5
|
Home-page: http://github.com/shahinism/python-negar
|
|
6
6
|
Author: Shahin Azad
|
|
@@ -13,7 +13,7 @@ Classifier: Environment :: Console
|
|
|
13
13
|
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
14
14
|
Classifier: Programming Language :: Python
|
|
15
15
|
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Requires-Python: >=3.
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
License-File: LICENSE
|
|
19
19
|
License-File: AUTHORS
|
|
@@ -42,7 +42,7 @@ Installation
|
|
|
42
42
|
|
|
43
43
|
## Git
|
|
44
44
|
|
|
45
|
-
You can get latest stable changes from
|
|
45
|
+
You can get the latest stable changes from the GitHub server:
|
|
46
46
|
|
|
47
47
|
$ git clone https://github.com/shahinism/python-negar.git
|
|
48
48
|
$ cd python-negar
|
|
@@ -62,11 +62,11 @@ Get the latest tarball & install:
|
|
|
62
62
|
|
|
63
63
|
### Windows
|
|
64
64
|
|
|
65
|
-
Download latest zip archive.
|
|
65
|
+
Download the latest zip archive.
|
|
66
66
|
|
|
67
67
|
https://github.com/shahinism/python-negar/archive/master.zip
|
|
68
68
|
|
|
69
|
-
Decompress it, and run the following command in root directory of `python-negar`
|
|
69
|
+
Decompress it, and run the following command in the root directory of `python-negar`
|
|
70
70
|
|
|
71
71
|
$ python setup.py install
|
|
72
72
|
|
|
@@ -85,7 +85,7 @@ Calling by default options:
|
|
|
85
85
|
* جایگزینی
|
|
86
86
|
+ خط تیره های پیاپی نظیر (--) و (---) با معادل های استاندارد شان
|
|
87
87
|
+ سه نقطه ی پیاپی (...) با کاراکتر استانداردش در زبان فارسی
|
|
88
|
-
+ علایمی نظیر
|
|
88
|
+
+ علایمی نظیر کوتیشن فارسی با گیومه ؛ 'نگار'
|
|
89
89
|
+ اعداد عربی '١٢٣٤٥٦٧٨٩٠' و انگلیسی '1234567890' با معادل فارسی
|
|
90
90
|
+ کاراکتر های غیر فارسی نظیر ',;%يةك' با معادل های فارسی
|
|
91
91
|
|
|
@@ -33,12 +33,11 @@ setup(
|
|
|
33
33
|
},
|
|
34
34
|
long_description_content_type="text/markdown",
|
|
35
35
|
long_description=open("README.md", encoding="utf8").read(),
|
|
36
|
-
python_requires=">=3.
|
|
36
|
+
python_requires=">=3.8",
|
|
37
37
|
classifiers=[
|
|
38
38
|
"Environment :: Console",
|
|
39
39
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
|
40
40
|
"Programming Language :: Python",
|
|
41
41
|
"Programming Language :: Python :: 3",
|
|
42
42
|
],
|
|
43
|
-
|
|
44
43
|
)
|
|
@@ -11,7 +11,9 @@ class Test(unittest.TestCase):
|
|
|
11
11
|
def wrapper(self, *args, **kwargs):
|
|
12
12
|
func(self, *args, **kwargs)
|
|
13
13
|
return self.assertEqual(f"{PersianEditor(self.input_)}", self.output_, message)
|
|
14
|
+
|
|
14
15
|
return wrapper
|
|
16
|
+
|
|
15
17
|
return decorator
|
|
16
18
|
|
|
17
19
|
# @unittest.skip("")
|
|
@@ -22,8 +24,8 @@ class Test(unittest.TestCase):
|
|
|
22
24
|
|
|
23
25
|
@_assertEqual("Fix Hamzeh")
|
|
24
26
|
def test_fix_hamzeh(self):
|
|
25
|
-
self.input_ = "کلماتی که با 'ی' پسوند همراه هستند مانند 'همه ی ' -- و البته امکان جایگزینی آن با حمزه 'ء' ( در صورت انتخاب کاربر )"
|
|
26
|
-
self.output_ = "کلماتی که با «ی» پسوند همراه هستند مانند «همهی» – و البته امکان جایگزینی آن با حمزه «ء» (در صورت انتخاب کاربر)"
|
|
27
|
+
self.input_ = "کلماتی که با 'ی' پسوند همراه هستند مانند 'همه ی ' -- و البته امکان جایگزینی آن با حمزه 'ء' ( در صورت انتخاب کاربر )" # noqa: E501
|
|
28
|
+
self.output_ = "کلماتی که با «ی» پسوند همراه هستند مانند «همهی» – و البته امکان جایگزینی آن با حمزه «ء» (در صورت انتخاب کاربر)" # noqa: E501
|
|
27
29
|
|
|
28
30
|
@_assertEqual("Numbers as a Version -- Triple Dots")
|
|
29
31
|
def test_versioning_numbers_triple(self):
|
|
@@ -61,7 +63,6 @@ class Test(unittest.TestCase):
|
|
|
61
63
|
def test_persian_quotations_ii(self):
|
|
62
64
|
self.input_ = "«تاثیر نسبی داشته است. »"
|
|
63
65
|
self.output_ = "«تاثیر نسبی داشته است.»"
|
|
64
|
-
|
|
65
66
|
|
|
66
67
|
@_assertEqual("Persian Numbers")
|
|
67
68
|
def test_persian_numbers(self):
|
|
@@ -102,7 +103,7 @@ class Test(unittest.TestCase):
|
|
|
102
103
|
def test_fix_prefix_ZWNJ_iii(self):
|
|
103
104
|
self.input_ = r"می شود"
|
|
104
105
|
self.output_ = "میشود"
|
|
105
|
-
|
|
106
|
+
|
|
106
107
|
@_assertEqual("Fix Suffix ZWNJ I")
|
|
107
108
|
def test_fix_suffix_ZWNJ_I(self):
|
|
108
109
|
self.input_ = r"در پسوند کلمات با نیمفاصله نظیر کتابها، خوشترین -- و البته امکان عدم تنظیم (در صورت انتخاب کاربر)"
|
|
@@ -127,7 +128,7 @@ class Test(unittest.TestCase):
|
|
|
127
128
|
def test_immutable_words_i(self):
|
|
128
129
|
self.input_ = "تنها ترین خدمتگزار (تنها ترین خدمتگزار)"
|
|
129
130
|
self.output_ = "تنهاترین خدمتگزار (تنهاترین خدمتگزار)"
|
|
130
|
-
|
|
131
|
+
|
|
131
132
|
@_assertEqual("Immutable Words II")
|
|
132
133
|
def test_immutable_words_ii(self):
|
|
133
134
|
self.input_ = "تنها ترین خدمتگزار (تنها ترین خدمتگزار)"
|
|
@@ -138,6 +139,11 @@ class Test(unittest.TestCase):
|
|
|
138
139
|
self.input_ = "بیستم ماه میلادی"
|
|
139
140
|
self.output_ = "بیستم ماه میلادی"
|
|
140
141
|
|
|
142
|
+
@_assertEqual("Ignote Comment")
|
|
143
|
+
def test_ignore_comment(self):
|
|
144
|
+
self.input_ = "کشیـــــــــده شده اند #> می نویسد .... "
|
|
145
|
+
self.output_ = "کشیده شدهاند #> می نویسد .... "
|
|
146
|
+
|
|
141
147
|
|
|
142
148
|
if __name__ == "__main__":
|
|
143
149
|
unittest.main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|