소스 검색

some typing and pep8

Bastien Sevajol 6 년 전
부모
커밋
4eb285365a
5개의 변경된 파일103개의 추가작업 그리고 46개의 파일을 삭제
  1. 1 1
      .gitignore
  2. 8 0
      README.txt
  3. 2 0
      setup.py
  4. 81 42
      tracim/lib/core/content.py
  5. 11 3
      tracim/models/data.py

+ 1 - 1
.gitignore 파일 보기

@@ -63,4 +63,4 @@ wsgidav.conf
63 63
 
64 64
 # binary translation files
65 65
 *.mo
66
-
66
+.mypy_cache/

+ 8 - 0
README.txt 파일 보기

@@ -35,3 +35,11 @@ Getting Started
35 35
 - Run your project.
36 36
 
37 37
     env/bin/pserve development.ini
38
+
39
+- Run mypy checks
40
+
41
+    mypy --ignore-missing-imports --disallow-untyped-defs tracim
42
+
43
+- Run pep8 checks
44
+
45
+    pep8 tracim

+ 2 - 0
setup.py 파일 보기

@@ -29,6 +29,8 @@ tests_require = [
29 29
     'pytest',
30 30
     'pytest-cov',
31 31
     'nose',
32
+    'pep8',
33
+    'mypy',
32 34
 ]
33 35
 
34 36
 setup(

+ 81 - 42
tracim/lib/core/content.py 파일 보기

@@ -49,7 +49,7 @@ from tracim.models.data import Workspace
49 49
 def compare_content_for_sorting_by_type_and_name(
50 50
         content1: Content,
51 51
         content2: Content
52
-):
52
+) -> int:
53 53
     """
54 54
     :param content1:
55 55
     :param content2:
@@ -58,7 +58,7 @@ def compare_content_for_sorting_by_type_and_name(
58 58
                 0 if content1 = content2
59 59
     """
60 60
 
61
-    if content1.type==content2.type:
61
+    if content1.type == content2.type:
62 62
         if content1.get_label().lower()>content2.get_label().lower():
63 63
             return 1
64 64
         elif content1.get_label().lower()<content2.get_label().lower():
@@ -66,11 +66,20 @@ def compare_content_for_sorting_by_type_and_name(
66 66
         return 0
67 67
     else:
68 68
         # TODO - D.A. - 2014-12-02 - Manage Content Types Dynamically
69
-        content_type_order = [ContentType.Folder, ContentType.Page, ContentType.Thread, ContentType.File]
70
-        result = content_type_order.index(content1.type)-content_type_order.index(content2.type)
71
-        if result<0:
69
+        content_type_order = [
70
+            ContentType.Folder,
71
+            ContentType.Page,
72
+            ContentType.Thread,
73
+            ContentType.File,
74
+        ]
75
+
76
+        content_1_type_index = content_type_order.index(content1.type)
77
+        content_2_type_index = content_type_order.index(content2.type)
78
+        result = content_1_type_index - content_2_type_index
79
+
80
+        if result < 0:
72 81
             return -1
73
-        elif result>0:
82
+        elif result > 0:
74 83
             return 1
75 84
         else:
76 85
             return 0
@@ -79,7 +88,7 @@ def compare_content_for_sorting_by_type_and_name(
79 88
 def compare_tree_items_for_sorting_by_type_and_name(
80 89
         item1: NodeTreeItem,
81 90
         item2: NodeTreeItem
82
-):
91
+) -> int:
83 92
     return compare_content_for_sorting_by_type_and_name(item1.node, item2.node)
84 93
 
85 94
 
@@ -100,13 +109,13 @@ class ContentApi(object):
100 109
             self,
101 110
             session: Session,
102 111
             current_user: typing.Optional[User],
103
-            show_archived=False,
104
-            show_deleted=False,
105
-            show_temporary=False,
106
-            all_content_in_treeview=True,
107
-            force_show_all_types=False,
108
-            disable_user_workspaces_filter=False,
109
-    ):
112
+            show_archived: bool = False,
113
+            show_deleted: bool = False,
114
+            show_temporary: bool = False,
115
+            all_content_in_treeview: bool = True,
116
+            force_show_all_types: bool = False,
117
+            disable_user_workspaces_filter: bool = False,
118
+    ) -> None:
110 119
         self._session = session
111 120
         self._user = current_user
112 121
         self._user_id = current_user.user_id if current_user else None
@@ -123,7 +132,7 @@ class ContentApi(object):
123 132
             show_archived: bool=False,
124 133
             show_deleted: bool=False,
125 134
             show_temporary: bool=False,
126
-    ):
135
+    ) -> typing.Generator['ContentApi', None, None]:
127 136
         """
128 137
         Use this method as context manager to update show_archived,
129 138
         show_deleted and show_temporary properties during context.
@@ -145,11 +154,10 @@ class ContentApi(object):
145 154
             self._show_deleted = previous_show_deleted
146 155
             self._show_temporary = previous_show_temporary
147 156
 
148
-    def get_revision_join(self):
157
+    def get_revision_join(self) -> sqlalchemy.sql.elements.BooleanClauseList:
149 158
         """
150 159
         Return the Content/ContentRevision query join condition
151 160
         :return: Content/ContentRevision query join condition
152
-        :rtype sqlalchemy.sql.elements.BooleanClauseList
153 161
         """
154 162
         return and_(Content.id == ContentRevisionRO.content_id,
155 163
                     ContentRevisionRO.revision_id == self._session.query(
@@ -159,32 +167,41 @@ class ContentApi(object):
159 167
                     .limit(1)
160 168
                     .correlate(Content))
161 169
 
162
-
163
-    def get_canonical_query(self):
170
+    def get_canonical_query(self) -> Query:
164 171
         """
165 172
         Return the Content/ContentRevision base query who join these table on the last revision.
166 173
         :return: Content/ContentRevision Query
167
-        :rtype sqlalchemy.orm.query.Query
168 174
         """
169
-        return self._session.query(Content).join(ContentRevisionRO, self.get_revision_join())
175
+        return self._session.query(Content)\
176
+            .join(ContentRevisionRO, self.get_revision_join())
170 177
 
171 178
     @classmethod
172
-    def sort_tree_items(cls, content_list: [NodeTreeItem])-> [Content]:
179
+    def sort_tree_items(
180
+        cls,
181
+        content_list: typing.List[NodeTreeItem],
182
+    )-> typing.List[NodeTreeItem]:
173 183
         news = []
174 184
         for item in content_list:
175 185
             news.append(item)
176 186
 
177
-        content_list.sort(key=cmp_to_key(compare_tree_items_for_sorting_by_type_and_name))
187
+        content_list.sort(key=cmp_to_key(
188
+            compare_tree_items_for_sorting_by_type_and_name,
189
+        ))
178 190
 
179 191
         return content_list
180 192
 
181
-
182 193
     @classmethod
183
-    def sort_content(cls, content_list: [Content])-> [Content]:
194
+    def sort_content(
195
+        cls,
196
+        content_list: typing.List[Content],
197
+    ) -> typing.List[Content]:
184 198
         content_list.sort(key=cmp_to_key(compare_content_for_sorting_by_type_and_name))
185 199
         return content_list
186 200
 
187
-    def __real_base_query(self, workspace: Workspace=None):
201
+    def __real_base_query(
202
+        self,
203
+        workspace: Workspace = None,
204
+    ) -> Query:
188 205
         result = self.get_canonical_query()
189 206
 
190 207
         # Exclude non displayable types
@@ -212,7 +229,7 @@ class ContentApi(object):
212 229
 
213 230
         return result
214 231
 
215
-    def _base_query(self, workspace: Workspace=None):
232
+    def _base_query(self, workspace: Workspace=None) -> Query:
216 233
         result = self.__real_base_query(workspace)
217 234
 
218 235
         if not self._show_deleted:
@@ -226,7 +243,10 @@ class ContentApi(object):
226 243
 
227 244
         return result
228 245
 
229
-    def __revisions_real_base_query(self, workspace: Workspace=None):
246
+    def __revisions_real_base_query(
247
+        self,
248
+        workspace: Workspace=None,
249
+    ) -> Query:
230 250
         result = self._session.query(ContentRevisionRO)
231 251
 
232 252
         # Exclude non displayable types
@@ -245,7 +265,10 @@ class ContentApi(object):
245 265
 
246 266
         return result
247 267
 
248
-    def _revisions_base_query(self, workspace: Workspace=None):
268
+    def _revisions_base_query(
269
+        self,
270
+        workspace: Workspace=None,
271
+    ) -> Query:
249 272
         result = self.__revisions_real_base_query(workspace)
250 273
 
251 274
         if not self._show_deleted:
@@ -259,7 +282,10 @@ class ContentApi(object):
259 282
 
260 283
         return result
261 284
 
262
-    def _hard_filtered_base_query(self, workspace: Workspace=None):
285
+    def _hard_filtered_base_query(
286
+        self,
287
+        workspace: Workspace=None,
288
+    ) -> Query:
263 289
         """
264 290
         If set to True, then filterign on is_deleted and is_archived will also
265 291
         filter parent properties. This is required for search() function which
@@ -291,10 +317,13 @@ class ContentApi(object):
291 317
 
292 318
         return result
293 319
 
294
-    def get_base_query(self, workspace: Workspace) -> Query:
320
+    def get_base_query(
321
+        self,
322
+        workspace: Workspace,
323
+    ) -> Query:
295 324
         return self._base_query(workspace)
296 325
 
297
-    def get_child_folders(self, parent: Content=None, workspace: Workspace=None, filter_by_allowed_content_types: list=[], removed_item_ids: list=[], allowed_node_types=None) -> [Content]:
326
+    def get_child_folders(self, parent: Content=None, workspace: Workspace=None, filter_by_allowed_content_types: list=[], removed_item_ids: list=[], allowed_node_types=None) -> typing.List[Content]:
298 327
         """
299 328
         This method returns child items (folders or items) for left bar treeview.
300 329
 
@@ -306,6 +335,9 @@ class ContentApi(object):
306 335
                For example, if you want to move a Page from a folder to another, you should show only folders that accept pages
307 336
         :return:
308 337
         """
338
+        filter_by_allowed_content_types = filter_by_allowed_content_types or []  # FDV
339
+        removed_item_ids = removed_item_ids or []  # FDV
340
+
309 341
         if not allowed_node_types:
310 342
             allowed_node_types = [ContentType.Folder]
311 343
         elif allowed_node_types==ContentType.Any:
@@ -332,7 +364,11 @@ class ContentApi(object):
332 364
         result = []
333 365
         for folder in folders:
334 366
             for allowed_content_type in filter_by_allowed_content_types:
335
-                if folder.type==ContentType.Folder and folder.properties['allowed_content'][allowed_content_type]==True:
367
+
368
+                is_folder = folder.type == ContentType.Folder
369
+                content_type__allowed = folder.properties['allowed_content'][allowed_content_type] == True
370
+
371
+                if is_folder and content_type__allowed:
336 372
                     result.append(folder)
337 373
                     break
338 374
 
@@ -636,7 +672,7 @@ class ContentApi(object):
636 672
             ),
637 673
         ))
638 674
 
639
-    def get_all(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> [Content]:
675
+    def get_all(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> typing.List[Content]:
640 676
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
641 677
         assert content_type is not None# DYN_REMOVE
642 678
         assert isinstance(content_type, str) # DYN_REMOVE
@@ -653,7 +689,7 @@ class ContentApi(object):
653 689
 
654 690
         return resultset.all()
655 691
 
656
-    def get_children(self, parent_id: int, content_types: list, workspace: Workspace=None) -> [Content]:
692
+    def get_children(self, parent_id: int, content_types: list, workspace: Workspace=None) -> typing.List[Content]:
657 693
         """
658 694
         Return parent_id childs of given content_types
659 695
         :param parent_id: parent id
@@ -672,7 +708,7 @@ class ContentApi(object):
672 708
         return resultset.all()
673 709
 
674 710
     # TODO find an other name to filter on is_deleted / is_archived
675
-    def get_all_with_filter(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> [Content]:
711
+    def get_all_with_filter(self, parent_id: int=None, content_type: str=ContentType.Any, workspace: Workspace=None) -> typing.List[Content]:
676 712
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
677 713
         assert content_type is not None# DYN_REMOVE
678 714
         assert isinstance(content_type, str) # DYN_REMOVE
@@ -690,7 +726,7 @@ class ContentApi(object):
690 726
 
691 727
         return resultset.all()
692 728
 
693
-    def get_all_without_exception(self, content_type: str, workspace: Workspace=None) -> [Content]:
729
+    def get_all_without_exception(self, content_type: str, workspace: Workspace=None) -> typing.List[Content]:
694 730
         assert content_type is not None# DYN_REMOVE
695 731
 
696 732
         resultset = self._base_query(workspace)
@@ -700,7 +736,7 @@ class ContentApi(object):
700 736
 
701 737
         return resultset.all()
702 738
 
703
-    def get_last_active(self, parent_id: int, content_type: str, workspace: Workspace=None, limit=10) -> [Content]:
739
+    def get_last_active(self, parent_id: int, content_type: str, workspace: Workspace=None, limit=10) -> typing.List[Content]:
704 740
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
705 741
         assert content_type is not None# DYN_REMOVE
706 742
         assert isinstance(content_type, str) # DYN_REMOVE
@@ -736,7 +772,7 @@ class ContentApi(object):
736 772
         return result
737 773
 
738 774
     def get_last_unread(self, parent_id: int, content_type: str,
739
-                        workspace: Workspace=None, limit=10) -> [Content]:
775
+                        workspace: Workspace=None, limit=10) -> typing.List[Content]:
740 776
         assert parent_id is None or isinstance(parent_id, int) # DYN_REMOVE
741 777
         assert content_type is not None# DYN_REMOVE
742 778
         assert isinstance(content_type, str) # DYN_REMOVE
@@ -1106,7 +1142,7 @@ class ContentApi(object):
1106 1142
 
1107 1143
         return keywords
1108 1144
 
1109
-    def search(self, keywords: [str]) -> sqlalchemy.orm.query.Query:
1145
+    def search(self, keywords: [str]) -> Query:
1110 1146
         """
1111 1147
         :return: a sorted list of Content items
1112 1148
         """
@@ -1123,7 +1159,7 @@ class ContentApi(object):
1123 1159
 
1124 1160
         return title_keyworded_items
1125 1161
 
1126
-    def get_all_types(self) -> [ContentType]:
1162
+    def get_all_types(self) -> typing.List[ContentType]:
1127 1163
         labels = ContentType.all()
1128 1164
         content_types = []
1129 1165
         for label in labels:
@@ -1131,7 +1167,10 @@ class ContentApi(object):
1131 1167
 
1132 1168
         return ContentType.sorted(content_types)
1133 1169
 
1134
-    def exclude_unavailable(self, contents: [Content]) -> [Content]:
1170
+    def exclude_unavailable(
1171
+        self,
1172
+        contents: typing.List[Content],
1173
+    ) -> typing.List[Content]:
1135 1174
         """
1136 1175
         Update and return list with content under archived/deleted removed.
1137 1176
         :param contents: List of contents to parse

+ 11 - 3
tracim/models/data.py 파일 보기

@@ -1,4 +1,5 @@
1 1
 # -*- coding: utf-8 -*-
2
+import typing
2 3
 import datetime as datetime_root
3 4
 import json
4 5
 import os
@@ -1327,14 +1328,21 @@ class RevisionReadStatus(DeclarativeBase):
1327 1328
 
1328 1329
 class NodeTreeItem(object):
1329 1330
     """
1330
-        This class implements a model that allow to simply represents the left-panel menu items
1331
-         This model is used by dbapi but is not directly related to sqlalchemy and database
1331
+        This class implements a model that allow to simply represents
1332
+        the left-panel menu items. This model is used by dbapi but
1333
+        is not directly related to sqlalchemy and database
1332 1334
     """
1333
-    def __init__(self, node: Content, children: list('NodeTreeItem'), is_selected = False):
1335
+    def __init__(
1336
+        self,
1337
+        node: Content,
1338
+        children: typing.List['NodeTreeItem'],
1339
+        is_selected: bool = False,
1340
+    ):
1334 1341
         self.node = node
1335 1342
         self.children = children
1336 1343
         self.is_selected = is_selected
1337 1344
 
1345
+
1338 1346
 class VirtualEvent(object):
1339 1347
     @classmethod
1340 1348
     def create_from(cls, object):