##// END OF EJS Templates
docs: describe, visualize, and verify internal code structure and layering...
Mads Kiilerich -
r8550:52816813 default
parent child Browse files
Show More
@@ -0,0 +1,295 b''
1 #!/usr/bin/env python3
2
3
4 import re
5 import sys
6
7
8 ignored_modules = set('''
9 argparse
10 base64
11 bcrypt
12 binascii
13 bleach
14 calendar
15 celery
16 celery
17 chardet
18 click
19 collections
20 configparser
21 copy
22 csv
23 ctypes
24 datetime
25 dateutil
26 decimal
27 decorator
28 difflib
29 distutils
30 docutils
31 email
32 errno
33 fileinput
34 functools
35 getpass
36 grp
37 hashlib
38 hmac
39 html
40 http
41 imp
42 importlib
43 inspect
44 io
45 ipaddr
46 IPython
47 isapi_wsgi
48 itertools
49 json
50 kajiki
51 ldap
52 logging
53 mako
54 markdown
55 mimetypes
56 mock
57 msvcrt
58 multiprocessing
59 operator
60 os
61 paginate
62 paginate_sqlalchemy
63 pam
64 paste
65 pkg_resources
66 platform
67 posixpath
68 pprint
69 pwd
70 pyflakes
71 pytest
72 pytest_localserver
73 random
74 re
75 routes
76 setuptools
77 shlex
78 shutil
79 smtplib
80 socket
81 ssl
82 stat
83 string
84 struct
85 subprocess
86 sys
87 tarfile
88 tempfile
89 textwrap
90 tgext
91 threading
92 time
93 traceback
94 traitlets
95 types
96 urllib
97 urlobject
98 uuid
99 warnings
100 webhelpers2
101 webob
102 webtest
103 whoosh
104 win32traceutil
105 zipfile
106 '''.split())
107
108 top_modules = set('''
109 kallithea.alembic
110 kallithea.bin
111 kallithea.config
112 kallithea.controllers
113 kallithea.templates.py
114 scripts
115 '''.split())
116
117 bottom_external_modules = set('''
118 tg
119 mercurial
120 sqlalchemy
121 alembic
122 formencode
123 pygments
124 dulwich
125 beaker
126 psycopg2
127 docs
128 setup
129 conftest
130 '''.split())
131
132 normal_modules = set('''
133 kallithea
134 kallithea.lib.celerylib.tasks
135 kallithea.lib
136 kallithea.lib.auth
137 kallithea.lib.auth_modules
138 kallithea.lib.base
139 kallithea.lib.celerylib
140 kallithea.lib.db_manage
141 kallithea.lib.helpers
142 kallithea.lib.hooks
143 kallithea.lib.indexers
144 kallithea.lib.utils
145 kallithea.lib.utils2
146 kallithea.lib.vcs
147 kallithea.lib.webutils
148 kallithea.model
149 kallithea.model.scm
150 kallithea.templates.py
151 '''.split())
152
153 shown_modules = normal_modules | top_modules
154
155 # break the chains somehow - this is a cleanup TODO list
156 known_violations = [
157 ('kallithea.lib.auth_modules', 'kallithea.lib.auth'), # needs base&facade
158 ('kallithea.lib.utils', 'kallithea.model'), # clean up utils
159 ('kallithea.lib.utils', 'kallithea.model.db'),
160 ('kallithea.lib.utils', 'kallithea.model.scm'),
161 ('kallithea.lib.celerylib.tasks', 'kallithea.lib.helpers'),
162 ('kallithea.lib.celerylib.tasks', 'kallithea.lib.hooks'),
163 ('kallithea.lib.celerylib.tasks', 'kallithea.lib.indexers'),
164 ('kallithea.lib.celerylib.tasks', 'kallithea.model'),
165 ('kallithea.model', 'kallithea.lib.auth'), # auth.HasXXX
166 ('kallithea.model', 'kallithea.lib.auth_modules'), # validators
167 ('kallithea.model', 'kallithea.lib.helpers'),
168 ('kallithea.model', 'kallithea.lib.hooks'), # clean up hooks
169 ('kallithea.model', 'kallithea.model.scm'),
170 ('kallithea.model.scm', 'kallithea.lib.hooks'),
171 ]
172
173 extra_edges = [
174 ('kallithea.config', 'kallithea.controllers'), # through TG
175 ('kallithea.lib.auth', 'kallithea.lib.auth_modules'), # custom loader
176 ]
177
178
179 def normalize(s):
180 """Given a string with dot path, return the string it should be shown as."""
181 parts = s.replace('.__init__', '').split('.')
182 short_2 = '.'.join(parts[:2])
183 short_3 = '.'.join(parts[:3])
184 short_4 = '.'.join(parts[:4])
185 if parts[0] in ['scripts', 'contributor_data', 'i18n_utils']:
186 return 'scripts'
187 if short_3 == 'kallithea.model.meta':
188 return 'kallithea.model.db'
189 if parts[:4] == ['kallithea', 'lib', 'vcs', 'ssh']:
190 return 'kallithea.lib.vcs.ssh'
191 if short_4 in shown_modules:
192 return short_4
193 if short_3 in shown_modules:
194 return short_3
195 if short_2 in shown_modules:
196 return short_2
197 if short_2 == 'kallithea.tests':
198 return None
199 if parts[0] in ignored_modules:
200 return None
201 assert parts[0] in bottom_external_modules, parts
202 return parts[0]
203
204
205 def main(filenames):
206 if not filenames or filenames[0].startswith('-'):
207 print('''\
208 Usage:
209 hg files 'set:!binary()&grep("^#!.*python")' 'set:**.py' | xargs scripts/deps.py
210 dot -Tsvg deps.dot > deps.svg
211 ''')
212 raise SystemExit(1)
213
214 files_imports = dict() # map filenames to its imports
215 import_deps = set() # set of tuples with module name and its imports
216 for fn in filenames:
217 with open(fn) as f:
218 s = f.read()
219
220 dot_name = (fn[:-3] if fn.endswith('.py') else fn).replace('/', '.')
221 file_imports = set()
222 for m in re.finditer(r'^ *(?:from ([^ ]*) import (?:([a-zA-Z].*)|\(([^)]*)\))|import (.*))$', s, re.MULTILINE):
223 m_from, m_from_import, m_from_import2, m_import = m.groups()
224 if m_from:
225 pre = m_from + '.'
226 if pre.startswith('.'):
227 pre = dot_name.rsplit('.', 1)[0] + pre
228 importlist = m_from_import or m_from_import2
229 else:
230 pre = ''
231 importlist = m_import
232 for imp in importlist.split('#', 1)[0].split(','):
233 full_imp = pre + imp.strip().split(' as ', 1)[0]
234 file_imports.add(full_imp)
235 import_deps.add((dot_name, full_imp))
236 files_imports[fn] = file_imports
237
238 # dump out all deps for debugging and analysis
239 with open('deps.txt', 'w') as f:
240 for fn, file_imports in sorted(files_imports.items()):
241 for file_import in sorted(file_imports):
242 if file_import.split('.', 1)[0] in ignored_modules:
243 continue
244 f.write('%s: %s\n' % (fn, file_import))
245
246 # find leafs that haven't been ignored - they are the important external dependencies and shown in the bottom row
247 only_imported = set(
248 set(normalize(b) for a, b in import_deps) -
249 set(normalize(a) for a, b in import_deps) -
250 set([None, 'kallithea'])
251 )
252
253 normalized_dep_edges = set()
254 for dot_name, full_imp in import_deps:
255 a = normalize(dot_name)
256 b = normalize(full_imp)
257 if a is None or b is None or a == b:
258 continue
259 normalized_dep_edges.add((a, b))
260 #print((dot_name, full_imp, a, b))
261 normalized_dep_edges.update(extra_edges)
262
263 unseen_shown_modules = shown_modules.difference(a for a, b in normalized_dep_edges).difference(b for a, b in normalized_dep_edges)
264 assert not unseen_shown_modules, unseen_shown_modules
265
266 with open('deps.dot', 'w') as f:
267 f.write('digraph {\n')
268 f.write('subgraph { rank = same; %s}\n' % ''.join('"%s"; ' % s for s in sorted(top_modules)))
269 f.write('subgraph { rank = same; %s}\n' % ''.join('"%s"; ' % s for s in sorted(only_imported)))
270 for a, b in sorted(normalized_dep_edges):
271 f.write(' "%s" -> "%s"%s\n' % (a, b, ' [color=red]' if (a, b) in known_violations else ' [color=green]' if (a, b) in extra_edges else ''))
272 f.write('}\n')
273
274 # verify dependencies by untangling dependency chain bottom-up:
275 todo = set(normalized_dep_edges)
276 for x in known_violations:
277 todo.remove(x)
278
279 while todo:
280 depending = set(a for a, b in todo)
281 depended = set(b for a, b in todo)
282 drop = depended - depending
283 if not drop:
284 print('ERROR: cycles:', len(todo))
285 for x in sorted(todo):
286 print('%s,' % (x,))
287 raise SystemExit(1)
288 #for do_b in sorted(drop):
289 # print('Picking', do_b, '- unblocks:', ' '.join(a for a, b in sorted((todo)) if b == do_b))
290 todo = set((a, b) for a, b in todo if b in depending)
291 #print()
292
293
294 if __name__ == '__main__':
295 main(sys.argv[1:])
@@ -1,55 +1,58 b''
1 1 syntax: glob
2 2 *.pyc
3 3 *.swp
4 4 *.sqlite
5 5 *.tox
6 6 *.egg-info
7 7 *.egg
8 8 *.mo
9 9 *.orig
10 10 *.rej
11 11 *.bak
12 12 .eggs/
13 13
14 14 syntax: regexp
15 15 ^extensions\.py$
16 16 ^build$
17 17 ^dist$
18 18 ^docs/build$
19 19 ^docs/_build$
20 20 ^data$
21 21 ^sql_dumps$
22 22 ^\.settings$
23 23 ^\.project$
24 24 ^\.pydevproject$
25 25 ^\.coverage$
26 26 ^kallithea/front-end/node_modules$
27 27 ^kallithea/front-end/package-lock\.json$
28 28 ^kallithea/front-end/theme\.less$
29 29 ^kallithea/front-end/tmp$
30 30 ^kallithea/public/codemirror$
31 31 ^kallithea/public/css/select2-spinner\.gif$
32 32 ^kallithea/public/css/select2\.png$
33 33 ^kallithea/public/css/select2x2\.png$
34 34 ^kallithea/public/css/style\.css$
35 35 ^kallithea/public/css/style\.css\.map$
36 36 ^kallithea/public/js/bootstrap\.js$
37 37 ^kallithea/public/js/dataTables\.bootstrap\.js$
38 38 ^kallithea/public/js/jquery\.atwho\.min\.js$
39 39 ^kallithea/public/js/jquery\.caret\.min\.js$
40 40 ^kallithea/public/js/jquery\.dataTables\.js$
41 41 ^kallithea/public/js/jquery\.flot\.js$
42 42 ^kallithea/public/js/jquery\.flot\.selection\.js$
43 43 ^kallithea/public/js/jquery\.flot\.time\.js$
44 44 ^kallithea/public/js/jquery\.min\.js$
45 45 ^kallithea/public/js/select2\.js$
46 46 ^kallithea\.db$
47 47 ^test\.db$
48 48 ^Kallithea\.egg-info$
49 49 ^my\.ini$
50 50 ^fabfile\.py$
51 51 ^\.idea$
52 52 ^\.cache$
53 53 ^\.pytest_cache$
54 54 ^venv$
55 55 /__pycache__$
56 ^deps\.dot$
57 ^deps\.svg$
58 ^deps\.txt$
@@ -1,309 +1,397 b''
1 1 .. _contributing:
2 2
3 3 =========================
4 4 Contributing to Kallithea
5 5 =========================
6 6
7 7 Kallithea is developed and maintained by its users. Please join us and scratch
8 8 your own itch.
9 9
10 10
11 11 Infrastructure
12 12 --------------
13 13
14 14 The main repository is hosted on Our Own Kallithea (aka OOK) at
15 15 https://kallithea-scm.org/repos/kallithea/, our self-hosted instance
16 16 of Kallithea.
17 17
18 18 Please use the `mailing list`_ to send patches or report issues.
19 19
20 20 We use Weblate_ to translate the user interface messages into languages other
21 21 than English. Join our project on `Hosted Weblate`_ to help us.
22 22 To register, you can use your Bitbucket or GitHub account. See :ref:`translations`
23 23 for more details.
24 24
25 25
26 26 Getting started
27 27 ---------------
28 28
29 29 To get started with Kallithea development run the following commands in your
30 30 bash shell::
31 31
32 32 hg clone https://kallithea-scm.org/repos/kallithea
33 33 cd kallithea
34 34 python3 -m venv venv
35 35 . venv/bin/activate
36 36 pip install --upgrade pip setuptools
37 37 pip install --upgrade -e . -r dev_requirements.txt python-ldap python-pam
38 38 kallithea-cli config-create my.ini
39 39 kallithea-cli db-create -c my.ini --user=user --email=user@example.com --password=password --repos=/tmp
40 40 kallithea-cli front-end-build
41 41 gearbox serve -c my.ini --reload &
42 42 firefox http://127.0.0.1:5000/
43 43
44 44
45 45 Contribution flow
46 46 -----------------
47 47
48 48 Starting from an existing Kallithea clone, make sure it is up to date with the
49 49 latest upstream changes::
50 50
51 51 hg pull
52 52 hg update
53 53
54 54 Review the :ref:`contributing-guidelines` and :ref:`coding-guidelines`.
55 55
56 56 If you are new to Mercurial, refer to Mercurial `Quick Start`_ and `Beginners
57 57 Guide`_ on the Mercurial wiki.
58 58
59 59 Now, make some changes and test them (see :ref:`contributing-tests`). Don't
60 60 forget to add new tests to cover new functionality or bug fixes.
61 61
62 62 For documentation changes, run ``make html`` from the ``docs`` directory to
63 63 generate the HTML result, then review them in your browser.
64 64
65 65 Before submitting any changes, run the cleanup script::
66 66
67 67 ./scripts/run-all-cleanup
68 68
69 69 When you are completely ready, you can send your changes to the community for
70 70 review and inclusion, via the mailing list (via ``hg email``).
71 71
72 72 .. _contributing-tests:
73 73
74 74
75 Internal dependencies
76 ---------------------
77
78 We try to keep the code base clean and modular and avoid circular dependencies.
79 Code should only invoke code in layers below itself.
80
81 Imports should import whole modules ``from`` their parent module, perhaps
82 ``as`` a shortened name. Avoid imports ``from`` modules.
83
84 To avoid cycles and partially initialized modules, ``__init__.py`` should *not*
85 contain any non-trivial imports. The top level of a module should *not* be a
86 facade for the module functionality.
87
88 Common code for a module is often in ``base.py``.
89
90 The important part of the dependency graph is approximately linear. In the
91 following list, modules may only depend on modules below them:
92
93 ``tests``
94 Just get the job done - anything goes.
95
96 ``bin/`` & ``config/`` & ``alembic/``
97 The main entry points, defined in ``setup.py``. Note: The TurboGears template
98 use ``config`` for the high WSGI application - this is not for low level
99 configuration.
100
101 ``controllers/``
102 The top level web application, with TurboGears using the ``root`` controller
103 as entry point, and ``routing`` dispatching to other controllers.
104
105 ``templates/**.html``
106 The "view", rendering to HTML. Invoked by controllers which can pass them
107 anything from lower layers - especially ``helpers`` available as ``h`` will
108 cut through all layers, and ``c`` gives access to global variables.
109
110 ``lib/helpers.py``
111 High level helpers, exposing everything to templates as ``h``. It depends on
112 everything and has a huge dependency chain, so it should not be used for
113 anything else. TODO.
114
115 ``controlles/base.py``
116 The base class of controllers, with lots of model knowledge.
117
118 ``lib/auth.py``
119 All things related to authentication. TODO.
120
121 ``lib/utils.py``
122 High level utils with lots of model knowledge. TODO.
123
124 ``lib/hooks.py``
125 Hooks into "everything" to give centralized logging to database, cache
126 invalidation, and extension handling. TODO.
127
128 ``model/``
129 Convenience business logic wrappers around database models.
130
131 ``model/db.py``
132 Defines the database schema and provides some additional logic.
133
134 ``model/scm.py``
135 All things related to anything. TODO.
136
137 SQLAlchemy
138 Database session and transaction in thread-local variables.
139
140 ``lib/utils2.py``
141 Low level utils specific to Kallithea.
142
143 ``lib/webutils.py``
144 Low level generic utils with awareness of the TurboGears environment.
145
146 TurboGears
147 Request, response and state like i18n gettext in thread-local variables.
148 External dependency with global state - usage should be minimized.
149
150 ``lib/vcs/``
151 Previously an independent library. No awareness of web, database, or state.
152
153 ``lib/*``
154 Various "pure" functionality not depending on anything else.
155
156 ``__init__``
157 Very basic Kallithea constants - some of them are set very early based on ``.ini``.
158
159 This is not exactly how it is right now, but we aim for something like that.
160 Especially the areas marked as TODO have some problems that need untangling.
161
162
75 163 Running tests
76 164 -------------
77 165
78 166 After finishing your changes make sure all tests pass cleanly. Run the testsuite
79 167 by invoking ``py.test`` from the project root::
80 168
81 169 py.test
82 170
83 171 Note that on unix systems, the temporary directory (``/tmp`` or where
84 172 ``$TMPDIR`` points) must allow executable files; Git hooks must be executable,
85 173 and the test suite creates repositories in the temporary directory. Linux
86 174 systems with /tmp mounted noexec will thus fail.
87 175
88 176 Tests can be run on PostgreSQL like::
89 177
90 178 sudo -u postgres createuser 'kallithea-test' --pwprompt # password password
91 179 sudo -u postgres createdb 'kallithea-test' --owner 'kallithea-test'
92 180 REUSE_TEST_DB='postgresql://kallithea-test:password@localhost/kallithea-test' py.test
93 181
94 182 Tests can be run on MariaDB/MySQL like::
95 183
96 184 echo "GRANT ALL PRIVILEGES ON \`kallithea-test\`.* TO 'kallithea-test'@'localhost' IDENTIFIED BY 'password'" | sudo -u mysql mysql
97 185 TEST_DB='mysql://kallithea-test:password@localhost/kallithea-test?charset=utf8mb4' py.test
98 186
99 187 You can also use ``tox`` to run the tests with all supported Python versions.
100 188
101 189 When running tests, Kallithea generates a `test.ini` based on template values
102 190 in `kallithea/tests/conftest.py` and populates the SQLite database specified
103 191 there.
104 192
105 193 It is possible to avoid recreating the full test database on each invocation of
106 194 the tests, thus eliminating the initial delay. To achieve this, run the tests as::
107 195
108 196 gearbox serve -c /tmp/kallithea-test-XXX/test.ini --pid-file=test.pid --daemon
109 197 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test
110 198 kill -9 $(cat test.pid)
111 199
112 200 In these commands, the following variables are used::
113 201
114 202 KALLITHEA_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
115 203 KALLITHEA_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for testing_vcs_operations
116 204
117 205 You can run individual tests by specifying their path as argument to py.test.
118 206 py.test also has many more options, see `py.test -h`. Some useful options
119 207 are::
120 208
121 209 -k EXPRESSION only run tests which match the given substring
122 210 expression. An expression is a python evaluable
123 211 expression where all names are substring-matched
124 212 against test names and their parent classes. Example:
125 213 -x, --exitfirst exit instantly on first error or failed test.
126 214 --lf rerun only the tests that failed at the last run (or
127 215 all if none failed)
128 216 --ff run all tests but run the last failures first. This
129 217 may re-order tests and thus lead to repeated fixture
130 218 setup/teardown
131 219 --pdb start the interactive Python debugger on errors.
132 220 -s, --capture=no don't capture stdout (any stdout output will be
133 221 printed immediately)
134 222
135 223 Performance tests
136 224 ^^^^^^^^^^^^^^^^^
137 225
138 226 A number of performance tests are present in the test suite, but they are
139 227 not run in a standard test run. These tests are useful to
140 228 evaluate the impact of certain code changes with respect to performance.
141 229
142 230 To run these tests::
143 231
144 232 env TEST_PERFORMANCE=1 py.test kallithea/tests/performance
145 233
146 234 To analyze performance, you could install pytest-profiling_, which enables the
147 235 --profile and --profile-svg options to py.test.
148 236
149 237 .. _pytest-profiling: https://github.com/manahl/pytest-plugins/tree/master/pytest-profiling
150 238
151 239 .. _contributing-guidelines:
152 240
153 241
154 242 Contribution guidelines
155 243 -----------------------
156 244
157 245 Kallithea is GPLv3 and we assume all contributions are made by the
158 246 committer/contributor and under GPLv3 unless explicitly stated. We do care a
159 247 lot about preservation of copyright and license information for existing code
160 248 that is brought into the project.
161 249
162 250 Contributions will be accepted in most formats -- such as commits hosted on your
163 251 own Kallithea instance, or patches sent by email to the `kallithea-general`_
164 252 mailing list.
165 253
166 254 Make sure to test your changes both manually and with the automatic tests
167 255 before posting.
168 256
169 257 We care about quality and review and keeping a clean repository history. We
170 258 might give feedback that requests polishing contributions until they are
171 259 "perfect". We might also rebase and collapse and make minor adjustments to your
172 260 changes when we apply them.
173 261
174 262 We try to make sure we have consensus on the direction the project is taking.
175 263 Everything non-sensitive should be discussed in public -- preferably on the
176 264 mailing list. We aim at having all non-trivial changes reviewed by at least
177 265 one other core developer before pushing. Obvious non-controversial changes will
178 266 be handled more casually.
179 267
180 268 There is a main development branch ("default") which is generally stable so that
181 269 it can be (and is) used in production. There is also a "stable" branch that is
182 270 almost exclusively reserved for bug fixes or trivial changes. Experimental
183 271 changes should live elsewhere (for example in a pull request) until they are
184 272 ready.
185 273
186 274 .. _coding-guidelines:
187 275
188 276
189 277 Coding guidelines
190 278 -----------------
191 279
192 280 We don't have a formal coding/formatting standard. We are currently using a mix
193 281 of Mercurial's (https://www.mercurial-scm.org/wiki/CodingStyle), pep8, and
194 282 consistency with existing code. Run ``scripts/run-all-cleanup`` before
195 283 committing to ensure some basic code formatting consistency.
196 284
197 285 We support Python 3.6 and later.
198 286
199 287 We try to support the most common modern web browsers. IE9 is still supported
200 288 to the extent it is feasible, IE8 is not.
201 289
202 290 We primarily support Linux and OS X on the server side but Windows should also work.
203 291
204 292 HTML templates should use 2 spaces for indentation ... but be pragmatic. We
205 293 should use templates cleverly and avoid duplication. We should use reasonable
206 294 semantic markup with element classes and IDs that can be used for styling and testing.
207 295 We should only use inline styles in places where it really is semantic (such as
208 296 ``display: none``).
209 297
210 298 JavaScript must use ``;`` between/after statements. Indentation 4 spaces. Inline
211 299 multiline functions should be indented two levels -- one for the ``()`` and one for
212 300 ``{}``.
213 301 Variables holding jQuery objects should be named with a leading ``$``.
214 302
215 303 Commit messages should have a leading short line summarizing the changes. For
216 304 bug fixes, put ``(Issue #123)`` at the end of this line.
217 305
218 306 Use American English grammar and spelling overall. Use `English title case`_ for
219 307 page titles, button labels, headers, and 'labels' for fields in forms.
220 308
221 309 .. _English title case: https://en.wikipedia.org/wiki/Capitalization#Title_case
222 310
223 311 Template helpers (that is, everything in ``kallithea.lib.helpers``)
224 312 should only be referenced from templates. If you need to call a
225 313 helper from the Python code, consider moving the function somewhere
226 314 else (e.g. to the model).
227 315
228 316 Notes on the SQLAlchemy session
229 317 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
230 318
231 319 Each HTTP request runs inside an independent SQLAlchemy session (as well
232 320 as in an independent database transaction). ``Session`` is the session manager
233 321 and factory. ``Session()`` will create a new session on-demand or return the
234 322 current session for the active thread. Many database operations are methods on
235 323 such session instances. The session will generally be removed by
236 324 TurboGears automatically.
237 325
238 326 Database model objects
239 327 (almost) always belong to a particular SQLAlchemy session, which means
240 328 that SQLAlchemy will ensure that they're kept in sync with the database
241 329 (but also means that they cannot be shared across requests).
242 330
243 331 Objects can be added to the session using ``Session().add``, but this is
244 332 rarely needed:
245 333
246 334 * When creating a database object by calling the constructor directly,
247 335 it must explicitly be added to the session.
248 336
249 337 * When creating an object using a factory function (like
250 338 ``create_repo``), the returned object has already (by convention)
251 339 been added to the session, and should not be added again.
252 340
253 341 * When getting an object from the session (via ``Session().query`` or
254 342 any of the utility functions that look up objects in the database),
255 343 it's already part of the session, and should not be added again.
256 344 SQLAlchemy monitors attribute modifications automatically for all
257 345 objects it knows about and syncs them to the database.
258 346
259 347 SQLAlchemy also flushes changes to the database automatically; manually
260 348 calling ``Session().flush`` is usually only necessary when the Python
261 349 code needs the database to assign an "auto-increment" primary key ID to
262 350 a freshly created model object (before flushing, the ID attribute will
263 351 be ``None``).
264 352
265 353 Debugging
266 354 ^^^^^^^^^
267 355
268 356 A good way to trace what Kallithea is doing is to keep an eye on the output on
269 357 stdout/stderr of the server process. Perhaps change ``my.ini`` to log at
270 358 ``DEBUG`` or ``INFO`` level, especially ``[logger_kallithea]``, but perhaps
271 359 also other loggers. It is often easier to add additional ``log`` or ``print``
272 360 statements than to use a Python debugger.
273 361
274 362 Sometimes it is simpler to disable ``errorpage.enabled`` and perhaps also
275 363 ``trace_errors.enable`` to expose raw errors instead of adding extra
276 364 processing. Enabling ``debug`` can be helpful for showing and exploring
277 365 tracebacks in the browser, but is also insecure and will add extra processing.
278 366
279 367 TurboGears2 DebugBar
280 368 ^^^^^^^^^^^^^^^^^^^^
281 369
282 370 It is possible to enable the TurboGears2-provided DebugBar_, a toolbar overlayed
283 371 over the Kallithea web interface, allowing you to see:
284 372
285 373 * timing information of the current request, including profiling information
286 374 * request data, including GET data, POST data, cookies, headers and environment
287 375 variables
288 376 * a list of executed database queries, including timing and result values
289 377
290 378 DebugBar is only activated when ``debug = true`` is set in the configuration
291 379 file. This is important, because the DebugBar toolbar will be visible for all
292 380 users, and allow them to see information they should not be allowed to see. Like
293 381 is anyway the case for ``debug = true``, do not use this in production!
294 382
295 383 To enable DebugBar, install ``tgext.debugbar`` and ``kajiki`` (typically via
296 384 ``pip``) and restart Kallithea (in debug mode).
297 385
298 386
299 387 Thank you for your contribution!
300 388 --------------------------------
301 389
302 390
303 391 .. _Weblate: http://weblate.org/
304 392 .. _mailing list: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
305 393 .. _kallithea-general: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
306 394 .. _Hosted Weblate: https://hosted.weblate.org/projects/kallithea/kallithea/
307 395 .. _DebugBar: https://github.com/TurboGears/tgext.debugbar
308 396 .. _Quick Start: https://www.mercurial-scm.org/wiki/QuickStart
309 397 .. _Beginners Guide: https://www.mercurial-scm.org/wiki/BeginnersGuides
@@ -1,14 +1,17 b''
1 1 #!/bin/sh
2 2
3 3 # Convenience script for running various idempotent source code cleanup scripts
4 4
5 5 set -e
6 6 set -x
7 7
8 hg files 'set:!binary()&grep("^#!.*python")' 'set:**.py' | xargs scripts/deps.py
9 dot -Tsvg deps.dot > deps.svg
10
8 11 scripts/docs-headings.py
9 12 scripts/generate-ini.py
10 13 scripts/whitespacecleanup.sh
11 14 hg files 'set:!binary()&grep("^#!.*python")' 'set:**.py' | xargs scripts/source_format.py
12 15
13 16 hg files 'set:!binary()&grep("^#!.*python")' 'set:**.py' | xargs scripts/pyflakes
14 17 echo "no blocking problems found by $0"
General Comments 0
You need to be logged in to leave comments. Login now