aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSix <unknown>2010-04-10 17:05:55 -0400
committerSix <unknown>2010-04-10 17:05:55 -0400
commit418bb176021361f539fe5de13c6af0b316d8e4be (patch)
treebf2eb2bda93c523f739b7592d4d6bfd138e6641f
downloaddodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.tar.bz2
dodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.tar.xz
dodai-macsupport-418bb176021361f539fe5de13c6af0b316d8e4be.zip
Initial import of source.
-rw-r--r--.hgignore4
-rw-r--r--LICENSE570
-rw-r--r--MANIFEST.in5
-rw-r--r--README39
-rw-r--r--dodai/__init__.py100
-rw-r--r--dodai/config/__init__.py64
-rw-r--r--dodai/config/db/__init__.py179
-rw-r--r--dodai/config/db/sa.py64
-rw-r--r--dodai/config/file.py116
-rw-r--r--dodai/config/log.py150
-rw-r--r--dodai/config/option.py61
-rw-r--r--dodai/config/sections.py172
-rw-r--r--dodai/db.py30
-rw-r--r--dodai/tools/__init__.py16
-rw-r--r--dodai/tools/himo.py362
-rw-r--r--examples/config/config.cfg29
-rw-r--r--examples/config/connect29
-rw-r--r--examples/example_01.py69
-rw-r--r--examples/example_02.py57
-rw-r--r--examples/example_03.py54
-rw-r--r--pavement.py116
-rw-r--r--test/config/connection29
-rw-r--r--test/test_config/config19
-rw-r--r--test/test_config/config.cfg67
-rw-r--r--test/test_config/test_db.py106
-rw-r--r--test/test_config/test_file.py101
-rw-r--r--test/test_config/test_init.py62
-rw-r--r--test/test_config/test_log.py147
-rw-r--r--test/test_config/test_option.py53
-rw-r--r--test/test_config/test_sections.py114
-rw-r--r--test/test_dodai.py38
31 files changed, 3022 insertions, 0 deletions
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..3b3ba75
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,4 @@
1syntax: glob
2*.pyc
3*~
4*.kpf
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2a315df
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,570 @@
1GNU General Public License version 3 (GPLv3)
2
3GNU GENERAL PUBLIC LICENSE
4
5Version 3, 29 June 2007
6
7Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
8
9Everyone is permitted to copy and distribute verbatim copies of this license
10document, but changing it is not allowed.
11
12Preamble
13
14The GNU General Public License is a free, copyleft license for software and
15other kinds of works.
16
17The licenses for most software and other practical works are designed to take
18away your freedom to share and change the works. By contrast, the GNU General
19Public License is intended to guarantee your freedom to share and change all
20versions of a program--to make sure it remains free software for all its users.
21We, the Free Software Foundation, use the GNU General Public License for most
22of our software; it applies also to any other work released this way by its
23authors. You can apply it to your programs, too.
24
25When we speak of free software, we are referring to freedom, not price. Our
26General Public Licenses are designed to make sure that you have the freedom to
27distribute copies of free software (and charge for them if you wish), that you
28receive source code or can get it if you want it, that you can change the
29software or use pieces of it in new free programs, and that you know you can
30do these things.
31
32To protect your rights, we need to prevent others from denying you these
33rights or asking you to surrender the rights. Therefore, you have certain
34responsibilities if you distribute copies of the software, or if you modify it:
35responsibilities to respect the freedom of others.
36
37For example, if you distribute copies of such a program, whether gratis or for
38a fee, you must pass on to the recipients the same freedoms that you received.
39You must make sure that they, too, receive or can get the source code. And you
40must show them these terms so they know their rights.
41
42Developers that use the GNU GPL protect your rights with two steps: (1) assert
43copyright on the software, and (2) offer you this License giving you legal
44permission to copy, distribute and/or modify it.
45
46For the developers' and authors' protection, the GPL clearly explains that
47there is no warranty for this free software. For both users' and authors' sake,
48the GPL requires that modified versions be marked as changed, so that their
49problems will not be attributed erroneously to authors of previous versions.
50
51Some devices are designed to deny users access to install or run modified
52versions of the software inside them, although the manufacturer can do so.
53This is fundamentally incompatible with the aim of protecting users' freedom
54to change the software. The systematic pattern of such abuse occurs in the
55area of products for individuals to use, which is precisely where it is most
56unacceptable. Therefore, we have designed this version of the GPL to prohibit
57the practice for those products. If such problems arise substantially in other
58domains, we stand ready to extend this provision to those domains in future
59versions of the GPL, as needed to protect the freedom of users.
60
61Finally, every program is threatened constantly by software patents. States
62should not allow patents to restrict development and use of software on
63general-purpose computers, but in those that do, we wish to avoid the special
64danger that patents applied to a free program could make it effectively
65proprietary. To prevent this, the GPL assures that patents cannot be used to
66render the program non-free.
67
68The precise terms and conditions for copying, distribution and modification
69follow.
70
71TERMS AND CONDITIONS
720. Definitions.
73
74“This License” refers to version 3 of the GNU General Public License.
75
76“Copyright” also means copyright-like laws that apply to other kinds of works,
77such as semiconductor masks.
78
79“The Program” refers to any copyrightable work licensed under this License.
80Each licensee is addressed as “you”. “Licensees” and “recipients” may be
81individuals or organizations.
82
83To “modify” a work means to copy from or adapt all or part of the work in a
84fashion requiring copyright permission, other than the making of an exact copy.
85The resulting work is called a “modified version” of the earlier work or a work
86“based on” the earlier work.
87
88A “covered work” means either the unmodified Program or a work based on the
89Program.
90
91To “propagate” a work means to do anything with it that, without permission,
92would make you directly or secondarily liable for infringement under applicable
93copyright law, except executing it on a computer or modifying a private copy.
94Propagation includes copying, distribution (with or without modification),
95making available to the public, and in some countries other activities as well.
96
97To “convey” a work means any kind of propagation that enables other parties to
98make or receive copies. Mere interaction with a user through a computer
99network, with no transfer of a copy, is not conveying.
100
101An interactive user interface displays “Appropriate Legal Notices” to the
102extent that it includes a convenient and prominently visible feature that (1)
103displays an appropriate copyright notice, and (2) tells the user that there is
104no warranty for the work (except to the extent that warranties are provided),
105that licensees may convey the work under this License, and how to view a copy
106of this License. If the interface presents a list of user commands or options,
107such as a menu, a prominent item in the list meets this criterion.
108
1091. Source Code.
110
111The “source code” for a work means the preferred form of the work for making
112modifications to it. “Object code” means any non-source form of a work.
113
114A “Standard Interface” means an interface that either is an official standard
115defined by a recognized standards body, or, in the case of interfaces specified
116for a particular programming language, one that is widely used among developers
117working in that language.
118
119The “System Libraries” of an executable work include anything, other than the
120work as a whole, that (a) is included in the normal form of packaging a Major
121Component, but which is not part of that Major Component, and (b) serves only
122to enable use of the work with that Major Component, or to implement a Standard
123Interface for which an implementation is available to the public in source code
124form. A “Major Component”, in this context, means a major essential component
125(kernel, window system, and so on) of the specific operating system (if any) on
126which the executable work runs, or a compiler used to produce the work, or an
127object code interpreter used to run it.
128
129The “Corresponding Source” for a work in object code form means all the source
130code needed to generate, install, and (for an executable work) run the object
131code and to modify the work, including scripts to control those activities.
132However, it does not include the work's System Libraries, or general-purpose
133tools or generally available free programs which are used unmodified in
134performing those activities but which are not part of the work. For example,
135Corresponding Source includes interface definition files associated with source
136files for the work, and the source code for shared libraries and dynamically
137linked subprograms that the work is specifically designed to require, such as
138by intimate data communication or control flow between those subprograms and
139other parts of the work.
140
141The Corresponding Source need not include anything that users can regenerate
142automatically from other parts of the Corresponding Source.
143
144The Corresponding Source for a work in source code form is that same work.
145
1462. Basic Permissions.
147
148All rights granted under this License are granted for the term of copyright on
149the Program, and are irrevocable provided the stated conditions are met. This
150License explicitly affirms your unlimited permission to run the unmodified
151Program. The output from running a covered work is covered by this License only
152if the output, given its content, constitutes a covered work. This License
153acknowledges your rights of fair use or other equivalent, as provided by
154copyright law.
155
156You may make, run and propagate covered works that you do not convey, without
157conditions so long as your license otherwise remains in force. You may convey
158covered works to others for the sole purpose of having them make modifications
159exclusively for you, or provide you with facilities for running those works,
160provided that you comply with the terms of this License in conveying all
161material for which you do not control copyright. Those thus making or running
162the covered works for you must do so exclusively on your behalf, under your
163direction and control, on terms that prohibit them from making any copies of
164your copyrighted material outside their relationship with you.
165
166Conveying under any other circumstances is permitted solely under the
167conditions stated below. Sublicensing is not allowed; section 10 makes it
168unnecessary.
169
1703. Protecting Users' Legal Rights From Anti-Circumvention Law.
171
172No covered work shall be deemed part of an effective technological measure
173under any applicable law fulfilling obligations under article 11 of the WIPO
174copyright treaty adopted on 20 December 1996, or similar laws prohibiting or
175restricting circumvention of such measures.
176
177When you convey a covered work, you waive any legal power to forbid
178circumvention of technological measures to the extent such circumvention is
179effected by exercising rights under this License with respect to the covered
180work, and you disclaim any intention to limit operation or modification of the
181work as a means of enforcing, against the work's users, your or third parties'
182legal rights to forbid circumvention of technological measures.
183
1844. Conveying Verbatim Copies.
185
186You may convey verbatim copies of the Program's source code as you receive it,
187in any medium, provided that you conspicuously and appropriately publish on
188each copy an appropriate copyright notice; keep intact all notices stating that
189this License and any non-permissive terms added in accord with section 7 apply
190to the code; keep intact all notices of the absence of any warranty; and give
191all recipients a copy of this License along with the Program.
192
193You may charge any price or no price for each copy that you convey, and you may
194offer support or warranty protection for a fee.
195
1965. Conveying Modified Source Versions.
197
198You may convey a work based on the Program, or the modifications to produce it
199from the Program, in the form of source code under the terms of section 4,
200provided that you also meet all of these conditions:
201
202 * a) The work must carry prominent notices stating that you modified it,
203 and giving a relevant date.
204 * b) The work must carry prominent notices stating that it is released
205 under this License and any conditions added under section 7. This
206 requirement modifies the requirement in section 4 to “keep intact all
207 notices”.
208 * c) You must license the entire work, as a whole, under this License to
209 anyone who comes into possession of a copy. This License will
210 therefore apply, along with any applicable section 7 additional terms,
211 to the whole of the work, and all its parts, regardless of how they
212 are packaged. This License gives no permission to license the work in
213 any other way, but it does not invalidate such permission if you have
214 separately received it.
215 * d) If the work has interactive user interfaces, each must display
216 Appropriate Legal Notices; however, if the Program has interactive
217 interfaces that do not display Appropriate Legal Notices, your work
218 need not make them do so.
219
220A compilation of a covered work with other separate and independent works,
221which are not by their nature extensions of the covered work, and which are not
222combined with it such as to form a larger program, in or on a volume of a
223storage or distribution medium, is called an “aggregate” if the compilation and
224its resulting copyright are not used to limit the access or legal rights of the
225compilation's users beyond what the individual works permit. Inclusion of a
226covered work in an aggregate does not cause this License to apply to the other
227parts of the aggregate.
228
2296. Conveying Non-Source Forms.
230
231You may convey a covered work in object code form under the terms of sections
2324 and 5, provided that you also convey the machine-readable Corresponding
233Source under the terms of this License, in one of these ways:
234
235 * a) Convey the object code in, or embodied in, a physical product
236 (including a physical distribution medium), accompanied by the
237 Corresponding Source fixed on a durable physical medium customarily
238 used for software interchange.
239 * b) Convey the object code in, or embodied in, a physical product
240 (including a physical distribution medium), accompanied by a written
241 offer, valid for at least three years and valid for as long as you
242 offer spare parts or customer support for that product model, to give
243 anyone who possesses the object code either (1) a copy of the
244 Corresponding Source for all the software in the product that is
245 covered by this License, on a durable physical medium customarily used
246 for software interchange, for a price no more than your reasonable
247 cost of physically performing this conveying of source, or (2) access
248 to copy the Corresponding Source from a network server at no charge.
249 * c) Convey individual copies of the object code with a copy of the written
250 offer to provide the Corresponding Source. This alternative is allowed
251 only occasionally and noncommercially, and only if you received the
252 object code with such an offer, in accord with subsection 6b.
253 * d) Convey the object code by offering access from a designated place
254 (gratis or for a charge), and offer equivalent access to the
255 Corresponding Source in the same way through the same place at no
256 further charge. You need not require recipients to copy the
257 Corresponding Source along with the object code. If the place to copy
258 the object code is a network server, the Corresponding Source may be
259 on a different server (operated by you or a third party) that supports
260 equivalent copying facilities, provided you maintain clear directions
261 next to the object code saying where to find the Corresponding Source.
262 Regardless of what server hosts the Corresponding Source, you remain
263 obligated to ensure that it is available for as long as needed to
264 satisfy these requirements.
265 * e) Convey the object code using peer-to-peer transmission, provided you
266 inform other peers where the object code and Corresponding Source of
267 the work are being offered to the general public at no charge under
268 subsection 6d.
269
270A separable portion of the object code, whose source code is excluded from the
271Corresponding Source as a System Library, need not be included in conveying the
272object code work.
273
274A “User Product” is either (1) a “consumer product”, which means any tangible
275personal property which is normally used for personal, family, or household
276purposes, or (2) anything designed or sold for incorporation into a dwelling.
277In determining whether a product is a consumer product, doubtful cases shall be
278resolved in favor of coverage. For a particular product received by a
279particular user, “normally used” refers to a typical or common use of that
280class of product, regardless of the status of the particular user or of the way
281in which the particular user actually uses, or expects or is expected to use,
282the product. A product is a consumer product regardless of whether the product
283has substantial commercial, industrial or non-consumer uses, unless such uses
284represent the only significant mode of use of the product.
285
286“Installation Information” for a User Product means any methods, procedures,
287authorization keys, or other information required to install and execute
288modified versions of a covered work in that User Product from a modified
289version of its Corresponding Source. The information must suffice to ensure
290that the continued functioning of the modified object code is in no case
291prevented or interfered with solely because modification has been made.
292
293If you convey an object code work under this section in, or with, or
294specifically for use in, a User Product, and the conveying occurs as part of a
295transaction in which the right of possession and use of the User Product is
296transferred to the recipient in perpetuity or for a fixed term (regardless of
297how the transaction is characterized), the Corresponding Source conveyed under
298this section must be accompanied by the Installation Information. But this
299requirement does not apply if neither you nor any third party retains the
300ability to install modified object code on the User Product (for example, the
301work has been installed in ROM).
302
303The requirement to provide Installation Information does not include a
304requirement to continue to provide support service, warranty, or updates for a
305work that has been modified or installed by the recipient, or for the User
306Product in which it has been modified or installed. Access to a network may be
307denied when the modification itself materially and adversely affects the
308operation of the network or violates the rules and protocols for communication
309across the network.
310
311Corresponding Source conveyed, and Installation Information provided, in accord
312with this section must be in a format that is publicly documented (and with an
313implementation available to the public in source code form), and must require
314no special password or key for unpacking, reading or copying.
315
3167. Additional Terms.
317
318“Additional permissions” are terms that supplement the terms of this License by
319making exceptions from one or more of its conditions. Additional permissions
320that are applicable to the entire Program shall be treated as though they were
321included in this License, to the extent that they are valid under applicable
322law. If additional permissions apply only to part of the Program, that part may
323be used separately under those permissions, but the entire Program remains
324governed by this License without regard to the additional permissions.
325
326When you convey a copy of a covered work, you may at your option remove any
327additional permissions from that copy, or from any part of it. (Additional
328permissions may be written to require their own removal in certain cases when
329you modify the work.) You may place additional permissions on material, added
330by you to a covered work, for which you have or can give appropriate copyright
331permission.
332
333Notwithstanding any other provision of this License, for material you add to a
334covered work, you may (if authorized by the copyright holders of that material)
335supplement the terms of this License with terms:
336
337 * a) Disclaiming warranty or limiting liability differently from the terms
338 of sections 15 and 16 of this License; or
339 * b) Requiring preservation of specified reasonable legal notices or author
340 attributions in that material or in the Appropriate Legal Notices
341 displayed by works containing it; or
342 * c) Prohibiting misrepresentation of the origin of that material, or
343 requiring that modified versions of such material be marked in
344 reasonable ways as different from the original version; or
345 * d) Limiting the use for publicity purposes of names of licensors or
346 authors of the material; or
347 * e) Declining to grant rights under trademark law for use of some trade
348 names, trademarks, or service marks; or
349 * f) Requiring indemnification of licensors and authors of that material by
350 anyone who conveys the material (or modified versions of it) with
351 contractual assumptions of liability to the recipient, for any
352 liability that these contractual assumptions directly impose on those
353 licensors and authors.
354
355All other non-permissive additional terms are considered “further restrictions”
356within the meaning of section 10. If the Program as you received it, or any
357part of it, contains a notice stating that it is governed by this License along
358with a term that is a further restriction, you may remove that term. If a
359license document contains a further restriction but permits relicensing or
360conveying under this License, you may add to a covered work material governed
361by the terms of that license document, provided that the further restriction
362does not survive such relicensing or conveying.
363
364If you add terms to a covered work in accord with this section, you must place,
365in the relevant source files, a statement of the additional terms that apply to
366those files, or a notice indicating where to find the applicable terms.
367
368Additional terms, permissive or non-permissive, may be stated in the form of a
369separately written license, or stated as exceptions; the above requirements
370apply either way.
371
3728. Termination.
373
374You may not propagate or modify a covered work except as expressly provided
375under this License. Any attempt otherwise to propagate or modify it is void,
376and will automatically terminate your rights under this License (including any
377patent licenses granted under the third paragraph of section 11).
378
379However, if you cease all violation of this License, then your license from a
380particular copyright holder is reinstated (a) provisionally, unless and until
381the copyright holder explicitly and finally terminates your license, and (b)
382permanently, if the copyright holder fails to notify you of the violation by
383some reasonable means prior to 60 days after the cessation.
384
385Moreover, your license from a particular copyright holder is reinstated
386permanently if the copyright holder notifies you of the violation by some
387reasonable means, this is the first time you have received notice of violation
388of this License (for any work) from that copyright holder, and you cure the
389violation prior to 30 days after your receipt of the notice.
390
391Termination of your rights under this section does not terminate the licenses
392of parties who have received copies or rights from you under this License. If
393your rights have been terminated and not permanently reinstated, you do not
394qualify to receive new licenses for the same material under section 10.
395
3969. Acceptance Not Required for Having Copies.
397
398You are not required to accept this License in order to receive or run a copy
399of the Program. Ancillary propagation of a covered work occurring solely as a
400consequence of using peer-to-peer transmission to receive a copy likewise does
401not require acceptance. However, nothing other than this License grants you
402permission to propagate or modify any covered work. These actions infringe
403copyright if you do not accept this License. Therefore, by modifying or
404propagating a covered work, you indicate your acceptance of this License to
405do so.
406
40710. Automatic Licensing of Downstream Recipients.
408
409Each time you convey a covered work, the recipient automatically receives a
410license from the original licensors, to run, modify and propagate that work,
411subject to this License. You are not responsible for enforcing compliance by
412third parties with this License.
413
414An “entity transaction” is a transaction transferring control of an
415organization, or substantially all assets of one, or subdividing an
416organization, or merging organizations. If propagation of a covered work
417results from an entity transaction, each party to that transaction who receives
418a copy of the work also receives whatever licenses to the work the party's
419predecessor in interest had or could give under the previous paragraph, plus a
420right to possession of the Corresponding Source of the work from the
421predecessor in interest, if the predecessor has it or can get it with
422reasonable efforts.
423
424You may not impose any further restrictions on the exercise of the rights
425granted or affirmed under this License. For example, you may not impose a
426license fee, royalty, or other charge for exercise of rights granted under this
427License, and you may not initiate litigation (including a cross-claim or
428counterclaim in a lawsuit) alleging that any patent claim is infringed by
429making, using, selling, offering for sale, or importing the Program or any
430portion of it.
431
43211. Patents.
433
434A “contributor” is a copyright holder who authorizes use under this License of
435the Program or a work on which the Program is based. The work thus licensed is
436called the contributor's “contributor version”.
437
438A contributor's “essential patent claims” are all patent claims owned or
439controlled by the contributor, whether already acquired or hereafter acquired,
440that would be infringed by some manner, permitted by this License, of making,
441using, or selling its contributor version, but do not include claims that would
442be infringed only as a consequence of further modification of the contributor
443version. For purposes of this definition, “control” includes the right to grant
444patent sublicenses in a manner consistent with the requirements of this License.
445
446Each contributor grants you a non-exclusive, worldwide, royalty-free patent
447license under the contributor's essential patent claims, to make, use, sell,
448offer for sale, import and otherwise run, modify and propagate the contents of
449its contributor version.
450
451In the following three paragraphs, a “patent license” is any express agreement
452or commitment, however denominated, not to enforce a patent (such as an express
453permission to practice a patent or covenant not to sue for patent
454infringement). To “grant” such a patent license to a party means to make such
455an agreement or commitment not to enforce a patent against the party.
456
457If you convey a covered work, knowingly relying on a patent license, and the
458Corresponding Source of the work is not available for anyone to copy, free of
459charge and under the terms of this License, through a publicly available
460network server or other readily accessible means, then you must either (1)
461cause the Corresponding Source to be so available, or (2) arrange to deprive
462yourself of the benefit of the patent license for this particular work, or (3)
463arrange, in a manner consistent with the requirements of this License, to
464extend the patent license to downstream recipients. “Knowingly relying” means
465you have actual knowledge that, but for the patent license, your conveying the
466covered work in a country, or your recipient's use of the covered work in a
467country, would infringe one or more identifiable patents in that country that
468you have reason to believe are valid.
469
470If, pursuant to or in connection with a single transaction or arrangement,
471you convey, or propagate by procuring conveyance of, a covered work, and grant
472a patent license to some of the parties receiving the covered work authorizing
473them to use, propagate, modify or convey a specific copy of the covered work,
474then the patent license you grant is automatically extended to all recipients
475of the covered work and works based on it.
476
477A patent license is “discriminatory” if it does not include within the scope of
478its coverage, prohibits the exercise of, or is conditioned on the non-exercise
479of one or more of the rights that are specifically granted under this License.
480You may not convey a covered work if you are a party to an arrangement with a
481third party that is in the business of distributing software, under which you
482make payment to the third party based on the extent of your activity of
483conveying the work, and under which the third party grants, to any of the
484parties who would receive the covered work from you, a discriminatory patent
485license (a) in connection with copies of the covered work conveyed by you (or
486copies made from those copies), or (b) primarily for and in connection with
487specific products or compilations that contain the covered work, unless you
488entered into that arrangement, or that patent license was granted, prior to
48928 March 2007.
490
491Nothing in this License shall be construed as excluding or limiting any implied
492license or other defenses to infringement that may otherwise be available to
493you under applicable patent law.
494
49512. No Surrender of Others' Freedom.
496
497If conditions are imposed on you (whether by court order, agreement or
498otherwise) that contradict the conditions of this License, they do not excuse
499you from the conditions of this License. If you cannot convey a covered work so
500as to satisfy simultaneously your obligations under this License and any other
501pertinent obligations, then as a consequence you may not convey it at all. For
502example, if you agree to terms that obligate you to collect a royalty for
503further conveying from those to whom you convey the Program, the only way you
504could satisfy both those terms and this License would be to refrain entirely
505from conveying the Program.
506
50713. Use with the GNU Affero General Public License.
508
509Notwithstanding any other provision of this License, you have permission to
510link or combine any covered work with a work licensed under version 3 of the
511GNU Affero General Public License into a single combined work, and to convey
512the resulting work. The terms of this License will continue to apply to the
513part which is the covered work, but the special requirements of the GNU Affero
514General Public License, section 13, concerning interaction through a network
515will apply to the combination as such.
516
51714. Revised Versions of this License.
518
519The Free Software Foundation may publish revised and/or new versions of the GNU
520General Public License from time to time. Such new versions will be similar in
521spirit to the present version, but may differ in detail to address new problems
522or concerns.
523
524Each version is given a distinguishing version number. If the Program specifies
525that a certain numbered version of the GNU General Public License “or any later
526version” applies to it, you have the option of following the terms and
527conditions either of that numbered version or of any later version published by
528the Free Software Foundation. If the Program does not specify a version number
529of the GNU General Public License, you may choose any version ever published by
530the Free Software Foundation.
531
532If the Program specifies that a proxy can decide which future versions of the
533GNU General Public License can be used, that proxy's public statement of
534acceptance of a version permanently authorizes you to choose that version for
535the Program.
536
537Later license versions may give you additional or different permissions.
538However, no additional obligations are imposed on any author or copyright
539holder as a result of your choosing to follow a later version.
540
54115. Disclaimer of Warranty.
542
543THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE
544LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
545PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER
546EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
547MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
548QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
549DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
550CORRECTION.
551
55216. Limitation of Liability.
553
554IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY
555COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS
556PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL,
557INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
558THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
559INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE
560PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY
561HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
56217. Interpretation of Sections 15 and 16.
563
564If the disclaimer of warranty and limitation of liability provided above cannot
565be given local legal effect according to their terms, reviewing courts shall
566apply local law that most closely approximates an absolute waiver of all civil
567liability in connection with the Program, unless a warranty or assumption of
568liability accompanies a copy of the Program in return for a fee.
569
570END OF TERMS AND CONDITIONS \ No newline at end of file
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..4e3618d
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
1include setup.py
2include pavement.py
3include paver-minilib.zip
4include LICENSE
5prune test
diff --git a/README b/README
new file mode 100644
index 0000000..cc8e664
--- /dev/null
+++ b/README
@@ -0,0 +1,39 @@
1DODAI
2
3A Python module to help with writing command line scripts
4
5This module is to be a foundation to your command line python
6scripts. This module provides for quick access to logger, configparser,
7optionparse and databases via sqlalchemy.
8
9
10INSTALLATION
11------------
12
13There are three ways to install dodai
14
151. The easy_install method
16
17 easy_install dodai
18
192. To do a traditional install, download compressed file from:
20 http://code.google.com/p/dodai/downloads/list
21
22 tar zxvf dodai-*
23 cd dodai-*
24 python setup.py install
25
263. If you have Paver installed then download compressed file from
27 http://code.google.com/p/dodai/downloads/list
28
29 tar zxvf dodai-*
30 cd dodai-*
31 paver install
32
33
34The installation will also install sqlalchemy. This installation will not
35install the required system and python libs needed to get sqlalchemy to work
36with your desired database. This includes things like: cx_Oracle, psycopg2,
37pyodbc, mysql-python etc. For more information on installing these check out
38the docs at http://code.google.com/p/dodai
39
diff --git a/dodai/__init__.py b/dodai/__init__.py
new file mode 100644
index 0000000..f1e90bc
--- /dev/null
+++ b/dodai/__init__.py
@@ -0,0 +1,100 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19
20import os
21import sys
22from dodai.config import Config
23from dodai.config.db import ConfigDbFile
24
25
26class Configure(Config):
27
28 CONFIG_FILES = ['config', 'configs', 'configure', 'connect', 'connections',
29 'connection']
30
31 def __init__(self, project_name, config_files=None):
32 self.config_files = []
33 self.project_name = project_name
34 self.home_directory = self._home_directory()
35 self._default_files()
36 self._add_files(config_files)
37 self._add_config_files()
38
39 def _add_files(self, filenames):
40 if filenames:
41 if isinstance(filenames, list) or isinstance(filenames, tuple):
42 for filename in filenames:
43 self._add_file(filename)
44 else:
45 self._add_file(filenames)
46
47 def _add_file(self, filename):
48 if os.path.isfile(filename):
49 if not filename in self.config_files:
50 self.config_files.append(filename)
51
52 def _default_files(self):
53 dirs = []
54 dirs.append(self._construct_system_config_directory())
55 dirs.append(self._construct_user_config_directory())
56 dirs.append(self._construct_project_config_directory())
57 files = []
58 for dir in dirs:
59 for name in self.CONFIG_FILES:
60 files.append(os.path.join(dir, name))
61 for filename in files:
62 self._add_file(filename)
63
64 def _home_directory(self):
65 out = None
66 try:
67 from win32com.shell import shellcon, shell
68 out = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0)
69 except ImportError:
70 out = os.path.expanduser("~")
71 return out
72
73 def _construct_system_config_directory(self):
74 out = os.path.join('etc', self.project_name.lower())
75 return out
76
77 def _construct_user_config_directory(self):
78 project_directory = ".{dir}".format(dir=self.project_name.lower())
79 out = os.path.join(self.home_directory, project_directory)
80 return out
81
82 def _construct_project_config_directory(self):
83 dir = os.path.dirname(os.path.abspath(sys.argv[0]))
84 out = os.path.join(dir, 'config')
85 return out
86
87 def _add_config_files(self):
88 if self.config_files:
89 self.files().add_file(self.config_files)
90 config = self.files().parser()
91 if self._has_connections(config):
92 self.dbs().add_config(config)
93
94 def _has_connections(self, config):
95 obj = ConfigDbFile(config)
96 connections = obj()
97 if connections:
98 return True
99 else:
100 return False
diff --git a/dodai/config/__init__.py b/dodai/config/__init__.py
new file mode 100644
index 0000000..aac9be7
--- /dev/null
+++ b/dodai/config/__init__.py
@@ -0,0 +1,64 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19
20class Config(object):
21
22 def __call__(self):
23 obj = ConfigResults()
24 if hasattr(self, 'vars'):
25 for key, val in self.vars.items():
26 setattr(obj, key, val)
27 return obj
28
29 def set(self, key, val):
30 if not hasattr(self, 'vars'):
31 self.vars = {}
32 self.vars[key] = val
33
34 def options(self):
35 if not hasattr(self, '_options'):
36 from dodai.config.option import ConfigOption
37 self._options = ConfigOption()
38 return self._options
39
40 def files(self):
41 if not hasattr(self, '_files'):
42 from dodai.config.file import ConfigFile
43 self._files = ConfigFile()
44 return self._files
45
46 def logs(self):
47 if not hasattr(self, '_logs'):
48 from dodai.config.log import ConfigLog
49 self._logs = ConfigLog()
50 return self._logs
51
52 def dbs(self):
53 if not hasattr(self, '_dbs'):
54 from dodai.config.db import ConfigDb
55 self._dbs = ConfigDb()
56 return self._dbs
57
58
59
60
61
62
63class ConfigResults(object):
64 pass
diff --git a/dodai/config/db/__init__.py b/dodai/config/db/__init__.py
new file mode 100644
index 0000000..fa510ac
--- /dev/null
+++ b/dodai/config/db/__init__.py
@@ -0,0 +1,179 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18class ConfigDb(object):
19
20 def __init__(self):
21 self.connections = {}
22 self._handlers = {}
23 from dodai.config.db.sa import Sa
24 self.register_handler('sa', Sa)
25
26 def register_handler(self, name, obj):
27 self._handlers[name] = [obj, None]
28
29 def add_config(self, config_parser=None):
30 if config_parser:
31 if hasattr(config_parser, 'sections') and \
32 hasattr(config_parser, 'options'):
33 config_obj = ConfigDbFile(config_parser)
34 self._add_connections(config_obj)
35 else:
36 raise NotConfigParserObject()
37
38 def _add_connections(self, config_obj):
39 connections = config_obj()
40 for name, obj in connections.items():
41 self.connections[name] = obj
42
43 def load(self, name):
44 if name in self.connections:
45 connection = self.connections[name]
46 if connection.db_obj:
47 return connection.db_obj
48 else:
49 handler = self._load_handler(connection.handler)
50 db_obj = handler.load(connection)
51 self.connections[name].db_obj = db_obj
52 return db_obj
53
54 def _load_handler(self, name):
55 if name in self._handlers:
56 handler = self._handlers[name]
57 cls = handler[0]
58 obj = handler[1]
59 if not obj:
60 obj = cls()
61 self._handlers[name] = [cls, obj]
62 return obj
63 raise UnknownHandlerException(name)
64
65
66
67class ConfigDbFile(object):
68
69 OPTIONS_REQUIRED = [
70 ['protocol', 'hostname', 'port', 'username', 'password','database'],
71 ['protocol', 'filename']
72 ]
73 OPTIONS_EXTRA = ['protocol_extra', 'handler']
74 DEFAULT_HANDLER = 'sa'
75
76 def __init__(self, config_parser):
77 self.parser = config_parser
78 self._options = self._all_options()
79 self.connections = {}
80
81 def __call__(self):
82 if not self.connections:
83 for section in self.parser.sections():
84 if self._is_valid(section):
85 obj = self._build_connection(section)
86 self.connections[obj.name] = obj
87 return self.connections
88
89 def _all_options(self):
90 out = []
91 for option_group in self.OPTIONS_REQUIRED:
92 for option in option_group:
93 if option not in out:
94 out.append(option)
95 for option in self.OPTIONS_EXTRA:
96 if option not in out:
97 out.append(option)
98 return out
99
100 def _is_valid(self, section):
101 for option_group in self.OPTIONS_REQUIRED:
102 total = len(option_group)
103 count = 0
104 for option in option_group:
105 if option in self.parser.options(section):
106 value = self.parser.get(section, option)
107 if value:
108 count += 1
109 if count >= total:
110 return True
111 return False
112
113 def _build_connection(self, section):
114 obj = ConfigDbConnection()
115 for option in self._options:
116 obj.name = section
117 if self.parser.has_option(section, option):
118 value = self.parser.get(section, option)
119 setattr(obj, option, value)
120 if not hasattr(obj, 'handler') or not obj.handler:
121 obj.handler = self.DEFAULT_HANDLER
122 return obj
123
124
125class BaseConfigDb(object):
126
127 PROTOCOLS = ['postgresql', 'mysql', 'sqlite', 'mssql', 'oracle']
128
129 def _clean(self, obj):
130 obj.protocol = self._clean_protocol(obj.protocol)
131 if hasattr(obj, 'port'):
132 obj.port = self._clean_port(obj.port)
133
134 def _clean_protocol(self, data):
135 data = data.lower()
136 if data in ('postgres', 'postgre'):
137 data = 'postgresql'
138 if data not in self.PROTOCOLS:
139 raise InvalidProtocolException(data)
140 else:
141 return data
142
143 def _clean_port(self, data):
144 try:
145 data = int(data)
146 except ValueError:
147 data = None
148 except TypeError:
149 data = None
150 if data:
151 if data <1 or data > 65535:
152 raise InvalidPortException(data)
153 return data
154
155
156class ConfigDbConnection(object):
157
158 def __init__(self):
159 self.db_obj = None
160
161
162class NotConfigParserObject(Exception):
163 pass
164
165
166class InvalidProtocolException(Exception):
167 pass
168
169
170class InvalidPortException(Exception):
171 pass
172
173
174class UnknownHandlerException(Exception):
175 pass
176
177
178class UnknownConnectionException(Exception):
179 pass
diff --git a/dodai/config/db/sa.py b/dodai/config/db/sa.py
new file mode 100644
index 0000000..06adf9c
--- /dev/null
+++ b/dodai/config/db/sa.py
@@ -0,0 +1,64 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18from dodai.config.db import BaseConfigDb
19from dodai.db import Db
20
21class Sa(BaseConfigDb):
22
23
24 def load(self, obj):
25 from sqlalchemy.orm import sessionmaker
26 self._clean(obj)
27 db = Db()
28 db.engine = self._build_engine(obj)
29 Session = sessionmaker(bind=db.engine)
30 db.session = Session()
31 db.name = obj.name
32 db.protocol = obj.protocol
33 if hasattr(obj, 'filename') and obj.filename:
34 db.filename = obj.filename
35 else:
36 db.hostname = obj.hostname
37 if hasattr(obj, 'port') and obj.port:
38 db.port = obj.port
39 db.database = obj.database
40 return db
41
42 def _build_connection_string(self, obj):
43 out = []
44 out.append('{db.protocol}')
45 if hasattr(obj, 'protocol_extra') and obj.protocol_extra:
46 out.append('+{db.protocol_extra}')
47 out.append('://')
48 if hasattr(obj, 'filename') and obj.filename:
49 out.append('{db.filename}')
50 else:
51 out.append('{db.username}:{db.password}@')
52 out.append('{db.hostname}')
53 if hasattr(obj, 'port') and obj.port:
54 out.append(':{db.port}')
55 out.append('/{db.database}')
56 out = ''.join(out)
57 out = out.format(db=obj)
58 return out
59
60 def _build_engine(self, obj):
61 from sqlalchemy import create_engine
62 connection_string = self._build_connection_string(obj)
63 db_obj = create_engine(connection_string)
64 return db_obj
diff --git a/dodai/config/file.py b/dodai/config/file.py
new file mode 100644
index 0000000..5cab6f8
--- /dev/null
+++ b/dodai/config/file.py
@@ -0,0 +1,116 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19import os
20import ConfigParser
21
22class ConfigFile(object):
23
24 def __init__(self):
25 self._files = []
26 self._parser = None
27 self.files_loaded = []
28 self._dir = None
29
30 def set_directory(self, path):
31 """ Sets the direcory where files will be looked for
32 raises: InvalidDirectoryException or DirectoryDoesNotExistException
33 """
34 if os.path.isdir(path):
35 self._dir = path
36 else:
37 if os.path.isfile(path):
38 raise InvalidDirectoryException(path)
39 else:
40 raise DirectoryDoesNotExistException(path)
41
42 def get_directory(self):
43 """ Returns the directory where files will be looked for
44 """
45 return self._dir
46
47 def add_file(self, path):
48 """ Adds a full file path with the given path (list or string)
49 raises: FileDoesNotExistException
50 """
51 if isinstance(path, list):
52 for file_ in path:
53 self._add_file(file_)
54 else:
55 if path not in self._files:
56 self._add_file(path)
57
58 def _add_file(self, path):
59 """ Adds the given file path file to the object if the filepath
60 doesn't already exist
61 """
62 if os.path.isfile(path):
63 if path not in self._files:
64 self._files.append(path)
65 else:
66 raise FileDoesNotExistException(path)
67
68 def get_files(self):
69 """ Returns a list of files that were added to this object
70 """
71 return self._files
72
73 def parser(self):
74 """ Returns a ConfigParser.ConfigParser object with files loaded
75 raises: NoFilesToLoadException
76 """
77 self._reset_parser()
78 if not self._parser:
79 if not self._files:
80 raise NoFilesToLoadException()
81 self._parser = ConfigParser.ConfigParser()
82 self.files_loaded = self._parser.read(self._files)
83 return self._parser
84
85 def load(self, name):
86 """ Takes the given name and merges it with the object's directory
87 then adds the path to the object
88 """
89 if not self._dir:
90 raise DirectoryNotSetException()
91 else:
92 path = os.path.join(self._dir, name)
93 self.add_file(path)
94
95 def _reset_parser(self):
96 """ Resets the _parser property if the files_loaded does not equal
97 the files assigned to this object
98 """
99 if self._parser:
100 if self.files_loaded != self._files:
101 self._parser = None
102
103class NoFilesToLoadException(Exception):
104 pass
105
106class DirectoryNotSetException(Exception):
107 pass
108
109class InvalidDirectoryException(Exception):
110 pass
111
112class DirectoryDoesNotExistException(Exception):
113 pass
114
115class FileDoesNotExistException(Exception):
116 pass
diff --git a/dodai/config/log.py b/dodai/config/log.py
new file mode 100644
index 0000000..fdb5c93
--- /dev/null
+++ b/dodai/config/log.py
@@ -0,0 +1,150 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19import logging
20import logging.handlers
21import os
22
23class ConfigLog(object):
24
25 LEVELS = {
26 logging.CRITICAL: [
27 'critical',
28 "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
29 "%(message)s"],
30 logging.ERROR: [
31 'error',
32 "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
33 "%(message)s"],
34 logging.WARNING: [
35 'warning',
36 "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
37 "%(message)s"],
38 logging.INFO: [
39 'info',
40 "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
41 "%(message)s"],
42 logging.DEBUG: [
43 'debug',
44 "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
45 "%(message)s"]
46 }
47
48 MAX_BYTES = 10485760
49 BACKUP_COUNT = 5
50 FILE_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
51 STDOUT_FORMAT = "%(message)s"
52
53 def __init__(self):
54 self.log_level = logging.CRITICAL
55 self.directory = None
56 self._levels = {}
57
58 def set_log_level(self, level):
59 try:
60 level = self._fetch_log_level(level)
61 except InvalidLevelException:
62 pass
63 else:
64 self.log_level = level
65
66 def set_directory(self, directory):
67 if os.path.isdir(directory):
68 self.directory = directory
69 else:
70 raise NoDirectoryExistException(directory)
71
72 def get_file_message_format(self, level):
73 if not self._levels:
74 self._levels = self.LEVELS
75 level = self._fetch_log_level(level)
76 return self._levels[level][1]
77
78 def get_screen_message_format(self, level):
79 if not self._levels:
80 self._levels = self.LEVELS
81 level = self._fetch_log_level(level)
82 return self._levels[level][2]
83
84 def _fetch_log_level(self, level):
85 out = None
86 if isinstance(level, str):
87 level = level.strip().lower()
88 if level in self.LEVELS:
89 out = level
90 else:
91 for key, items in self.LEVELS.items():
92 if level == items[0]:
93 out = key
94 if not out:
95 raise InvalidLevelException(level)
96 else:
97 return out
98
99 def _build_filepath(self, data):
100 data = os.path.normpath(data)
101 if data.startswith(os.path.sep):
102 dir = os.path.dirname(data)
103 if not os.path.isdir(dir):
104 raise NoDirectoryExistException(dir)
105 else:
106 if not self.directory:
107 raise DirectoryNotSetException()
108 else:
109 data = os.path.join(self.directory, data)
110 return data
111
112 def load(self, name):
113 log =logging.getLogger(name)
114 log.setLevel(self.log_level)
115 return log
116
117 def attach_file_handler(self, log, filename):
118 filepath = self._build_filepath(filename)
119 handler = logging.handlers.RotatingFileHandler(
120 filepath, maxBytes = self.MAX_BYTES,
121 backupCount=self.BACKUP_COUNT)
122 file_format = self.get_file_message_format(self.log_level)
123 format_obj = logging.Formatter(file_format)
124 handler.setFormatter(format_obj)
125 handler.setLevel(self.log_level)
126 log.addHandler(handler)
127
128 def attach_screen_handler(self, log, level=None):
129 if level:
130 level = self._fetch_log_level(level)
131 else:
132 level = self.log_level
133 message_format = self.get_screen_message_format(level)
134 handler = logging.StreamHandler()
135 handler.setLevel(level)
136 format_obj = logging.Formatter(message_format)
137 handler.setFormatter(format_obj)
138 log.addHandler(handler)
139
140
141class NoDirectoryExistException(Exception):
142 pass
143
144
145class DirectoryNotSetException(Exception):
146 pass
147
148
149class InvalidLevelException(Exception):
150 pass
diff --git a/dodai/config/option.py b/dodai/config/option.py
new file mode 100644
index 0000000..0561881
--- /dev/null
+++ b/dodai/config/option.py
@@ -0,0 +1,61 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19from optparse import OptionParser
20
21class ConfigOption(object):
22
23 def __init__(self):
24
25 self.parser = OptionParser()
26 self._options = None
27 self._args = []
28
29 def get_args(self):
30 self._parse_args()
31 return self._args
32
33 def get_options(self):
34 self._parse_args()
35 return self._options
36
37 def _parse_args(self):
38 options, args = self.parser.parse_args()
39 self._options = options
40 self._args = args
41
42 def add_quiet(self):
43
44 self.parser.add_option("-q", "--quiet", dest="verbose", default=True,
45 action="store_false",
46 help="Don't print status messages to the screen")
47
48 def add_verbose(self):
49 self.parser.add_option("-v", "--verbose", dest="verbose",
50 action="store_true",
51 default=False, help="Print status messages to the screen")
52
53 def add_log_level(self, default='critical'):
54 self.parser.add_option("-l", "--log-level", dest="log_level",
55 default=default, help="Sets the log level")
56
57 def add_setup(self):
58 self.parser.add_option('', "--setup", dest="setup",
59 action="store_true", default=False,
60 help="run the setup which builds the config "\
61 "files.")
diff --git a/dodai/config/sections.py b/dodai/config/sections.py
new file mode 100644
index 0000000..feb59be
--- /dev/null
+++ b/dodai/config/sections.py
@@ -0,0 +1,172 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unicodedata
19
20class ConfigSections(object):
21 """
22 An iterable object that contains ConfigSection objects
23
24 """
25
26 def __init__(self, string_object = None):
27 """
28 Iterable object that handles the conversion of a config
29 parser object to a list of section objects.
30
31
32 string_object: This is an object (non instantiated or
33 callable) that the results of the config's
34 sections, and options will be stored in.
35 This enables you to store your values as a
36 custom object. A good object to use is the
37 dodai.tools.himo Himo object. If the
38 string_object is not given the default python
39 str() object will be used.
40
41 """
42 self._string_object = string_object or None
43 self._sections = {}
44
45 def __call__(self, parser):
46 """
47 Parses the given parser object into this object's sections.
48
49 parser: The actual parser object that is used to
50 get the sections. This object must have
51 the sections(), options() and get()
52 methods. A good object to use is the native
53 ConfigParse object. However, you can create
54 your own
55
56 """
57 self._build_sections(parser)
58
59 def _build_sections(self, parser):
60 # Builds ConfigSection objects from the parser object
61
62 for section_name in parser.sections():
63 section = self.get_section(section_name)
64 self._build_options(parser, section_name, section)
65
66 def _build_options(self, parser, section_name, section):
67 # Adds the options to the section object
68
69 for key in parser.options(section_name):
70 key = unicode(self._build_string_object(key))
71 value = self._build_string_object(parser.get(section_name, key))
72 setattr(section, key, value)
73
74 def _build_string_object(self, data):
75 if self._string_object:
76 return self._string_object(data)
77 else:
78 return data
79
80 def get_section(self, section_name):
81 """
82 Returns a ConfigSection object from this object's section
83 dictionary or creates a new ConfigSection object, which is
84 stored int this object's section dictionary then is returned
85
86 """
87 section_name = unicode(self._build_string_object(section_name))
88 if section_name in self._sections:
89 return self._sections[section_name]
90 else:
91 section = ConfigSection(section_name)
92 self._sections[section_name] = section
93 return section
94
95 def __getitem__(self, key):
96 key = normalize_key(key)
97 return self._sections[key]
98
99 def __getattr__(self, key):
100 key = normalize_key(key)
101 try:
102 out = self._sections[key]
103 except KeyError:
104 return getattr(self._sections, key)
105 else:
106 return out
107
108 def __iter__(self, *args, **kargs):
109 return self._sections.__iter__(*args, **kargs)
110
111
112 def __len__(self):
113 return len(self._sections)
114
115class ConfigSection(object):
116 """
117 A generic object to hold keys and values primarily from a config file
118
119 """
120 def __init__(self, title):
121 """
122 Holds keys and values primarily from a section of a config file
123
124 title: The title of the section of the config file
125
126 """
127 self.___title___ = title
128 self.___options___ = {}
129
130
131 def get_title(self):
132 """
133 Returns the title of the section
134
135 """
136 return self.___title___
137
138
139 def __setattr__(self, key, value):
140 if key.startswith('___') and key.endswith('___'):
141 object.__setattr__(self, key, value)
142 else:
143 key = normalize_key(key)
144 if self.___options___.has_key(key):
145 self.___options___[key] = value
146 else:
147 dict.__setitem__(self.___options___, key, value)
148
149 def __getattr__(self, key):
150 if key.startswith('___') and key.endswith('___'):
151 return self.__dict__[key]
152 else:
153 key = normalize_key(key)
154 try:
155 out = self.___options___[key]
156 except KeyError:
157 return getattr(self.___options___, key)
158 else:
159 return out
160
161 def __getitem__(self, key):
162 key = normalize_key(key)
163 return self.___options___[key]
164
165 def __iter__(self, *args, **kargs):
166 return self.___options___.__iter__(*args, **kargs)
167
168
169def normalize_key(key):
170 key = unicode(key)
171 key = unicodedata.normalize('NFC', key)
172 return key
diff --git a/dodai/db.py b/dodai/db.py
new file mode 100644
index 0000000..d65f60a
--- /dev/null
+++ b/dodai/db.py
@@ -0,0 +1,30 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Sodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19class Db(object):
20 pass
21
22 def __init__(self):
23 self.name = None
24 self.protocol = None
25 self.hostname = None
26 self.port = None
27 self.database = None
28 self.filename = None
29 self.engine = None
30 self.session = None
diff --git a/dodai/tools/__init__.py b/dodai/tools/__init__.py
new file mode 100644
index 0000000..c54f7f2
--- /dev/null
+++ b/dodai/tools/__init__.py
@@ -0,0 +1,16 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
diff --git a/dodai/tools/himo.py b/dodai/tools/himo.py
new file mode 100644
index 0000000..5a96f91
--- /dev/null
+++ b/dodai/tools/himo.py
@@ -0,0 +1,362 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import chardet
19import re
20import sys
21import unicodedata
22from htmlentitydefs import name2codepoint
23from htmlentitydefs import codepoint2name
24from decimal import Decimal as D
25
26class Himo(object):
27 """
28 A unicode-string object with some added features to help with
29 unicode decoding and output conversions.
30 """
31
32 MAP = {169:u'(C)', 174:u'(R)', 8471:u'(P)'}
33
34 def __init__(self, data, encoding=None):
35 """
36 data: Accepts any type of string object (int, float,
37 string, unicode)
38
39 encoding: Character encoding to help with converting the input
40 into unicode
41
42 The input data will be converted into an unicode object, unless
43 the input data is already an unicode object. If the param
44 'encoding' is set, the input data will be converted to unicode
45 using that value. If no 'encoding' is given this object will
46 attempt to figure out the encoding. First the encoding of the
47 operating system will be used. If there are any errors, the
48 chardet module will be used. This object makes no guarantees
49 that the correct encoding will be detected.
50
51 """
52
53 self._encoding = encoding or self._system_encoding()
54 self.data = self._decode(data)
55
56 def ascii(self):
57 """
58 Returns an ascii representation of this object value.
59 Throws HimoAsciiError if this method was unable to
60 convert a unicode character down to it's root character.
61 For example if in your string you have a character
62 like the letter 'e' but it has an accent mark over it,
63 this method will convert that character to it's root
64 character. Thus 'e' with an accent mark over it will
65 replaced with the regular letter 'e'.
66
67 """
68 out = []
69 for char in self.data:
70 if ord(char) < 127:
71 out.append(char)
72 elif ord(char) in self.MAP:
73 out.append(self.MAP[ord(char)])
74 else:
75 num = unicodedata.decomposition(char).split(' ')[0]
76 if num:
77 out.append(unichr(int(num, 16)))
78 else:
79 print char
80 raise HimoAsciiError("Unable to convert 'u{0}' "\
81 "character to ascii".format(ord(char)))
82 return str(''.join(out))
83
84 def html(self):
85 """
86 Returns a unicode string containing this object's value
87 html enetity encoded.
88 """
89 out = []
90 for char in self.data:
91 out.append(self._html_char_encode(char))
92 return ''.join(out)
93
94 def decimal(self):
95 """
96 Returns a decimal object with the value of this object
97
98 """
99
100 return D(self.data)
101
102 def _decode(self, data):
103 # Returns a unicode string. If data contains any html encoded
104 # characters, the characters will be converted to their unicode
105 # equivalent
106
107 data = self._as_unicode(data)
108 expression = re.compile(r'&(#?)(x?)(\w+);')
109 return expression.subn(self._html_decode, data)[0]
110
111 def _as_unicode(self, data):
112 # Returns string as a unicode string
113
114 if not isinstance(data, unicode):
115 if not isinstance(data, str):
116 data = str(data)
117 try:
118 data = data.decode(self._encoding)
119 except UnicodeDecodeError:
120 info = chardet.detect(data)
121 self.encoding = info['encoding']
122 data = data.decode(info['encoding'])
123 return unicodedata.normalize('NFC', data)
124
125 def _html_char_encode(self, char):
126 # Returns an html version of the char
127
128 number = ord(char)
129 try:
130 char = "&{0};".format(codepoint2name[number])
131 except KeyError:
132 if number > 127:
133 char = "&#{0};".format(number)
134 return char
135
136 def _html_decode(self, values):
137 # Returns the unicode character from the re.subn
138
139 value = values.group(3)
140 if values.group(1):
141 if values.group(2):
142 return unichr(int('0x{0}'.format(value), 16))
143 else:
144 return unichr(int(value))
145 else:
146 try:
147 char = name2codepoint[value]
148 except KeyError:
149 return values.group()
150 else:
151 return unichr(char)
152
153 def _system_encoding(self):
154 # Returns the character encoding of the system
155
156 encoding = sys.getfilesystemencoding()
157 if not encoding:
158 encoding = sys.getdefaultencoding()
159 return encoding
160
161 #def __cmp__(self, other):
162 # if self.__eq__(other):
163 # return 1
164 # else:
165 # pool = [str(self.data), str(other)]
166 # pool.sort()
167 # if pool[0] == self.data:
168 # return -1
169 # else:
170 # return 1
171
172
173 def _is_himo(self, other):
174 if hasattr(other, '_is_himo'):
175 return True
176 return False
177
178 def __len__(self):
179 return len(self.data)
180
181 def __repr__(self):
182 return repr(self.data)
183
184 def __str__(self):
185 return self.data.encode(self._encoding)
186
187 def __iter__(self):
188 for char in self.data:
189 yield char
190
191 def __int__(self):
192 return int(self.data)
193
194 def __float__(self):
195 return float(self.data)
196
197 def __eq__(self, other):
198 if self._is_himo(other):
199 other = other.data
200 return self.data.__eq__(other)
201
202 def __ne__(self, other):
203 if self._is_himo(other):
204 other = other.data
205 return self.data.__ne__(other)
206
207 def __gt__(self, other):
208 if self._is_himo(other):
209 other = other.data
210 lines = [self.data, other]
211 lines.sort()
212 if lines[0] == self.data:
213 return True
214 else:
215 return False
216
217 def __lt__(self, other):
218 if self._is_himo(other):
219 other = other.data
220 lines = [self.data, other]
221 lines.sort()
222 if lines[0] != self.data:
223 return True
224 else:
225 return False
226
227 def __cmp__(self, other):
228 if self.__eq__(other):
229 return 0
230 elif self.__lt__(other):
231 return -1
232 else:
233 return 1
234
235 def __unicode__(self):
236 return self.data
237
238 def capitalize(self, *args, **kargs):
239 return self.data.capitalize(*args, **kargs)
240
241 def center(self, *args, **kargs):
242 return self.data.center(*args, **kargs)
243
244 def count(self, *args, **kargs):
245 return self.data.count(*args, **kargs)
246
247 def decode(self, *args, **kargs):
248 return self.data.decode(*args, **kargs)
249
250 def encode(self, *args, **kargs):
251 return self.data.encode(*args, **kargs)
252
253 def encode(self, *args, **kargs):
254 return self.data.encode(*args, **kargs)
255
256 def endswith(self, *args, **kargs):
257 return self.data.endswith(*args, **kargs)
258
259 def expandtabs(self, *args, **kargs):
260 return self.data.expandtabs(*args, **kargs)
261
262 def find(self, *args, **kargs):
263 return self.data.find(*args, **kargs)
264
265 def format(self, *args, **kargs):
266 return self.data.format(*args, **kargs)
267
268 def index(self, *args, **kargs):
269 return self.data.index(*args, **kargs)
270
271 def isalnum(self, *args, **kargs):
272 return self.data.isalnum(*args, **kargs)
273
274 def isalpha(self, *args, **kargs):
275 return self.data.isalpha(*args, **kargs)
276
277 def isdecimal(self, *args, **kargs):
278 return self.data.isdecimal(*args, **kargs)
279
280 def isdigit(self, *args, **kargs):
281 return self.data.isdigit(*args, **kargs)
282
283 def islower(self, *args, **kargs):
284 return self.data.islower(*args, **kargs)
285
286 def isnumeric(self, *args, **kargs):
287 return self.data.isnumeric(*args, **kargs)
288
289 def isspace(self, *args, **kargs):
290 return self.data.isspace(*args, **kargs)
291
292 def istitle(self, *args, **kargs):
293 return self.data.istitle(*args, **kargs)
294
295 def isupper(self, *args, **kargs):
296 return self.data.isupper(*args, **kargs)
297
298 def join(self, *args, **kargs):
299 return self.data.join(*args, **kargs)
300
301 def ljust(self, *args, **kargs):
302 return self.data.ljust(*args, **kargs)
303
304 def lower(self, *args, **kargs):
305 return self.data.lower(*args, **kargs)
306
307 def lstrip(self, *args, **kargs):
308 return self.data.lstrip(*args, **kargs)
309
310 def partition(self, *args, **kargs):
311 return self.data.partition(*args, **kargs)
312
313 def replace(self, *args, **kargs):
314 return self.data.replace(*args, **kargs)
315
316 def rfind(self, *args, **kargs):
317 return self.data.rfind(*args, **kargs)
318
319 def rindex(self, *args, **kargs):
320 return self.data.rindex(*args, **kargs)
321
322 def rjust(self, *args, **kargs):
323 return self.data.rjust(*args, **kargs)
324
325 def rpartition(self, *args, **kargs):
326 return self.data.rpartition(*args, **kargs)
327
328 def rsplit(self, *args, **kargs):
329 return self.data.rsplit(*args, **kargs)
330
331 def rstrip(self, *args, **kargs):
332 return self.data.rstrip(*args, **kargs)
333
334 def split(self, *args, **kargs):
335 return self.data.split(*args, **kargs)
336
337 def splitlines(self, *args, **kargs):
338 return self.data.splitlines(*args, **kargs)
339
340 def startswith(self, *args, **kargs):
341 return self.data.startswith(*args, **kargs)
342
343 def strip(self, *args, **kargs):
344 return self.data.strip(*args, **kargs)
345
346 def swapcase(self, *args, **kargs):
347 return self.data.swapcase(*args, **kargs)
348
349 def title(self, *args, **kargs):
350 return self.data.title(*args, **kargs)
351
352 def translate(self, *args, **kargs):
353 return self.data.translate(*args, **kargs)
354
355 def upper(self, *args, **kargs):
356 return self.data.upper(*args, **kargs)
357
358 def zfill(self, *args, **kargs):
359 return self.data.zfill(*args, **kargs)
360
361class HimoAsciiError(Exception):
362 pass
diff --git a/examples/config/config.cfg b/examples/config/config.cfg
new file mode 100644
index 0000000..36b0414
--- /dev/null
+++ b/examples/config/config.cfg
@@ -0,0 +1,29 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19[title]
20foo=bar
21
22
23[test_db]
24protocol=postgresql
25hostname=127.0.0.1
26username=test
27password=test
28port=12345
29database=testing
diff --git a/examples/config/connect b/examples/config/connect
new file mode 100644
index 0000000..36b0414
--- /dev/null
+++ b/examples/config/connect
@@ -0,0 +1,29 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19[title]
20foo=bar
21
22
23[test_db]
24protocol=postgresql
25hostname=127.0.0.1
26username=test
27password=test
28port=12345
29database=testing
diff --git a/examples/example_01.py b/examples/example_01.py
new file mode 100644
index 0000000..7915e5f
--- /dev/null
+++ b/examples/example_01.py
@@ -0,0 +1,69 @@
1#!/usr/bin/env python
2# Copyright (C) 2010 Leonard Thomas
3#
4# This file is part of Dodai.
5#
6# Dodai is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Dodai is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
18
19
20##############################################################################
21# The following is for setting up the correct python path. Ignore this
22# section for your project
23import sys
24import os.path as p
25path = p.dirname(p.dirname(p.abspath(__file__)))
26sys.path.append(path)
27##############################################################################
28
29from dodai.config import Config
30
31def main(config):
32
33 config.log.debug('testing one two three')
34 config.log.critical('testing of critical')
35 print config.__dict__
36
37
38
39if __name__ == "__main__":
40
41 config = Config()
42 config.options().add_quiet()
43 config.options().add_log_level()
44 config.options().parser.add_option('-c', '--crazy', dest='crazy',
45 default=False, help="Crazy mode")
46 config.set('crazy', config.options().get_options().crazy)
47 config.set('verbose', config.options().get_options().verbose)
48
49
50 path = p.join(p.dirname(p.abspath(__file__)), 'logs')
51 config.logs().set_directory(path)
52 config.logs().set_log_level(config.options().get_options().log_level)
53 log = config.logs().load(__file__)
54 config.logs().attach_file_handler(log, 'example.log')
55 config.logs().attach_screen_handler(log, 'critical')
56 config.set('log', log)
57
58
59 path = p.join(p.dirname(p.abspath(__file__)), 'config')
60 config.files().set_directory(path)
61 config.files().load('config.cfg')
62 foo = config.files().parser().get('title', 'foo')
63 config.set('foo', foo)
64
65
66
67
68
69 main(config())
diff --git a/examples/example_02.py b/examples/example_02.py
new file mode 100644
index 0000000..2844121
--- /dev/null
+++ b/examples/example_02.py
@@ -0,0 +1,57 @@
1#!/usr/bin/env python
2# Copyright (C) 2010 Leonard Thomas
3#
4# This file is part of dodai.
5#
6# dodai is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Foobar is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with dodai. If not, see <http://www.gnu.org/licenses/>.
18
19
20##############################################################################
21# The following is for setting up the correct python path. Ignore this
22# section for your project
23import sys
24import os.path as p
25path = p.dirname(p.dirname(p.abspath(__file__)))
26sys.path.append(path)
27##############################################################################
28
29"""
30This example requires that you have sqlalchemy installed as well as the
31psycopg2 package.
32
33On ubuntu you can do:
34 apt-get install libpq-dev
35 easy_install psycopg2
36 easy_install sqlalchemy
37
38"""
39
40
41from dodai.config import Config
42
43
44def main(config):
45 print config.db.__dict__
46
47
48if __name__ == "__main__":
49
50 config = Config()
51 path = p.join(p.dirname(p.abspath(__file__)), 'config')
52 config.files().set_directory(path)
53 config.files().load('config.cfg')
54 config.dbs().add_config(config_parser=config.files().parser())
55 db = config.dbs().load('test_db')
56 config.set('db', db)
57 main(config())
diff --git a/examples/example_03.py b/examples/example_03.py
new file mode 100644
index 0000000..b94c39e
--- /dev/null
+++ b/examples/example_03.py
@@ -0,0 +1,54 @@
1#!/usr/bin/env python
2# Copyright (C) 2010 Leonard Thomas
3#
4# This file is part of dodai.
5#
6# dodai is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# Foobar is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with dodai. If not, see <http://www.gnu.org/licenses/>.
18
19
20##############################################################################
21# The following is for setting up the correct python path. Ignore this
22# section for your project
23import sys
24import os.path as p
25path = p.dirname(p.dirname(p.abspath(__file__)))
26sys.path.append(path)
27##############################################################################
28
29"""
30This example requires that you have sqlalchemy installed as well as the
31psycopg2 package.
32
33On ubuntu you can do:
34 apt-get install libpq-dev
35 easy_install psycopg2
36 easy_install sqlalchemy
37
38"""
39
40from dodai import Configure
41
42
43def main(config):
44 print config.db.engine
45 print config.db.session
46 print config.home_directory
47
48if __name__ == "__main__":
49
50 config = Configure('test')
51 db = config.dbs().load('test_db')
52 config.set('db', db)
53 config.set('home_directory', config.home_directory)
54 main(config())
diff --git a/pavement.py b/pavement.py
new file mode 100644
index 0000000..ff49926
--- /dev/null
+++ b/pavement.py
@@ -0,0 +1,116 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18PACKAGE = 'dodai'
19LICENSE='GPLv3'
20VERSION = '0.3'
21AUTHOR='Leonard Thomas'
22AUTHOR_EMAIL='six@choushi.net'
23URL='http://code.google.com/p/dodai'
24DOWNLOAD_URL = 'http://code.google.com/p/dodai/downloads/list'
25PY_VERSION_LOW = '2.6.0'
26PY_VERSION_HIGH = '3.0.0'
27PLATFORMS = ['Linux']
28SETUP_REQUIRES=['sqlalchemy']
29CLASSIFIERS = [
30 'Development Status :: 4 - Beta',
31 'Environment :: Console',
32 'Intended Audience :: Developers',
33 'License :: OSI Approved :: GNU Affero General Public License v3',
34 'Natural Language :: English',
35 'Operating System :: POSIX',
36 'Operating System :: POSIX :: Linux',
37 'Programming Language :: Python',
38 'Programming Language :: Python :: 2.6',
39 'Topic :: Database',
40 'Topic :: Software Development',
41 'Topic :: Software Development :: Libraries',
42 'Topic :: Software Development :: Libraries :: Application Frameworks',
43 'Topic :: Software Development :: Libraries :: Python Modules',]
44DESCRIPTION = 'Tools for writing python scripts'
45LONG_DESCRIPTION = "This module is to be a foundation to your command line "\
46 "python scripts. This module provides for quick access to logger, "\
47 "configparser, optionparse and databases via sqlalchemy."\
48
49
50
51import sys
52import platform
53import paver
54import paver.setuputils
55from paver.easy import options
56from paver.easy import Bunch
57from paver.easy import task
58from paver.easy import needs
59from paver.misctasks import generate_setup
60from paver.misctasks import minilib
61from setuptools import setup
62from setuptools import find_packages
63
64#from paver.easy import *
65#from paver.misctasks import generate_setup, minilib
66#from setuptools import setup, find_packages
67#import paver.setuputils
68paver.setuputils.install_distutils_tasks()
69
70options(
71 setup=Bunch(
72 name=PACKAGE,
73 version=VERSION,
74 zip_safe=False,
75 description=DESCRIPTION,
76 author=AUTHOR,
77 author_email=AUTHOR_EMAIL,
78 url=URL,
79 download_url=DOWNLOAD_URL,
80 packages=find_packages(),
81 classifiers=CLASSIFIERS,
82 long_description=LONG_DESCRIPTION,
83 license=LICENSE,
84 setup_requires=SETUP_REQUIRES,
85 install_requires=[],
86 platforms = PLATFORMS
87
88))
89
90
91def is_valid_version():
92 if sys.version >= PY_VERSION_LOW and sys.version < PY_VERSION_HIGH:
93 return True
94 else:
95 return False
96
97def is_valid_platform():
98 if platform.system() in PLATFORMS:
99 return True
100 else:
101 return False
102
103@task
104def build():
105 if not is_valid_version():
106 raise Exception('Invalid Python version')
107 if not is_valid_platform():
108 error='{0} not install on: {1}'.format(PACKAGE, platform.system())
109 raise Exception(error)
110
111
112@task
113@needs('build', 'generate_setup', 'minilib', 'setuptools.command.sdist')
114def sdist():
115 """Overrides sdist to make sure that our setup.py is generated."""
116 pass
diff --git a/test/config/connection b/test/config/connection
new file mode 100644
index 0000000..36b0414
--- /dev/null
+++ b/test/config/connection
@@ -0,0 +1,29 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18
19[title]
20foo=bar
21
22
23[test_db]
24protocol=postgresql
25hostname=127.0.0.1
26username=test
27password=test
28port=12345
29database=testing
diff --git a/test/test_config/config b/test/test_config/config
new file mode 100644
index 0000000..d3b7019
--- /dev/null
+++ b/test/test_config/config
@@ -0,0 +1,19 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18[test_section]
19foo=bar
diff --git a/test/test_config/config.cfg b/test/test_config/config.cfg
new file mode 100644
index 0000000..14764ae
--- /dev/null
+++ b/test/test_config/config.cfg
@@ -0,0 +1,67 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18[testing]
19foo=bar
20
21
22
23[test_db]
24protocol=postgresql
25hostname=127.0.0.1
26username=test
27password=test
28port=12345
29database=testing
30schema=tesuto
31
32[test_db_two]
33protocol=postgre
34protocol_extra=psycopg2
35hostname=127.0.0.1
36username=test
37password=test
38port=12345
39database=testing
40
41[test_db_three]
42protocol=postgresss
43hostname=127.0.0.1
44username=test
45password=test
46port=12345
47database=testing
48
49[test_db_four]
50protocol=postgre
51hostname=127.0.0.1
52username=test
53password=test
54port=tea
55database=testing
56
57[test_db_five]
58protocol=postgres
59hostname=127.0.0.1
60username=test
61password=test
62port=12345ad
63database=testing
64
65[test_db_six]
66protocol=sqlite
67filename=/tmp/test
diff --git a/test/test_config/test_db.py b/test/test_config/test_db.py
new file mode 100644
index 0000000..ed46eae
--- /dev/null
+++ b/test/test_config/test_db.py
@@ -0,0 +1,106 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19import os
20from dodai.config.db import ConfigDb
21from dodai.config.db import ConfigDbFile
22from dodai.config.db import BaseConfigDb
23from dodai.config.db import NotConfigParserObject
24from dodai.config.db import InvalidProtocolException
25from dodai.config.db import InvalidPortException
26from dodai.config.db import UnknownHandlerException
27from dodai.config.db import UnknownConnectionException
28from dodai.config.db.sa import Sa
29from dodai.config.file import ConfigFile
30from dodai.db import Db
31
32class TestConfigDb(unittest.TestCase):
33
34
35 def setUp(self):
36 self.config_db = ConfigDb()
37 config = ConfigFile()
38 config.set_directory(os.path.dirname(os.path.abspath(__file__)))
39 config.load('config.cfg')
40 self.parser = config.parser()
41
42 def test_setup(self):
43 obj = self.config_db._handlers['sa'][0]
44 self.assertTrue(obj == Sa)
45
46 def test_register_handler(self):
47 self.config_db.register_handler('foo', Exception)
48 self.assertTrue('foo' in self.config_db._handlers.keys())
49
50 def test_add_config_one(self):
51 self.config_db.add_config(config_parser=self.parser)
52 self.assertTrue('test_db' in self.config_db.connections.keys())
53
54 def test_add_config_two(self):
55 self.failUnlessRaises(NotConfigParserObject, self.config_db.add_config,
56 config_parser='blah')
57
58 def test_load_one(self):
59 self.config_db.add_config(config_parser=self.parser)
60 obj = self.config_db.load('test_db')
61 self.assertTrue(isinstance(obj, Db))
62
63 def test_load_two(self):
64 self.config_db.add_config(config_parser=self.parser)
65 obj = self.config_db.load('test_db')
66 obj = self.config_db.load('test_db')
67 self.assertTrue(isinstance(obj, Db))
68
69 def test_load_handler(self):
70 self.failUnlessRaises(UnknownHandlerException,
71 self.config_db._load_handler, 'test')
72
73 def test_clean_protocol_one(self):
74 self.config_db.add_config(config_parser=self.parser)
75 obj = self.config_db.load('test_db_two')
76 self.assertTrue(isinstance(obj, Db))
77
78 def test_clean_protocol_one(self):
79 self.config_db.add_config(config_parser=self.parser)
80 obj = self.config_db.load('test_db_two')
81 self.assertTrue(isinstance(obj, Db))
82
83 def test_clean_protocol_two(self):
84 self.config_db.add_config(config_parser=self.parser)
85 self.failUnlessRaises(InvalidProtocolException, self.config_db.load,
86 'test_db_three')
87
88 def test_clean_port_one(self):
89 obj = BaseConfigDb()
90 data = obj._clean_port('ad')
91 self.assertTrue(data == None)
92
93 def test_clean_port_two(self):
94 obj = BaseConfigDb()
95 data = obj._clean_port(None)
96 self.assertTrue(data == None)
97
98 def test_clean_port_three(self):
99 obj = BaseConfigDb()
100 self.failUnlessRaises(InvalidPortException, obj._clean_port, 66666)
101
102
103 def test_file_load_one(self):
104 self.config_db.add_config(config_parser=self.parser)
105 obj = self.config_db.load('test_db_six')
106 self.assertTrue(isinstance(obj, Db))
diff --git a/test/test_config/test_file.py b/test/test_config/test_file.py
new file mode 100644
index 0000000..1ed014e
--- /dev/null
+++ b/test/test_config/test_file.py
@@ -0,0 +1,101 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19import os
20from dodai.config.file import ConfigFile
21from dodai.config.file import DirectoryDoesNotExistException
22from dodai.config.file import DirectoryNotSetException
23from dodai.config.file import InvalidDirectoryException
24from dodai.config.file import FileDoesNotExistException
25from dodai.config.file import NoFilesToLoadException
26import ConfigParser
27
28class TestConfigFile(unittest.TestCase):
29
30 def setUp(self):
31 self.obj = ConfigFile()
32 self.path = os.path.dirname(__file__)
33 self.filename = 'config'
34 self.filepath = os.path.join(self.path, self.filename)
35 next_file = os.path.join(self.path, 'config.cfg')
36 self.paths = [self.filepath, next_file]
37
38 def test_file_add(self):
39 self.obj.add_file(self.filepath)
40 paths = [self.filepath]
41 files = self.obj.get_files()
42 self.assertEqual(files, paths)
43
44 def test_double_file_add(self):
45 self.obj.add_file(self.filepath)
46 self.obj.add_file(self.filepath)
47 paths = [self.filepath]
48 files = self.obj.get_files()
49 self.assertEqual(files, paths)
50
51 def test_file_does_not_exist(self):
52 path = os.path.join(self.path, 'foo')
53 self.failUnlessRaises(FileDoesNotExistException,
54 self.obj.add_file, path)
55
56 def test_multiple_file_add(self):
57 self.obj.add_file(self.paths)
58 files = self.obj.get_files()
59 self.assertEqual(files, self.paths)
60
61 def test_empty_parser(self):
62 self.failUnlessRaises(Exception, self.obj.parser)
63
64 def test_parser(self):
65 self.obj.add_file(self.filepath)
66 parser = self.obj.parser()
67 self.assertTrue(isinstance(parser, ConfigParser.ConfigParser))
68
69 def test_parser_error(self):
70 self.failUnlessRaises(NoFilesToLoadException, self.obj.parser)
71
72 def test_set_directory(self):
73 self.obj.set_directory(self.path)
74 dir = self.obj.get_directory()
75 self.assertEqual(dir, self.path)
76
77 def test_invalid_directory(self):
78 self.failUnlessRaises(InvalidDirectoryException,
79 self.obj.set_directory, self.filepath)
80
81 def test_directory_does_not_exist(self):
82 path = os.path.join(self.path, 'nowayjose')
83 self.failUnlessRaises(DirectoryDoesNotExistException,
84 self.obj.set_directory, path)
85
86 def test_load(self):
87 self.obj.set_directory(self.path)
88 self.obj.load(self.filename)
89 check = [self.filepath]
90 self.assertEqual(check, self.obj.get_files())
91
92 def test_no_directory_set(self):
93 self.failUnlessRaises(DirectoryNotSetException,
94 self.obj.load, self.filename)
95
96 def test_reset_parser(self):
97 self.obj.add_file(self.filepath)
98 self.obj.parser()
99 self.obj.add_file(self.paths)
100 self.obj.parser()
101 self.assertEqual(self.obj.files_loaded, self.obj.get_files())
diff --git a/test/test_config/test_init.py b/test/test_config/test_init.py
new file mode 100644
index 0000000..92b44c6
--- /dev/null
+++ b/test/test_config/test_init.py
@@ -0,0 +1,62 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19from dodai.config import Config
20from dodai.config.option import ConfigOption
21from dodai.config.file import ConfigFile
22from dodai.config.log import ConfigLog
23from dodai.config import ConfigResults
24from dodai.config.db import ConfigDb
25
26class TestConfig(unittest.TestCase):
27
28 def setUp(self):
29 self.obj = Config()
30
31 def test_set_one(self):
32 self.obj.set('foo', 'bar')
33 self.assertTrue('foo' in self.obj.vars.keys())
34
35 def test_set_two(self):
36 self.obj.set('foo', 'bar')
37 self.assertTrue('bar' == self.obj.vars['foo'])
38
39 def test_options(self):
40 obj = self.obj.options()
41 self.assertTrue(isinstance(obj, ConfigOption))
42
43 def test_files(self):
44 obj = self.obj.files()
45 self.assertTrue(isinstance(obj, ConfigFile))
46
47 def test_logs(self):
48 obj = self.obj.logs()
49 self.assertTrue(isinstance(obj, ConfigLog))
50
51 def test_call_one(self):
52 obj = self.obj()
53 self.assertTrue(isinstance(obj, ConfigResults))
54
55 def test_call_two(self):
56 self.obj.set('foo', 'bar')
57 obj = self.obj()
58 self.assertTrue(obj.foo == 'bar')
59
60 def test_db_one(self):
61 obj = self.obj.dbs()
62 self.assertTrue(isinstance(obj, ConfigDb))
diff --git a/test/test_config/test_log.py b/test/test_config/test_log.py
new file mode 100644
index 0000000..d3c46bc
--- /dev/null
+++ b/test/test_config/test_log.py
@@ -0,0 +1,147 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19import os
20import logging
21from logging import Logger
22from dodai.config.log import ConfigLog
23from dodai.config.log import NoDirectoryExistException
24from dodai.config.log import DirectoryNotSetException
25from dodai.config.log import InvalidLevelException
26from logging.handlers import RotatingFileHandler
27from logging import StreamHandler
28
29class TestConfigLog(unittest.TestCase):
30
31
32 def setUp(self):
33 self.obj = ConfigLog()
34 self.path = os.path.dirname(__file__)
35 self.filename = 'test_log_file'
36 self.filepath = os.path.join(self.path, self.filename)
37
38 def tearDown(self):
39 if os.path.isfile(self.filepath):
40 os.remove(self.filepath)
41
42 def test_set_log_level_one(self):
43 self.obj.set_log_level(logging.INFO)
44 self.assertTrue(self.obj.log_level == logging.INFO)
45
46 def test_set_log_level_two(self):
47 self.obj.set_log_level('wArnIng')
48 self.assertTrue(self.obj.log_level == logging.WARNING)
49
50 def test_set_log_level_three(self):
51 default = self.obj.log_level
52 self.obj.set_log_level('i08w9umY3ngas')
53 self.assertTrue(self.obj.log_level == default)
54
55 def test_fetch_log_level_one(self):
56 level = self.obj._fetch_log_level(logging.DEBUG)
57 self.assertTrue(level == logging.DEBUG)
58
59 def test_fetch_log_level_two(self):
60 level = self.obj._fetch_log_level('ErRoR')
61 self.assertTrue(level == logging.ERROR)
62
63 def test_fetch_log_level_three(self):
64 self.failUnlessRaises(InvalidLevelException,
65 self.obj._fetch_log_level,
66 'ba_ri08w9as')
67
68 def test_get_file_message_format(self):
69 default = self.obj.LEVELS[logging.DEBUG][1]
70 out = self.obj.get_file_message_format(logging.DEBUG)
71 self.assertTrue(default == out)
72
73 def test_get_screen_message_format(self):
74 default = self.obj.LEVELS[logging.WARNING][2]
75 out = self.obj.get_screen_message_format(logging.WARNING)
76 self.assertTrue(default == out)
77
78 def test_set_directory_one(self):
79 self.obj.set_directory(self.path)
80 self.assertTrue(self.obj.directory == self.path)
81
82 def test_set_directory_two(self):
83 self.failUnlessRaises(NoDirectoryExistException,
84 self.obj.set_directory,
85 __file__)
86
87 def test_load_one(self):
88 log = self.obj.load('test')
89 self.assertTrue(isinstance(log, Logger))
90
91 def test_build_filepath_one(self):
92 path = self.obj._build_filepath(self.filepath)
93 self.assertTrue(self.filepath == path)
94
95 def test_build_filepath_two(self):
96 self.obj.set_directory(self.path)
97 path = self.obj._build_filepath(self.filename)
98 self.assertTrue(self.filepath == path)
99
100 def test_build_filepath_three(self):
101 self.failUnlessRaises(NoDirectoryExistException,
102 self.obj._build_filepath,
103 os.path.join(__file__, 'blah'))
104
105 def test_build_filepath_four(self):
106 self.failUnlessRaises(DirectoryNotSetException,
107 self.obj._build_filepath,
108 self.filename)
109
110 def test_attach_file_handler(self):
111 self.obj.set_log_level(logging.WARNING)
112 self.obj.set_directory(self.path)
113 log = self.obj.load('test')
114 self.obj.attach_file_handler(log, self.filename)
115 handlers = log.handlers
116 has_stream = False
117 for handle in handlers:
118 print handle
119 if isinstance(handle, RotatingFileHandler):
120 has_stream = True
121 self.assertTrue(has_stream, 'RotatingFileHandler is missing')
122
123 def test_attach_screen_handler_one(self):
124 self.obj.set_log_level(logging.DEBUG)
125 self.obj.set_directory(self.path)
126 log = self.obj.load('testing')
127 self.obj.attach_screen_handler(log, logging.CRITICAL)
128 handlers = log.handlers
129 has_stream = False
130 for handle in handlers:
131 print handle
132 if isinstance(handle, StreamHandler):
133 has_stream = True
134 self.assertTrue(has_stream, 'StreamHandler is missing')
135
136 def test_attach_screen_handler_two(self):
137 self.obj.set_log_level(logging.DEBUG)
138 self.obj.set_directory(self.path)
139 log = self.obj.load('testing')
140 self.obj.attach_screen_handler(log)
141 handlers = log.handlers
142 has_stream = False
143 for handle in handlers:
144 print handle
145 if isinstance(handle, StreamHandler):
146 has_stream = True
147 self.assertTrue(has_stream, 'StreamHandler is missing')
diff --git a/test/test_config/test_option.py b/test/test_config/test_option.py
new file mode 100644
index 0000000..3fc9e6f
--- /dev/null
+++ b/test/test_config/test_option.py
@@ -0,0 +1,53 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19from dodai.config.option import ConfigOption
20from optparse import OptionParser
21
22class TestConfigOption(unittest.TestCase):
23
24 def setUp(self):
25 self.obj = ConfigOption()
26
27 def test_parser(self):
28 self.assertTrue(isinstance(self.obj.parser, OptionParser))
29
30 def test_add_quiet(self):
31 self.obj.add_quiet()
32 self.assertTrue(self.obj.parser.has_option('-q'))
33
34 def test_add_verbose(self):
35 self.obj.add_verbose()
36 self.assertTrue(self.obj.parser.has_option('-v'))
37
38 def test_add_log_level(self):
39 self.obj.add_log_level('critical')
40 self.assertTrue(self.obj.parser.has_option('-l'))
41
42 def test_add_setup(self):
43 self.obj.add_setup()
44 self.assertTrue(self.obj.parser.has_option('--setup'))
45
46 def test_get_args(self):
47 args = self.obj.get_args()
48 self.assertTrue(args == [])
49
50 def test_get_options(self):
51 self.obj.add_quiet()
52 options = self.obj.get_options()
53 self.assertTrue(options.verbose == True)
diff --git a/test/test_config/test_sections.py b/test/test_config/test_sections.py
new file mode 100644
index 0000000..2aba3c7
--- /dev/null
+++ b/test/test_config/test_sections.py
@@ -0,0 +1,114 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import sys
19import os
20import ConfigParser
21import unittest
22path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
23sys.path.append(path)
24from dodai.tools.himo import Himo
25from dodai.config.sections import ConfigSections
26
27
28class TestSections(unittest.TestCase):
29
30 def setUp(self):
31 path = os.path.dirname(__file__)
32 filepath = os.path.join(path, 'config.cfg')
33 self.parser = ConfigParser.ConfigParser()
34 self.parser.readfp(open(filepath))
35 self.sections = ConfigSections(Himo)
36
37 def test_call(self):
38 self.sections(self.parser)
39 count = len(self.parser.sections())
40 self.assertEqual(count, len(self.sections))
41
42 def test_iterator(self):
43 result = True
44 for section in self.sections:
45 if not section.get_title() in self.parser.sections():
46 result = False
47 self.assertTrue(result==True)
48
49 def test_get_section(self):
50 self.sections(self.parser)
51 self.sections(self.parser)
52 check = self.sections.get_section('test_db')
53 self.assertEqual(check.get_title(), 'test_db')
54
55 def test_build_string_object(self):
56 sections = ConfigSections()
57 sections(self.parser)
58 count = len(self.parser.sections())
59 self.assertEqual(count, len(sections))
60
61 def test_getitem(self):
62 self.sections(self.parser)
63 title = self.sections['test_db'].get_title()
64 self.assertEqual(title, 'test_db')
65
66 def test_getattr(self):
67 self.sections(self.parser)
68 title = self.sections.test_db.get_title()
69 self.assertEqual(title, 'test_db')
70
71 def test_get_keys(self):
72 self.sections(self.parser)
73 keys = self.sections.keys()
74 self.assertTrue(len(keys))
75
76 def test_section_object_one(self):
77 self.sections(self.parser)
78 keys = self.sections.test_db.keys()
79 self.assertTrue(len(keys))
80
81 def test_section_object_two(self):
82 self.sections(self.parser)
83 keys = self.sections.test_db.___options___.keys()
84 self.assertTrue(len(keys))
85
86 def test_section_object_three(self):
87 self.sections(self.parser)
88 self.sections.test_db.___blah___ = 'test'
89 val = self.sections.test_db.__getattr__('___blah___')
90 self.assertTrue(val == 'test')
91
92 def test_section_object_four(self):
93 self.sections(self.parser)
94 self.sections.test_db.foo = 'bar'
95 val = self.sections.test_db.__getattr__('foo')
96 self.assertTrue(val == 'bar')
97
98 def test_section_object_five(self):
99 self.sections(self.parser)
100 keys = []
101 for key in self.sections.test_db:
102 keys.append(key)
103 self.assertTrue(keys)
104
105 def test_section_object_six(self):
106 self.sections(self.parser)
107 self.sections.test_db.foo = 'bar'
108 val = self.sections.test_db['foo']
109 self.assertTrue(val == 'bar')
110
111
112
113if __name__ == '__main__':
114 unittest.main()
diff --git a/test/test_dodai.py b/test/test_dodai.py
new file mode 100644
index 0000000..a521a38
--- /dev/null
+++ b/test/test_dodai.py
@@ -0,0 +1,38 @@
1# Copyright (C) 2010 Leonard Thomas
2#
3# This file is part of Dodai.
4#
5# Dodai is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# Dodai is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with Dodai. If not, see <http://www.gnu.org/licenses/>.
17
18import unittest
19import os
20from dodai import Configure
21
22class TestConfigure(unittest.TestCase):
23
24 def setUp(self):
25 path = os.path.dirname(os.path.abspath(__file__))
26 path = os.path.join(path, 'config')
27 filename = os.path.join(path, 'connection')
28 self.filename = filename
29 self.obj = Configure('test', config_files=[filename])
30
31 def test_results(self):
32 files = self.obj.config_files
33 self.assertTrue(len(files) == 1)
34
35 def test_add_files(self):
36 self.obj._add_files(self.filename)
37 files = self.obj.config_files
38 self.assertTrue(len(files) == 1)