From 4c4d664c2e881e1865e4fa2dee9776e643b11e30 Mon Sep 17 00:00:00 2001 From: gwen Date: Thu, 29 Aug 2013 15:55:06 +0200 Subject: [PATCH 01/42] tiramisu placed under the lgpl licence --- COPYING | 4 +- doc/doctest.txt | 6 - doc/index.txt | 7 +- gpl-3.0.txt | 674 ------------------------------------------------ lgpl-3.0.txt | 165 ++++++++++++ 5 files changed, 173 insertions(+), 683 deletions(-) delete mode 100644 gpl-3.0.txt create mode 100644 lgpl-3.0.txt diff --git a/COPYING b/COPYING index 58ed914..1db1c0c 100644 --- a/COPYING +++ b/COPYING @@ -1,8 +1,8 @@ -Tiramisu is placed under the terms of the GNU General Public License v3.0 as +Tiramisu is placed under the terms of the GNU LESSER GENERAL PUBLIC LICENSE V3 as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. -See gpl-3.0.txt for more informations. +See lgpl-3.0.txt for more informations. The documentation is licenced under the terms of a Creative Commons Attribution-ShareAlike 3.0 Unported License. diff --git a/doc/doctest.txt b/doc/doctest.txt index be73752..803260e 100644 --- a/doc/doctest.txt +++ b/doc/doctest.txt @@ -38,18 +38,12 @@ others .. automodule:: test.test_option_consistency :members: -.. automodule:: test.test_option - :members: - .. automodule:: test.test_cache :members: .. automodule:: test.test_option_setting :members: -.. automodule:: test.test_config - :members: - .. automodule:: test.test_freeze :members: diff --git a/doc/index.txt b/doc/index.txt index 41c2ce3..561c047 100644 --- a/doc/index.txt +++ b/doc/index.txt @@ -48,9 +48,14 @@ Indices and tables * :ref:`modindex` * :ref:`search` -.. note:: This documentation is licensed under a `Creative Commons +.. note:: The tiramisu code is licensed under the `LGPL licence`_ + and this documentation is licensed under the `Creative Commons Attribution-ShareAlike 3.0 Unported License`_\ . + + .. _`Creative Commons Attribution-ShareAlike 3.0 Unported License`: http://creativecommons.org/licenses/by-sa/3.0/deed.en_US +.. _`LGPL licence`: http://www.gnu.org/licenses/lgpl.html + .. todolist:: diff --git a/gpl-3.0.txt b/gpl-3.0.txt deleted file mode 100644 index 818433e..0000000 --- a/gpl-3.0.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/lgpl-3.0.txt b/lgpl-3.0.txt new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/lgpl-3.0.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. From 4d6d8bf20113d22926b2bd740d14e48d6906481c Mon Sep 17 00:00:00 2001 From: gwen Date: Thu, 29 Aug 2013 16:38:23 +0200 Subject: [PATCH 02/42] version for setup.py --- setup.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1ca3915..2b57b1c 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- from distutils.core import setup +from os.path import dirname, abspath, join, normpath, isdir, basename +from os import listdir import os import subprocess @@ -26,6 +28,19 @@ def fetch_version(): return version +def return_storages(): + "returns all the storage plugins that are living in tiramisu/storage" + here = dirname(abspath(__file__)) + storages_path = normpath(join(here, 'tiramisu', 'storage')) + dir_content = [ content for content in listdir(storages_path) \ + if not content =='__pycache__'] + storages = filter(isdir, [join(storages_path, content) \ + for content in dir_content]) + storage_list = [basename(storage) for storage in storages] + return storage_list + +packages = ['tiramisu', 'tiramisu.storage'] +packages.extend(return_storages()) setup( author='cadoles team', @@ -34,5 +49,5 @@ setup( version=fetch_version(), description='configuration management tool', url='http://labs.libre-entreprise.org/projects/tiramisu', - packages=['tiramisu'] + packages=packages ) From 8a7078d3b0397f150903fdf0b262d9176c9a5e43 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 22 Sep 2013 22:33:09 +0200 Subject: [PATCH 03/42] gpl to lgpl --- tiramisu/__init__.py | 14 ++++++++++++++ tiramisu/autolib.py | 21 ++++++++++----------- tiramisu/config.py | 21 ++++++++++----------- tiramisu/error.py | 25 ++++++++++--------------- tiramisu/i18n.py | 19 ++++++++++++++++++- tiramisu/option.py | 21 ++++++++++----------- tiramisu/setting.py | 25 ++++++++++--------------- tiramisu/storage/__init__.py | 25 ++++++++++--------------- tiramisu/storage/dictionary/__init__.py | 22 ++++++++++------------ tiramisu/storage/dictionary/setting.py | 22 ++++++++++------------ tiramisu/storage/dictionary/storage.py | 22 ++++++++++------------ tiramisu/storage/dictionary/value.py | 22 ++++++++++------------ tiramisu/storage/sqlite3/__init__.py | 22 ++++++++++------------ tiramisu/storage/sqlite3/setting.py | 22 ++++++++++------------ tiramisu/storage/sqlite3/sqlite3db.py | 22 ++++++++++------------ tiramisu/storage/sqlite3/storage.py | 22 ++++++++++------------ tiramisu/storage/sqlite3/value.py | 22 ++++++++++------------ tiramisu/storage/util.py | 22 ++++++++++------------ tiramisu/value.py | 22 ++++++++++------------ 19 files changed, 202 insertions(+), 211 deletions(-) diff --git a/tiramisu/__init__.py b/tiramisu/__init__.py index e69de29..f5f3f32 100644 --- a/tiramisu/__init__.py +++ b/tiramisu/__init__.py @@ -0,0 +1,14 @@ +# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index de8a8c5..20d693c 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -1,18 +1,17 @@ # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # # The original `Config` design model is unproudly borrowed from # the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/ diff --git a/tiramisu/config.py b/tiramisu/config.py index f1b2851..02c6f74 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -2,19 +2,18 @@ "options handler global entry point" # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # # The original `Config` design model is unproudly borrowed from # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ diff --git a/tiramisu/error.py b/tiramisu/error.py index 6c92be3..e4e5991 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -1,23 +1,18 @@ # -*- coding: utf-8 -*- # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# The original `Config` design model is unproudly borrowed from -# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ -# the whole pypy projet is under MIT licence +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ "user defined exceptions" diff --git a/tiramisu/i18n.py b/tiramisu/i18n.py index a1fd01a..0223ccf 100644 --- a/tiramisu/i18n.py +++ b/tiramisu/i18n.py @@ -1,5 +1,22 @@ -#!/usr/bin/env python # -*- coding: UTF-8 -*- +# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence "internationalisation utilities" import gettext import os diff --git a/tiramisu/option.py b/tiramisu/option.py index 10aba5c..64d3f7e 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -2,19 +2,18 @@ "option types and option description" # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # # The original `Config` design model is unproudly borrowed from # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 684ec74..bea7b7a 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -2,23 +2,18 @@ "sets the options of the configuration objects Config object itself" # Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# The original `Config` design model is unproudly borrowed from -# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ -# the whole pypy projet is under MIT licence +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from time import time from copy import copy diff --git a/tiramisu/storage/__init__.py b/tiramisu/storage/__init__.py index c232472..e9a1b1a 100644 --- a/tiramisu/storage/__init__.py +++ b/tiramisu/storage/__init__.py @@ -1,22 +1,17 @@ # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# The original `Config` design model is unproudly borrowed from -# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/ -# the whole pypy projet is under MIT licence +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ """Config's informations are, by default, volatiles. This means, all values and diff --git a/tiramisu/storage/dictionary/__init__.py b/tiramisu/storage/dictionary/__init__.py index bc81450..0264b23 100644 --- a/tiramisu/storage/dictionary/__init__.py +++ b/tiramisu/storage/dictionary/__init__.py @@ -1,20 +1,18 @@ # -*- coding: utf-8 -*- # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ """Default plugin for storage. All informations are store in a simple dictionary in memory. diff --git a/tiramisu/storage/dictionary/setting.py b/tiramisu/storage/dictionary/setting.py index 1b7001b..73758f4 100644 --- a/tiramisu/storage/dictionary/setting.py +++ b/tiramisu/storage/dictionary/setting.py @@ -2,20 +2,18 @@ "default plugin for setting: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from ..util import Cache diff --git a/tiramisu/storage/dictionary/storage.py b/tiramisu/storage/dictionary/storage.py index 465fe26..702ded4 100644 --- a/tiramisu/storage/dictionary/storage.py +++ b/tiramisu/storage/dictionary/storage.py @@ -1,20 +1,18 @@ # -*- coding: utf-8 -*- # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from tiramisu.i18n import _ from tiramisu.error import ConfigError diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index fedf1ec..bf3196c 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -2,20 +2,18 @@ "default plugin for value: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from ..util import Cache diff --git a/tiramisu/storage/sqlite3/__init__.py b/tiramisu/storage/sqlite3/__init__.py index 8d79070..4f9754b 100644 --- a/tiramisu/storage/sqlite3/__init__.py +++ b/tiramisu/storage/sqlite3/__init__.py @@ -1,20 +1,18 @@ # -*- coding: utf-8 -*- # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ """Sqlite3 plugin for storage. This storage is not made to be used in productive environment. It was developing as proof of concept. diff --git a/tiramisu/storage/sqlite3/setting.py b/tiramisu/storage/sqlite3/setting.py index ed79181..0b71dd2 100644 --- a/tiramisu/storage/sqlite3/setting.py +++ b/tiramisu/storage/sqlite3/setting.py @@ -2,20 +2,18 @@ "default plugin for setting: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from .sqlite3db import Sqlite3DB diff --git a/tiramisu/storage/sqlite3/sqlite3db.py b/tiramisu/storage/sqlite3/sqlite3db.py index 68f2886..2b33117 100644 --- a/tiramisu/storage/sqlite3/sqlite3db.py +++ b/tiramisu/storage/sqlite3/sqlite3db.py @@ -2,20 +2,18 @@ "sqlite3 cache" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ try: from cPickle import loads, dumps diff --git a/tiramisu/storage/sqlite3/storage.py b/tiramisu/storage/sqlite3/storage.py index 3b4f265..b441466 100644 --- a/tiramisu/storage/sqlite3/storage.py +++ b/tiramisu/storage/sqlite3/storage.py @@ -2,20 +2,18 @@ "default plugin for cache: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from os import unlink diff --git a/tiramisu/storage/sqlite3/value.py b/tiramisu/storage/sqlite3/value.py index 672ecab..eaa434f 100644 --- a/tiramisu/storage/sqlite3/value.py +++ b/tiramisu/storage/sqlite3/value.py @@ -2,20 +2,18 @@ "default plugin for value: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from .sqlite3db import Sqlite3DB diff --git a/tiramisu/storage/util.py b/tiramisu/storage/util.py index 68482e6..ff7232d 100644 --- a/tiramisu/storage/util.py +++ b/tiramisu/storage/util.py @@ -2,20 +2,18 @@ "default plugin for cache: set it in a simple dictionary" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from tiramisu.setting import owners diff --git a/tiramisu/value.py b/tiramisu/value.py index d587de1..f1833fb 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -2,20 +2,18 @@ "takes care of the option's values and multi values" # Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors) # -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. # +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . # ____________________________________________________________ from time import time from copy import copy From ead8db435699a6ac57e36b73b99b34fc1c03b192 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 28 Sep 2013 20:02:41 +0200 Subject: [PATCH 04/42] update translation --- translations/fr/tiramisu.po | 246 +++++++++++++++++++++--------------- translations/tiramisu.pot | 230 ++++++++++++++++++--------------- 2 files changed, 273 insertions(+), 203 deletions(-) diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 0075059..256a0da 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-09-26 22:33+CEST\n" +"POT-Creation-Date: 2013-09-28 19:06+CEST\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: LANGUAGE \n" @@ -11,14 +11,14 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.4\n" -#: tiramisu/autolib.py:145 +#: tiramisu/autolib.py:144 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" "impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : " "{2}" -#: tiramisu/autolib.py:154 +#: tiramisu/autolib.py:153 msgid "" "unable to carry out a calculation, option value with multi types must have " "same length for: {0}" @@ -26,80 +26,80 @@ msgstr "" "impossible d'effectuer le calcul, la valeur d'une option avec le type multi " "doit avoir la même longueur pour : {0}" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "descr doit être une optiondescription pas un {0}" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" -#: tiramisu/config.py:163 +#: tiramisu/config.py:162 msgid "" "no option description found for this config (may be metaconfig without meta)" msgstr "" "pas d'option description trouvé pour cette config (peut être une metaconfig " "sans meta)" -#: tiramisu/config.py:189 +#: tiramisu/config.py:188 msgid "can't assign to an OptionDescription" msgstr "ne peut pas attribuer une valeur à une OptionDescription" -#: tiramisu/config.py:320 +#: tiramisu/config.py:319 msgid "unknown type_ type {0}for _find" msgstr "type_ type {0} pour _find inconnu" -#: tiramisu/config.py:359 +#: tiramisu/config.py:358 msgid "no option found in config with these criteria" msgstr "aucune option trouvée dans la config avec ces critères" -#: tiramisu/config.py:409 +#: tiramisu/config.py:408 msgid "make_dict can't filtering with value without option" msgstr "make_dict ne peut filtrer sur une valeur mais sans option" -#: tiramisu/config.py:430 +#: tiramisu/config.py:429 msgid "unexpected path {0}, should start with {1}" msgstr "chemin imprévu {0}, devrait commencer par {1}" -#: tiramisu/config.py:490 +#: tiramisu/config.py:489 msgid "opt in getowner must be an option not {0}" msgstr "opt dans getowner doit être une option pas {0}" -#: tiramisu/option.py:70 +#: tiramisu/option.py:68 msgid "invalid name: {0} for option" msgstr "nom invalide : {0} pour l'option" -#: tiramisu/option.py:80 +#: tiramisu/option.py:77 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "type des properties invalide {0} pour {1}, doit être un tuple" -#: tiramisu/option.py:122 +#: tiramisu/option.py:115 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" -#: tiramisu/option.py:149 tiramisu/value.py:362 +#: tiramisu/option.py:142 tiramisu/value.py:360 msgid "information's item not found: {0}" msgstr "aucune config spécifié alors que c'est nécessaire" -#: tiramisu/option.py:266 +#: tiramisu/option.py:204 msgid "cannot serialize Option, only in OptionDescription" msgstr "ne peut serialiser une Option, seulement via une OptionDescription" -#: tiramisu/option.py:367 +#: tiramisu/option.py:307 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" "une default_multi est renseignée alors que multi est False dans l'option : " "{0}" -#: tiramisu/option.py:373 +#: tiramisu/option.py:313 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "la valeur default_multi est invalide {0} pour l'option {1} : {2}" -#: tiramisu/option.py:378 +#: tiramisu/option.py:318 msgid "default value not allowed if option: {0} is calculated" msgstr "la valeur par défaut n'est pas possible si l'option {0} est calculée" -#: tiramisu/option.py:381 +#: tiramisu/option.py:321 msgid "" "params defined for a callback function but no callback defined yet for " "option {0}" @@ -107,52 +107,68 @@ msgstr "" "params définis pour une fonction callback mais par de callback encore " "définis pour l'option {0}" -#: tiramisu/option.py:486 tiramisu/value.py:547 +#: tiramisu/option.py:360 +msgid "option not in all_cons_opts" +msgstr "option non présentante dans all_cons_opts" + +#: tiramisu/option.py:432 tiramisu/value.py:545 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/option.py:506 -msgid "invalid value {0} for option {1} which must be a list" -msgstr "valeur invalide {0} pour l'option {1} qui doit être une liste" +#: tiramisu/option.py:449 +msgid "which must be a list" +msgstr "lequel doit être une liste" -#: tiramisu/option.py:577 -msgid "invalid value {0} for option {1} must be different as {2} option" +#: tiramisu/option.py:509 +msgid "consistency should be set with an option" +msgstr "consistency doit être configuré avec une option" + +#: tiramisu/option.py:511 +msgid "cannot add consistency with itself" +msgstr "ne peut ajouter une consistency avec lui même" + +#: tiramisu/option.py:513 +msgid "every options in consistency should be multi or none" msgstr "" -"valeur invalide {0} pour l'option {1} doit être différente de l'option {2}" +"toutes les options d'une consistency devrait être multi ou ne pas l'être" -#: tiramisu/option.py:636 +#: tiramisu/option.py:533 +msgid "same value for {0} and {1}" +msgstr "même valeur pour {0} et {1}" + +#: tiramisu/option.py:642 msgid "values must be a tuple for {0}" msgstr "values doit être un tuple pour {0}" -#: tiramisu/option.py:639 +#: tiramisu/option.py:645 msgid "open_values must be a boolean for {0}" msgstr "open_values doit être un booléen pour {0}" -#: tiramisu/option.py:661 +#: tiramisu/option.py:667 msgid "value {0} is not permitted, only {1} is allowed" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" -#: tiramisu/option.py:673 +#: tiramisu/option.py:679 msgid "value must be a boolean" msgstr "valeur doit être un booléen" -#: tiramisu/option.py:683 +#: tiramisu/option.py:689 msgid "value must be an integer" msgstr "valeur doit être un nombre entier" -#: tiramisu/option.py:693 +#: tiramisu/option.py:699 msgid "value must be a float" msgstr "valeur doit être un nombre flottant" -#: tiramisu/option.py:703 +#: tiramisu/option.py:709 msgid "value must be a string, not {0}" msgstr "valeur doit être une chaîne, pas {0}" -#: tiramisu/option.py:721 +#: tiramisu/option.py:727 msgid "value must be an unicode" msgstr "valeur doit être une valeur unicode" -#: tiramisu/option.py:733 +#: tiramisu/option.py:739 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" @@ -188,106 +204,124 @@ msgstr "le réseau ne doit pas être dans la classe reservée" msgid "invalid netmask address {0}" msgstr "masque de sous-réseau invalide {0}" -#: tiramisu/option.py:916 +#: tiramisu/option.py:910 +msgid "invalid len for opts" +msgstr "longueur invalide pour opts" + +#: tiramisu/option.py:922 msgid "invalid network {0} ({1}) with netmask {2} ({3}), this network is an IP" msgstr "réseau invalide {0} ({1}) avec masque {2} ({3}), ce réseau est une IP" -#: tiramisu/option.py:921 +#: tiramisu/option.py:927 msgid "invalid IP {0} ({1}) with netmask {2} ({3}), this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2} ({3}), cette IP est un réseau" -#: tiramisu/option.py:926 +#: tiramisu/option.py:932 msgid "invalid IP {0} ({1}) with netmask {2} ({3})" msgstr "IP invalide {0} ({1}) avec masque {2} ({3})" -#: tiramisu/option.py:928 +#: tiramisu/option.py:934 msgid "invalid network {0} ({1}) with netmask {2} ({3})" msgstr "réseau invalide {0} ({1}) avec masque {2} ({3})" -#: tiramisu/option.py:939 +#: tiramisu/option.py:948 msgid "invalid broadcast address {0}" msgstr "adresse de broadcast invalide {0}" +#: tiramisu/option.py:952 +msgid "invalid len for vals" +msgstr "longueur invalide pour vals" + #: tiramisu/option.py:957 +msgid "" +"invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" +msgstr "" +"Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" + +#: tiramisu/option.py:979 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:960 +#: tiramisu/option.py:982 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:990 +#: tiramisu/option.py:1012 msgid "invalid value for {0}, must have dot" msgstr "valeur invalide pour {0}, doit avoir un point" -#: tiramisu/option.py:993 +#: tiramisu/option.py:1015 msgid "invalid domainname's length for {0} (max {1})" msgstr "longueur du nom de domaine invalide pour {0} (maximum {1})" -#: tiramisu/option.py:996 +#: tiramisu/option.py:1018 msgid "invalid domainname's length for {0} (min 2)" msgstr "longueur du nom de domaine invalide pour {0} (minimum 2)" -#: tiramisu/option.py:1000 +#: tiramisu/option.py:1022 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1027 +#: tiramisu/option.py:1049 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1044 +#: tiramisu/option.py:1067 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1095 +#: tiramisu/option.py:1118 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1129 +#: tiramisu/option.py:1148 +msgid "consistency with option {0} which is not in Config" +msgstr "consistency avec l'option {0} qui n'est pas dans une Config" + +#: tiramisu/option.py:1156 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1135 +#: tiramisu/option.py:1162 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1145 +#: tiramisu/option.py:1172 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1158 +#: tiramisu/option.py:1185 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1161 +#: tiramisu/option.py:1188 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1164 +#: tiramisu/option.py:1191 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1202 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1184 +#: tiramisu/option.py:1211 msgid "no child has same nom has master group for: {0}" msgstr "pas d'enfant avec le nom du groupe maître pour {0} " -#: tiramisu/option.py:1187 +#: tiramisu/option.py:1214 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" -#: tiramisu/option.py:1277 +#: tiramisu/option.py:1306 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" "type requirements malformé pour l'option : {0}, doit être un dictionnaire" -#: tiramisu/option.py:1294 +#: tiramisu/option.py:1323 msgid "" "malformed requirements for option: {0} require must have option, expected " "and action keys" @@ -295,110 +329,110 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1328 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1303 +#: tiramisu/option.py:1332 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1307 +#: tiramisu/option.py:1336 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1340 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1343 msgid "malformed requirements option {0} should not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1320 +#: tiramisu/option.py:1349 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1325 +#: tiramisu/option.py:1354 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1350 +#: tiramisu/option.py:1379 msgid "{0} should be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1353 +#: tiramisu/option.py:1382 msgid "{0}_params should be a dict" msgstr "{0}_params devrait être un dict" -#: tiramisu/option.py:1356 +#: tiramisu/option.py:1385 msgid "{0}_params with key {1} should not have length different to 1" msgstr "" "{0}_params avec la clef {1} devrait ne pas avoir une longueur différent de 1" -#: tiramisu/option.py:1360 +#: tiramisu/option.py:1389 msgid "{0}_params should be tuple for key \"{1}\"" msgstr "{0}_params devrait être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1366 +#: tiramisu/option.py:1395 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1369 +#: tiramisu/option.py:1398 msgid "{0}_params should have an option not a {0} for first argument" msgstr "{0}_params devrait avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1373 +#: tiramisu/option.py:1402 msgid "{0}_params should have a boolean not a {0} for second argument" msgstr "{0}_params devrait avoir un boolean pas un {0} pour second argument" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "ne peut redéfinir ({0})" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "ne peut supprimer ({0})" -#: tiramisu/setting.py:259 +#: tiramisu/setting.py:254 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" "ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est " "calculée" -#: tiramisu/setting.py:322 +#: tiramisu/setting.py:317 msgid "opt and all_properties must not be set together in reset" msgstr "opt et all_properties ne doit pas être renseigné ensemble dans reset" -#: tiramisu/setting.py:337 +#: tiramisu/setting.py:332 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" "si opt n'est pas None, path devrait ne pas être à None dans _getproperties" -#: tiramisu/setting.py:440 +#: tiramisu/setting.py:435 msgid "cannot change the value for option {0} this option is frozen" msgstr "" "ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" -#: tiramisu/setting.py:446 +#: tiramisu/setting.py:441 msgid "trying to access to an option named: {0} with properties {1}" msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}" -#: tiramisu/setting.py:464 +#: tiramisu/setting.py:459 msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:471 tiramisu/value.py:301 +#: tiramisu/setting.py:466 tiramisu/value.py:299 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" -#: tiramisu/setting.py:558 +#: tiramisu/setting.py:553 msgid "" "malformed requirements imbrication detected for option: '{0}' with " "requirement on: '{1}'" @@ -406,73 +440,80 @@ msgstr "" "imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "requirement sur : '{1}'" -#: tiramisu/setting.py:570 +#: tiramisu/setting.py:565 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "storage_type est déjà défini, impossible de le redéfinir" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "option {0} n'existe pas dans l'espace de stockage {1}" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" "impossible de supprimer une session dans un espace de stockage dictionary" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "session déjà utilisée" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "un espace de stockage dictionary ne peut être persistant" -#: tiramisu/value.py:308 +#: tiramisu/value.py:306 msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:416 +#: tiramisu/value.py:414 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:440 +#: tiramisu/value.py:438 msgid "invalid len for the master: {0} which has {1} as slave with greater len" msgstr "" "longueur invalide pour un maître : {0} qui a {1} une esclave avec une plus " "grande longueur" -#: tiramisu/value.py:470 +#: tiramisu/value.py:468 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:507 +#: tiramisu/value.py:505 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:511 +#: tiramisu/value.py:509 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:520 +#: tiramisu/value.py:518 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:528 +#: tiramisu/value.py:526 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:536 +#: tiramisu/value.py:534 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:564 +#: tiramisu/value.py:562 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" +#~ msgid "invalid value {0} for option {1} which must be a list" +#~ msgstr "valeur invalide {0} pour l'option {1} qui doit être une liste" + +#~ msgid "invalid value {0} for option {1} must be different as {2} option" +#~ msgstr "" +#~ "valeur invalide {0} pour l'option {1} doit être différente de l'option {2}" + #~ msgid "validator should return a boolean, not {0}" #~ msgstr "le validator devrait retourner un boolean, pas un {0}" @@ -491,9 +532,6 @@ msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" #~ msgid "invalid name: {0} for optiondescription" #~ msgstr "nom invalide : {0} pour l'optiondescription" -#~ msgid "metaconfig's children must be a list" -#~ msgstr "enfants d'une metaconfig doit être une liste" - #~ msgid "metaconfig's children must be config, not {0}" #~ msgstr "enfants d'une metaconfig doit être une config, pas {0}" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index dfd4b86..57b90e8 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2013-09-26 22:33+CEST\n" +"POT-Creation-Date: 2013-09-28 19:06+CEST\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,131 +15,147 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:145 +#: tiramisu/autolib.py:144 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" -#: tiramisu/autolib.py:154 +#: tiramisu/autolib.py:153 msgid "unable to carry out a calculation, option value with multi types must have same length for: {0}" msgstr "" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "" -#: tiramisu/config.py:163 +#: tiramisu/config.py:162 msgid "no option description found for this config (may be metaconfig without meta)" msgstr "" -#: tiramisu/config.py:189 +#: tiramisu/config.py:188 msgid "can't assign to an OptionDescription" msgstr "" -#: tiramisu/config.py:320 +#: tiramisu/config.py:319 msgid "unknown type_ type {0}for _find" msgstr "" -#: tiramisu/config.py:359 +#: tiramisu/config.py:358 msgid "no option found in config with these criteria" msgstr "" -#: tiramisu/config.py:409 +#: tiramisu/config.py:408 msgid "make_dict can't filtering with value without option" msgstr "" -#: tiramisu/config.py:430 +#: tiramisu/config.py:429 msgid "unexpected path {0}, should start with {1}" msgstr "" -#: tiramisu/config.py:490 +#: tiramisu/config.py:489 msgid "opt in getowner must be an option not {0}" msgstr "" -#: tiramisu/option.py:70 +#: tiramisu/option.py:68 msgid "invalid name: {0} for option" msgstr "" -#: tiramisu/option.py:80 +#: tiramisu/option.py:77 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "" -#: tiramisu/option.py:122 +#: tiramisu/option.py:115 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "" -#: tiramisu/option.py:149 tiramisu/value.py:362 +#: tiramisu/option.py:142 tiramisu/value.py:360 msgid "information's item not found: {0}" msgstr "" -#: tiramisu/option.py:266 +#: tiramisu/option.py:204 msgid "cannot serialize Option, only in OptionDescription" msgstr "" -#: tiramisu/option.py:367 +#: tiramisu/option.py:307 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" -#: tiramisu/option.py:373 +#: tiramisu/option.py:313 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "" -#: tiramisu/option.py:378 +#: tiramisu/option.py:318 msgid "default value not allowed if option: {0} is calculated" msgstr "" -#: tiramisu/option.py:381 +#: tiramisu/option.py:321 msgid "params defined for a callback function but no callback defined yet for option {0}" msgstr "" -#: tiramisu/option.py:486 tiramisu/value.py:547 +#: tiramisu/option.py:360 +msgid "option not in all_cons_opts" +msgstr "" + +#: tiramisu/option.py:432 tiramisu/value.py:545 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/option.py:506 -msgid "invalid value {0} for option {1} which must be a list" +#: tiramisu/option.py:449 +msgid "which must be a list" msgstr "" -#: tiramisu/option.py:577 -msgid "invalid value {0} for option {1} must be different as {2} option" +#: tiramisu/option.py:509 +msgid "consistency should be set with an option" msgstr "" -#: tiramisu/option.py:636 +#: tiramisu/option.py:511 +msgid "cannot add consistency with itself" +msgstr "" + +#: tiramisu/option.py:513 +msgid "every options in consistency should be multi or none" +msgstr "" + +#: tiramisu/option.py:533 +msgid "same value for {0} and {1}" +msgstr "" + +#: tiramisu/option.py:642 msgid "values must be a tuple for {0}" msgstr "" -#: tiramisu/option.py:639 +#: tiramisu/option.py:645 msgid "open_values must be a boolean for {0}" msgstr "" -#: tiramisu/option.py:661 +#: tiramisu/option.py:667 msgid "value {0} is not permitted, only {1} is allowed" msgstr "" -#: tiramisu/option.py:673 +#: tiramisu/option.py:679 msgid "value must be a boolean" msgstr "" -#: tiramisu/option.py:683 +#: tiramisu/option.py:689 msgid "value must be an integer" msgstr "" -#: tiramisu/option.py:693 +#: tiramisu/option.py:699 msgid "value must be a float" msgstr "" -#: tiramisu/option.py:703 +#: tiramisu/option.py:709 msgid "value must be a string, not {0}" msgstr "" -#: tiramisu/option.py:721 +#: tiramisu/option.py:727 msgid "value must be an unicode" msgstr "" -#: tiramisu/option.py:733 +#: tiramisu/option.py:739 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "" @@ -175,263 +191,279 @@ msgstr "" msgid "invalid netmask address {0}" msgstr "" -#: tiramisu/option.py:916 +#: tiramisu/option.py:910 +msgid "invalid len for opts" +msgstr "" + +#: tiramisu/option.py:922 msgid "invalid network {0} ({1}) with netmask {2} ({3}), this network is an IP" msgstr "" -#: tiramisu/option.py:921 +#: tiramisu/option.py:927 msgid "invalid IP {0} ({1}) with netmask {2} ({3}), this IP is a network" msgstr "" -#: tiramisu/option.py:926 +#: tiramisu/option.py:932 msgid "invalid IP {0} ({1}) with netmask {2} ({3})" msgstr "" -#: tiramisu/option.py:928 +#: tiramisu/option.py:934 msgid "invalid network {0} ({1}) with netmask {2} ({3})" msgstr "" -#: tiramisu/option.py:939 +#: tiramisu/option.py:948 msgid "invalid broadcast address {0}" msgstr "" +#: tiramisu/option.py:952 +msgid "invalid len for vals" +msgstr "" + #: tiramisu/option.py:957 +msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" +msgstr "" + +#: tiramisu/option.py:979 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:960 +#: tiramisu/option.py:982 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:990 +#: tiramisu/option.py:1012 msgid "invalid value for {0}, must have dot" msgstr "" -#: tiramisu/option.py:993 +#: tiramisu/option.py:1015 msgid "invalid domainname's length for {0} (max {1})" msgstr "" -#: tiramisu/option.py:996 +#: tiramisu/option.py:1018 msgid "invalid domainname's length for {0} (min 2)" msgstr "" -#: tiramisu/option.py:1000 +#: tiramisu/option.py:1022 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1027 +#: tiramisu/option.py:1049 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1044 +#: tiramisu/option.py:1067 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1095 +#: tiramisu/option.py:1118 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1129 +#: tiramisu/option.py:1148 +msgid "consistency with option {0} which is not in Config" +msgstr "" + +#: tiramisu/option.py:1156 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1135 +#: tiramisu/option.py:1162 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1145 +#: tiramisu/option.py:1172 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1158 +#: tiramisu/option.py:1185 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1161 +#: tiramisu/option.py:1188 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1164 +#: tiramisu/option.py:1191 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1202 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1184 +#: tiramisu/option.py:1211 msgid "no child has same nom has master group for: {0}" msgstr "" -#: tiramisu/option.py:1187 +#: tiramisu/option.py:1214 msgid "group_type: {0} not allowed" msgstr "" -#: tiramisu/option.py:1277 +#: tiramisu/option.py:1306 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" -#: tiramisu/option.py:1294 +#: tiramisu/option.py:1323 msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1328 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" -#: tiramisu/option.py:1303 +#: tiramisu/option.py:1332 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" -#: tiramisu/option.py:1307 +#: tiramisu/option.py:1336 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1340 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1343 msgid "malformed requirements option {0} should not be a multi" msgstr "" -#: tiramisu/option.py:1320 +#: tiramisu/option.py:1349 msgid "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" -#: tiramisu/option.py:1325 +#: tiramisu/option.py:1354 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "" -#: tiramisu/option.py:1350 +#: tiramisu/option.py:1379 msgid "{0} should be a function" msgstr "" -#: tiramisu/option.py:1353 +#: tiramisu/option.py:1382 msgid "{0}_params should be a dict" msgstr "" -#: tiramisu/option.py:1356 +#: tiramisu/option.py:1385 msgid "{0}_params with key {1} should not have length different to 1" msgstr "" -#: tiramisu/option.py:1360 +#: tiramisu/option.py:1389 msgid "{0}_params should be tuple for key \"{1}\"" msgstr "" -#: tiramisu/option.py:1366 +#: tiramisu/option.py:1395 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1369 +#: tiramisu/option.py:1398 msgid "{0}_params should have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1373 +#: tiramisu/option.py:1402 msgid "{0}_params should have a boolean not a {0} for second argument" msgstr "" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "" -#: tiramisu/setting.py:259 +#: tiramisu/setting.py:254 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" -#: tiramisu/setting.py:322 +#: tiramisu/setting.py:317 msgid "opt and all_properties must not be set together in reset" msgstr "" -#: tiramisu/setting.py:337 +#: tiramisu/setting.py:332 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" -#: tiramisu/setting.py:440 +#: tiramisu/setting.py:435 msgid "cannot change the value for option {0} this option is frozen" msgstr "" -#: tiramisu/setting.py:446 +#: tiramisu/setting.py:441 msgid "trying to access to an option named: {0} with properties {1}" msgstr "" -#: tiramisu/setting.py:464 +#: tiramisu/setting.py:459 msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:471 tiramisu/value.py:301 +#: tiramisu/setting.py:466 tiramisu/value.py:299 msgid "invalid generic owner {0}" msgstr "" -#: tiramisu/setting.py:558 +#: tiramisu/setting.py:553 msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'" msgstr "" -#: tiramisu/setting.py:570 +#: tiramisu/setting.py:565 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "" -#: tiramisu/value.py:308 +#: tiramisu/value.py:306 msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:416 +#: tiramisu/value.py:414 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:440 +#: tiramisu/value.py:438 msgid "invalid len for the master: {0} which has {1} as slave with greater len" msgstr "" -#: tiramisu/value.py:470 +#: tiramisu/value.py:468 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:507 +#: tiramisu/value.py:505 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:511 +#: tiramisu/value.py:509 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:520 +#: tiramisu/value.py:518 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:528 +#: tiramisu/value.py:526 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:536 +#: tiramisu/value.py:534 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:564 +#: tiramisu/value.py:562 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From 6f5d471db19abca10c43c3c0b0907eebd268e221 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 4 Feb 2014 21:40:07 +0100 Subject: [PATCH 05/42] if option with requires has a property, calculated properties are store in storage --- test/test_requires.py | 22 ++++++++++++++++++++++ tiramisu/setting.py | 10 +++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/test/test_requires.py b/test/test_requires.py index 4cf9372..ff9c2a6 100644 --- a/test/test_requires.py +++ b/test/test_requires.py @@ -24,6 +24,28 @@ def test_requires(): except PropertiesOptionError as err: props = err.proptype assert props == ['disabled'] + c.activate_service = True + c.ip_address_service + + +def test_requires_with_requires(): + a = BoolOption('activate_service', '', True) + b = IPOption('ip_address_service', '', + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b]) + c = Config(od) + c.read_write() + c.cfgimpl_get_settings()[b].append('test') + c.ip_address_service + c.activate_service = False + props = [] + try: + c.ip_address_service + except PropertiesOptionError as err: + props = err.proptype + assert props == ['disabled'] + c.activate_service = True + c.ip_address_service def test_requires_invalid(): diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 99347f1..4092ae6 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -361,7 +361,7 @@ class Settings(object): def _getproperties(self, opt=None, path=None, is_apply_req=True): if opt is None: - props = self._p_.getproperties(path, default_properties) + props = copy(self._p_.getproperties(path, default_properties)) else: if path is None: raise ValueError(_('if opt is not None, path should not be' @@ -372,8 +372,8 @@ class Settings(object): ntime = int(time()) is_cached, props = self._p_.getcache(path, ntime) if is_cached: - return props - props = self._p_.getproperties(path, opt._properties) + return copy(props) + props = copy(self._p_.getproperties(path, opt._properties)) if is_apply_req: props |= self.apply_requires(opt, path) if 'cache' in self: @@ -435,8 +435,8 @@ class Settings(object): (typically with the `frozen` property) """ # opt properties - properties = copy(self._getproperties(opt_or_descr, path)) - self_properties = copy(self._getproperties()) + properties = self._getproperties(opt_or_descr, path) + self_properties = self._getproperties() # remove opt permissive # permissive affect option's permission with or without permissive # global property From fc7f3c24a5882040f775481bcc6c3a9898e6cc43 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 6 Feb 2014 19:19:48 +0100 Subject: [PATCH 06/42] properties option in consistencies are now allowed Conflicts: tiramisu/option.py (PortOption._validate): Strange try/except removed. --- test/test_option_consistency.py | 11 +++++++++++ tiramisu/option.py | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 4db3410..a7ff41c 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -283,3 +283,14 @@ def test_consistency_not_all(): c.a = ['192.168.1.0'] c.b = ['255.255.255.0'] c.c = ['192.168.1.255'] + + +def test_consistency_permissive(): + a = IntOption('a', '', 1) + b = IntOption('b', '', 2, properties=('hidden',)) + od = OptionDescription('od', '', [a, b]) + a.impl_add_consistency('not_equal', b) + c = Config(od) + c.cfgimpl_get_settings().setpermissive(('hidden',)) + c.read_write() + c.a = 1 diff --git a/tiramisu/option.py b/tiramisu/option.py index ad99416..9df3d01 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -367,7 +367,8 @@ class Option(BaseOption): #if context, calculate value, otherwise get default value if context is not None: opt_value = context._getattr( - descr.impl_get_path_by_opt(opt), validate=False) + descr.impl_get_path_by_opt(opt), validate=False, + force_permissive=True) else: opt_value = opt.impl_getdefault() From 8d751ecc9beca1a328f0e52a52325ea9d7d8c559 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 17 Feb 2014 18:36:29 +0100 Subject: [PATCH 07/42] valid port type before compare to min and max value --- tiramisu/option.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index af7a67a..d46c8c9 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -852,12 +852,13 @@ class PortOption(Option): for val in value: try: - if not self._min_value <= int(val) <= self._max_value: - raise ValueError(_('invalid port, must be an between {0} ' - 'and {1}').format(self._min_value, - self._max_value)) + int(val) except ValueError: raise ValueError(_('invalid port')) + if not self._min_value <= int(val) <= self._max_value: + raise ValueError(_('invalid port, must be an between {0} ' + 'and {1}').format(self._min_value, + self._max_value)) class NetworkOption(Option): From bf0501b1d623fcc76232e79f0fd7518d35060dd5 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 20 Feb 2014 14:27:29 +0100 Subject: [PATCH 08/42] tiramisu/setting.py : properties store in cache was a reference to a list modified in validation, should copy properties in cache --- test/test_option_setting.py | 11 +++++++++++ tiramisu/setting.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/test/test_option_setting.py b/test/test_option_setting.py index ed5f7d7..94755e8 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -367,3 +367,14 @@ def test_reset_multiple(): setting[option].append('test') setting.reset(all_properties=True) setting.reset(all_properties=True) + + +def test_properties_cached(): + b1 = BoolOption("b1", "", properties=('test',)) + descr = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])]) + c = Config(descr) + c.read_write() + setting = c.cfgimpl_get_settings() + option = c.cfgimpl_get_description().sub.b1 + c._setattr('sub.b1', True, force_permissive=True) + assert str(setting[b1]) == "['test']" diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 38cf7b5..e2ddb7d 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -392,7 +392,7 @@ class Settings(object): if ntime is None: ntime = int(time()) ntime = ntime + expires_time - self._p_.setcache(path, props, ntime) + self._p_.setcache(path, copy(props), ntime) return props def append(self, propname): From d5b83c123c76e084b3688e8d7c0203bae77e89d7 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 20 Feb 2014 14:27:29 +0100 Subject: [PATCH 09/42] tiramisu/setting.py : properties store in cache was a reference to a list modified in validation, should copy properties in cache --- test/test_option_setting.py | 11 +++++++++++ tiramisu/setting.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/test/test_option_setting.py b/test/test_option_setting.py index ed5f7d7..94755e8 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -367,3 +367,14 @@ def test_reset_multiple(): setting[option].append('test') setting.reset(all_properties=True) setting.reset(all_properties=True) + + +def test_properties_cached(): + b1 = BoolOption("b1", "", properties=('test',)) + descr = OptionDescription("opt", "", [OptionDescription("sub", "", [b1])]) + c = Config(descr) + c.read_write() + setting = c.cfgimpl_get_settings() + option = c.cfgimpl_get_description().sub.b1 + c._setattr('sub.b1', True, force_permissive=True) + assert str(setting[b1]) == "['test']" diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 38cf7b5..e2ddb7d 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -392,7 +392,7 @@ class Settings(object): if ntime is None: ntime = int(time()) ntime = ntime + expires_time - self._p_.setcache(path, props, ntime) + self._p_.setcache(path, copy(props), ntime) return props def append(self, propname): From 716d2b2348424fa02e2e5fc1f6b77707dd248fd1 Mon Sep 17 00:00:00 2001 From: gwen Date: Tue, 25 Feb 2014 14:19:54 +0100 Subject: [PATCH 10/42] allows a DomainnameOption to start with a number --- test/test_config_domain.py | 11 ++++++++++- tiramisu/option.py | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/test/test_config_domain.py b/test/test_config_domain.py index f4579a6..fd9f0cc 100644 --- a/test/test_config_domain.py +++ b/test/test_config_domain.py @@ -16,7 +16,7 @@ def test_domainname(): raises(ValueError, "c.d = 'toto'") c.d = 'toto3.com' raises(ValueError, "c.d = 'toto3.3la'") - raises(ValueError, "c.d = '3toto.com'") + #raises(ValueError, "c.d = '3toto.com'") raises(ValueError, "c.d = 'toto.co3'") raises(ValueError, "c.d = 'toto_super.com'") c.d = 'toto-.com' @@ -25,6 +25,15 @@ def test_domainname(): c.f = 'toto.com' c.f = 'toto' +def test_domainname_special(): + """domain name option that starts with a number + """ + d = DomainnameOption('d', '') + od = OptionDescription('a', '', [d]) + c = Config(od) + c.read_write() + c.d = '1toto.com' + c.d = '123toto.com' def test_domainname_netbios(): d = DomainnameOption('d', '', type_='netbios') diff --git a/tiramisu/option.py b/tiramisu/option.py index 9df3d01..4c16aa9 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1004,7 +1004,7 @@ class DomainnameOption(Option): else: extrachar = '\.' end = '+[a-z]*' - self._domain_re = re.compile(r'^(?:[a-z][a-z\d\-{0}]{{,{1}}}{2}){3}$' + self._domain_re = re.compile(r'^(?:[a-z\d][a-z\d\-{0}]{{,{1}}}{2}){3}$' ''.format(extrachar, length, extrachar_mandatory, end)) super(DomainnameOption, self).__init__(name, doc, default=default, default_multi=default_multi, From 0c9d6554ae71b9bace5f3e5b4004a2b2dcadf0de Mon Sep 17 00:00:00 2001 From: gwen Date: Tue, 25 Feb 2014 15:20:03 +0100 Subject: [PATCH 11/42] a hostname shall not start with a number --- test/test_config_domain.py | 10 +++++++--- tiramisu/option.py | 9 +++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/test/test_config_domain.py b/test/test_config_domain.py index fd9f0cc..9fd9ed3 100644 --- a/test/test_config_domain.py +++ b/test/test_config_domain.py @@ -25,15 +25,19 @@ def test_domainname(): c.f = 'toto.com' c.f = 'toto' -def test_domainname_special(): - """domain name option that starts with a number +def test_special_domain_name(): + """domain name option that starts with a number or not """ d = DomainnameOption('d', '') - od = OptionDescription('a', '', [d]) + e = DomainnameOption('e', '', type_='netbios') + od = OptionDescription('a', '', [d,e]) c = Config(od) c.read_write() c.d = '1toto.com' c.d = '123toto.com' + c.e = 'toto' + raises(ValueError, "c.e = '1toto'") + def test_domainname_netbios(): d = DomainnameOption('d', '', type_='netbios') diff --git a/tiramisu/option.py b/tiramisu/option.py index 4c16aa9..8b5eb68 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -993,6 +993,10 @@ class DomainnameOption(Option): end = '' extrachar = '' extrachar_mandatory = '' + if self._type != 'netbios': + allow_number = '\d' + else: + allow_number = '' if self._type == 'netbios': length = 14 elif self._type == 'hostname': @@ -1004,8 +1008,9 @@ class DomainnameOption(Option): else: extrachar = '\.' end = '+[a-z]*' - self._domain_re = re.compile(r'^(?:[a-z\d][a-z\d\-{0}]{{,{1}}}{2}){3}$' - ''.format(extrachar, length, extrachar_mandatory, end)) + self._domain_re = re.compile(r'^(?:[a-z{0}][a-z\d\-{1}]{{,{2}}}{3}){4}$' + ''.format(allow_number, extrachar, length, + extrachar_mandatory, end)) super(DomainnameOption, self).__init__(name, doc, default=default, default_multi=default_multi, callback=callback, From 9f903d3e042da303d580f1125a36d52b5b744f5d Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 6 Mar 2014 22:09:12 +0100 Subject: [PATCH 12/42] add username's option --- test/test_option_username.py | 25 +++++++++++++++++++++++++ tiramisu/option.py | 12 ++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 test/test_option_username.py diff --git a/test/test_option_username.py b/test/test_option_username.py new file mode 100644 index 0000000..472e9cd --- /dev/null +++ b/test/test_option_username.py @@ -0,0 +1,25 @@ +"configuration objects global API" +import autopath +from py.test import raises + +from tiramisu.config import Config +from tiramisu.option import UsernameOption + +def test_username(): + UsernameOption('a', '', 'string') + UsernameOption('a', '', '_string') + UsernameOption('a', '', 's_tring') + UsernameOption('a', '', 'string_') + UsernameOption('a', '', 'string$') + UsernameOption('a', '', '_string$') + raises(ValueError, "UsernameOption('a', '', 'strin$g')") + UsernameOption('a', '', 's-tring') + raises(ValueError, "UsernameOption('a', '', '-string')") + UsernameOption('a', '', 's9tring') + raises(ValueError, "UsernameOption('a', '', '9string')") + raises(ValueError, "UsernameOption('a', '', '')") + UsernameOption('a', '', 's') + UsernameOption('a', '', 's2345678901234567890123456789012') + raises(ValueError, "UsernameOption('a', '', 's23456789012345678901234567890123')") + UsernameOption('a', '', 's234567890123456789012345678901$') + raises(ValueError, "UsernameOption('a', '', 's2345678901234567890123456789012$')") diff --git a/tiramisu/option.py b/tiramisu/option.py index b9960b6..da93102 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1079,6 +1079,18 @@ class URLOption(DomainnameOption): raise ValueError(_('invalid url, should ends with filename')) +class UsernameOption(Option): + __slots__ = tuple() + _opt_type = 'username' + #regexp build with 'man 8 adduser' informations + username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$") + + def _validate(self, value): + match = self.username_re.search(value) + if not match: + raise ValueError(_('invalid username')) + + class FilenameOption(Option): __slots__ = tuple() _opt_type = 'file' From c1755192118cdae368fffd59478925f374580022 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 6 Mar 2014 22:09:44 +0100 Subject: [PATCH 13/42] pep8 --- tiramisu/option.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index da93102..851872d 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -857,8 +857,8 @@ class PortOption(Option): raise ValueError(_('invalid port')) if not self._min_value <= int(val) <= self._max_value: raise ValueError(_('invalid port, must be an between {0} ' - 'and {1}').format(self._min_value, - self._max_value)) + 'and {1}').format(self._min_value, + self._max_value)) class NetworkOption(Option): From d3f9d20ab5d33592304298194fe4199c98b13f9c Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 8 Mar 2014 18:53:22 +0100 Subject: [PATCH 14/42] add extend in config setting --- test/test_option_setting.py | 9 +++++++++ tiramisu/setting.py | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 94755e8..28327d5 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -310,6 +310,15 @@ def test_access_by_get_whith_hide(): raises(AttributeError, "c.find(byname='b1')") +def test_extend_config_properties(): + descr = make_description() + cfg = Config(descr) + setting = cfg.cfgimpl_get_settings() + assert str(setting) == str(['cache', 'expire', 'validator']) + setting.extend(['test', 'test2']) + assert str(setting) == str(['test', 'cache', 'test2', 'expire', 'validator']) + + def test_append_properties(): descr = make_description() cfg = Config(descr) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index e2ddb7d..d3b0a3b 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -408,6 +408,10 @@ class Settings(object): props.remove(propname) self._setproperties(props, None, None) + def extend(self, propnames): + for propname in propnames: + self.append(propname) + def _setproperties(self, properties, opt, path): """save properties for specified opt (never save properties if same has option properties) From 6e8b570a372d25dbcba50ac2247abb4a8ac20b53 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 9 Mar 2014 20:06:44 +0100 Subject: [PATCH 15/42] mandatory_warnings is now in values and add force_cache to values --- test/test_cache.py | 19 +++++++++++++++++++ test/test_mandatory.py | 18 +++++++++--------- tiramisu/config.py | 18 ++---------------- tiramisu/value.py | 38 +++++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 26 deletions(-) diff --git a/test/test_cache.py b/test/test_cache.py index f483c76..ef4f1a3 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -253,3 +253,22 @@ def test_reset_cache_only(): c.cfgimpl_reset_cache(only=('settings',)) assert 'u1' in values._p_.get_cached(c) assert 'u1' not in settings._p_.get_cached(c) + + +def test_force_cache(): + u1 = IntOption('u1', '', multi=True) + u2 = IntOption('u2', '') + u3 = IntOption('u3', '', multi=True) + u4 = IntOption('u4', '', properties=('disabled',)) + od = OptionDescription('od1', '', [u1, u2, u3, u4]) + c = Config(od) + c.cfgimpl_get_settings().remove('expire') + + c.cfgimpl_get_values().force_cache() + assert c.cfgimpl_get_values()._p_.get_cached(c) == {'u1': ([], None), 'u3': ([], None), 'u2': (None, None), 'u4': (None, None)} + assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'u4': (set(['disabled']), None), 'u1': (set([]), None), 'u3': (set([]), None), 'u2': (set([]), None)} + c.read_only() + + c.cfgimpl_get_values().force_cache() + assert c.cfgimpl_get_values()._p_.get_cached(c) == {'u1': ([], None), 'u3': ([], None), 'u2': (None, None)} + assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'u4': (set(['disabled']), None), 'u1': (set([]), None), 'u3': (set([]), None), 'u2': (set([]), None)} diff --git a/test/test_mandatory.py b/test/test_mandatory.py index c535e31..5b9878a 100644 --- a/test/test_mandatory.py +++ b/test/test_mandatory.py @@ -1,7 +1,7 @@ import autopath #from py.test import raises -from tiramisu.config import Config, mandatory_warnings +from tiramisu.config import Config from tiramisu.option import StrOption, UnicodeOption, OptionDescription from tiramisu.error import PropertiesOptionError @@ -205,11 +205,11 @@ def test_mandatory_warnings_ro(): except PropertiesOptionError as err: proc = err.proptype assert proc == ['mandatory'] - assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] config.read_write() config.str = 'a' config.read_only() - assert list(mandatory_warnings(config)) == ['str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] def test_mandatory_warnings_rw(): @@ -218,9 +218,9 @@ def test_mandatory_warnings_rw(): config.str = '' config.read_write() config.str - assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] config.str = 'a' - assert list(mandatory_warnings(config)) == ['str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] def test_mandatory_warnings_disabled(): @@ -230,9 +230,9 @@ def test_mandatory_warnings_disabled(): setting = config.cfgimpl_get_settings() config.read_write() config.str - assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('disabled') - assert list(mandatory_warnings(config)) == ['str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] def test_mandatory_warnings_frozen(): @@ -242,7 +242,7 @@ def test_mandatory_warnings_frozen(): setting = config.cfgimpl_get_settings() config.read_write() config.str - assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('frozen') config.read_only() - assert list(mandatory_warnings(config)) == ['str', 'str1', 'unicode2', 'str3'] + assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] diff --git a/tiramisu/config.py b/tiramisu/config.py index c9fb992..473cdb4 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -716,19 +716,5 @@ class MetaConfig(GroupConfig): def mandatory_warnings(config): - """convenience function to trace Options that are mandatory and - where no value has been set - - :returns: generator of mandatory Option's path - - """ - #if value in cache, properties are not calculated - config.cfgimpl_reset_cache(only=('values',)) - for path in config.cfgimpl_get_description().impl_getpaths( - include_groups=True): - try: - config._getattr(path, force_properties=frozenset(('mandatory',))) - except PropertiesOptionError as err: - if err.proptype == ['mandatory']: - yield path - config.cfgimpl_reset_cache(only=('values',)) + #only for retro-compatibility + config.cfgimpl_get_values().mandatory_warnings() diff --git a/tiramisu/value.py b/tiramisu/value.py index ed70f90..c07ddfc 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -21,7 +21,7 @@ from time import time from copy import copy import sys import weakref -from tiramisu.error import ConfigError, SlaveError +from tiramisu.error import ConfigError, SlaveError, PropertiesOptionError from tiramisu.setting import owners, multitypes, expires_time, undefined from tiramisu.autolib import carry_out_calculation from tiramisu.i18n import _ @@ -395,6 +395,42 @@ class Values(object): raise ValueError(_("information's item" " not found: {0}").format(key)) + def mandatory_warnings(self): + """convenience function to trace Options that are mandatory and + where no value has been set + + :returns: generator of mandatory Option's path + + """ + #if value in cache, properties are not calculated + self.reset_cache(False) + context = self.context() + for path in context.cfgimpl_get_description().impl_getpaths( + include_groups=True): + try: + context._getattr(path, + force_properties=frozenset(('mandatory',))) + except PropertiesOptionError as err: + if err.proptype == ['mandatory']: + yield path + self.reset_cache(False) + + def force_cache(self): + """parse all option to force data in cache + """ + context = self.context() + if not 'cache' in context.cfgimpl_get_settings(): + raise PropertiesOptionError(_('can force cache only if cache ' + 'is actived in config')) + #remove all cached properties and value to update "expired" time + context.cfgimpl_reset_cache() + for path in context.cfgimpl_get_description().impl_getpaths( + include_groups=True): + try: + context._getattr(path) + except PropertiesOptionError: + pass + def __getstate__(self): return {'_p_': self._p_} From f2154e23227e0322e183abf6890e405a6fcaaadb Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 9 Mar 2014 20:14:17 +0100 Subject: [PATCH 16/42] update translation --- tiramisu/option.py | 2 +- translations/fr/tiramisu.po | 258 ++++++++++++++++++++---------------- translations/tiramisu.pot | 222 ++++++++++++++++++------------- 3 files changed, 274 insertions(+), 208 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index 851872d..20cdf86 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -842,7 +842,7 @@ class PortOption(Option): if self._allow_range and ":" in str(value): value = str(value).split(':') if len(value) != 2: - raise ValueError(_('invalid part, range must have two values ' + raise ValueError(_('invalid port, range must have two values ' 'only')) if not value[0] < value[1]: raise ValueError(_('invalid port, first port in range must be' diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 83a9289..459e281 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,19 +2,19 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-01-25 11:30+CET\n" +"POT-Creation-Date: 2014-03-09 20:13+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" +"Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.4\n" -"Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: tiramisu/autolib.py:159 +#: tiramisu/autolib.py:162 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -29,42 +29,65 @@ msgstr "descr doit être une optiondescription pas un {0}" msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" -#: tiramisu/config.py:166 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:427 +#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 +#: tiramisu/value.py:449 msgid "the context does not exist anymore" msgstr "le context n'existe plus" -#: tiramisu/config.py:171 -msgid "" -"no option description found for this config (may be metaconfig without meta)" +#: tiramisu/config.py:169 +msgid "no option description found for this config (may be GroupConfig)" msgstr "" -"pas d'option description trouvé pour cette config (peut être une metaconfig " -"sans meta)" +"pas d'option description trouvé pour cette config (peut être un GroupConfig)" -#: tiramisu/config.py:197 +#: tiramisu/config.py:195 msgid "can't assign to an OptionDescription" msgstr "ne peut pas attribuer une valeur à une OptionDescription" -#: tiramisu/config.py:330 +#: tiramisu/config.py:325 msgid "unknown type_ type {0}for _find" msgstr "type_ type {0} pour _find inconnu" -#: tiramisu/config.py:369 +#: tiramisu/config.py:364 msgid "no option found in config with these criteria" msgstr "aucune option trouvée dans la config avec ces critères" -#: tiramisu/config.py:419 +#: tiramisu/config.py:414 msgid "make_dict can't filtering with value without option" msgstr "make_dict ne peut filtrer sur une valeur mais sans option" -#: tiramisu/config.py:440 +#: tiramisu/config.py:435 msgid "unexpected path {0}, should start with {1}" msgstr "chemin imprévu {0}, devrait commencer par {1}" -#: tiramisu/config.py:500 +#: tiramisu/config.py:489 msgid "opt in getowner must be an option not {0}" msgstr "opt dans getowner doit être une option pas {0}" +#: tiramisu/config.py:532 +msgid "cannot serialize Config with MetaConfig" +msgstr "impossible de sérialiser une Config avec une MetaConfig" + +#: tiramisu/config.py:546 +msgid "this storage is not serialisable, could be a none persistent storage" +msgstr "ce storage n'est sérialisable, devrait être une storage non persistant" + +#: tiramisu/config.py:609 +msgid "metaconfig's children must be a list" +msgstr "enfants d'une metaconfig doit être une liste" + +#: tiramisu/config.py:703 +msgid "metaconfig's children should be config, not {0}" +msgstr "enfants d'une metaconfig doit être une config, pas {0}" + +#: tiramisu/config.py:707 +msgid "child has already a metaconfig's" +msgstr "enfant a déjà une metaconfig" + +#: tiramisu/config.py:711 +msgid "all config in metaconfig must have the same optiondescription" +msgstr "" +"toutes les configs d'une metaconfig doivent avoir la même optiondescription" + #: tiramisu/option.py:67 msgid "invalid name: {0} for option" msgstr "nom invalide : {0} pour l'option" @@ -77,7 +100,7 @@ msgstr "type des properties invalide {0} pour {1}, doit être un tuple" msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" -#: tiramisu/option.py:141 tiramisu/value.py:376 +#: tiramisu/option.py:141 tiramisu/value.py:395 msgid "information's item not found: {0}" msgstr "aucune config spécifiée alors que c'est nécessaire" @@ -107,242 +130,251 @@ msgstr "" "params définis pour une fonction callback mais par de callback encore " "définis pour l'option {0}" -#: tiramisu/option.py:359 -msgid "option not in all_cons_opts" -msgstr "option non présentante dans all_cons_opts" - -#: tiramisu/option.py:425 tiramisu/option.py:435 +#: tiramisu/option.py:423 tiramisu/option.py:433 msgid "invalid value for option {0}: {1}" msgstr "valeur invalide pour l'option {0} : {1}" -#: tiramisu/option.py:452 +#: tiramisu/option.py:450 msgid "invalid value {0} for option {1} which must be a list" msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste" -#: tiramisu/option.py:508 +#: tiramisu/option.py:506 msgid "consistency should be set with an option" msgstr "consistency doit être configuré avec une option" -#: tiramisu/option.py:510 +#: tiramisu/option.py:508 msgid "cannot add consistency with itself" msgstr "ne peut ajouter une consistency avec lui même" -#: tiramisu/option.py:512 +#: tiramisu/option.py:510 msgid "every options in consistency should be multi or none" msgstr "" "toutes les options d'une consistency devrait être multi ou ne pas l'être" -#: tiramisu/option.py:532 +#: tiramisu/option.py:530 msgid "same value for {0} and {1}" msgstr "même valeur pour {0} et {1}" -#: tiramisu/option.py:641 +#: tiramisu/option.py:623 msgid "values must be a tuple for {0}" msgstr "values doit être un tuple pour {0}" -#: tiramisu/option.py:644 +#: tiramisu/option.py:626 msgid "open_values must be a boolean for {0}" msgstr "open_values doit être un booléen pour {0}" -#: tiramisu/option.py:666 +#: tiramisu/option.py:648 msgid "value {0} is not permitted, only {1} is allowed" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" -#: tiramisu/option.py:678 +#: tiramisu/option.py:660 msgid "invalid boolean" msgstr "booléen invalide" -#: tiramisu/option.py:688 +#: tiramisu/option.py:670 msgid "invalid integer" msgstr "nombre invalide" -#: tiramisu/option.py:698 +#: tiramisu/option.py:680 msgid "invalid float" msgstr "invalide nombre flottan" -#: tiramisu/option.py:708 +#: tiramisu/option.py:690 msgid "invalid string" msgstr "invalide caractère" -#: tiramisu/option.py:725 +#: tiramisu/option.py:707 msgid "invalid unicode" msgstr "invalide unicode" -#: tiramisu/option.py:737 +#: tiramisu/option.py:719 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" -#: tiramisu/option.py:787 tiramisu/option.py:792 +#: tiramisu/option.py:770 tiramisu/option.py:773 tiramisu/option.py:778 msgid "invalid IP" msgstr "adresse IP invalide" -#: tiramisu/option.py:797 +#: tiramisu/option.py:783 msgid "invalid IP, mustn't not be in reserved class" msgstr "adresse IP invalide, ne doit pas être d'une classe reservée" -#: tiramisu/option.py:799 +#: tiramisu/option.py:785 msgid "invalid IP, must be in private class" msgstr "adresse IP invalide, doit être dans la classe privée" -#: tiramisu/option.py:837 +#: tiramisu/option.py:823 msgid "inconsistency in allowed range" msgstr "inconsistence dans la plage autorisée" -#: tiramisu/option.py:842 +#: tiramisu/option.py:828 msgid "max value is empty" msgstr "la valeur maximum est vide" -#: tiramisu/option.py:882 +#: tiramisu/option.py:845 +msgid "invalid port, range must have two values only" +msgstr "port invalide, une plage doit avoir deux valeurs seulement" + +#: tiramisu/option.py:848 +msgid "invalid port, first port in range must be smaller than the second one" +msgstr "" +"port invalide, le premier port d'une plage doit être plus petit que le second" + +#: tiramisu/option.py:857 +msgid "invalid port" +msgstr "port invalide" + +#: tiramisu/option.py:859 +msgid "invalid port, must be an between {0} and {1}" +msgstr "port invalide, port doit être entre {0} et {1}" + +#: tiramisu/option.py:873 msgid "invalid network address" msgstr "adresse réseau invalide" -#: tiramisu/option.py:887 +#: tiramisu/option.py:878 msgid "invalid network address, must not be in reserved class" msgstr "adresse réseau invalide, ne doit pas être dans la classe reservée" -#: tiramisu/option.py:899 +#: tiramisu/option.py:890 msgid "invalid netmask address" msgstr "masque de sous-réseau invalide" -#: tiramisu/option.py:915 +#: tiramisu/option.py:906 msgid "invalid len for opts" msgstr "longueur invalide pour opts" -#: tiramisu/option.py:927 -msgid "invalid network {0} ({1}) with netmask {2}, this network is an IP" -msgstr "réseau invalide {0} ({1}) avec masque {2}, ce réseau est une IP" - -#: tiramisu/option.py:932 +#: tiramisu/option.py:920 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau" -#: tiramisu/option.py:937 -msgid "invalid IP {0} ({1}) with netmask {2}" -msgstr "IP invalide {0} ({1}) avec masque {2}" - -#: tiramisu/option.py:939 +#: tiramisu/option.py:925 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "réseau invalide {0} ({1}) avec masque {2}" -#: tiramisu/option.py:953 +#: tiramisu/option.py:939 msgid "invalid broadcast address" msgstr "adresse de broadcast invalide" -#: tiramisu/option.py:957 +#: tiramisu/option.py:943 msgid "invalid len for vals" msgstr "longueur invalide pour vals" -#: tiramisu/option.py:962 +#: tiramisu/option.py:948 msgid "" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" "Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" -#: tiramisu/option.py:984 +#: tiramisu/option.py:970 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:987 +#: tiramisu/option.py:973 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:989 +#: tiramisu/option.py:975 msgid "allow_without_dot must be a boolean" msgstr "allow_without_dot doit être un booléen" -#: tiramisu/option.py:1028 +#: tiramisu/option.py:1019 msgid "invalid domainname, must have dot" msgstr "nom de domaine invalide, doit avoir un point" -#: tiramisu/option.py:1030 +#: tiramisu/option.py:1021 msgid "invalid domainname's length (max 255)" msgstr "longueur du nom de domaine invalide (maximum {1})" -#: tiramisu/option.py:1032 +#: tiramisu/option.py:1023 msgid "invalid domainname's length (min 2)" msgstr "longueur du nom de domaine invalide (minimum 2)" -#: tiramisu/option.py:1034 +#: tiramisu/option.py:1025 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1047 +#: tiramisu/option.py:1038 msgid "invalid email address, should contains one @" msgstr "adresse email invalide, devrait contenir un @" -#: tiramisu/option.py:1050 +#: tiramisu/option.py:1041 msgid "invalid username in email address" msgstr "nom d'utilisateur invalide dans une adresse email" -#: tiramisu/option.py:1063 +#: tiramisu/option.py:1054 msgid "invalid url, should start with http:// or https://" msgstr "URL invalide, devrait démarré avec http:// ou https://" -#: tiramisu/option.py:1082 +#: tiramisu/option.py:1073 msgid "invalid url, port must be an between 0 and 65536" msgstr "URL invalide, port doit être entre 0 et 65536" -#: tiramisu/option.py:1088 +#: tiramisu/option.py:1079 msgid "invalid url, should ends with filename" msgstr "URL invalide, devrait finir avec un nom de fichier" -#: tiramisu/option.py:1099 +#: tiramisu/option.py:1091 +msgid "invalid username" +msgstr "utilisateur invalide" + +#: tiramisu/option.py:1102 msgid "invalid filename" msgstr "nom de fichier invalide" -#: tiramisu/option.py:1126 +#: tiramisu/option.py:1129 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1144 +#: tiramisu/option.py:1147 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1195 +#: tiramisu/option.py:1198 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1225 +#: tiramisu/option.py:1228 msgid "consistency with option {0} which is not in Config" msgstr "consistency avec l'option {0} qui n'est pas dans une Config" -#: tiramisu/option.py:1233 +#: tiramisu/option.py:1236 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1239 +#: tiramisu/option.py:1242 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1249 +#: tiramisu/option.py:1252 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1261 +#: tiramisu/option.py:1264 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1267 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1267 +#: tiramisu/option.py:1270 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1277 +#: tiramisu/option.py:1280 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1285 +#: tiramisu/option.py:1288 msgid "callback of master's option shall not refered a slave's ones" msgstr "" "callback d'une variable maitre ne devrait pas référencer des variables " "esclaves" -#: tiramisu/option.py:1293 +#: tiramisu/option.py:1296 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" @@ -458,7 +490,7 @@ msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1} msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:514 tiramisu/value.py:315 +#: tiramisu/setting.py:514 tiramisu/value.py:334 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" @@ -495,52 +527,65 @@ msgstr "session déjà utilisée" msgid "a dictionary cannot be persistent" msgstr "un espace de stockage dictionary ne peut être persistant" -#: tiramisu/value.py:322 +#: tiramisu/value.py:341 msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:442 +#: tiramisu/value.py:426 +msgid "{0} is already a Multi " +msgstr "{0} est déjà une Multi" + +#: tiramisu/value.py:462 tiramisu/value.py:526 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:466 -msgid "invalid len for the master: {0} which has {1} as slave with greater len" -msgstr "" -"longueur invalide pour un maître : {0} qui a {1} une esclave avec une plus " -"grande longueur" - -#: tiramisu/value.py:496 +#: tiramisu/value.py:498 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:535 +#: tiramisu/value.py:536 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:539 +#: tiramisu/value.py:540 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:548 +#: tiramisu/value.py:549 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:556 +#: tiramisu/value.py:557 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:564 +#: tiramisu/value.py:565 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:575 +#: tiramisu/value.py:576 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/value.py:593 +#: tiramisu/value.py:594 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" +#~ msgid "option not in all_cons_opts" +#~ msgstr "option non présentante dans all_cons_opts" + +#~ msgid "invalid network {0} ({1}) with netmask {2}, this network is an IP" +#~ msgstr "réseau invalide {0} ({1}) avec masque {2}, ce réseau est une IP" + +#~ msgid "invalid IP {0} ({1}) with netmask {2}" +#~ msgstr "IP invalide {0} ({1}) avec masque {2}" + +#~ msgid "" +#~ "invalid len for the master: {0} which has {1} as slave with greater len" +#~ msgstr "" +#~ "longueur invalide pour un maître : {0} qui a {1} une esclave avec une " +#~ "plus grande longueur" + #~ msgid "" #~ "unable to carry out a calculation, option value with multi types must " #~ "have same length for: {0}" @@ -588,17 +633,6 @@ msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" #~ msgid "invalid name: {0} for optiondescription" #~ msgstr "nom invalide : {0} pour l'optiondescription" -#~ msgid "metaconfig's children must be config, not {0}" -#~ msgstr "enfants d'une metaconfig doit être une config, pas {0}" - -#~ msgid "all config in metaconfig must have same optiondescription" -#~ msgstr "" -#~ "toutes les configs d'une metaconfig doivent avoir la même " -#~ "optiondescription" - -#~ msgid "child has already a metaconfig's" -#~ msgstr "enfant a déjà une metaconfig" - #~ msgid "not allowed group_type : {0}" #~ msgstr "group_type non autorisé : {0}" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index e572a40..2a20646 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-01-25 11:30+CET\n" +"POT-Creation-Date: 2014-03-09 20:13+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,7 +15,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:159 +#: tiramisu/autolib.py:162 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -27,39 +27,63 @@ msgstr "" msgid "unknown group_type: {0}" msgstr "" -#: tiramisu/config.py:166 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:427 +#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 +#: tiramisu/value.py:449 msgid "the context does not exist anymore" msgstr "" -#: tiramisu/config.py:171 -msgid "no option description found for this config (may be metaconfig without meta)" +#: tiramisu/config.py:169 +msgid "no option description found for this config (may be GroupConfig)" msgstr "" -#: tiramisu/config.py:197 +#: tiramisu/config.py:195 msgid "can't assign to an OptionDescription" msgstr "" -#: tiramisu/config.py:330 +#: tiramisu/config.py:325 msgid "unknown type_ type {0}for _find" msgstr "" -#: tiramisu/config.py:369 +#: tiramisu/config.py:364 msgid "no option found in config with these criteria" msgstr "" -#: tiramisu/config.py:419 +#: tiramisu/config.py:414 msgid "make_dict can't filtering with value without option" msgstr "" -#: tiramisu/config.py:440 +#: tiramisu/config.py:435 msgid "unexpected path {0}, should start with {1}" msgstr "" -#: tiramisu/config.py:500 +#: tiramisu/config.py:489 msgid "opt in getowner must be an option not {0}" msgstr "" +#: tiramisu/config.py:532 +msgid "cannot serialize Config with MetaConfig" +msgstr "" + +#: tiramisu/config.py:546 +msgid "this storage is not serialisable, could be a none persistent storage" +msgstr "" + +#: tiramisu/config.py:609 +msgid "metaconfig's children must be a list" +msgstr "" + +#: tiramisu/config.py:703 +msgid "metaconfig's children should be config, not {0}" +msgstr "" + +#: tiramisu/config.py:707 +msgid "child has already a metaconfig's" +msgstr "" + +#: tiramisu/config.py:711 +msgid "all config in metaconfig must have the same optiondescription" +msgstr "" + #: tiramisu/option.py:67 msgid "invalid name: {0} for option" msgstr "" @@ -72,7 +96,7 @@ msgstr "" msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "" -#: tiramisu/option.py:141 tiramisu/value.py:376 +#: tiramisu/option.py:141 tiramisu/value.py:395 msgid "information's item not found: {0}" msgstr "" @@ -96,235 +120,243 @@ msgstr "" msgid "params defined for a callback function but no callback defined yet for option {0}" msgstr "" -#: tiramisu/option.py:359 -msgid "option not in all_cons_opts" -msgstr "" - -#: tiramisu/option.py:425 tiramisu/option.py:435 +#: tiramisu/option.py:423 tiramisu/option.py:433 msgid "invalid value for option {0}: {1}" msgstr "" -#: tiramisu/option.py:452 +#: tiramisu/option.py:450 msgid "invalid value {0} for option {1} which must be a list" msgstr "" -#: tiramisu/option.py:508 +#: tiramisu/option.py:506 msgid "consistency should be set with an option" msgstr "" -#: tiramisu/option.py:510 +#: tiramisu/option.py:508 msgid "cannot add consistency with itself" msgstr "" -#: tiramisu/option.py:512 +#: tiramisu/option.py:510 msgid "every options in consistency should be multi or none" msgstr "" -#: tiramisu/option.py:532 +#: tiramisu/option.py:530 msgid "same value for {0} and {1}" msgstr "" -#: tiramisu/option.py:641 +#: tiramisu/option.py:623 msgid "values must be a tuple for {0}" msgstr "" -#: tiramisu/option.py:644 +#: tiramisu/option.py:626 msgid "open_values must be a boolean for {0}" msgstr "" -#: tiramisu/option.py:666 +#: tiramisu/option.py:648 msgid "value {0} is not permitted, only {1} is allowed" msgstr "" -#: tiramisu/option.py:678 +#: tiramisu/option.py:660 msgid "invalid boolean" msgstr "" -#: tiramisu/option.py:688 +#: tiramisu/option.py:670 msgid "invalid integer" msgstr "" -#: tiramisu/option.py:698 +#: tiramisu/option.py:680 msgid "invalid float" msgstr "" -#: tiramisu/option.py:708 +#: tiramisu/option.py:690 msgid "invalid string" msgstr "" -#: tiramisu/option.py:725 +#: tiramisu/option.py:707 msgid "invalid unicode" msgstr "" -#: tiramisu/option.py:737 +#: tiramisu/option.py:719 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "" -#: tiramisu/option.py:787 tiramisu/option.py:792 +#: tiramisu/option.py:770 tiramisu/option.py:773 tiramisu/option.py:778 msgid "invalid IP" msgstr "" -#: tiramisu/option.py:797 +#: tiramisu/option.py:783 msgid "invalid IP, mustn't not be in reserved class" msgstr "" -#: tiramisu/option.py:799 +#: tiramisu/option.py:785 msgid "invalid IP, must be in private class" msgstr "" -#: tiramisu/option.py:837 +#: tiramisu/option.py:823 msgid "inconsistency in allowed range" msgstr "" -#: tiramisu/option.py:842 +#: tiramisu/option.py:828 msgid "max value is empty" msgstr "" -#: tiramisu/option.py:882 +#: tiramisu/option.py:845 +msgid "invalid port, range must have two values only" +msgstr "" + +#: tiramisu/option.py:848 +msgid "invalid port, first port in range must be smaller than the second one" +msgstr "" + +#: tiramisu/option.py:857 +msgid "invalid port" +msgstr "" + +#: tiramisu/option.py:859 +msgid "invalid port, must be an between {0} and {1}" +msgstr "" + +#: tiramisu/option.py:873 msgid "invalid network address" msgstr "" -#: tiramisu/option.py:887 +#: tiramisu/option.py:878 msgid "invalid network address, must not be in reserved class" msgstr "" -#: tiramisu/option.py:899 +#: tiramisu/option.py:890 msgid "invalid netmask address" msgstr "" -#: tiramisu/option.py:915 +#: tiramisu/option.py:906 msgid "invalid len for opts" msgstr "" -#: tiramisu/option.py:927 -msgid "invalid network {0} ({1}) with netmask {2}, this network is an IP" -msgstr "" - -#: tiramisu/option.py:932 +#: tiramisu/option.py:920 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "" -#: tiramisu/option.py:937 -msgid "invalid IP {0} ({1}) with netmask {2}" -msgstr "" - -#: tiramisu/option.py:939 +#: tiramisu/option.py:925 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "" -#: tiramisu/option.py:953 +#: tiramisu/option.py:939 msgid "invalid broadcast address" msgstr "" -#: tiramisu/option.py:957 +#: tiramisu/option.py:943 msgid "invalid len for vals" msgstr "" -#: tiramisu/option.py:962 +#: tiramisu/option.py:948 msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:984 +#: tiramisu/option.py:970 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:987 +#: tiramisu/option.py:973 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:989 +#: tiramisu/option.py:975 msgid "allow_without_dot must be a boolean" msgstr "" -#: tiramisu/option.py:1028 +#: tiramisu/option.py:1019 msgid "invalid domainname, must have dot" msgstr "" -#: tiramisu/option.py:1030 +#: tiramisu/option.py:1021 msgid "invalid domainname's length (max 255)" msgstr "" -#: tiramisu/option.py:1032 +#: tiramisu/option.py:1023 msgid "invalid domainname's length (min 2)" msgstr "" -#: tiramisu/option.py:1034 +#: tiramisu/option.py:1025 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1047 +#: tiramisu/option.py:1038 msgid "invalid email address, should contains one @" msgstr "" -#: tiramisu/option.py:1050 +#: tiramisu/option.py:1041 msgid "invalid username in email address" msgstr "" -#: tiramisu/option.py:1063 +#: tiramisu/option.py:1054 msgid "invalid url, should start with http:// or https://" msgstr "" -#: tiramisu/option.py:1082 +#: tiramisu/option.py:1073 msgid "invalid url, port must be an between 0 and 65536" msgstr "" -#: tiramisu/option.py:1088 +#: tiramisu/option.py:1079 msgid "invalid url, should ends with filename" msgstr "" -#: tiramisu/option.py:1099 +#: tiramisu/option.py:1091 +msgid "invalid username" +msgstr "" + +#: tiramisu/option.py:1102 msgid "invalid filename" msgstr "" -#: tiramisu/option.py:1126 +#: tiramisu/option.py:1129 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1144 +#: tiramisu/option.py:1147 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1195 +#: tiramisu/option.py:1198 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1225 +#: tiramisu/option.py:1228 msgid "consistency with option {0} which is not in Config" msgstr "" -#: tiramisu/option.py:1233 +#: tiramisu/option.py:1236 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1239 +#: tiramisu/option.py:1242 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1249 +#: tiramisu/option.py:1252 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1261 +#: tiramisu/option.py:1264 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1267 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1267 +#: tiramisu/option.py:1270 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1277 +#: tiramisu/option.py:1280 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1285 +#: tiramisu/option.py:1288 msgid "callback of master's option shall not refered a slave's ones" msgstr "" -#: tiramisu/option.py:1293 +#: tiramisu/option.py:1296 msgid "group_type: {0} not allowed" msgstr "" @@ -424,7 +456,7 @@ msgstr "" msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:514 tiramisu/value.py:315 +#: tiramisu/setting.py:514 tiramisu/value.py:334 msgid "invalid generic owner {0}" msgstr "" @@ -456,47 +488,47 @@ msgstr "" msgid "a dictionary cannot be persistent" msgstr "" -#: tiramisu/value.py:322 +#: tiramisu/value.py:341 msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:442 +#: tiramisu/value.py:426 +msgid "{0} is already a Multi " +msgstr "" + +#: tiramisu/value.py:462 tiramisu/value.py:526 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:466 -msgid "invalid len for the master: {0} which has {1} as slave with greater len" -msgstr "" - -#: tiramisu/value.py:496 +#: tiramisu/value.py:498 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:535 +#: tiramisu/value.py:536 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:539 +#: tiramisu/value.py:540 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:548 +#: tiramisu/value.py:549 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:556 +#: tiramisu/value.py:557 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:564 +#: tiramisu/value.py:565 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:575 +#: tiramisu/value.py:576 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/value.py:593 +#: tiramisu/value.py:594 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From fbc79ced078def2550753c52832d74d5cfd18164 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 9 Mar 2014 20:16:38 +0100 Subject: [PATCH 17/42] update translation --- translations/fr/tiramisu.po | 41 +++++++++++++++++++++---------------- translations/tiramisu.pot | 40 ++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 459e281..90a62dc 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-09 20:13+CET\n" +"POT-Creation-Date: 2014-03-09 20:14+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -30,7 +30,7 @@ msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" #: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:449 +#: tiramisu/value.py:485 msgid "the context does not exist anymore" msgstr "le context n'existe plus" @@ -477,24 +477,24 @@ msgid "if opt is not None, path should not be None in _getproperties" msgstr "" "si opt n'est pas None, path devrait ne pas être à None dans _getproperties" -#: tiramisu/setting.py:483 +#: tiramisu/setting.py:487 msgid "cannot change the value for option {0} this option is frozen" msgstr "" "ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" -#: tiramisu/setting.py:489 +#: tiramisu/setting.py:493 msgid "trying to access to an option named: {0} with properties {1}" msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}" -#: tiramisu/setting.py:507 +#: tiramisu/setting.py:511 msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:514 tiramisu/value.py:334 +#: tiramisu/setting.py:518 tiramisu/value.py:334 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" -#: tiramisu/setting.py:602 +#: tiramisu/setting.py:606 msgid "" "malformed requirements imbrication detected for option: '{0}' with " "requirement on: '{1}'" @@ -502,7 +502,7 @@ msgstr "" "imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "requirement sur : '{1}'" -#: tiramisu/setting.py:613 +#: tiramisu/setting.py:617 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}" @@ -531,43 +531,48 @@ msgstr "un espace de stockage dictionary ne peut être persistant" msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:426 +#: tiramisu/value.py:423 +msgid "can force cache only if cache is actived in config" +msgstr "" +"peut force la mise en cache seulement si le cache est activé dans la config" + +#: tiramisu/value.py:462 msgid "{0} is already a Multi " msgstr "{0} est déjà une Multi" -#: tiramisu/value.py:462 tiramisu/value.py:526 +#: tiramisu/value.py:498 tiramisu/value.py:562 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:498 +#: tiramisu/value.py:534 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:536 +#: tiramisu/value.py:572 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:540 +#: tiramisu/value.py:576 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:549 +#: tiramisu/value.py:585 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:557 +#: tiramisu/value.py:593 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:565 +#: tiramisu/value.py:601 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:576 +#: tiramisu/value.py:612 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/value.py:594 +#: tiramisu/value.py:630 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index 2a20646..df39688 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-09 20:13+CET\n" +"POT-Creation-Date: 2014-03-09 20:14+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -28,7 +28,7 @@ msgid "unknown group_type: {0}" msgstr "" #: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:449 +#: tiramisu/value.py:485 msgid "the context does not exist anymore" msgstr "" @@ -444,27 +444,27 @@ msgstr "" msgid "if opt is not None, path should not be None in _getproperties" msgstr "" -#: tiramisu/setting.py:483 +#: tiramisu/setting.py:487 msgid "cannot change the value for option {0} this option is frozen" msgstr "" -#: tiramisu/setting.py:489 +#: tiramisu/setting.py:493 msgid "trying to access to an option named: {0} with properties {1}" msgstr "" -#: tiramisu/setting.py:507 +#: tiramisu/setting.py:511 msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:514 tiramisu/value.py:334 +#: tiramisu/setting.py:518 tiramisu/value.py:334 msgid "invalid generic owner {0}" msgstr "" -#: tiramisu/setting.py:602 +#: tiramisu/setting.py:606 msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'" msgstr "" -#: tiramisu/setting.py:613 +#: tiramisu/setting.py:617 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "" @@ -492,43 +492,47 @@ msgstr "" msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:426 +#: tiramisu/value.py:423 +msgid "can force cache only if cache is actived in config" +msgstr "" + +#: tiramisu/value.py:462 msgid "{0} is already a Multi " msgstr "" -#: tiramisu/value.py:462 tiramisu/value.py:526 +#: tiramisu/value.py:498 tiramisu/value.py:562 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:498 +#: tiramisu/value.py:534 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:536 +#: tiramisu/value.py:572 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:540 +#: tiramisu/value.py:576 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:549 +#: tiramisu/value.py:585 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:557 +#: tiramisu/value.py:593 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:565 +#: tiramisu/value.py:601 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:576 +#: tiramisu/value.py:612 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/value.py:594 +#: tiramisu/value.py:630 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From db9ab7a1e991759ccbb7dc5c13af41a0b24cca40 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 9 Mar 2014 20:22:29 +0100 Subject: [PATCH 18/42] test if cache property is not set in config when force_cache --- test/test_cache.py | 7 +++++++ tiramisu/value.py | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/test_cache.py b/test/test_cache.py index ef4f1a3..e1cd609 100644 --- a/test/test_cache.py +++ b/test/test_cache.py @@ -4,7 +4,11 @@ from tiramisu import setting setting.expires_time = 1 from tiramisu.option import IntOption, OptionDescription from tiramisu.config import Config +from tiramisu.error import ConfigError + + from time import sleep, time +from py.test import raises def make_description(): @@ -272,3 +276,6 @@ def test_force_cache(): c.cfgimpl_get_values().force_cache() assert c.cfgimpl_get_values()._p_.get_cached(c) == {'u1': ([], None), 'u3': ([], None), 'u2': (None, None)} assert c.cfgimpl_get_settings()._p_.get_cached(c) == {'u4': (set(['disabled']), None), 'u1': (set([]), None), 'u3': (set([]), None), 'u2': (set([]), None)} + + c.cfgimpl_get_settings().remove('cache') + raises(ConfigError, "c.cfgimpl_get_values().force_cache()") diff --git a/tiramisu/value.py b/tiramisu/value.py index c07ddfc..a82e1a4 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -420,8 +420,8 @@ class Values(object): """ context = self.context() if not 'cache' in context.cfgimpl_get_settings(): - raise PropertiesOptionError(_('can force cache only if cache ' - 'is actived in config')) + raise ConfigError(_('can force cache only if cache ' + 'is actived in config')) #remove all cached properties and value to update "expired" time context.cfgimpl_reset_cache() for path in context.cfgimpl_get_description().impl_getpaths( From d7b04ebed0011a87d92594a6a42d41196aefe850 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 11 Mar 2014 18:57:19 +0100 Subject: [PATCH 19/42] add consistency in_network for IPOption This new consistency can validate that an IPv4 is a specified (network/netmask) network --- test/test_option_consistency.py | 23 ++++ tiramisu/option.py | 12 ++ translations/fr/tiramisu.po | 128 ++++++++++---------- translations/tiramisu.pot | 200 ++++++++++++++++---------------- 4 files changed, 203 insertions(+), 160 deletions(-) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 1beb4bb..b40c340 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -169,6 +169,29 @@ def test_consistency_network_netmask(): raises(ValueError, "c.a = '192.168.1.1'") +def test_consistency_ip_in_network(): + a = NetworkOption('a', '') + b = NetmaskOption('b', '') + c = IPOption('c', '') + od = OptionDescription('od', '', [a, b, c]) + c.impl_add_consistency('in_network', a, b) + cfg = Config(od) + cfg.a = '192.168.1.0' + cfg.b = '255.255.255.0' + cfg.c = '192.168.1.1' + raises(ValueError, "cfg.c = '192.168.2.1'") + + +def test_consistency_ip_in_network_len_error(): + a = NetworkOption('a', '') + b = NetmaskOption('b', '') + c = IPOption('c', '') + od = OptionDescription('od', '', [a, b, c]) + c.impl_add_consistency('in_network', a) + cfg = Config(od) + raises(ConfigError, "cfg.a = '192.168.2.0'") + + def test_consistency_ip_netmask_network_error(): a = IPOption('a', '') b = NetworkOption('b', '') diff --git a/tiramisu/option.py b/tiramisu/option.py index 20cdf86..7622811 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -784,6 +784,18 @@ class IPOption(Option): if self._private_only and not ip.iptype() == 'PRIVATE': raise ValueError(_("invalid IP, must be in private class")) + def _cons_in_network(self, opts, vals): + if len(vals) != 3: + raise ConfigError(_('invalid len for vals')) + if None in vals: + return + ip, network, netmask = vals + if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): + raise ValueError(_('invalid IP {0} ({1}) with network {2} ' + '({3}) and netmask {4} ({5})').format( + ip, opts[0]._name, network, + opts[1]._name, netmask, opts[2]._name)) + class PortOption(Option): """represents the choice of a port diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 459e281..d80b026 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-09 20:13+CET\n" +"POT-Creation-Date: 2014-03-11 18:51+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -203,187 +203,191 @@ msgstr "adresse IP invalide, ne doit pas être d'une classe reservée" msgid "invalid IP, must be in private class" msgstr "adresse IP invalide, doit être dans la classe privée" -#: tiramisu/option.py:823 +#: tiramisu/option.py:789 tiramisu/option.py:955 +msgid "invalid len for vals" +msgstr "longueur invalide pour vals" + +#: tiramisu/option.py:794 +msgid "invalid IP {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" +msgstr "IP invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" + +#: tiramisu/option.py:835 msgid "inconsistency in allowed range" msgstr "inconsistence dans la plage autorisée" -#: tiramisu/option.py:828 +#: tiramisu/option.py:840 msgid "max value is empty" msgstr "la valeur maximum est vide" -#: tiramisu/option.py:845 +#: tiramisu/option.py:857 msgid "invalid port, range must have two values only" msgstr "port invalide, une plage doit avoir deux valeurs seulement" -#: tiramisu/option.py:848 +#: tiramisu/option.py:860 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" "port invalide, le premier port d'une plage doit être plus petit que le second" -#: tiramisu/option.py:857 +#: tiramisu/option.py:869 msgid "invalid port" msgstr "port invalide" -#: tiramisu/option.py:859 +#: tiramisu/option.py:871 msgid "invalid port, must be an between {0} and {1}" msgstr "port invalide, port doit être entre {0} et {1}" -#: tiramisu/option.py:873 +#: tiramisu/option.py:885 msgid "invalid network address" msgstr "adresse réseau invalide" -#: tiramisu/option.py:878 +#: tiramisu/option.py:890 msgid "invalid network address, must not be in reserved class" msgstr "adresse réseau invalide, ne doit pas être dans la classe reservée" -#: tiramisu/option.py:890 +#: tiramisu/option.py:902 msgid "invalid netmask address" msgstr "masque de sous-réseau invalide" -#: tiramisu/option.py:906 +#: tiramisu/option.py:918 msgid "invalid len for opts" msgstr "longueur invalide pour opts" -#: tiramisu/option.py:920 +#: tiramisu/option.py:932 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau" -#: tiramisu/option.py:925 +#: tiramisu/option.py:937 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "réseau invalide {0} ({1}) avec masque {2}" -#: tiramisu/option.py:939 +#: tiramisu/option.py:951 msgid "invalid broadcast address" msgstr "adresse de broadcast invalide" -#: tiramisu/option.py:943 -msgid "invalid len for vals" -msgstr "longueur invalide pour vals" - -#: tiramisu/option.py:948 +#: tiramisu/option.py:960 msgid "" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" "Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" -#: tiramisu/option.py:970 +#: tiramisu/option.py:982 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:973 +#: tiramisu/option.py:985 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:975 +#: tiramisu/option.py:987 msgid "allow_without_dot must be a boolean" msgstr "allow_without_dot doit être un booléen" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1031 msgid "invalid domainname, must have dot" msgstr "nom de domaine invalide, doit avoir un point" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1033 msgid "invalid domainname's length (max 255)" msgstr "longueur du nom de domaine invalide (maximum {1})" -#: tiramisu/option.py:1023 +#: tiramisu/option.py:1035 msgid "invalid domainname's length (min 2)" msgstr "longueur du nom de domaine invalide (minimum 2)" -#: tiramisu/option.py:1025 +#: tiramisu/option.py:1037 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1038 +#: tiramisu/option.py:1050 msgid "invalid email address, should contains one @" msgstr "adresse email invalide, devrait contenir un @" -#: tiramisu/option.py:1041 +#: tiramisu/option.py:1053 msgid "invalid username in email address" msgstr "nom d'utilisateur invalide dans une adresse email" -#: tiramisu/option.py:1054 +#: tiramisu/option.py:1066 msgid "invalid url, should start with http:// or https://" msgstr "URL invalide, devrait démarré avec http:// ou https://" -#: tiramisu/option.py:1073 +#: tiramisu/option.py:1085 msgid "invalid url, port must be an between 0 and 65536" msgstr "URL invalide, port doit être entre 0 et 65536" -#: tiramisu/option.py:1079 +#: tiramisu/option.py:1091 msgid "invalid url, should ends with filename" msgstr "URL invalide, devrait finir avec un nom de fichier" -#: tiramisu/option.py:1091 +#: tiramisu/option.py:1103 msgid "invalid username" msgstr "utilisateur invalide" -#: tiramisu/option.py:1102 +#: tiramisu/option.py:1114 msgid "invalid filename" msgstr "nom de fichier invalide" -#: tiramisu/option.py:1129 +#: tiramisu/option.py:1141 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1147 +#: tiramisu/option.py:1159 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1198 +#: tiramisu/option.py:1210 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1228 +#: tiramisu/option.py:1240 msgid "consistency with option {0} which is not in Config" msgstr "consistency avec l'option {0} qui n'est pas dans une Config" -#: tiramisu/option.py:1236 +#: tiramisu/option.py:1248 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1242 +#: tiramisu/option.py:1254 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1252 +#: tiramisu/option.py:1264 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1276 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1267 +#: tiramisu/option.py:1279 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1270 +#: tiramisu/option.py:1282 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1280 +#: tiramisu/option.py:1292 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1288 +#: tiramisu/option.py:1300 msgid "callback of master's option shall not refered a slave's ones" msgstr "" "callback d'une variable maitre ne devrait pas référencer des variables " "esclaves" -#: tiramisu/option.py:1296 +#: tiramisu/option.py:1308 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" -#: tiramisu/option.py:1385 +#: tiramisu/option.py:1397 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" "type requirements malformé pour l'option : {0}, doit être un dictionnaire" -#: tiramisu/option.py:1402 +#: tiramisu/option.py:1414 msgid "" "malformed requirements for option: {0} require must have option, expected " "and action keys" @@ -391,66 +395,66 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1407 +#: tiramisu/option.py:1419 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1411 +#: tiramisu/option.py:1423 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1415 +#: tiramisu/option.py:1427 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1419 +#: tiramisu/option.py:1431 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1422 +#: tiramisu/option.py:1434 msgid "malformed requirements option {0} should not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1428 +#: tiramisu/option.py:1440 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1433 +#: tiramisu/option.py:1445 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1458 +#: tiramisu/option.py:1470 msgid "{0} should be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1461 +#: tiramisu/option.py:1473 msgid "{0}_params should be a dict" msgstr "{0}_params devrait être un dict" -#: tiramisu/option.py:1464 +#: tiramisu/option.py:1476 msgid "{0}_params with key {1} should not have length different to 1" msgstr "" "{0}_params avec la clef {1} devrait ne pas avoir une longueur différent de 1" -#: tiramisu/option.py:1468 +#: tiramisu/option.py:1480 msgid "{0}_params should be tuple for key \"{1}\"" msgstr "{0}_params devrait être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1474 +#: tiramisu/option.py:1486 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1489 msgid "{0}_params should have an option not a {0} for first argument" msgstr "{0}_params devrait avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1481 +#: tiramisu/option.py:1493 msgid "{0}_params should have a boolean not a {0} for second argument" msgstr "{0}_params devrait avoir un boolean pas un {0} pour second argument" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index 2a20646..d35e6a5 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-09 20:13+CET\n" +"POT-Creation-Date: 2014-03-11 18:51+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -192,235 +192,239 @@ msgstr "" msgid "invalid IP, must be in private class" msgstr "" -#: tiramisu/option.py:823 -msgid "inconsistency in allowed range" -msgstr "" - -#: tiramisu/option.py:828 -msgid "max value is empty" -msgstr "" - -#: tiramisu/option.py:845 -msgid "invalid port, range must have two values only" -msgstr "" - -#: tiramisu/option.py:848 -msgid "invalid port, first port in range must be smaller than the second one" -msgstr "" - -#: tiramisu/option.py:857 -msgid "invalid port" -msgstr "" - -#: tiramisu/option.py:859 -msgid "invalid port, must be an between {0} and {1}" -msgstr "" - -#: tiramisu/option.py:873 -msgid "invalid network address" -msgstr "" - -#: tiramisu/option.py:878 -msgid "invalid network address, must not be in reserved class" -msgstr "" - -#: tiramisu/option.py:890 -msgid "invalid netmask address" -msgstr "" - -#: tiramisu/option.py:906 -msgid "invalid len for opts" -msgstr "" - -#: tiramisu/option.py:920 -msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" -msgstr "" - -#: tiramisu/option.py:925 -msgid "invalid network {0} ({1}) with netmask {2}" -msgstr "" - -#: tiramisu/option.py:939 -msgid "invalid broadcast address" -msgstr "" - -#: tiramisu/option.py:943 +#: tiramisu/option.py:789 tiramisu/option.py:955 msgid "invalid len for vals" msgstr "" -#: tiramisu/option.py:948 +#: tiramisu/option.py:794 +msgid "invalid IP {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" +msgstr "" + +#: tiramisu/option.py:835 +msgid "inconsistency in allowed range" +msgstr "" + +#: tiramisu/option.py:840 +msgid "max value is empty" +msgstr "" + +#: tiramisu/option.py:857 +msgid "invalid port, range must have two values only" +msgstr "" + +#: tiramisu/option.py:860 +msgid "invalid port, first port in range must be smaller than the second one" +msgstr "" + +#: tiramisu/option.py:869 +msgid "invalid port" +msgstr "" + +#: tiramisu/option.py:871 +msgid "invalid port, must be an between {0} and {1}" +msgstr "" + +#: tiramisu/option.py:885 +msgid "invalid network address" +msgstr "" + +#: tiramisu/option.py:890 +msgid "invalid network address, must not be in reserved class" +msgstr "" + +#: tiramisu/option.py:902 +msgid "invalid netmask address" +msgstr "" + +#: tiramisu/option.py:918 +msgid "invalid len for opts" +msgstr "" + +#: tiramisu/option.py:932 +msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" +msgstr "" + +#: tiramisu/option.py:937 +msgid "invalid network {0} ({1}) with netmask {2}" +msgstr "" + +#: tiramisu/option.py:951 +msgid "invalid broadcast address" +msgstr "" + +#: tiramisu/option.py:960 msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:970 +#: tiramisu/option.py:982 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:973 +#: tiramisu/option.py:985 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:975 +#: tiramisu/option.py:987 msgid "allow_without_dot must be a boolean" msgstr "" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1031 msgid "invalid domainname, must have dot" msgstr "" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1033 msgid "invalid domainname's length (max 255)" msgstr "" -#: tiramisu/option.py:1023 +#: tiramisu/option.py:1035 msgid "invalid domainname's length (min 2)" msgstr "" -#: tiramisu/option.py:1025 +#: tiramisu/option.py:1037 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1038 +#: tiramisu/option.py:1050 msgid "invalid email address, should contains one @" msgstr "" -#: tiramisu/option.py:1041 +#: tiramisu/option.py:1053 msgid "invalid username in email address" msgstr "" -#: tiramisu/option.py:1054 +#: tiramisu/option.py:1066 msgid "invalid url, should start with http:// or https://" msgstr "" -#: tiramisu/option.py:1073 +#: tiramisu/option.py:1085 msgid "invalid url, port must be an between 0 and 65536" msgstr "" -#: tiramisu/option.py:1079 +#: tiramisu/option.py:1091 msgid "invalid url, should ends with filename" msgstr "" -#: tiramisu/option.py:1091 +#: tiramisu/option.py:1103 msgid "invalid username" msgstr "" -#: tiramisu/option.py:1102 +#: tiramisu/option.py:1114 msgid "invalid filename" msgstr "" -#: tiramisu/option.py:1129 +#: tiramisu/option.py:1141 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1147 +#: tiramisu/option.py:1159 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1198 +#: tiramisu/option.py:1210 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1228 +#: tiramisu/option.py:1240 msgid "consistency with option {0} which is not in Config" msgstr "" -#: tiramisu/option.py:1236 +#: tiramisu/option.py:1248 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1242 +#: tiramisu/option.py:1254 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1252 +#: tiramisu/option.py:1264 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1276 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1267 +#: tiramisu/option.py:1279 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1270 +#: tiramisu/option.py:1282 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1280 +#: tiramisu/option.py:1292 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1288 +#: tiramisu/option.py:1300 msgid "callback of master's option shall not refered a slave's ones" msgstr "" -#: tiramisu/option.py:1296 +#: tiramisu/option.py:1308 msgid "group_type: {0} not allowed" msgstr "" -#: tiramisu/option.py:1385 +#: tiramisu/option.py:1397 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" -#: tiramisu/option.py:1402 +#: tiramisu/option.py:1414 msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1407 +#: tiramisu/option.py:1419 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" -#: tiramisu/option.py:1411 +#: tiramisu/option.py:1423 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" -#: tiramisu/option.py:1415 +#: tiramisu/option.py:1427 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" -#: tiramisu/option.py:1419 +#: tiramisu/option.py:1431 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1422 +#: tiramisu/option.py:1434 msgid "malformed requirements option {0} should not be a multi" msgstr "" -#: tiramisu/option.py:1428 +#: tiramisu/option.py:1440 msgid "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" -#: tiramisu/option.py:1433 +#: tiramisu/option.py:1445 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "" -#: tiramisu/option.py:1458 +#: tiramisu/option.py:1470 msgid "{0} should be a function" msgstr "" -#: tiramisu/option.py:1461 +#: tiramisu/option.py:1473 msgid "{0}_params should be a dict" msgstr "" -#: tiramisu/option.py:1464 +#: tiramisu/option.py:1476 msgid "{0}_params with key {1} should not have length different to 1" msgstr "" -#: tiramisu/option.py:1468 +#: tiramisu/option.py:1480 msgid "{0}_params should be tuple for key \"{1}\"" msgstr "" -#: tiramisu/option.py:1474 +#: tiramisu/option.py:1486 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1489 msgid "{0}_params should have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1481 +#: tiramisu/option.py:1493 msgid "{0}_params should have a boolean not a {0} for second argument" msgstr "" From 544cd93c733c6033549b5972b95d894cd5cf2461 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 12 Mar 2014 14:57:36 +0100 Subject: [PATCH 20/42] can make_dict with disabled suboption --- test/test_config_api.py | 12 ++++++++++++ tiramisu/config.py | 23 +++++++++++++---------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/test/test_config_api.py b/test/test_config_api.py index 4be9e80..93f8c95 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -115,6 +115,18 @@ def test_make_dict(): raises(ValueError, 'd2 = config.make_dict(withvalue="3")') +def test_make_dict_with_disabled(): + descr = OptionDescription("opt", "", [ + OptionDescription("s1", "", [ + BoolOption("a", "", default=False), + BoolOption("b", "", default=False, properties=('disabled',))]), + IntOption("int", "", default=42)]) + config = Config(descr) + config.read_only() + d = config.make_dict() + assert d == {"s1.a": False, "int": 42} + + def test_find_in_config(): "finds option in config" descr = make_description() diff --git a/tiramisu/config.py b/tiramisu/config.py index c9fb992..4c59dbe 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -448,17 +448,20 @@ class SubConfig(object): return pathsvalues def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten): - if isinstance(opt, OptionDescription): - pathsvalues += getattr(self, path).make_dict(flatten, - _currpath + - path.split('.')) - else: - value = self._getattr(opt._name) - if flatten: - name = opt._name + try: + if isinstance(opt, OptionDescription): + pathsvalues += getattr(self, path).make_dict(flatten, + _currpath + + path.split('.')) else: - name = '.'.join(_currpath + [opt._name]) - pathsvalues.append((name, value)) + value = self._getattr(opt._name) + if flatten: + name = opt._name + else: + name = '.'.join(_currpath + [opt._name]) + pathsvalues.append((name, value)) + except PropertiesOptionError: + pass def cfgimpl_get_path(self): descr = self.cfgimpl_get_description() From 5f46763696f2b5cc3758d6efa568005cbb250a68 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 12 Mar 2014 16:44:48 +0100 Subject: [PATCH 21/42] add test for consistency with callback --- test/test_option_consistency.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index b40c340..45e8213 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -345,3 +345,17 @@ def test_consistency_permissive(): c.cfgimpl_get_settings().setpermissive(('hidden',)) c.read_write() c.a = 1 + + +def return_val(*args, **kwargs): + return '192.168.1.1' + + +def test_consistency_with_callback(): + a = NetworkOption('a', '', default='192.168.1.0') + b = NetmaskOption('b', '', default='255.255.255.0') + c = IPOption('c', '', callback=return_val, callback_params={'': ((a, False),)}) + od = OptionDescription('od', '', [a, b, c]) + c.impl_add_consistency('in_network', a, b) + cfg = Config(od) + cfg.c From ff802b46e5bb9a465807fc5f8853695e1661e6e7 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 12 Mar 2014 21:56:53 +0100 Subject: [PATCH 22/42] consistencies can make a warning instead of raises for that, you have to set something like: a.impl_add_consistency('not_equal', b, warnings_only=True) warning product now adapted message --- test/test_option_consistency.py | 16 ++- test/test_option_validator.py | 18 +-- tiramisu/option.py | 164 ++++++++++++++-------- translations/fr/tiramisu.po | 239 ++++++++++++++++++-------------- translations/tiramisu.pot | 236 +++++++++++++++++-------------- 5 files changed, 391 insertions(+), 282 deletions(-) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index b40c340..0a7de3c 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -5,7 +5,8 @@ from tiramisu.setting import owners, groups from tiramisu.config import Config from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\ BroadcastOption, SymLinkOption, OptionDescription -from tiramisu.error import ConfigError +from tiramisu.error import ConfigError, ValueWarning +import warnings def test_consistency(): @@ -19,6 +20,19 @@ def test_consistency(): raises(ConfigError, "a.impl_add_consistency('not_equal', 'a')") +def test_consistency_warnings_only(): + a = IntOption('a', '') + b = IntOption('b', '') + od = OptionDescription('od', '', [a, b]) + a.impl_add_consistency('not_equal', b, warnings_only=True) + c = Config(od) + c.a = 1 + warnings.simplefilter("always", ValueWarning) + with warnings.catch_warnings(record=True) as w: + c.b = 1 + assert w != [] + + def test_consistency_not_equal(): a = IntOption('a', '') b = IntOption('b', '') diff --git a/test/test_option_validator.py b/test/test_option_validator.py index dc08c82..76ebfc8 100644 --- a/test/test_option_validator.py +++ b/test/test_option_validator.py @@ -88,7 +88,7 @@ def test_validator_warning(): cfg.opt2 = 'val' assert len(w) == 1 assert w[0].message.opt == opt2 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt2', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error') # with warnings.catch_warnings(record=True) as w: cfg.opt3.append('val') @@ -98,7 +98,7 @@ def test_validator_warning(): cfg.opt3.append('val1') assert len(w) == 1 assert w[0].message.opt == opt3 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt3', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error') raises(ValueError, "cfg.opt2 = 1") # with warnings.catch_warnings(record=True) as w: @@ -106,9 +106,9 @@ def test_validator_warning(): cfg.opt3.append('val') assert len(w) == 2 assert w[0].message.opt == opt2 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt2', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('opt2', 'error') assert w[1].message.opt == opt3 - assert str(w[1].message) == _('invalid value for option {0}: {1}').format('opt3', 'error') + assert str(w[1].message) == _("warning on the value of the option {0}: {1}").format('opt3', 'error') def test_validator_warning_master_slave(): @@ -128,29 +128,29 @@ def test_validator_warning_master_slave(): cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1'] assert len(w) == 1 assert w[0].message.opt == netmask_admin_eth0 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('netmask_admin_eth0', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('netmask_admin_eth0', 'error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') # with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') # warnings.resetwarnings() with warnings.catch_warnings(record=True) as w: cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val'] assert len(w) == 1 assert w[0].message.opt == ip_admin_eth0 - assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error') + assert str(w[0].message) == _("warning on the value of the option {0}: {1}").format('ip_admin_eth0', 'error') diff --git a/tiramisu/option.py b/tiramisu/option.py index 7622811..db6acbd 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -336,7 +336,7 @@ class Option(BaseOption): self._consistencies = None def _launch_consistency(self, func, option, value, context, index, - all_cons_opts): + all_cons_opts, warnings_only): """Launch consistency now :param func: function name, this name should start with _cons_ @@ -351,6 +351,8 @@ class Option(BaseOption): :type index: `int` :param all_cons_opts: all options concerne by this consistency :type all_cons_opts: `list` of `tiramisu.option.Option` + :param warnings_only: specific raise error for warning + :type warnings_only: `boolean` """ if context is not None: descr = context.cfgimpl_get_description() @@ -379,7 +381,7 @@ class Option(BaseOption): except IndexError: #so return if no value return - getattr(self, func)(all_cons_opts, all_cons_vals) + getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only) def impl_validate(self, value, context=None, validate=True, force_index=None): @@ -422,22 +424,31 @@ class Option(BaseOption): except ValueError as err: raise ValueError(_('invalid value for option {0}: {1}' '').format(self._name, err)) + error = None + warning = None try: # valid with self._validator val_validator(_value) - # if not context launch consistency validation + # if context launch consistency validation if context is not None: - descr._valid_consistency(self, _value, context, _index) - self._second_level_validation(_value) - except ValueError as err: - msg = _("invalid value for option {0}: {1}").format( - self._name, err) + descr._valid_consistency(self, _value, context, _index, + self._warnings_only) + self._second_level_validation(_value, self._warnings_only) + except ValueError as error: if self._warnings_only: - warnings.warn_explicit(ValueWarning(msg, self), - ValueWarning, - self.__class__.__name__, 0) - else: - raise ValueError(msg) + warning = error + error = None + except ValueWarning as warning: + pass + if warning: + msg = _("warning on the value of the option {0}: {1}").format( + self._name, warning) + warnings.warn_explicit(ValueWarning(msg, self), + ValueWarning, + self.__class__.__name__, 0) + elif error: + raise ValueError(_("invalid value for option {0}: {1}").format( + self._name, error)) # generic calculation if context is not None: @@ -490,7 +501,7 @@ class Option(BaseOption): def impl_is_multi(self): return self._multi - def impl_add_consistency(self, func, *other_opts): + def impl_add_consistency(self, func, *other_opts, **params): """Add consistency means that value will be validate with other_opts option's values. @@ -498,16 +509,18 @@ class Option(BaseOption): :type func: `str` :param other_opts: options used to validate value :type other_opts: `list` of `tiramisu.option.Option` + :param params: extra params (only warnings_only are allowed) """ if self._consistencies is None: self._consistencies = [] + warnings_only = params.get('warnings_only', False) for opt in other_opts: if not isinstance(opt, Option): - raise ConfigError(_('consistency should be set with an option')) + raise ConfigError(_('consistency must be set with an option')) if self is opt: raise ConfigError(_('cannot add consistency with itself')) if self.impl_is_multi() != opt.impl_is_multi(): - raise ConfigError(_('every options in consistency should be ' + raise ConfigError(_('every options in consistency must be ' 'multi or none')) func = '_cons_{0}'.format(func) all_cons_opts = tuple([self] + list(other_opts)) @@ -516,19 +529,23 @@ class Option(BaseOption): if self.impl_is_multi(): for idx, val in enumerate(value): self._launch_consistency(func, self, val, None, - idx, all_cons_opts) + idx, all_cons_opts, warnings_only) else: self._launch_consistency(func, self, value, None, - None, all_cons_opts) - self._consistencies.append((func, all_cons_opts)) + None, all_cons_opts, warnings_only) + self._consistencies.append((func, all_cons_opts, params)) self.impl_validate(self.impl_getdefault()) - def _cons_not_equal(self, opts, vals): + def _cons_not_equal(self, opts, vals, warnings_only): for idx_inf, val_inf in enumerate(vals): for idx_sup, val_sup in enumerate(vals[idx_inf + 1:]): if val_inf == val_sup is not None: - raise ValueError(_("same value for {0} and {1}").format( - opts[idx_inf]._name, opts[idx_inf + idx_sup + 1]._name)) + if warnings_only: + msg = _("same value for {0} and {1}, should be different") + else: + msg = _("same value for {0} and {1}, must be different") + raise ValueError(msg.format(opts[idx_inf]._name, + opts[idx_inf + idx_sup + 1]._name)) def _impl_convert_callbacks(self, descr, load=False): if not load and self._callback is None: @@ -592,14 +609,14 @@ class Option(BaseOption): values.append(descr.impl_get_opt_by_path(obj)) else: values.append(descr.impl_get_path_by_opt(obj)) - new_value.append((consistency[0], tuple(values))) + new_value.append((consistency[0], tuple(values), consistency[2])) if load: del(self._state_consistencies) self._consistencies = new_value else: self._state_consistencies = new_value - def _second_level_validation(self, value): + def _second_level_validation(self, value, warnings_only): pass @@ -777,24 +794,36 @@ class IPOption(Option): except ValueError: raise ValueError(_('invalid IP')) - def _second_level_validation(self, value): + def _second_level_validation(self, value, warnings_only): ip = IP('{0}/32'.format(value)) if not self._allow_reserved and ip.iptype() == 'RESERVED': - raise ValueError(_("invalid IP, mustn't not be in reserved class")) + if warnings_only: + msg = _("IP shouldn't be in reserved class") + else: + msg = _("invalid IP, mustn't be in reserved class") + raise ValueError(msg) if self._private_only and not ip.iptype() == 'PRIVATE': - raise ValueError(_("invalid IP, must be in private class")) + if warnings_only: + msg = _("IP should be in private class") + else: + msg = _("invalid IP, must be in private class") + raise ValueError(msg) - def _cons_in_network(self, opts, vals): + def _cons_in_network(self, opts, vals, warnings_only): if len(vals) != 3: raise ConfigError(_('invalid len for vals')) if None in vals: return ip, network, netmask = vals if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): - raise ValueError(_('invalid IP {0} ({1}) with network {2} ' - '({3}) and netmask {4} ({5})').format( - ip, opts[0]._name, network, - opts[1]._name, netmask, opts[2]._name)) + if warnings_only: + msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}' + ' ({5})') + else: + msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with ' + 'netmask {4} ({5})') + raise ValueError(msg.format(ip, opts[0]._name, network, + opts[1]._name, netmask, opts[2]._name)) class PortOption(Option): @@ -884,10 +913,14 @@ class NetworkOption(Option): except ValueError: raise ValueError(_('invalid network address')) - def _second_level_validation(self, value): + def _second_level_validation(self, value, warnings_only): ip = IP(value) if ip.iptype() == 'RESERVED': - raise ValueError(_("invalid network address, must not be in reserved class")) + if warnings_only: + msg = _("network address shouldn't be in reserved class") + else: + msg = _("invalid network address, mustn't be in reserved class") + raise ValueError(msg) class NetmaskOption(Option): @@ -901,19 +934,20 @@ class NetmaskOption(Option): except ValueError: raise ValueError(_('invalid netmask address')) - def _cons_network_netmask(self, opts, vals): + def _cons_network_netmask(self, opts, vals, warnings_only): #opts must be (netmask, network) options if None in vals: return - self.__cons_netmask(opts, vals[0], vals[1], False) + self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only) - def _cons_ip_netmask(self, opts, vals): + def _cons_ip_netmask(self, opts, vals, warnings_only): #opts must be (netmask, ip) options if None in vals: return - self.__cons_netmask(opts, vals[0], vals[1], True) + self.__cons_netmask(opts, vals[0], vals[1], True, warnings_only) - def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net): + def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net, + warnings_only): if len(opts) != 2: raise ConfigError(_('invalid len for opts')) msg = None @@ -950,7 +984,7 @@ class BroadcastOption(Option): except ValueError: raise ValueError(_('invalid broadcast address')) - def _cons_broadcast(self, opts, vals): + def _cons_broadcast(self, opts, vals, warnings_only): if len(vals) != 3: raise ConfigError(_('invalid len for vals')) if None in vals: @@ -1047,7 +1081,7 @@ class EmailOption(DomainnameOption): try: username, domain = splitted except ValueError: - raise ValueError(_('invalid email address, should contains one @' + raise ValueError(_('invalid email address, must contains one @' )) if not self.username_re.search(username): raise ValueError(_('invalid username in email address')) @@ -1063,7 +1097,7 @@ class URLOption(DomainnameOption): def _validate(self, value): match = self.proto_re.search(value) if not match: - raise ValueError(_('invalid url, should start with http:// or ' + raise ValueError(_('invalid url, must start with http:// or ' 'https://')) value = value[len(match.group(0)):] # get domain/files @@ -1088,7 +1122,7 @@ class URLOption(DomainnameOption): super(URLOption, self)._validate(domain) # validate file if files is not None and files != '' and not self.path_re.search(files): - raise ValueError(_('invalid url, should ends with filename')) + raise ValueError(_('invalid url, must ends with filename')) class UsernameOption(Option): @@ -1217,11 +1251,12 @@ class OptionDescription(BaseOption): if not force_no_consistencies and \ option._consistencies is not None: for consistency in option._consistencies: - func, all_cons_opts = consistency + func, all_cons_opts, params = consistency for opt in all_cons_opts: _consistencies.setdefault(opt, []).append((func, - all_cons_opts)) + all_cons_opts, + params)) else: _currpath.append(attr) option.impl_build_cache(cache_path, @@ -1311,18 +1346,29 @@ class OptionDescription(BaseOption): def impl_get_group_type(self): return self._group_type - def _valid_consistency(self, option, value, context, index): + def _valid_consistency(self, option, value, context, index, warnings_only): if self._cache_consistencies is None: return True #consistencies is something like [('_cons_not_equal', (opt1, opt2))] consistencies = self._cache_consistencies.get(option) if consistencies is not None: - for func, all_cons_opts in consistencies: + for func, all_cons_opts, params in consistencies: + if not warnings_only: + l_warnings_only = params.get('warnings_only', False) + else: + l_warnings_only = warnings_only #all_cons_opts[0] is the option where func is set - all_cons_opts[0]._launch_consistency(func, option, - value, - context, index, - all_cons_opts) + try: + all_cons_opts[0]._launch_consistency(func, option, + value, + context, index, + all_cons_opts, + l_warnings_only) + except ValueError as err: + if l_warnings_only: + raise ValueWarning(err.message, option) + else: + raise err def _impl_getstate(self, descr=None): """enables us to export into a dict @@ -1432,7 +1478,7 @@ def validate_requires_arg(requires, name): 'must be an option in option {0}').format(name)) if option.impl_is_multi(): raise ValueError(_('malformed requirements option {0} ' - 'should not be a multi').format(name)) + 'must not be a multi').format(name)) if expected is not None: try: option._validate(expected) @@ -1467,17 +1513,17 @@ def validate_requires_arg(requires, name): def validate_callback(callback, callback_params, type_): if type(callback) != FunctionType: - raise ValueError(_('{0} should be a function').format(type_)) + raise ValueError(_('{0} must be a function').format(type_)) if callback_params is not None: if not isinstance(callback_params, dict): - raise ValueError(_('{0}_params should be a dict').format(type_)) + raise ValueError(_('{0}_params must be a dict').format(type_)) for key, callbacks in callback_params.items(): if key != '' and len(callbacks) != 1: - raise ValueError(_('{0}_params with key {1} should not have ' - 'length different to 1').format(type_, + raise ValueError(_("{0}_params with key {1} mustn't have " + "length different to 1").format(type_, key)) if not isinstance(callbacks, tuple): - raise ValueError(_('{0}_params should be tuple for key "{1}"' + raise ValueError(_('{0}_params must be tuple for key "{1}"' ).format(type_, key)) for callbk in callbacks: if isinstance(callbk, tuple): @@ -1486,11 +1532,11 @@ def validate_callback(callback, callback_params, type_): raise ValueError(_('validator not support tuple')) if not isinstance(option, Option) and not \ isinstance(option, SymLinkOption): - raise ValueError(_('{0}_params should have an option ' + raise ValueError(_('{0}_params must have an option ' 'not a {0} for first argument' ).format(type_, type(option))) if force_permissive not in [True, False]: - raise ValueError(_('{0}_params should have a boolean' + raise ValueError(_('{0}_params must have a boolean' ' not a {0} for second argument' ).format(type_, type( force_permissive))) diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index d80b026..e5ce1a1 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-11 18:51+CET\n" +"POT-Creation-Date: 2014-03-12 21:49+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -130,264 +130,289 @@ msgstr "" "params définis pour une fonction callback mais par de callback encore " "définis pour l'option {0}" -#: tiramisu/option.py:423 tiramisu/option.py:433 +#: tiramisu/option.py:425 tiramisu/option.py:450 msgid "invalid value for option {0}: {1}" msgstr "valeur invalide pour l'option {0} : {1}" -#: tiramisu/option.py:450 +#: tiramisu/option.py:444 +msgid "warning on the value of the option {0}: {1}" +msgstr "avertissement sur la valeur de l'option {0} : {1}" + +#: tiramisu/option.py:461 msgid "invalid value {0} for option {1} which must be a list" msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste" -#: tiramisu/option.py:506 -msgid "consistency should be set with an option" +#: tiramisu/option.py:519 +msgid "consistency must be set with an option" msgstr "consistency doit être configuré avec une option" -#: tiramisu/option.py:508 +#: tiramisu/option.py:521 msgid "cannot add consistency with itself" msgstr "ne peut ajouter une consistency avec lui même" -#: tiramisu/option.py:510 -msgid "every options in consistency should be multi or none" +#: tiramisu/option.py:523 +msgid "every options in consistency must be multi or none" msgstr "" -"toutes les options d'une consistency devrait être multi ou ne pas l'être" +"toutes les options d'une consistency doivent être multi ou ne pas l'être" -#: tiramisu/option.py:530 -msgid "same value for {0} and {1}" -msgstr "même valeur pour {0} et {1}" +#: tiramisu/option.py:544 +msgid "same value for {0} and {1}, should be different" +msgstr "même valeur pour {0} et {1}, devrait être différent" -#: tiramisu/option.py:623 +#: tiramisu/option.py:546 +msgid "same value for {0} and {1}, must be different" +msgstr "même valeur pour {0} et {1}, doit être différent" + +#: tiramisu/option.py:640 msgid "values must be a tuple for {0}" msgstr "values doit être un tuple pour {0}" -#: tiramisu/option.py:626 +#: tiramisu/option.py:643 msgid "open_values must be a boolean for {0}" msgstr "open_values doit être un booléen pour {0}" -#: tiramisu/option.py:648 +#: tiramisu/option.py:665 msgid "value {0} is not permitted, only {1} is allowed" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" -#: tiramisu/option.py:660 +#: tiramisu/option.py:677 msgid "invalid boolean" msgstr "booléen invalide" -#: tiramisu/option.py:670 +#: tiramisu/option.py:687 msgid "invalid integer" msgstr "nombre invalide" -#: tiramisu/option.py:680 +#: tiramisu/option.py:697 msgid "invalid float" msgstr "invalide nombre flottan" -#: tiramisu/option.py:690 +#: tiramisu/option.py:707 msgid "invalid string" msgstr "invalide caractère" -#: tiramisu/option.py:707 +#: tiramisu/option.py:724 msgid "invalid unicode" msgstr "invalide unicode" -#: tiramisu/option.py:719 +#: tiramisu/option.py:736 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" -#: tiramisu/option.py:770 tiramisu/option.py:773 tiramisu/option.py:778 +#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 msgid "invalid IP" msgstr "adresse IP invalide" -#: tiramisu/option.py:783 -msgid "invalid IP, mustn't not be in reserved class" -msgstr "adresse IP invalide, ne doit pas être d'une classe reservée" +#: tiramisu/option.py:801 +msgid "IP shouldn't be in reserved class" +msgstr "l'adresse IP ne devrait pas être d'une classe réservée" -#: tiramisu/option.py:785 +#: tiramisu/option.py:803 +msgid "invalid IP, mustn't be in reserved class" +msgstr "adresse IP invalide, ne doit pas être dans une classe réservée" + +#: tiramisu/option.py:807 +msgid "IP should be in private class" +msgstr "l'adresse IP devrait être dans une classe privée" + +#: tiramisu/option.py:809 msgid "invalid IP, must be in private class" msgstr "adresse IP invalide, doit être dans la classe privée" -#: tiramisu/option.py:789 tiramisu/option.py:955 +#: tiramisu/option.py:814 tiramisu/option.py:989 msgid "invalid len for vals" msgstr "longueur invalide pour vals" -#: tiramisu/option.py:794 -msgid "invalid IP {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" -msgstr "IP invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" +#: tiramisu/option.py:820 +msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" +msgstr "IP {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" -#: tiramisu/option.py:835 +#: tiramisu/option.py:823 +msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" +msgstr "" +"IP invalide {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" + +#: tiramisu/option.py:864 msgid "inconsistency in allowed range" msgstr "inconsistence dans la plage autorisée" -#: tiramisu/option.py:840 +#: tiramisu/option.py:869 msgid "max value is empty" msgstr "la valeur maximum est vide" -#: tiramisu/option.py:857 +#: tiramisu/option.py:886 msgid "invalid port, range must have two values only" msgstr "port invalide, une plage doit avoir deux valeurs seulement" -#: tiramisu/option.py:860 +#: tiramisu/option.py:889 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" "port invalide, le premier port d'une plage doit être plus petit que le second" -#: tiramisu/option.py:869 +#: tiramisu/option.py:898 msgid "invalid port" msgstr "port invalide" -#: tiramisu/option.py:871 +#: tiramisu/option.py:900 msgid "invalid port, must be an between {0} and {1}" msgstr "port invalide, port doit être entre {0} et {1}" -#: tiramisu/option.py:885 +#: tiramisu/option.py:914 msgid "invalid network address" msgstr "adresse réseau invalide" -#: tiramisu/option.py:890 -msgid "invalid network address, must not be in reserved class" -msgstr "adresse réseau invalide, ne doit pas être dans la classe reservée" +#: tiramisu/option.py:920 +msgid "network address shouldn't be in reserved class" +msgstr "l'adresse réseau ne devait pas être dans la classe réservée" -#: tiramisu/option.py:902 +#: tiramisu/option.py:922 +msgid "invalid network address, mustn't be in reserved class" +msgstr "adresse réseau invalide, ne doit pas être dans la classe réservée" + +#: tiramisu/option.py:935 msgid "invalid netmask address" msgstr "masque de sous-réseau invalide" -#: tiramisu/option.py:918 +#: tiramisu/option.py:952 msgid "invalid len for opts" msgstr "longueur invalide pour opts" -#: tiramisu/option.py:932 +#: tiramisu/option.py:966 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau" -#: tiramisu/option.py:937 +#: tiramisu/option.py:971 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "réseau invalide {0} ({1}) avec masque {2}" -#: tiramisu/option.py:951 +#: tiramisu/option.py:985 msgid "invalid broadcast address" msgstr "adresse de broadcast invalide" -#: tiramisu/option.py:960 +#: tiramisu/option.py:994 msgid "" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" "Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" -#: tiramisu/option.py:982 +#: tiramisu/option.py:1016 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:985 +#: tiramisu/option.py:1019 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:987 +#: tiramisu/option.py:1021 msgid "allow_without_dot must be a boolean" msgstr "allow_without_dot doit être un booléen" -#: tiramisu/option.py:1031 +#: tiramisu/option.py:1065 msgid "invalid domainname, must have dot" msgstr "nom de domaine invalide, doit avoir un point" -#: tiramisu/option.py:1033 +#: tiramisu/option.py:1067 msgid "invalid domainname's length (max 255)" msgstr "longueur du nom de domaine invalide (maximum {1})" -#: tiramisu/option.py:1035 +#: tiramisu/option.py:1069 msgid "invalid domainname's length (min 2)" msgstr "longueur du nom de domaine invalide (minimum 2)" -#: tiramisu/option.py:1037 +#: tiramisu/option.py:1071 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1050 -msgid "invalid email address, should contains one @" -msgstr "adresse email invalide, devrait contenir un @" +#: tiramisu/option.py:1084 +msgid "invalid email address, must contains one @" +msgstr "adresse email invalide, doit contenir un @" -#: tiramisu/option.py:1053 +#: tiramisu/option.py:1087 msgid "invalid username in email address" msgstr "nom d'utilisateur invalide dans une adresse email" -#: tiramisu/option.py:1066 -msgid "invalid url, should start with http:// or https://" -msgstr "URL invalide, devrait démarré avec http:// ou https://" +#: tiramisu/option.py:1100 +msgid "invalid url, must start with http:// or https://" +msgstr "URL invalide, doit démarrer avec http:// ou https://" -#: tiramisu/option.py:1085 +#: tiramisu/option.py:1119 msgid "invalid url, port must be an between 0 and 65536" msgstr "URL invalide, port doit être entre 0 et 65536" -#: tiramisu/option.py:1091 -msgid "invalid url, should ends with filename" -msgstr "URL invalide, devrait finir avec un nom de fichier" +#: tiramisu/option.py:1125 +msgid "invalid url, must ends with filename" +msgstr "URL invalide, doit finir avec un nom de fichier" -#: tiramisu/option.py:1103 +#: tiramisu/option.py:1137 msgid "invalid username" msgstr "utilisateur invalide" -#: tiramisu/option.py:1114 +#: tiramisu/option.py:1148 msgid "invalid filename" msgstr "nom de fichier invalide" -#: tiramisu/option.py:1141 +#: tiramisu/option.py:1175 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1159 +#: tiramisu/option.py:1193 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1210 +#: tiramisu/option.py:1244 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1240 +#: tiramisu/option.py:1275 msgid "consistency with option {0} which is not in Config" msgstr "consistency avec l'option {0} qui n'est pas dans une Config" -#: tiramisu/option.py:1248 +#: tiramisu/option.py:1283 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1254 +#: tiramisu/option.py:1289 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1299 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1276 +#: tiramisu/option.py:1311 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1279 +#: tiramisu/option.py:1314 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1282 +#: tiramisu/option.py:1317 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1292 +#: tiramisu/option.py:1327 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1300 +#: tiramisu/option.py:1335 msgid "callback of master's option shall not refered a slave's ones" msgstr "" "callback d'une variable maitre ne devrait pas référencer des variables " "esclaves" -#: tiramisu/option.py:1308 +#: tiramisu/option.py:1343 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" -#: tiramisu/option.py:1397 +#: tiramisu/option.py:1443 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" "type requirements malformé pour l'option : {0}, doit être un dictionnaire" -#: tiramisu/option.py:1414 +#: tiramisu/option.py:1460 msgid "" "malformed requirements for option: {0} require must have option, expected " "and action keys" @@ -395,68 +420,68 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1419 +#: tiramisu/option.py:1465 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1423 +#: tiramisu/option.py:1469 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1427 +#: tiramisu/option.py:1473 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1431 +#: tiramisu/option.py:1477 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1434 -msgid "malformed requirements option {0} should not be a multi" +#: tiramisu/option.py:1480 +msgid "malformed requirements option {0} must not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1440 +#: tiramisu/option.py:1486 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1445 +#: tiramisu/option.py:1491 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1470 -msgid "{0} should be a function" +#: tiramisu/option.py:1516 +msgid "{0} must be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1473 -msgid "{0}_params should be a dict" -msgstr "{0}_params devrait être un dict" +#: tiramisu/option.py:1519 +msgid "{0}_params must be a dict" +msgstr "{0}_params doit être un dict" -#: tiramisu/option.py:1476 -msgid "{0}_params with key {1} should not have length different to 1" +#: tiramisu/option.py:1522 +msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" -"{0}_params avec la clef {1} devrait ne pas avoir une longueur différent de 1" +"{0}_params avec la clef {1} ne doit pas avoir une longueur différent de 1" -#: tiramisu/option.py:1480 -msgid "{0}_params should be tuple for key \"{1}\"" -msgstr "{0}_params devrait être un tuple pour la clef \"{1}\"" +#: tiramisu/option.py:1526 +msgid "{0}_params must be tuple for key \"{1}\"" +msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1486 +#: tiramisu/option.py:1532 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1489 -msgid "{0}_params should have an option not a {0} for first argument" -msgstr "{0}_params devrait avoir une option pas un {0} pour premier argument" +#: tiramisu/option.py:1535 +msgid "{0}_params must have an option not a {0} for first argument" +msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1493 -msgid "{0}_params should have a boolean not a {0} for second argument" -msgstr "{0}_params devrait avoir un boolean pas un {0} pour second argument" +#: tiramisu/option.py:1539 +msgid "{0}_params must have a boolean not a {0} for second argument" +msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" #: tiramisu/setting.py:116 msgid "can't rebind {0}" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index d35e6a5..738fa53 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-11 18:51+CET\n" +"POT-Creation-Date: 2014-03-12 21:49+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -120,312 +120,336 @@ msgstr "" msgid "params defined for a callback function but no callback defined yet for option {0}" msgstr "" -#: tiramisu/option.py:423 tiramisu/option.py:433 +#: tiramisu/option.py:425 tiramisu/option.py:450 msgid "invalid value for option {0}: {1}" msgstr "" -#: tiramisu/option.py:450 +#: tiramisu/option.py:444 +msgid "warning on the value of the option {0}: {1}" +msgstr "" + +#: tiramisu/option.py:461 msgid "invalid value {0} for option {1} which must be a list" msgstr "" -#: tiramisu/option.py:506 -msgid "consistency should be set with an option" +#: tiramisu/option.py:519 +msgid "consistency must be set with an option" msgstr "" -#: tiramisu/option.py:508 +#: tiramisu/option.py:521 msgid "cannot add consistency with itself" msgstr "" -#: tiramisu/option.py:510 -msgid "every options in consistency should be multi or none" +#: tiramisu/option.py:523 +msgid "every options in consistency must be multi or none" msgstr "" -#: tiramisu/option.py:530 -msgid "same value for {0} and {1}" +#: tiramisu/option.py:544 +msgid "same value for {0} and {1}, should be different" msgstr "" -#: tiramisu/option.py:623 +#: tiramisu/option.py:546 +msgid "same value for {0} and {1}, must be different" +msgstr "" + +#: tiramisu/option.py:640 msgid "values must be a tuple for {0}" msgstr "" -#: tiramisu/option.py:626 +#: tiramisu/option.py:643 msgid "open_values must be a boolean for {0}" msgstr "" -#: tiramisu/option.py:648 +#: tiramisu/option.py:665 msgid "value {0} is not permitted, only {1} is allowed" msgstr "" -#: tiramisu/option.py:660 +#: tiramisu/option.py:677 msgid "invalid boolean" msgstr "" -#: tiramisu/option.py:670 +#: tiramisu/option.py:687 msgid "invalid integer" msgstr "" -#: tiramisu/option.py:680 +#: tiramisu/option.py:697 msgid "invalid float" msgstr "" -#: tiramisu/option.py:690 +#: tiramisu/option.py:707 msgid "invalid string" msgstr "" -#: tiramisu/option.py:707 +#: tiramisu/option.py:724 msgid "invalid unicode" msgstr "" -#: tiramisu/option.py:719 +#: tiramisu/option.py:736 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "" -#: tiramisu/option.py:770 tiramisu/option.py:773 tiramisu/option.py:778 +#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 msgid "invalid IP" msgstr "" -#: tiramisu/option.py:783 -msgid "invalid IP, mustn't not be in reserved class" +#: tiramisu/option.py:801 +msgid "IP shouldn't be in reserved class" msgstr "" -#: tiramisu/option.py:785 +#: tiramisu/option.py:803 +msgid "invalid IP, mustn't be in reserved class" +msgstr "" + +#: tiramisu/option.py:807 +msgid "IP should be in private class" +msgstr "" + +#: tiramisu/option.py:809 msgid "invalid IP, must be in private class" msgstr "" -#: tiramisu/option.py:789 tiramisu/option.py:955 +#: tiramisu/option.py:814 tiramisu/option.py:989 msgid "invalid len for vals" msgstr "" -#: tiramisu/option.py:794 -msgid "invalid IP {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" +#: tiramisu/option.py:820 +msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:835 +#: tiramisu/option.py:823 +msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" +msgstr "" + +#: tiramisu/option.py:864 msgid "inconsistency in allowed range" msgstr "" -#: tiramisu/option.py:840 +#: tiramisu/option.py:869 msgid "max value is empty" msgstr "" -#: tiramisu/option.py:857 +#: tiramisu/option.py:886 msgid "invalid port, range must have two values only" msgstr "" -#: tiramisu/option.py:860 +#: tiramisu/option.py:889 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" -#: tiramisu/option.py:869 +#: tiramisu/option.py:898 msgid "invalid port" msgstr "" -#: tiramisu/option.py:871 +#: tiramisu/option.py:900 msgid "invalid port, must be an between {0} and {1}" msgstr "" -#: tiramisu/option.py:885 +#: tiramisu/option.py:914 msgid "invalid network address" msgstr "" -#: tiramisu/option.py:890 -msgid "invalid network address, must not be in reserved class" +#: tiramisu/option.py:920 +msgid "network address shouldn't be in reserved class" msgstr "" -#: tiramisu/option.py:902 +#: tiramisu/option.py:922 +msgid "invalid network address, mustn't be in reserved class" +msgstr "" + +#: tiramisu/option.py:935 msgid "invalid netmask address" msgstr "" -#: tiramisu/option.py:918 +#: tiramisu/option.py:952 msgid "invalid len for opts" msgstr "" -#: tiramisu/option.py:932 +#: tiramisu/option.py:966 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "" -#: tiramisu/option.py:937 +#: tiramisu/option.py:971 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "" -#: tiramisu/option.py:951 +#: tiramisu/option.py:985 msgid "invalid broadcast address" msgstr "" -#: tiramisu/option.py:960 +#: tiramisu/option.py:994 msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:982 +#: tiramisu/option.py:1016 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:985 +#: tiramisu/option.py:1019 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:987 +#: tiramisu/option.py:1021 msgid "allow_without_dot must be a boolean" msgstr "" -#: tiramisu/option.py:1031 +#: tiramisu/option.py:1065 msgid "invalid domainname, must have dot" msgstr "" -#: tiramisu/option.py:1033 +#: tiramisu/option.py:1067 msgid "invalid domainname's length (max 255)" msgstr "" -#: tiramisu/option.py:1035 +#: tiramisu/option.py:1069 msgid "invalid domainname's length (min 2)" msgstr "" -#: tiramisu/option.py:1037 +#: tiramisu/option.py:1071 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1050 -msgid "invalid email address, should contains one @" +#: tiramisu/option.py:1084 +msgid "invalid email address, must contains one @" msgstr "" -#: tiramisu/option.py:1053 +#: tiramisu/option.py:1087 msgid "invalid username in email address" msgstr "" -#: tiramisu/option.py:1066 -msgid "invalid url, should start with http:// or https://" +#: tiramisu/option.py:1100 +msgid "invalid url, must start with http:// or https://" msgstr "" -#: tiramisu/option.py:1085 +#: tiramisu/option.py:1119 msgid "invalid url, port must be an between 0 and 65536" msgstr "" -#: tiramisu/option.py:1091 -msgid "invalid url, should ends with filename" +#: tiramisu/option.py:1125 +msgid "invalid url, must ends with filename" msgstr "" -#: tiramisu/option.py:1103 +#: tiramisu/option.py:1137 msgid "invalid username" msgstr "" -#: tiramisu/option.py:1114 +#: tiramisu/option.py:1148 msgid "invalid filename" msgstr "" -#: tiramisu/option.py:1141 +#: tiramisu/option.py:1175 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1159 +#: tiramisu/option.py:1193 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1210 +#: tiramisu/option.py:1244 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1240 +#: tiramisu/option.py:1275 msgid "consistency with option {0} which is not in Config" msgstr "" -#: tiramisu/option.py:1248 +#: tiramisu/option.py:1283 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1254 +#: tiramisu/option.py:1289 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1264 +#: tiramisu/option.py:1299 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1276 +#: tiramisu/option.py:1311 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1279 +#: tiramisu/option.py:1314 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1282 +#: tiramisu/option.py:1317 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1292 +#: tiramisu/option.py:1327 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1300 +#: tiramisu/option.py:1335 msgid "callback of master's option shall not refered a slave's ones" msgstr "" -#: tiramisu/option.py:1308 +#: tiramisu/option.py:1343 msgid "group_type: {0} not allowed" msgstr "" -#: tiramisu/option.py:1397 +#: tiramisu/option.py:1443 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" -#: tiramisu/option.py:1414 +#: tiramisu/option.py:1460 msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1419 +#: tiramisu/option.py:1465 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" -#: tiramisu/option.py:1423 +#: tiramisu/option.py:1469 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" -#: tiramisu/option.py:1427 +#: tiramisu/option.py:1473 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" -#: tiramisu/option.py:1431 +#: tiramisu/option.py:1477 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1434 -msgid "malformed requirements option {0} should not be a multi" -msgstr "" - -#: tiramisu/option.py:1440 -msgid "malformed requirements second argument must be valid for option {0}: {1}" -msgstr "" - -#: tiramisu/option.py:1445 -msgid "inconsistency in action types for option: {0} action: {1}" -msgstr "" - -#: tiramisu/option.py:1470 -msgid "{0} should be a function" -msgstr "" - -#: tiramisu/option.py:1473 -msgid "{0}_params should be a dict" -msgstr "" - -#: tiramisu/option.py:1476 -msgid "{0}_params with key {1} should not have length different to 1" -msgstr "" - #: tiramisu/option.py:1480 -msgid "{0}_params should be tuple for key \"{1}\"" +msgid "malformed requirements option {0} must not be a multi" msgstr "" #: tiramisu/option.py:1486 +msgid "malformed requirements second argument must be valid for option {0}: {1}" +msgstr "" + +#: tiramisu/option.py:1491 +msgid "inconsistency in action types for option: {0} action: {1}" +msgstr "" + +#: tiramisu/option.py:1516 +msgid "{0} must be a function" +msgstr "" + +#: tiramisu/option.py:1519 +msgid "{0}_params must be a dict" +msgstr "" + +#: tiramisu/option.py:1522 +msgid "{0}_params with key {1} mustn't have length different to 1" +msgstr "" + +#: tiramisu/option.py:1526 +msgid "{0}_params must be tuple for key \"{1}\"" +msgstr "" + +#: tiramisu/option.py:1532 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1489 -msgid "{0}_params should have an option not a {0} for first argument" +#: tiramisu/option.py:1535 +msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1493 -msgid "{0}_params should have a boolean not a {0} for second argument" +#: tiramisu/option.py:1539 +msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" #: tiramisu/setting.py:116 From f43ef2dafee43fec2945dfdf28c638803a9a10d3 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 13 Mar 2014 14:12:44 +0100 Subject: [PATCH 23/42] now there are two warnings_only's level: - option's level for validation and _second_level_validation - consistencies level --- tiramisu/option.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index db6acbd..af862af 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -429,10 +429,6 @@ class Option(BaseOption): try: # valid with self._validator val_validator(_value) - # if context launch consistency validation - if context is not None: - descr._valid_consistency(self, _value, context, _index, - self._warnings_only) self._second_level_validation(_value, self._warnings_only) except ValueError as error: if self._warnings_only: @@ -440,6 +436,15 @@ class Option(BaseOption): error = None except ValueWarning as warning: pass + if error is None and warning is None: + try: + # if context launch consistency validation + if context is not None: + descr._valid_consistency(self, _value, context, _index) + except ValueError as error: + pass + except ValueWarning as warning: + pass if warning: msg = _("warning on the value of the option {0}: {1}").format( self._name, warning) @@ -1346,26 +1351,23 @@ class OptionDescription(BaseOption): def impl_get_group_type(self): return self._group_type - def _valid_consistency(self, option, value, context, index, warnings_only): + def _valid_consistency(self, option, value, context, index): if self._cache_consistencies is None: return True #consistencies is something like [('_cons_not_equal', (opt1, opt2))] consistencies = self._cache_consistencies.get(option) if consistencies is not None: for func, all_cons_opts, params in consistencies: - if not warnings_only: - l_warnings_only = params.get('warnings_only', False) - else: - l_warnings_only = warnings_only + warnings_only = params.get('warnings_only', False) #all_cons_opts[0] is the option where func is set try: all_cons_opts[0]._launch_consistency(func, option, value, context, index, all_cons_opts, - l_warnings_only) + warnings_only) except ValueError as err: - if l_warnings_only: + if warnings_only: raise ValueWarning(err.message, option) else: raise err From 2e55a6c6f87e6745568e6729645a10faa2432e37 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 15 Mar 2014 10:20:48 +0100 Subject: [PATCH 24/42] new version's files --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0f82de4..1f7391f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0rc1 +master From 1c80f559962ad53238f3ebc1da5113976ef1c93d Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 24 Mar 2014 21:13:26 +0100 Subject: [PATCH 25/42] update warning's message --- tiramisu/option.py | 6 +- translations/fr/tiramisu.po | 290 ++++++++++++++++++------------------ translations/tiramisu.pot | 288 +++++++++++++++++------------------ 3 files changed, 292 insertions(+), 292 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index fee61b5..30277e2 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -802,13 +802,13 @@ class IPOption(Option): ip = IP('{0}/32'.format(value)) if not self._allow_reserved and ip.iptype() == 'RESERVED': if warnings_only: - msg = _("IP shouldn't be in reserved class") + msg = _("IP is in reserved class") else: msg = _("invalid IP, mustn't be in reserved class") raise ValueError(msg) if self._private_only and not ip.iptype() == 'PRIVATE': if warnings_only: - msg = _("IP should be in private class") + msg = _("IP is not in private class") else: msg = _("invalid IP, must be in private class") raise ValueError(msg) @@ -921,7 +921,7 @@ class NetworkOption(Option): ip = IP(value) if ip.iptype() == 'RESERVED': if warnings_only: - msg = _("network address shouldn't be in reserved class") + msg = _("network address is in reserved class") else: msg = _("invalid network address, mustn't be in reserved class") raise ValueError(msg) diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 3dee004..0e1b339 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-12 21:49+CET\n" +"POT-Creation-Date: 2014-03-24 19:54+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -14,115 +14,115 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: tiramisu/autolib.py:162 +#: tiramisu/autolib.py:161 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" "impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : " "{2}" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "descr doit être une optiondescription pas un {0}" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" -#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:485 +#: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 +#: tiramisu/value.py:483 msgid "the context does not exist anymore" msgstr "le context n'existe plus" -#: tiramisu/config.py:169 +#: tiramisu/config.py:168 msgid "no option description found for this config (may be GroupConfig)" msgstr "" "pas d'option description trouvé pour cette config (peut être un GroupConfig)" -#: tiramisu/config.py:195 +#: tiramisu/config.py:194 msgid "can't assign to an OptionDescription" msgstr "ne peut pas attribuer une valeur à une OptionDescription" -#: tiramisu/config.py:325 +#: tiramisu/config.py:324 msgid "unknown type_ type {0}for _find" msgstr "type_ type {0} pour _find inconnu" -#: tiramisu/config.py:364 +#: tiramisu/config.py:363 msgid "no option found in config with these criteria" msgstr "aucune option trouvée dans la config avec ces critères" -#: tiramisu/config.py:414 +#: tiramisu/config.py:413 msgid "make_dict can't filtering with value without option" msgstr "make_dict ne peut filtrer sur une valeur mais sans option" -#: tiramisu/config.py:435 +#: tiramisu/config.py:434 msgid "unexpected path {0}, should start with {1}" msgstr "chemin imprévu {0}, devrait commencer par {1}" -#: tiramisu/config.py:489 +#: tiramisu/config.py:491 msgid "opt in getowner must be an option not {0}" msgstr "opt dans getowner doit être une option pas {0}" -#: tiramisu/config.py:532 +#: tiramisu/config.py:534 msgid "cannot serialize Config with MetaConfig" msgstr "impossible de sérialiser une Config avec une MetaConfig" -#: tiramisu/config.py:546 +#: tiramisu/config.py:548 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "ce storage n'est sérialisable, devrait être une storage non persistant" -#: tiramisu/config.py:609 +#: tiramisu/config.py:611 msgid "metaconfig's children must be a list" msgstr "enfants d'une metaconfig doit être une liste" -#: tiramisu/config.py:703 +#: tiramisu/config.py:705 msgid "metaconfig's children should be config, not {0}" msgstr "enfants d'une metaconfig doit être une config, pas {0}" -#: tiramisu/config.py:707 +#: tiramisu/config.py:709 msgid "child has already a metaconfig's" msgstr "enfant a déjà une metaconfig" -#: tiramisu/config.py:711 +#: tiramisu/config.py:713 msgid "all config in metaconfig must have the same optiondescription" msgstr "" "toutes les configs d'une metaconfig doivent avoir la même optiondescription" -#: tiramisu/option.py:67 +#: tiramisu/option.py:66 msgid "invalid name: {0} for option" msgstr "nom invalide : {0} pour l'option" -#: tiramisu/option.py:76 +#: tiramisu/option.py:75 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "type des properties invalide {0} pour {1}, doit être un tuple" -#: tiramisu/option.py:114 +#: tiramisu/option.py:113 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" -#: tiramisu/option.py:141 tiramisu/value.py:395 +#: tiramisu/option.py:140 tiramisu/value.py:393 msgid "information's item not found: {0}" msgstr "aucune config spécifiée alors que c'est nécessaire" -#: tiramisu/option.py:203 +#: tiramisu/option.py:202 msgid "cannot serialize Option, only in OptionDescription" msgstr "ne peut serialiser une Option, seulement via une OptionDescription" -#: tiramisu/option.py:306 +#: tiramisu/option.py:305 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" "une default_multi est renseignée alors que multi est False dans l'option : " "{0}" -#: tiramisu/option.py:312 +#: tiramisu/option.py:311 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "la valeur default_multi est invalide {0} pour l'option {1} : {2}" -#: tiramisu/option.py:317 +#: tiramisu/option.py:316 msgid "default value not allowed if option: {0} is calculated" msgstr "la valeur par défaut n'est pas possible si l'option {0} est calculée" -#: tiramisu/option.py:320 +#: tiramisu/option.py:319 msgid "" "params defined for a callback function but no callback defined yet for " "option {0}" @@ -130,289 +130,289 @@ msgstr "" "params définis pour une fonction callback mais par de callback encore " "définis pour l'option {0}" -#: tiramisu/option.py:425 tiramisu/option.py:450 +#: tiramisu/option.py:424 tiramisu/option.py:454 msgid "invalid value for option {0}: {1}" msgstr "valeur invalide pour l'option {0} : {1}" -#: tiramisu/option.py:444 +#: tiramisu/option.py:448 msgid "warning on the value of the option {0}: {1}" msgstr "avertissement sur la valeur de l'option {0} : {1}" -#: tiramisu/option.py:461 +#: tiramisu/option.py:465 msgid "invalid value {0} for option {1} which must be a list" msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste" -#: tiramisu/option.py:519 +#: tiramisu/option.py:523 msgid "consistency must be set with an option" msgstr "consistency doit être configuré avec une option" -#: tiramisu/option.py:521 +#: tiramisu/option.py:525 msgid "cannot add consistency with itself" msgstr "ne peut ajouter une consistency avec lui même" -#: tiramisu/option.py:523 +#: tiramisu/option.py:527 msgid "every options in consistency must be multi or none" msgstr "" "toutes les options d'une consistency doivent être multi ou ne pas l'être" -#: tiramisu/option.py:544 +#: tiramisu/option.py:548 msgid "same value for {0} and {1}, should be different" msgstr "même valeur pour {0} et {1}, devrait être différent" -#: tiramisu/option.py:546 +#: tiramisu/option.py:550 msgid "same value for {0} and {1}, must be different" msgstr "même valeur pour {0} et {1}, doit être différent" -#: tiramisu/option.py:640 +#: tiramisu/option.py:644 msgid "values must be a tuple for {0}" msgstr "values doit être un tuple pour {0}" -#: tiramisu/option.py:643 +#: tiramisu/option.py:647 msgid "open_values must be a boolean for {0}" msgstr "open_values doit être un booléen pour {0}" -#: tiramisu/option.py:665 +#: tiramisu/option.py:669 msgid "value {0} is not permitted, only {1} is allowed" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" -#: tiramisu/option.py:677 +#: tiramisu/option.py:681 msgid "invalid boolean" msgstr "booléen invalide" -#: tiramisu/option.py:687 +#: tiramisu/option.py:691 msgid "invalid integer" msgstr "nombre invalide" -#: tiramisu/option.py:697 +#: tiramisu/option.py:701 msgid "invalid float" msgstr "invalide nombre flottan" -#: tiramisu/option.py:707 +#: tiramisu/option.py:711 msgid "invalid string" msgstr "invalide caractère" -#: tiramisu/option.py:724 +#: tiramisu/option.py:728 msgid "invalid unicode" msgstr "invalide unicode" -#: tiramisu/option.py:736 +#: tiramisu/option.py:740 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" -#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 +#: tiramisu/option.py:791 tiramisu/option.py:794 tiramisu/option.py:799 msgid "invalid IP" msgstr "adresse IP invalide" -#: tiramisu/option.py:801 -msgid "IP shouldn't be in reserved class" -msgstr "l'adresse IP ne devrait pas être d'une classe réservée" +#: tiramisu/option.py:805 +msgid "IP is in reserved class" +msgstr "l'adresse IP est dans une plage d'adresse réservée" -#: tiramisu/option.py:803 +#: tiramisu/option.py:807 msgid "invalid IP, mustn't be in reserved class" msgstr "adresse IP invalide, ne doit pas être dans une classe réservée" -#: tiramisu/option.py:807 -msgid "IP should be in private class" -msgstr "l'adresse IP devrait être dans une classe privée" +#: tiramisu/option.py:811 +msgid "IP is not in private class" +msgstr "l'adresse IP n'est pas dans une plage d'adressage privée" -#: tiramisu/option.py:809 +#: tiramisu/option.py:813 msgid "invalid IP, must be in private class" msgstr "adresse IP invalide, doit être dans la classe privée" -#: tiramisu/option.py:814 tiramisu/option.py:989 +#: tiramisu/option.py:818 tiramisu/option.py:993 msgid "invalid len for vals" msgstr "longueur invalide pour vals" -#: tiramisu/option.py:820 +#: tiramisu/option.py:824 msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "IP {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" -#: tiramisu/option.py:823 +#: tiramisu/option.py:827 msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" "IP invalide {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" -#: tiramisu/option.py:864 +#: tiramisu/option.py:868 msgid "inconsistency in allowed range" msgstr "inconsistence dans la plage autorisée" -#: tiramisu/option.py:869 +#: tiramisu/option.py:873 msgid "max value is empty" msgstr "la valeur maximum est vide" -#: tiramisu/option.py:886 +#: tiramisu/option.py:890 msgid "invalid port, range must have two values only" msgstr "port invalide, une plage doit avoir deux valeurs seulement" -#: tiramisu/option.py:889 +#: tiramisu/option.py:893 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" "port invalide, le premier port d'une plage doit être plus petit que le second" -#: tiramisu/option.py:898 +#: tiramisu/option.py:902 msgid "invalid port" msgstr "port invalide" -#: tiramisu/option.py:900 +#: tiramisu/option.py:904 msgid "invalid port, must be an between {0} and {1}" msgstr "port invalide, port doit être entre {0} et {1}" -#: tiramisu/option.py:914 +#: tiramisu/option.py:918 msgid "invalid network address" msgstr "adresse réseau invalide" -#: tiramisu/option.py:920 -msgid "network address shouldn't be in reserved class" -msgstr "l'adresse réseau ne devait pas être dans la classe réservée" +#: tiramisu/option.py:924 +msgid "network address is in reserved class" +msgstr "l'adresse réseau est pas dans une plage d'adresse réservée" -#: tiramisu/option.py:922 +#: tiramisu/option.py:926 msgid "invalid network address, mustn't be in reserved class" msgstr "adresse réseau invalide, ne doit pas être dans la classe réservée" -#: tiramisu/option.py:935 +#: tiramisu/option.py:939 msgid "invalid netmask address" msgstr "masque de sous-réseau invalide" -#: tiramisu/option.py:952 +#: tiramisu/option.py:956 msgid "invalid len for opts" msgstr "longueur invalide pour opts" -#: tiramisu/option.py:966 +#: tiramisu/option.py:970 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau" -#: tiramisu/option.py:971 +#: tiramisu/option.py:975 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "réseau invalide {0} ({1}) avec masque {2}" -#: tiramisu/option.py:985 +#: tiramisu/option.py:989 msgid "invalid broadcast address" msgstr "adresse de broadcast invalide" -#: tiramisu/option.py:994 +#: tiramisu/option.py:998 msgid "" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" "Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" -#: tiramisu/option.py:1016 +#: tiramisu/option.py:1020 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1023 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1025 msgid "allow_without_dot must be a boolean" msgstr "allow_without_dot doit être un booléen" -#: tiramisu/option.py:1065 +#: tiramisu/option.py:1069 msgid "invalid domainname, must have dot" msgstr "nom de domaine invalide, doit avoir un point" -#: tiramisu/option.py:1067 +#: tiramisu/option.py:1071 msgid "invalid domainname's length (max 255)" msgstr "longueur du nom de domaine invalide (maximum {1})" -#: tiramisu/option.py:1069 +#: tiramisu/option.py:1073 msgid "invalid domainname's length (min 2)" msgstr "longueur du nom de domaine invalide (minimum 2)" -#: tiramisu/option.py:1071 +#: tiramisu/option.py:1075 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1084 +#: tiramisu/option.py:1088 msgid "invalid email address, must contains one @" msgstr "adresse email invalide, doit contenir un @" -#: tiramisu/option.py:1087 +#: tiramisu/option.py:1091 msgid "invalid username in email address" msgstr "nom d'utilisateur invalide dans une adresse email" -#: tiramisu/option.py:1100 +#: tiramisu/option.py:1104 msgid "invalid url, must start with http:// or https://" msgstr "URL invalide, doit démarrer avec http:// ou https://" -#: tiramisu/option.py:1119 +#: tiramisu/option.py:1123 msgid "invalid url, port must be an between 0 and 65536" msgstr "URL invalide, port doit être entre 0 et 65536" -#: tiramisu/option.py:1125 +#: tiramisu/option.py:1129 msgid "invalid url, must ends with filename" msgstr "URL invalide, doit finir avec un nom de fichier" -#: tiramisu/option.py:1137 +#: tiramisu/option.py:1141 msgid "invalid username" msgstr "utilisateur invalide" -#: tiramisu/option.py:1148 +#: tiramisu/option.py:1152 msgid "invalid filename" msgstr "nom de fichier invalide" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1179 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1193 +#: tiramisu/option.py:1197 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1244 +#: tiramisu/option.py:1248 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1275 +#: tiramisu/option.py:1279 msgid "consistency with option {0} which is not in Config" msgstr "consistency avec l'option {0} qui n'est pas dans une Config" -#: tiramisu/option.py:1283 +#: tiramisu/option.py:1287 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1289 +#: tiramisu/option.py:1293 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1303 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1315 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1318 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1317 +#: tiramisu/option.py:1321 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1327 +#: tiramisu/option.py:1331 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1335 +#: tiramisu/option.py:1339 msgid "callback of master's option shall not refered a slave's ones" msgstr "" "callback d'une variable maitre ne devrait pas référencer des variables " "esclaves" -#: tiramisu/option.py:1343 +#: tiramisu/option.py:1347 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" -#: tiramisu/option.py:1443 +#: tiramisu/option.py:1444 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" "type requirements malformé pour l'option : {0}, doit être un dictionnaire" -#: tiramisu/option.py:1460 +#: tiramisu/option.py:1461 msgid "" "malformed requirements for option: {0} require must have option, expected " "and action keys" @@ -420,110 +420,110 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1465 +#: tiramisu/option.py:1466 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1469 +#: tiramisu/option.py:1470 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1473 +#: tiramisu/option.py:1474 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1478 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1480 +#: tiramisu/option.py:1481 msgid "malformed requirements option {0} must not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1486 +#: tiramisu/option.py:1487 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1491 +#: tiramisu/option.py:1492 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1516 +#: tiramisu/option.py:1517 msgid "{0} must be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1519 +#: tiramisu/option.py:1520 msgid "{0}_params must be a dict" msgstr "{0}_params doit être un dict" -#: tiramisu/option.py:1522 +#: tiramisu/option.py:1523 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" "{0}_params avec la clef {1} ne doit pas avoir une longueur différent de 1" -#: tiramisu/option.py:1526 +#: tiramisu/option.py:1527 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1532 +#: tiramisu/option.py:1533 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1535 +#: tiramisu/option.py:1536 msgid "{0}_params must have an option not a {0} for first argument" msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1539 +#: tiramisu/option.py:1540 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "ne peut redéfinir ({0})" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "ne peut supprimer ({0})" -#: tiramisu/setting.py:272 +#: tiramisu/setting.py:267 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" "ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est " "calculée" -#: tiramisu/setting.py:363 +#: tiramisu/setting.py:358 msgid "opt and all_properties must not be set together in reset" msgstr "opt et all_properties ne doit pas être renseigné ensemble dans reset" -#: tiramisu/setting.py:378 +#: tiramisu/setting.py:373 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" "si opt n'est pas None, path devrait ne pas être à None dans _getproperties" -#: tiramisu/setting.py:487 +#: tiramisu/setting.py:482 msgid "cannot change the value for option {0} this option is frozen" msgstr "" "ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" -#: tiramisu/setting.py:493 +#: tiramisu/setting.py:488 msgid "trying to access to an option named: {0} with properties {1}" msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}" -#: tiramisu/setting.py:511 +#: tiramisu/setting.py:506 msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:518 tiramisu/value.py:334 +#: tiramisu/setting.py:513 tiramisu/value.py:332 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" -#: tiramisu/setting.py:606 +#: tiramisu/setting.py:601 msgid "" "malformed requirements imbrication detected for option: '{0}' with " "requirement on: '{1}'" @@ -531,77 +531,77 @@ msgstr "" "imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "requirement sur : '{1}'" -#: tiramisu/setting.py:617 +#: tiramisu/setting.py:612 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "storage_type est déjà défini, impossible de le redéfinir" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "option {0} n'existe pas dans l'espace de stockage {1}" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" "impossible de supprimer une session dans un espace de stockage dictionary" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "session déjà utilisée" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "un espace de stockage dictionary ne peut être persistant" -#: tiramisu/value.py:341 +#: tiramisu/value.py:339 msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:423 +#: tiramisu/value.py:421 msgid "can force cache only if cache is actived in config" msgstr "" "peut force la mise en cache seulement si le cache est activé dans la config" -#: tiramisu/value.py:462 +#: tiramisu/value.py:460 msgid "{0} is already a Multi " msgstr "{0} est déjà une Multi" -#: tiramisu/value.py:498 tiramisu/value.py:562 +#: tiramisu/value.py:496 tiramisu/value.py:560 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:534 +#: tiramisu/value.py:532 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:572 +#: tiramisu/value.py:570 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:576 +#: tiramisu/value.py:574 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:585 +#: tiramisu/value.py:583 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:593 +#: tiramisu/value.py:591 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:601 +#: tiramisu/value.py:599 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:612 +#: tiramisu/value.py:610 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/value.py:630 +#: tiramisu/value.py:628 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index 81a388e..eb41967 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-12 21:49+CET\n" +"POT-Creation-Date: 2014-03-24 19:54+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,552 +15,552 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:162 +#: tiramisu/autolib.py:161 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "" -#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:485 +#: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 +#: tiramisu/value.py:483 msgid "the context does not exist anymore" msgstr "" -#: tiramisu/config.py:169 +#: tiramisu/config.py:168 msgid "no option description found for this config (may be GroupConfig)" msgstr "" -#: tiramisu/config.py:195 +#: tiramisu/config.py:194 msgid "can't assign to an OptionDescription" msgstr "" -#: tiramisu/config.py:325 +#: tiramisu/config.py:324 msgid "unknown type_ type {0}for _find" msgstr "" -#: tiramisu/config.py:364 +#: tiramisu/config.py:363 msgid "no option found in config with these criteria" msgstr "" -#: tiramisu/config.py:414 +#: tiramisu/config.py:413 msgid "make_dict can't filtering with value without option" msgstr "" -#: tiramisu/config.py:435 +#: tiramisu/config.py:434 msgid "unexpected path {0}, should start with {1}" msgstr "" -#: tiramisu/config.py:489 +#: tiramisu/config.py:491 msgid "opt in getowner must be an option not {0}" msgstr "" -#: tiramisu/config.py:532 +#: tiramisu/config.py:534 msgid "cannot serialize Config with MetaConfig" msgstr "" -#: tiramisu/config.py:546 +#: tiramisu/config.py:548 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "" -#: tiramisu/config.py:609 +#: tiramisu/config.py:611 msgid "metaconfig's children must be a list" msgstr "" -#: tiramisu/config.py:703 +#: tiramisu/config.py:705 msgid "metaconfig's children should be config, not {0}" msgstr "" -#: tiramisu/config.py:707 +#: tiramisu/config.py:709 msgid "child has already a metaconfig's" msgstr "" -#: tiramisu/config.py:711 +#: tiramisu/config.py:713 msgid "all config in metaconfig must have the same optiondescription" msgstr "" -#: tiramisu/option.py:67 +#: tiramisu/option.py:66 msgid "invalid name: {0} for option" msgstr "" -#: tiramisu/option.py:76 +#: tiramisu/option.py:75 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "" -#: tiramisu/option.py:114 +#: tiramisu/option.py:113 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "" -#: tiramisu/option.py:141 tiramisu/value.py:395 +#: tiramisu/option.py:140 tiramisu/value.py:393 msgid "information's item not found: {0}" msgstr "" -#: tiramisu/option.py:203 +#: tiramisu/option.py:202 msgid "cannot serialize Option, only in OptionDescription" msgstr "" -#: tiramisu/option.py:306 +#: tiramisu/option.py:305 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" -#: tiramisu/option.py:312 +#: tiramisu/option.py:311 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "" -#: tiramisu/option.py:317 +#: tiramisu/option.py:316 msgid "default value not allowed if option: {0} is calculated" msgstr "" -#: tiramisu/option.py:320 +#: tiramisu/option.py:319 msgid "params defined for a callback function but no callback defined yet for option {0}" msgstr "" -#: tiramisu/option.py:425 tiramisu/option.py:450 +#: tiramisu/option.py:424 tiramisu/option.py:454 msgid "invalid value for option {0}: {1}" msgstr "" -#: tiramisu/option.py:444 +#: tiramisu/option.py:448 msgid "warning on the value of the option {0}: {1}" msgstr "" -#: tiramisu/option.py:461 +#: tiramisu/option.py:465 msgid "invalid value {0} for option {1} which must be a list" msgstr "" -#: tiramisu/option.py:519 +#: tiramisu/option.py:523 msgid "consistency must be set with an option" msgstr "" -#: tiramisu/option.py:521 +#: tiramisu/option.py:525 msgid "cannot add consistency with itself" msgstr "" -#: tiramisu/option.py:523 +#: tiramisu/option.py:527 msgid "every options in consistency must be multi or none" msgstr "" -#: tiramisu/option.py:544 +#: tiramisu/option.py:548 msgid "same value for {0} and {1}, should be different" msgstr "" -#: tiramisu/option.py:546 +#: tiramisu/option.py:550 msgid "same value for {0} and {1}, must be different" msgstr "" -#: tiramisu/option.py:640 +#: tiramisu/option.py:644 msgid "values must be a tuple for {0}" msgstr "" -#: tiramisu/option.py:643 +#: tiramisu/option.py:647 msgid "open_values must be a boolean for {0}" msgstr "" -#: tiramisu/option.py:665 +#: tiramisu/option.py:669 msgid "value {0} is not permitted, only {1} is allowed" msgstr "" -#: tiramisu/option.py:677 +#: tiramisu/option.py:681 msgid "invalid boolean" msgstr "" -#: tiramisu/option.py:687 +#: tiramisu/option.py:691 msgid "invalid integer" msgstr "" -#: tiramisu/option.py:697 +#: tiramisu/option.py:701 msgid "invalid float" msgstr "" -#: tiramisu/option.py:707 +#: tiramisu/option.py:711 msgid "invalid string" msgstr "" -#: tiramisu/option.py:724 +#: tiramisu/option.py:728 msgid "invalid unicode" msgstr "" -#: tiramisu/option.py:736 +#: tiramisu/option.py:740 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "" -#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 +#: tiramisu/option.py:791 tiramisu/option.py:794 tiramisu/option.py:799 msgid "invalid IP" msgstr "" -#: tiramisu/option.py:801 -msgid "IP shouldn't be in reserved class" -msgstr "" - -#: tiramisu/option.py:803 -msgid "invalid IP, mustn't be in reserved class" +#: tiramisu/option.py:805 +msgid "IP is in reserved class" msgstr "" #: tiramisu/option.py:807 -msgid "IP should be in private class" +msgid "invalid IP, mustn't be in reserved class" msgstr "" -#: tiramisu/option.py:809 +#: tiramisu/option.py:811 +msgid "IP is not in private class" +msgstr "" + +#: tiramisu/option.py:813 msgid "invalid IP, must be in private class" msgstr "" -#: tiramisu/option.py:814 tiramisu/option.py:989 +#: tiramisu/option.py:818 tiramisu/option.py:993 msgid "invalid len for vals" msgstr "" -#: tiramisu/option.py:820 +#: tiramisu/option.py:824 msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:823 +#: tiramisu/option.py:827 msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:864 +#: tiramisu/option.py:868 msgid "inconsistency in allowed range" msgstr "" -#: tiramisu/option.py:869 +#: tiramisu/option.py:873 msgid "max value is empty" msgstr "" -#: tiramisu/option.py:886 +#: tiramisu/option.py:890 msgid "invalid port, range must have two values only" msgstr "" -#: tiramisu/option.py:889 +#: tiramisu/option.py:893 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" -#: tiramisu/option.py:898 +#: tiramisu/option.py:902 msgid "invalid port" msgstr "" -#: tiramisu/option.py:900 +#: tiramisu/option.py:904 msgid "invalid port, must be an between {0} and {1}" msgstr "" -#: tiramisu/option.py:914 +#: tiramisu/option.py:918 msgid "invalid network address" msgstr "" -#: tiramisu/option.py:920 -msgid "network address shouldn't be in reserved class" +#: tiramisu/option.py:924 +msgid "network address is in reserved class" msgstr "" -#: tiramisu/option.py:922 +#: tiramisu/option.py:926 msgid "invalid network address, mustn't be in reserved class" msgstr "" -#: tiramisu/option.py:935 +#: tiramisu/option.py:939 msgid "invalid netmask address" msgstr "" -#: tiramisu/option.py:952 +#: tiramisu/option.py:956 msgid "invalid len for opts" msgstr "" -#: tiramisu/option.py:966 +#: tiramisu/option.py:970 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "" -#: tiramisu/option.py:971 +#: tiramisu/option.py:975 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "" -#: tiramisu/option.py:985 +#: tiramisu/option.py:989 msgid "invalid broadcast address" msgstr "" -#: tiramisu/option.py:994 +#: tiramisu/option.py:998 msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:1016 +#: tiramisu/option.py:1020 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1023 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1025 msgid "allow_without_dot must be a boolean" msgstr "" -#: tiramisu/option.py:1065 +#: tiramisu/option.py:1069 msgid "invalid domainname, must have dot" msgstr "" -#: tiramisu/option.py:1067 +#: tiramisu/option.py:1071 msgid "invalid domainname's length (max 255)" msgstr "" -#: tiramisu/option.py:1069 +#: tiramisu/option.py:1073 msgid "invalid domainname's length (min 2)" msgstr "" -#: tiramisu/option.py:1071 +#: tiramisu/option.py:1075 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1084 +#: tiramisu/option.py:1088 msgid "invalid email address, must contains one @" msgstr "" -#: tiramisu/option.py:1087 +#: tiramisu/option.py:1091 msgid "invalid username in email address" msgstr "" -#: tiramisu/option.py:1100 +#: tiramisu/option.py:1104 msgid "invalid url, must start with http:// or https://" msgstr "" -#: tiramisu/option.py:1119 +#: tiramisu/option.py:1123 msgid "invalid url, port must be an between 0 and 65536" msgstr "" -#: tiramisu/option.py:1125 +#: tiramisu/option.py:1129 msgid "invalid url, must ends with filename" msgstr "" -#: tiramisu/option.py:1137 +#: tiramisu/option.py:1141 msgid "invalid username" msgstr "" -#: tiramisu/option.py:1148 +#: tiramisu/option.py:1152 msgid "invalid filename" msgstr "" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1179 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1193 +#: tiramisu/option.py:1197 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1244 +#: tiramisu/option.py:1248 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1275 +#: tiramisu/option.py:1279 msgid "consistency with option {0} which is not in Config" msgstr "" -#: tiramisu/option.py:1283 +#: tiramisu/option.py:1287 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1289 +#: tiramisu/option.py:1293 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1303 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1315 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1318 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1317 +#: tiramisu/option.py:1321 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1327 +#: tiramisu/option.py:1331 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1335 +#: tiramisu/option.py:1339 msgid "callback of master's option shall not refered a slave's ones" msgstr "" -#: tiramisu/option.py:1343 +#: tiramisu/option.py:1347 msgid "group_type: {0} not allowed" msgstr "" -#: tiramisu/option.py:1443 +#: tiramisu/option.py:1444 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" -#: tiramisu/option.py:1460 +#: tiramisu/option.py:1461 msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1465 +#: tiramisu/option.py:1466 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" -#: tiramisu/option.py:1469 +#: tiramisu/option.py:1470 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" -#: tiramisu/option.py:1473 +#: tiramisu/option.py:1474 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1478 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1480 +#: tiramisu/option.py:1481 msgid "malformed requirements option {0} must not be a multi" msgstr "" -#: tiramisu/option.py:1486 +#: tiramisu/option.py:1487 msgid "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" -#: tiramisu/option.py:1491 +#: tiramisu/option.py:1492 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "" -#: tiramisu/option.py:1516 +#: tiramisu/option.py:1517 msgid "{0} must be a function" msgstr "" -#: tiramisu/option.py:1519 +#: tiramisu/option.py:1520 msgid "{0}_params must be a dict" msgstr "" -#: tiramisu/option.py:1522 +#: tiramisu/option.py:1523 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" -#: tiramisu/option.py:1526 +#: tiramisu/option.py:1527 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "" -#: tiramisu/option.py:1532 +#: tiramisu/option.py:1533 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1535 +#: tiramisu/option.py:1536 msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1539 +#: tiramisu/option.py:1540 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "" -#: tiramisu/setting.py:272 +#: tiramisu/setting.py:267 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" -#: tiramisu/setting.py:363 +#: tiramisu/setting.py:358 msgid "opt and all_properties must not be set together in reset" msgstr "" -#: tiramisu/setting.py:378 +#: tiramisu/setting.py:373 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" -#: tiramisu/setting.py:487 +#: tiramisu/setting.py:482 msgid "cannot change the value for option {0} this option is frozen" msgstr "" -#: tiramisu/setting.py:493 +#: tiramisu/setting.py:488 msgid "trying to access to an option named: {0} with properties {1}" msgstr "" -#: tiramisu/setting.py:511 +#: tiramisu/setting.py:506 msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:518 tiramisu/value.py:334 +#: tiramisu/setting.py:513 tiramisu/value.py:332 msgid "invalid generic owner {0}" msgstr "" -#: tiramisu/setting.py:606 +#: tiramisu/setting.py:601 msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'" msgstr "" -#: tiramisu/setting.py:617 +#: tiramisu/setting.py:612 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "" -#: tiramisu/value.py:341 +#: tiramisu/value.py:339 msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:423 +#: tiramisu/value.py:421 msgid "can force cache only if cache is actived in config" msgstr "" -#: tiramisu/value.py:462 +#: tiramisu/value.py:460 msgid "{0} is already a Multi " msgstr "" -#: tiramisu/value.py:498 tiramisu/value.py:562 +#: tiramisu/value.py:496 tiramisu/value.py:560 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:534 +#: tiramisu/value.py:532 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:572 +#: tiramisu/value.py:570 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:576 +#: tiramisu/value.py:574 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:585 +#: tiramisu/value.py:583 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:593 +#: tiramisu/value.py:591 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:601 +#: tiramisu/value.py:599 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:612 +#: tiramisu/value.py:610 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/value.py:630 +#: tiramisu/value.py:628 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From b3d04a1f6825e67068e6f67236460b20aab01674 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 24 Mar 2014 21:13:26 +0100 Subject: [PATCH 26/42] update warning's message --- tiramisu/option.py | 6 +- translations/fr/tiramisu.po | 290 ++++++++++++++++++------------------ translations/tiramisu.pot | 288 +++++++++++++++++------------------ 3 files changed, 292 insertions(+), 292 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index fee61b5..30277e2 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -802,13 +802,13 @@ class IPOption(Option): ip = IP('{0}/32'.format(value)) if not self._allow_reserved and ip.iptype() == 'RESERVED': if warnings_only: - msg = _("IP shouldn't be in reserved class") + msg = _("IP is in reserved class") else: msg = _("invalid IP, mustn't be in reserved class") raise ValueError(msg) if self._private_only and not ip.iptype() == 'PRIVATE': if warnings_only: - msg = _("IP should be in private class") + msg = _("IP is not in private class") else: msg = _("invalid IP, must be in private class") raise ValueError(msg) @@ -921,7 +921,7 @@ class NetworkOption(Option): ip = IP(value) if ip.iptype() == 'RESERVED': if warnings_only: - msg = _("network address shouldn't be in reserved class") + msg = _("network address is in reserved class") else: msg = _("invalid network address, mustn't be in reserved class") raise ValueError(msg) diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 3dee004..0e1b339 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-12 21:49+CET\n" +"POT-Creation-Date: 2014-03-24 19:54+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -14,115 +14,115 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: tiramisu/autolib.py:162 +#: tiramisu/autolib.py:161 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" "impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : " "{2}" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "descr doit être une optiondescription pas un {0}" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" -#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:485 +#: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 +#: tiramisu/value.py:483 msgid "the context does not exist anymore" msgstr "le context n'existe plus" -#: tiramisu/config.py:169 +#: tiramisu/config.py:168 msgid "no option description found for this config (may be GroupConfig)" msgstr "" "pas d'option description trouvé pour cette config (peut être un GroupConfig)" -#: tiramisu/config.py:195 +#: tiramisu/config.py:194 msgid "can't assign to an OptionDescription" msgstr "ne peut pas attribuer une valeur à une OptionDescription" -#: tiramisu/config.py:325 +#: tiramisu/config.py:324 msgid "unknown type_ type {0}for _find" msgstr "type_ type {0} pour _find inconnu" -#: tiramisu/config.py:364 +#: tiramisu/config.py:363 msgid "no option found in config with these criteria" msgstr "aucune option trouvée dans la config avec ces critères" -#: tiramisu/config.py:414 +#: tiramisu/config.py:413 msgid "make_dict can't filtering with value without option" msgstr "make_dict ne peut filtrer sur une valeur mais sans option" -#: tiramisu/config.py:435 +#: tiramisu/config.py:434 msgid "unexpected path {0}, should start with {1}" msgstr "chemin imprévu {0}, devrait commencer par {1}" -#: tiramisu/config.py:489 +#: tiramisu/config.py:491 msgid "opt in getowner must be an option not {0}" msgstr "opt dans getowner doit être une option pas {0}" -#: tiramisu/config.py:532 +#: tiramisu/config.py:534 msgid "cannot serialize Config with MetaConfig" msgstr "impossible de sérialiser une Config avec une MetaConfig" -#: tiramisu/config.py:546 +#: tiramisu/config.py:548 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "ce storage n'est sérialisable, devrait être une storage non persistant" -#: tiramisu/config.py:609 +#: tiramisu/config.py:611 msgid "metaconfig's children must be a list" msgstr "enfants d'une metaconfig doit être une liste" -#: tiramisu/config.py:703 +#: tiramisu/config.py:705 msgid "metaconfig's children should be config, not {0}" msgstr "enfants d'une metaconfig doit être une config, pas {0}" -#: tiramisu/config.py:707 +#: tiramisu/config.py:709 msgid "child has already a metaconfig's" msgstr "enfant a déjà une metaconfig" -#: tiramisu/config.py:711 +#: tiramisu/config.py:713 msgid "all config in metaconfig must have the same optiondescription" msgstr "" "toutes les configs d'une metaconfig doivent avoir la même optiondescription" -#: tiramisu/option.py:67 +#: tiramisu/option.py:66 msgid "invalid name: {0} for option" msgstr "nom invalide : {0} pour l'option" -#: tiramisu/option.py:76 +#: tiramisu/option.py:75 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "type des properties invalide {0} pour {1}, doit être un tuple" -#: tiramisu/option.py:114 +#: tiramisu/option.py:113 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" -#: tiramisu/option.py:141 tiramisu/value.py:395 +#: tiramisu/option.py:140 tiramisu/value.py:393 msgid "information's item not found: {0}" msgstr "aucune config spécifiée alors que c'est nécessaire" -#: tiramisu/option.py:203 +#: tiramisu/option.py:202 msgid "cannot serialize Option, only in OptionDescription" msgstr "ne peut serialiser une Option, seulement via une OptionDescription" -#: tiramisu/option.py:306 +#: tiramisu/option.py:305 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" "une default_multi est renseignée alors que multi est False dans l'option : " "{0}" -#: tiramisu/option.py:312 +#: tiramisu/option.py:311 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "la valeur default_multi est invalide {0} pour l'option {1} : {2}" -#: tiramisu/option.py:317 +#: tiramisu/option.py:316 msgid "default value not allowed if option: {0} is calculated" msgstr "la valeur par défaut n'est pas possible si l'option {0} est calculée" -#: tiramisu/option.py:320 +#: tiramisu/option.py:319 msgid "" "params defined for a callback function but no callback defined yet for " "option {0}" @@ -130,289 +130,289 @@ msgstr "" "params définis pour une fonction callback mais par de callback encore " "définis pour l'option {0}" -#: tiramisu/option.py:425 tiramisu/option.py:450 +#: tiramisu/option.py:424 tiramisu/option.py:454 msgid "invalid value for option {0}: {1}" msgstr "valeur invalide pour l'option {0} : {1}" -#: tiramisu/option.py:444 +#: tiramisu/option.py:448 msgid "warning on the value of the option {0}: {1}" msgstr "avertissement sur la valeur de l'option {0} : {1}" -#: tiramisu/option.py:461 +#: tiramisu/option.py:465 msgid "invalid value {0} for option {1} which must be a list" msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste" -#: tiramisu/option.py:519 +#: tiramisu/option.py:523 msgid "consistency must be set with an option" msgstr "consistency doit être configuré avec une option" -#: tiramisu/option.py:521 +#: tiramisu/option.py:525 msgid "cannot add consistency with itself" msgstr "ne peut ajouter une consistency avec lui même" -#: tiramisu/option.py:523 +#: tiramisu/option.py:527 msgid "every options in consistency must be multi or none" msgstr "" "toutes les options d'une consistency doivent être multi ou ne pas l'être" -#: tiramisu/option.py:544 +#: tiramisu/option.py:548 msgid "same value for {0} and {1}, should be different" msgstr "même valeur pour {0} et {1}, devrait être différent" -#: tiramisu/option.py:546 +#: tiramisu/option.py:550 msgid "same value for {0} and {1}, must be different" msgstr "même valeur pour {0} et {1}, doit être différent" -#: tiramisu/option.py:640 +#: tiramisu/option.py:644 msgid "values must be a tuple for {0}" msgstr "values doit être un tuple pour {0}" -#: tiramisu/option.py:643 +#: tiramisu/option.py:647 msgid "open_values must be a boolean for {0}" msgstr "open_values doit être un booléen pour {0}" -#: tiramisu/option.py:665 +#: tiramisu/option.py:669 msgid "value {0} is not permitted, only {1} is allowed" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" -#: tiramisu/option.py:677 +#: tiramisu/option.py:681 msgid "invalid boolean" msgstr "booléen invalide" -#: tiramisu/option.py:687 +#: tiramisu/option.py:691 msgid "invalid integer" msgstr "nombre invalide" -#: tiramisu/option.py:697 +#: tiramisu/option.py:701 msgid "invalid float" msgstr "invalide nombre flottan" -#: tiramisu/option.py:707 +#: tiramisu/option.py:711 msgid "invalid string" msgstr "invalide caractère" -#: tiramisu/option.py:724 +#: tiramisu/option.py:728 msgid "invalid unicode" msgstr "invalide unicode" -#: tiramisu/option.py:736 +#: tiramisu/option.py:740 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" -#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 +#: tiramisu/option.py:791 tiramisu/option.py:794 tiramisu/option.py:799 msgid "invalid IP" msgstr "adresse IP invalide" -#: tiramisu/option.py:801 -msgid "IP shouldn't be in reserved class" -msgstr "l'adresse IP ne devrait pas être d'une classe réservée" +#: tiramisu/option.py:805 +msgid "IP is in reserved class" +msgstr "l'adresse IP est dans une plage d'adresse réservée" -#: tiramisu/option.py:803 +#: tiramisu/option.py:807 msgid "invalid IP, mustn't be in reserved class" msgstr "adresse IP invalide, ne doit pas être dans une classe réservée" -#: tiramisu/option.py:807 -msgid "IP should be in private class" -msgstr "l'adresse IP devrait être dans une classe privée" +#: tiramisu/option.py:811 +msgid "IP is not in private class" +msgstr "l'adresse IP n'est pas dans une plage d'adressage privée" -#: tiramisu/option.py:809 +#: tiramisu/option.py:813 msgid "invalid IP, must be in private class" msgstr "adresse IP invalide, doit être dans la classe privée" -#: tiramisu/option.py:814 tiramisu/option.py:989 +#: tiramisu/option.py:818 tiramisu/option.py:993 msgid "invalid len for vals" msgstr "longueur invalide pour vals" -#: tiramisu/option.py:820 +#: tiramisu/option.py:824 msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "IP {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" -#: tiramisu/option.py:823 +#: tiramisu/option.py:827 msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" "IP invalide {0} ({1}) pas dans le réseau {2} ({3}) avec le masque {4} ({5})" -#: tiramisu/option.py:864 +#: tiramisu/option.py:868 msgid "inconsistency in allowed range" msgstr "inconsistence dans la plage autorisée" -#: tiramisu/option.py:869 +#: tiramisu/option.py:873 msgid "max value is empty" msgstr "la valeur maximum est vide" -#: tiramisu/option.py:886 +#: tiramisu/option.py:890 msgid "invalid port, range must have two values only" msgstr "port invalide, une plage doit avoir deux valeurs seulement" -#: tiramisu/option.py:889 +#: tiramisu/option.py:893 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" "port invalide, le premier port d'une plage doit être plus petit que le second" -#: tiramisu/option.py:898 +#: tiramisu/option.py:902 msgid "invalid port" msgstr "port invalide" -#: tiramisu/option.py:900 +#: tiramisu/option.py:904 msgid "invalid port, must be an between {0} and {1}" msgstr "port invalide, port doit être entre {0} et {1}" -#: tiramisu/option.py:914 +#: tiramisu/option.py:918 msgid "invalid network address" msgstr "adresse réseau invalide" -#: tiramisu/option.py:920 -msgid "network address shouldn't be in reserved class" -msgstr "l'adresse réseau ne devait pas être dans la classe réservée" +#: tiramisu/option.py:924 +msgid "network address is in reserved class" +msgstr "l'adresse réseau est pas dans une plage d'adresse réservée" -#: tiramisu/option.py:922 +#: tiramisu/option.py:926 msgid "invalid network address, mustn't be in reserved class" msgstr "adresse réseau invalide, ne doit pas être dans la classe réservée" -#: tiramisu/option.py:935 +#: tiramisu/option.py:939 msgid "invalid netmask address" msgstr "masque de sous-réseau invalide" -#: tiramisu/option.py:952 +#: tiramisu/option.py:956 msgid "invalid len for opts" msgstr "longueur invalide pour opts" -#: tiramisu/option.py:966 +#: tiramisu/option.py:970 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau" -#: tiramisu/option.py:971 +#: tiramisu/option.py:975 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "réseau invalide {0} ({1}) avec masque {2}" -#: tiramisu/option.py:985 +#: tiramisu/option.py:989 msgid "invalid broadcast address" msgstr "adresse de broadcast invalide" -#: tiramisu/option.py:994 +#: tiramisu/option.py:998 msgid "" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" "Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" -#: tiramisu/option.py:1016 +#: tiramisu/option.py:1020 msgid "unknown type_ {0} for hostname" msgstr "type_ inconnu {0} pour le nom d'hôte" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1023 msgid "allow_ip must be a boolean" msgstr "allow_ip doit être un booléen" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1025 msgid "allow_without_dot must be a boolean" msgstr "allow_without_dot doit être un booléen" -#: tiramisu/option.py:1065 +#: tiramisu/option.py:1069 msgid "invalid domainname, must have dot" msgstr "nom de domaine invalide, doit avoir un point" -#: tiramisu/option.py:1067 +#: tiramisu/option.py:1071 msgid "invalid domainname's length (max 255)" msgstr "longueur du nom de domaine invalide (maximum {1})" -#: tiramisu/option.py:1069 +#: tiramisu/option.py:1073 msgid "invalid domainname's length (min 2)" msgstr "longueur du nom de domaine invalide (minimum 2)" -#: tiramisu/option.py:1071 +#: tiramisu/option.py:1075 msgid "invalid domainname" msgstr "nom de domaine invalide" -#: tiramisu/option.py:1084 +#: tiramisu/option.py:1088 msgid "invalid email address, must contains one @" msgstr "adresse email invalide, doit contenir un @" -#: tiramisu/option.py:1087 +#: tiramisu/option.py:1091 msgid "invalid username in email address" msgstr "nom d'utilisateur invalide dans une adresse email" -#: tiramisu/option.py:1100 +#: tiramisu/option.py:1104 msgid "invalid url, must start with http:// or https://" msgstr "URL invalide, doit démarrer avec http:// ou https://" -#: tiramisu/option.py:1119 +#: tiramisu/option.py:1123 msgid "invalid url, port must be an between 0 and 65536" msgstr "URL invalide, port doit être entre 0 et 65536" -#: tiramisu/option.py:1125 +#: tiramisu/option.py:1129 msgid "invalid url, must ends with filename" msgstr "URL invalide, doit finir avec un nom de fichier" -#: tiramisu/option.py:1137 +#: tiramisu/option.py:1141 msgid "invalid username" msgstr "utilisateur invalide" -#: tiramisu/option.py:1148 +#: tiramisu/option.py:1152 msgid "invalid filename" msgstr "nom de fichier invalide" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1179 msgid "duplicate option name: {0}" msgstr "nom de l'option dupliqué : {0}" -#: tiramisu/option.py:1193 +#: tiramisu/option.py:1197 msgid "unknown Option {0} in OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}" -#: tiramisu/option.py:1244 +#: tiramisu/option.py:1248 msgid "duplicate option: {0}" msgstr "option dupliquée : {0}" -#: tiramisu/option.py:1275 +#: tiramisu/option.py:1279 msgid "consistency with option {0} which is not in Config" msgstr "consistency avec l'option {0} qui n'est pas dans une Config" -#: tiramisu/option.py:1283 +#: tiramisu/option.py:1287 msgid "no option for path {0}" msgstr "pas d'option pour le chemin {0}" -#: tiramisu/option.py:1289 +#: tiramisu/option.py:1293 msgid "no option {0} found" msgstr "pas d'option {0} trouvée" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1303 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1315 msgid "master group {0} shall not have a subgroup" msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1318 msgid "master group {0} shall not have a symlinkoption" msgstr "groupe maître {0} ne doit pas avoir de symlinkoption" -#: tiramisu/option.py:1317 +#: tiramisu/option.py:1321 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" "option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "multi" -#: tiramisu/option.py:1327 +#: tiramisu/option.py:1331 msgid "master group with wrong master name for {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}" -#: tiramisu/option.py:1335 +#: tiramisu/option.py:1339 msgid "callback of master's option shall not refered a slave's ones" msgstr "" "callback d'une variable maitre ne devrait pas référencer des variables " "esclaves" -#: tiramisu/option.py:1343 +#: tiramisu/option.py:1347 msgid "group_type: {0} not allowed" msgstr "group_type : {0} non autorisé" -#: tiramisu/option.py:1443 +#: tiramisu/option.py:1444 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" "type requirements malformé pour l'option : {0}, doit être un dictionnaire" -#: tiramisu/option.py:1460 +#: tiramisu/option.py:1461 msgid "" "malformed requirements for option: {0} require must have option, expected " "and action keys" @@ -420,110 +420,110 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1465 +#: tiramisu/option.py:1466 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1469 +#: tiramisu/option.py:1470 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1473 +#: tiramisu/option.py:1474 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1478 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1480 +#: tiramisu/option.py:1481 msgid "malformed requirements option {0} must not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1486 +#: tiramisu/option.py:1487 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1491 +#: tiramisu/option.py:1492 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1516 +#: tiramisu/option.py:1517 msgid "{0} must be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1519 +#: tiramisu/option.py:1520 msgid "{0}_params must be a dict" msgstr "{0}_params doit être un dict" -#: tiramisu/option.py:1522 +#: tiramisu/option.py:1523 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" "{0}_params avec la clef {1} ne doit pas avoir une longueur différent de 1" -#: tiramisu/option.py:1526 +#: tiramisu/option.py:1527 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1532 +#: tiramisu/option.py:1533 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1535 +#: tiramisu/option.py:1536 msgid "{0}_params must have an option not a {0} for first argument" msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1539 +#: tiramisu/option.py:1540 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "ne peut redéfinir ({0})" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "ne peut supprimer ({0})" -#: tiramisu/setting.py:272 +#: tiramisu/setting.py:267 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" "ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est " "calculée" -#: tiramisu/setting.py:363 +#: tiramisu/setting.py:358 msgid "opt and all_properties must not be set together in reset" msgstr "opt et all_properties ne doit pas être renseigné ensemble dans reset" -#: tiramisu/setting.py:378 +#: tiramisu/setting.py:373 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" "si opt n'est pas None, path devrait ne pas être à None dans _getproperties" -#: tiramisu/setting.py:487 +#: tiramisu/setting.py:482 msgid "cannot change the value for option {0} this option is frozen" msgstr "" "ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" -#: tiramisu/setting.py:493 +#: tiramisu/setting.py:488 msgid "trying to access to an option named: {0} with properties {1}" msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}" -#: tiramisu/setting.py:511 +#: tiramisu/setting.py:506 msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:518 tiramisu/value.py:334 +#: tiramisu/setting.py:513 tiramisu/value.py:332 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" -#: tiramisu/setting.py:606 +#: tiramisu/setting.py:601 msgid "" "malformed requirements imbrication detected for option: '{0}' with " "requirement on: '{1}'" @@ -531,77 +531,77 @@ msgstr "" "imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "requirement sur : '{1}'" -#: tiramisu/setting.py:617 +#: tiramisu/setting.py:612 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "storage_type est déjà défini, impossible de le redéfinir" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "option {0} n'existe pas dans l'espace de stockage {1}" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" "impossible de supprimer une session dans un espace de stockage dictionary" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "session déjà utilisée" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "un espace de stockage dictionary ne peut être persistant" -#: tiramisu/value.py:341 +#: tiramisu/value.py:339 msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:423 +#: tiramisu/value.py:421 msgid "can force cache only if cache is actived in config" msgstr "" "peut force la mise en cache seulement si le cache est activé dans la config" -#: tiramisu/value.py:462 +#: tiramisu/value.py:460 msgid "{0} is already a Multi " msgstr "{0} est déjà une Multi" -#: tiramisu/value.py:498 tiramisu/value.py:562 +#: tiramisu/value.py:496 tiramisu/value.py:560 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:534 +#: tiramisu/value.py:532 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:572 +#: tiramisu/value.py:570 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:576 +#: tiramisu/value.py:574 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:585 +#: tiramisu/value.py:583 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:593 +#: tiramisu/value.py:591 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:601 +#: tiramisu/value.py:599 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:612 +#: tiramisu/value.py:610 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/value.py:630 +#: tiramisu/value.py:628 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index 81a388e..eb41967 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-12 21:49+CET\n" +"POT-Creation-Date: 2014-03-24 19:54+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,552 +15,552 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:162 +#: tiramisu/autolib.py:161 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" -#: tiramisu/config.py:52 +#: tiramisu/config.py:51 msgid "descr must be an optiondescription, not {0}" msgstr "" -#: tiramisu/config.py:127 +#: tiramisu/config.py:126 msgid "unknown group_type: {0}" msgstr "" -#: tiramisu/config.py:164 tiramisu/setting.py:339 tiramisu/value.py:57 -#: tiramisu/value.py:485 +#: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 +#: tiramisu/value.py:483 msgid "the context does not exist anymore" msgstr "" -#: tiramisu/config.py:169 +#: tiramisu/config.py:168 msgid "no option description found for this config (may be GroupConfig)" msgstr "" -#: tiramisu/config.py:195 +#: tiramisu/config.py:194 msgid "can't assign to an OptionDescription" msgstr "" -#: tiramisu/config.py:325 +#: tiramisu/config.py:324 msgid "unknown type_ type {0}for _find" msgstr "" -#: tiramisu/config.py:364 +#: tiramisu/config.py:363 msgid "no option found in config with these criteria" msgstr "" -#: tiramisu/config.py:414 +#: tiramisu/config.py:413 msgid "make_dict can't filtering with value without option" msgstr "" -#: tiramisu/config.py:435 +#: tiramisu/config.py:434 msgid "unexpected path {0}, should start with {1}" msgstr "" -#: tiramisu/config.py:489 +#: tiramisu/config.py:491 msgid "opt in getowner must be an option not {0}" msgstr "" -#: tiramisu/config.py:532 +#: tiramisu/config.py:534 msgid "cannot serialize Config with MetaConfig" msgstr "" -#: tiramisu/config.py:546 +#: tiramisu/config.py:548 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "" -#: tiramisu/config.py:609 +#: tiramisu/config.py:611 msgid "metaconfig's children must be a list" msgstr "" -#: tiramisu/config.py:703 +#: tiramisu/config.py:705 msgid "metaconfig's children should be config, not {0}" msgstr "" -#: tiramisu/config.py:707 +#: tiramisu/config.py:709 msgid "child has already a metaconfig's" msgstr "" -#: tiramisu/config.py:711 +#: tiramisu/config.py:713 msgid "all config in metaconfig must have the same optiondescription" msgstr "" -#: tiramisu/option.py:67 +#: tiramisu/option.py:66 msgid "invalid name: {0} for option" msgstr "" -#: tiramisu/option.py:76 +#: tiramisu/option.py:75 msgid "invalid properties type {0} for {1}, must be a tuple" msgstr "" -#: tiramisu/option.py:114 +#: tiramisu/option.py:113 msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "" -#: tiramisu/option.py:141 tiramisu/value.py:395 +#: tiramisu/option.py:140 tiramisu/value.py:393 msgid "information's item not found: {0}" msgstr "" -#: tiramisu/option.py:203 +#: tiramisu/option.py:202 msgid "cannot serialize Option, only in OptionDescription" msgstr "" -#: tiramisu/option.py:306 +#: tiramisu/option.py:305 msgid "a default_multi is set whereas multi is False in option: {0}" msgstr "" -#: tiramisu/option.py:312 +#: tiramisu/option.py:311 msgid "invalid default_multi value {0} for option {1}: {2}" msgstr "" -#: tiramisu/option.py:317 +#: tiramisu/option.py:316 msgid "default value not allowed if option: {0} is calculated" msgstr "" -#: tiramisu/option.py:320 +#: tiramisu/option.py:319 msgid "params defined for a callback function but no callback defined yet for option {0}" msgstr "" -#: tiramisu/option.py:425 tiramisu/option.py:450 +#: tiramisu/option.py:424 tiramisu/option.py:454 msgid "invalid value for option {0}: {1}" msgstr "" -#: tiramisu/option.py:444 +#: tiramisu/option.py:448 msgid "warning on the value of the option {0}: {1}" msgstr "" -#: tiramisu/option.py:461 +#: tiramisu/option.py:465 msgid "invalid value {0} for option {1} which must be a list" msgstr "" -#: tiramisu/option.py:519 +#: tiramisu/option.py:523 msgid "consistency must be set with an option" msgstr "" -#: tiramisu/option.py:521 +#: tiramisu/option.py:525 msgid "cannot add consistency with itself" msgstr "" -#: tiramisu/option.py:523 +#: tiramisu/option.py:527 msgid "every options in consistency must be multi or none" msgstr "" -#: tiramisu/option.py:544 +#: tiramisu/option.py:548 msgid "same value for {0} and {1}, should be different" msgstr "" -#: tiramisu/option.py:546 +#: tiramisu/option.py:550 msgid "same value for {0} and {1}, must be different" msgstr "" -#: tiramisu/option.py:640 +#: tiramisu/option.py:644 msgid "values must be a tuple for {0}" msgstr "" -#: tiramisu/option.py:643 +#: tiramisu/option.py:647 msgid "open_values must be a boolean for {0}" msgstr "" -#: tiramisu/option.py:665 +#: tiramisu/option.py:669 msgid "value {0} is not permitted, only {1} is allowed" msgstr "" -#: tiramisu/option.py:677 +#: tiramisu/option.py:681 msgid "invalid boolean" msgstr "" -#: tiramisu/option.py:687 +#: tiramisu/option.py:691 msgid "invalid integer" msgstr "" -#: tiramisu/option.py:697 +#: tiramisu/option.py:701 msgid "invalid float" msgstr "" -#: tiramisu/option.py:707 +#: tiramisu/option.py:711 msgid "invalid string" msgstr "" -#: tiramisu/option.py:724 +#: tiramisu/option.py:728 msgid "invalid unicode" msgstr "" -#: tiramisu/option.py:736 +#: tiramisu/option.py:740 msgid "malformed symlinkoption must be an option for symlink {0}" msgstr "" -#: tiramisu/option.py:787 tiramisu/option.py:790 tiramisu/option.py:795 +#: tiramisu/option.py:791 tiramisu/option.py:794 tiramisu/option.py:799 msgid "invalid IP" msgstr "" -#: tiramisu/option.py:801 -msgid "IP shouldn't be in reserved class" -msgstr "" - -#: tiramisu/option.py:803 -msgid "invalid IP, mustn't be in reserved class" +#: tiramisu/option.py:805 +msgid "IP is in reserved class" msgstr "" #: tiramisu/option.py:807 -msgid "IP should be in private class" +msgid "invalid IP, mustn't be in reserved class" msgstr "" -#: tiramisu/option.py:809 +#: tiramisu/option.py:811 +msgid "IP is not in private class" +msgstr "" + +#: tiramisu/option.py:813 msgid "invalid IP, must be in private class" msgstr "" -#: tiramisu/option.py:814 tiramisu/option.py:989 +#: tiramisu/option.py:818 tiramisu/option.py:993 msgid "invalid len for vals" msgstr "" -#: tiramisu/option.py:820 +#: tiramisu/option.py:824 msgid "IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:823 +#: tiramisu/option.py:827 msgid "invalid IP {0} ({1}) not in network {2} ({3}) with netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:864 +#: tiramisu/option.py:868 msgid "inconsistency in allowed range" msgstr "" -#: tiramisu/option.py:869 +#: tiramisu/option.py:873 msgid "max value is empty" msgstr "" -#: tiramisu/option.py:886 +#: tiramisu/option.py:890 msgid "invalid port, range must have two values only" msgstr "" -#: tiramisu/option.py:889 +#: tiramisu/option.py:893 msgid "invalid port, first port in range must be smaller than the second one" msgstr "" -#: tiramisu/option.py:898 +#: tiramisu/option.py:902 msgid "invalid port" msgstr "" -#: tiramisu/option.py:900 +#: tiramisu/option.py:904 msgid "invalid port, must be an between {0} and {1}" msgstr "" -#: tiramisu/option.py:914 +#: tiramisu/option.py:918 msgid "invalid network address" msgstr "" -#: tiramisu/option.py:920 -msgid "network address shouldn't be in reserved class" +#: tiramisu/option.py:924 +msgid "network address is in reserved class" msgstr "" -#: tiramisu/option.py:922 +#: tiramisu/option.py:926 msgid "invalid network address, mustn't be in reserved class" msgstr "" -#: tiramisu/option.py:935 +#: tiramisu/option.py:939 msgid "invalid netmask address" msgstr "" -#: tiramisu/option.py:952 +#: tiramisu/option.py:956 msgid "invalid len for opts" msgstr "" -#: tiramisu/option.py:966 +#: tiramisu/option.py:970 msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network" msgstr "" -#: tiramisu/option.py:971 +#: tiramisu/option.py:975 msgid "invalid network {0} ({1}) with netmask {2}" msgstr "" -#: tiramisu/option.py:985 +#: tiramisu/option.py:989 msgid "invalid broadcast address" msgstr "" -#: tiramisu/option.py:994 +#: tiramisu/option.py:998 msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" msgstr "" -#: tiramisu/option.py:1016 +#: tiramisu/option.py:1020 msgid "unknown type_ {0} for hostname" msgstr "" -#: tiramisu/option.py:1019 +#: tiramisu/option.py:1023 msgid "allow_ip must be a boolean" msgstr "" -#: tiramisu/option.py:1021 +#: tiramisu/option.py:1025 msgid "allow_without_dot must be a boolean" msgstr "" -#: tiramisu/option.py:1065 +#: tiramisu/option.py:1069 msgid "invalid domainname, must have dot" msgstr "" -#: tiramisu/option.py:1067 +#: tiramisu/option.py:1071 msgid "invalid domainname's length (max 255)" msgstr "" -#: tiramisu/option.py:1069 +#: tiramisu/option.py:1073 msgid "invalid domainname's length (min 2)" msgstr "" -#: tiramisu/option.py:1071 +#: tiramisu/option.py:1075 msgid "invalid domainname" msgstr "" -#: tiramisu/option.py:1084 +#: tiramisu/option.py:1088 msgid "invalid email address, must contains one @" msgstr "" -#: tiramisu/option.py:1087 +#: tiramisu/option.py:1091 msgid "invalid username in email address" msgstr "" -#: tiramisu/option.py:1100 +#: tiramisu/option.py:1104 msgid "invalid url, must start with http:// or https://" msgstr "" -#: tiramisu/option.py:1119 +#: tiramisu/option.py:1123 msgid "invalid url, port must be an between 0 and 65536" msgstr "" -#: tiramisu/option.py:1125 +#: tiramisu/option.py:1129 msgid "invalid url, must ends with filename" msgstr "" -#: tiramisu/option.py:1137 +#: tiramisu/option.py:1141 msgid "invalid username" msgstr "" -#: tiramisu/option.py:1148 +#: tiramisu/option.py:1152 msgid "invalid filename" msgstr "" -#: tiramisu/option.py:1175 +#: tiramisu/option.py:1179 msgid "duplicate option name: {0}" msgstr "" -#: tiramisu/option.py:1193 +#: tiramisu/option.py:1197 msgid "unknown Option {0} in OptionDescription {1}" msgstr "" -#: tiramisu/option.py:1244 +#: tiramisu/option.py:1248 msgid "duplicate option: {0}" msgstr "" -#: tiramisu/option.py:1275 +#: tiramisu/option.py:1279 msgid "consistency with option {0} which is not in Config" msgstr "" -#: tiramisu/option.py:1283 +#: tiramisu/option.py:1287 msgid "no option for path {0}" msgstr "" -#: tiramisu/option.py:1289 +#: tiramisu/option.py:1293 msgid "no option {0} found" msgstr "" -#: tiramisu/option.py:1299 +#: tiramisu/option.py:1303 msgid "cannot change group_type if already set (old {0}, new {1})" msgstr "" -#: tiramisu/option.py:1311 +#: tiramisu/option.py:1315 msgid "master group {0} shall not have a subgroup" msgstr "" -#: tiramisu/option.py:1314 +#: tiramisu/option.py:1318 msgid "master group {0} shall not have a symlinkoption" msgstr "" -#: tiramisu/option.py:1317 +#: tiramisu/option.py:1321 msgid "not allowed option {0} in group {1}: this option is not a multi" msgstr "" -#: tiramisu/option.py:1327 +#: tiramisu/option.py:1331 msgid "master group with wrong master name for {0}" msgstr "" -#: tiramisu/option.py:1335 +#: tiramisu/option.py:1339 msgid "callback of master's option shall not refered a slave's ones" msgstr "" -#: tiramisu/option.py:1343 +#: tiramisu/option.py:1347 msgid "group_type: {0} not allowed" msgstr "" -#: tiramisu/option.py:1443 +#: tiramisu/option.py:1444 msgid "malformed requirements type for option: {0}, must be a dict" msgstr "" -#: tiramisu/option.py:1460 +#: tiramisu/option.py:1461 msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1465 +#: tiramisu/option.py:1466 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" -#: tiramisu/option.py:1469 +#: tiramisu/option.py:1470 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" -#: tiramisu/option.py:1473 +#: tiramisu/option.py:1474 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" -#: tiramisu/option.py:1477 +#: tiramisu/option.py:1478 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1480 +#: tiramisu/option.py:1481 msgid "malformed requirements option {0} must not be a multi" msgstr "" -#: tiramisu/option.py:1486 +#: tiramisu/option.py:1487 msgid "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" -#: tiramisu/option.py:1491 +#: tiramisu/option.py:1492 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "" -#: tiramisu/option.py:1516 +#: tiramisu/option.py:1517 msgid "{0} must be a function" msgstr "" -#: tiramisu/option.py:1519 +#: tiramisu/option.py:1520 msgid "{0}_params must be a dict" msgstr "" -#: tiramisu/option.py:1522 +#: tiramisu/option.py:1523 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" -#: tiramisu/option.py:1526 +#: tiramisu/option.py:1527 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "" -#: tiramisu/option.py:1532 +#: tiramisu/option.py:1533 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1535 +#: tiramisu/option.py:1536 msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1539 +#: tiramisu/option.py:1540 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" -#: tiramisu/setting.py:116 +#: tiramisu/setting.py:111 msgid "can't rebind {0}" msgstr "" -#: tiramisu/setting.py:121 +#: tiramisu/setting.py:116 msgid "can't unbind {0}" msgstr "" -#: tiramisu/setting.py:272 +#: tiramisu/setting.py:267 msgid "cannot append {0} property for option {1}: this property is calculated" msgstr "" -#: tiramisu/setting.py:363 +#: tiramisu/setting.py:358 msgid "opt and all_properties must not be set together in reset" msgstr "" -#: tiramisu/setting.py:378 +#: tiramisu/setting.py:373 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" -#: tiramisu/setting.py:487 +#: tiramisu/setting.py:482 msgid "cannot change the value for option {0} this option is frozen" msgstr "" -#: tiramisu/setting.py:493 +#: tiramisu/setting.py:488 msgid "trying to access to an option named: {0} with properties {1}" msgstr "" -#: tiramisu/setting.py:511 +#: tiramisu/setting.py:506 msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:518 tiramisu/value.py:334 +#: tiramisu/setting.py:513 tiramisu/value.py:332 msgid "invalid generic owner {0}" msgstr "" -#: tiramisu/setting.py:606 +#: tiramisu/setting.py:601 msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'" msgstr "" -#: tiramisu/setting.py:617 +#: tiramisu/setting.py:612 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "" -#: tiramisu/storage/__init__.py:52 +#: tiramisu/storage/__init__.py:47 msgid "storage_type is already set, cannot rebind it" msgstr "" -#: tiramisu/storage/__init__.py:86 +#: tiramisu/storage/__init__.py:81 msgid "option {0} not already exists in storage {1}" msgstr "" -#: tiramisu/storage/dictionary/storage.py:39 +#: tiramisu/storage/dictionary/storage.py:37 msgid "dictionary storage cannot delete session" msgstr "" -#: tiramisu/storage/dictionary/storage.py:50 +#: tiramisu/storage/dictionary/storage.py:48 msgid "session already used" msgstr "" -#: tiramisu/storage/dictionary/storage.py:52 +#: tiramisu/storage/dictionary/storage.py:50 msgid "a dictionary cannot be persistent" msgstr "" -#: tiramisu/value.py:341 +#: tiramisu/value.py:339 msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:423 +#: tiramisu/value.py:421 msgid "can force cache only if cache is actived in config" msgstr "" -#: tiramisu/value.py:462 +#: tiramisu/value.py:460 msgid "{0} is already a Multi " msgstr "" -#: tiramisu/value.py:498 tiramisu/value.py:562 +#: tiramisu/value.py:496 tiramisu/value.py:560 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:534 +#: tiramisu/value.py:532 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:572 +#: tiramisu/value.py:570 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:576 +#: tiramisu/value.py:574 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:585 +#: tiramisu/value.py:583 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:593 +#: tiramisu/value.py:591 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:601 +#: tiramisu/value.py:599 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:612 +#: tiramisu/value.py:610 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/value.py:630 +#: tiramisu/value.py:628 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From 45bd71a318ce2fc89a0fe7cae3d1835f7721594e Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 26 Mar 2014 19:44:49 +0100 Subject: [PATCH 27/42] context could be useful in a callback, now we can retrieve context in a function (be careful to infinite loop) --- test/test_option_calculation.py | 30 ++++++++++++++ tiramisu/autolib.py | 69 ++++++++++++++++++--------------- tiramisu/option.py | 35 ++++++++++------- 3 files changed, 89 insertions(+), 45 deletions(-) diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index 89f9291..ad1b54f 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -44,6 +44,13 @@ def return_calc(i, j, k): return i + j + k +def is_config(config, **kwargs): + if isinstance(config, Config): + return 'yes' + else: + return 'no' + + def make_description(): gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcdummy = BoolOption('dummy', 'dummy', default=False) @@ -254,6 +261,29 @@ def test_callback_invalid(): raises(ValueError, "StrOption('val2', '', callback=return_value, callback_params={'': 'string'})") raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': (('string', False),)})") raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, 'string'),)})") + raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, False, 'unknown'),)})") + raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1,),)})") + + +def test_callback_with_context(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'': ((None,),), 'value': ('string',)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'yes' + + +def test_callback_with_context_named(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'config': ((None,),)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'yes' + + +def test_callback_with_error(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'': ('string',), 'value': ('string',)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'no' def test_callback_value(): diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 0b97644..e837f79 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -145,39 +145,44 @@ def carry_out_calculation(option, config, callback, callback_params, for key, callbacks in callback_params.items(): for callbk in callbacks: if isinstance(callbk, tuple): - # callbk is something link (opt, True|False) - opt, force_permissive = callbk - path = config.cfgimpl_get_description().impl_get_path_by_opt( - opt) - # get value - try: - value = config._getattr(path, force_permissive=True, validate=False) - # convert to list, not modifie this multi - if value.__class__.__name__ == 'Multi': - value = list(value) - except PropertiesOptionError as err: - if force_permissive: - continue - raise ConfigError(_('unable to carry out a calculation, ' - 'option {0} has properties: {1} for: ' - '{2}').format(opt._name, - err.proptype, - option._name)) + if len(callbk) == 1: + tcparams.setdefault(key, []).append((config, False)) + else: + # callbk is something link (opt, True|False) + opt, force_permissive = callbk + path = config.cfgimpl_get_description( + ).impl_get_path_by_opt(opt) + # get value + try: + value = config._getattr(path, force_permissive=True, + validate=False) + # convert to list, not modifie this multi + if value.__class__.__name__ == 'Multi': + value = list(value) + except PropertiesOptionError as err: + if force_permissive: + continue + raise ConfigError(_('unable to carry out a calculation' + ', option {0} has properties: {1} ' + 'for: {2}').format(opt._name, + err.proptype, + option._name)) - is_multi = False - if opt.impl_is_multi(): - #opt is master, search if option is a slave - if opt.impl_get_multitype() == multitypes.master: - if option in opt.impl_get_master_slaves(): - is_multi = True - #opt is slave, search if option is an other slaves - elif opt.impl_get_multitype() == multitypes.slave: - if option in opt.impl_get_master_slaves().impl_get_master_slaves(): - is_multi = True - if is_multi: - len_multi = len(value) - one_is_multi = True - tcparams.setdefault(key, []).append((value, is_multi)) + is_multi = False + if opt.impl_is_multi(): + #opt is master, search if option is a slave + if opt.impl_get_multitype() == multitypes.master: + if option in opt.impl_get_master_slaves(): + is_multi = True + #opt is slave, search if option is an other slaves + elif opt.impl_get_multitype() == multitypes.slave: + if option in opt.impl_get_master_slaves( + ).impl_get_master_slaves(): + is_multi = True + if is_multi: + len_multi = len(value) + one_is_multi = True + tcparams.setdefault(key, []).append((value, is_multi)) else: # callbk is a value and not a multi tcparams.setdefault(key, []).append((callbk, False)) diff --git a/tiramisu/option.py b/tiramisu/option.py index 30277e2..d8853df 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1528,16 +1528,25 @@ def validate_callback(callback, callback_params, type_): ).format(type_, key)) for callbk in callbacks: if isinstance(callbk, tuple): - option, force_permissive = callbk - if type_ == 'validator' and not force_permissive: - raise ValueError(_('validator not support tuple')) - if not isinstance(option, Option) and not \ - isinstance(option, SymLinkOption): - raise ValueError(_('{0}_params must have an option ' - 'not a {0} for first argument' - ).format(type_, type(option))) - if force_permissive not in [True, False]: - raise ValueError(_('{0}_params must have a boolean' - ' not a {0} for second argument' - ).format(type_, type( - force_permissive))) + if len(callbk) == 1: + if callbk != (None,): + raise ValueError(_('{0}_params with length of ' + 'tuple as 1 must only have ' + 'None as first value')) + elif len(callbk) != 2: + raise ValueError(_('{0}_params must only 1 or 2 as ' + 'length')) + else: + option, force_permissive = callbk + if type_ == 'validator' and not force_permissive: + raise ValueError(_('validator not support tuple')) + if not isinstance(option, Option) and not \ + isinstance(option, SymLinkOption): + raise ValueError(_('{0}_params must have an option' + ' not a {0} for first argument' + ).format(type_, type(option))) + if force_permissive not in [True, False]: + raise ValueError(_('{0}_params must have a boolean' + ' not a {0} for second argument' + ).format(type_, type( + force_permissive))) From 835d6d6da03c2e88263d580640b92511b92a1980 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 26 Mar 2014 19:44:49 +0100 Subject: [PATCH 28/42] context could be useful in a callback, now we can retrieve context in a function (be careful to infinite loop) --- test/test_option_calculation.py | 30 ++++++++++++++ tiramisu/autolib.py | 69 ++++++++++++++++++--------------- tiramisu/option.py | 35 ++++++++++------- 3 files changed, 89 insertions(+), 45 deletions(-) diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index 89f9291..ad1b54f 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -44,6 +44,13 @@ def return_calc(i, j, k): return i + j + k +def is_config(config, **kwargs): + if isinstance(config, Config): + return 'yes' + else: + return 'no' + + def make_description(): gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcdummy = BoolOption('dummy', 'dummy', default=False) @@ -254,6 +261,29 @@ def test_callback_invalid(): raises(ValueError, "StrOption('val2', '', callback=return_value, callback_params={'': 'string'})") raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': (('string', False),)})") raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, 'string'),)})") + raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, False, 'unknown'),)})") + raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1,),)})") + + +def test_callback_with_context(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'': ((None,),), 'value': ('string',)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'yes' + + +def test_callback_with_context_named(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'config': ((None,),)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'yes' + + +def test_callback_with_error(): + val1 = StrOption("val1", "", callback=is_config, callback_params={'': ('string',), 'value': ('string',)}) + maconfig = OptionDescription('rootconfig', '', [val1]) + cfg = Config(maconfig) + assert cfg.val1 == 'no' def test_callback_value(): diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 0b97644..e837f79 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -145,39 +145,44 @@ def carry_out_calculation(option, config, callback, callback_params, for key, callbacks in callback_params.items(): for callbk in callbacks: if isinstance(callbk, tuple): - # callbk is something link (opt, True|False) - opt, force_permissive = callbk - path = config.cfgimpl_get_description().impl_get_path_by_opt( - opt) - # get value - try: - value = config._getattr(path, force_permissive=True, validate=False) - # convert to list, not modifie this multi - if value.__class__.__name__ == 'Multi': - value = list(value) - except PropertiesOptionError as err: - if force_permissive: - continue - raise ConfigError(_('unable to carry out a calculation, ' - 'option {0} has properties: {1} for: ' - '{2}').format(opt._name, - err.proptype, - option._name)) + if len(callbk) == 1: + tcparams.setdefault(key, []).append((config, False)) + else: + # callbk is something link (opt, True|False) + opt, force_permissive = callbk + path = config.cfgimpl_get_description( + ).impl_get_path_by_opt(opt) + # get value + try: + value = config._getattr(path, force_permissive=True, + validate=False) + # convert to list, not modifie this multi + if value.__class__.__name__ == 'Multi': + value = list(value) + except PropertiesOptionError as err: + if force_permissive: + continue + raise ConfigError(_('unable to carry out a calculation' + ', option {0} has properties: {1} ' + 'for: {2}').format(opt._name, + err.proptype, + option._name)) - is_multi = False - if opt.impl_is_multi(): - #opt is master, search if option is a slave - if opt.impl_get_multitype() == multitypes.master: - if option in opt.impl_get_master_slaves(): - is_multi = True - #opt is slave, search if option is an other slaves - elif opt.impl_get_multitype() == multitypes.slave: - if option in opt.impl_get_master_slaves().impl_get_master_slaves(): - is_multi = True - if is_multi: - len_multi = len(value) - one_is_multi = True - tcparams.setdefault(key, []).append((value, is_multi)) + is_multi = False + if opt.impl_is_multi(): + #opt is master, search if option is a slave + if opt.impl_get_multitype() == multitypes.master: + if option in opt.impl_get_master_slaves(): + is_multi = True + #opt is slave, search if option is an other slaves + elif opt.impl_get_multitype() == multitypes.slave: + if option in opt.impl_get_master_slaves( + ).impl_get_master_slaves(): + is_multi = True + if is_multi: + len_multi = len(value) + one_is_multi = True + tcparams.setdefault(key, []).append((value, is_multi)) else: # callbk is a value and not a multi tcparams.setdefault(key, []).append((callbk, False)) diff --git a/tiramisu/option.py b/tiramisu/option.py index 30277e2..d8853df 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1528,16 +1528,25 @@ def validate_callback(callback, callback_params, type_): ).format(type_, key)) for callbk in callbacks: if isinstance(callbk, tuple): - option, force_permissive = callbk - if type_ == 'validator' and not force_permissive: - raise ValueError(_('validator not support tuple')) - if not isinstance(option, Option) and not \ - isinstance(option, SymLinkOption): - raise ValueError(_('{0}_params must have an option ' - 'not a {0} for first argument' - ).format(type_, type(option))) - if force_permissive not in [True, False]: - raise ValueError(_('{0}_params must have a boolean' - ' not a {0} for second argument' - ).format(type_, type( - force_permissive))) + if len(callbk) == 1: + if callbk != (None,): + raise ValueError(_('{0}_params with length of ' + 'tuple as 1 must only have ' + 'None as first value')) + elif len(callbk) != 2: + raise ValueError(_('{0}_params must only 1 or 2 as ' + 'length')) + else: + option, force_permissive = callbk + if type_ == 'validator' and not force_permissive: + raise ValueError(_('validator not support tuple')) + if not isinstance(option, Option) and not \ + isinstance(option, SymLinkOption): + raise ValueError(_('{0}_params must have an option' + ' not a {0} for first argument' + ).format(type_, type(option))) + if force_permissive not in [True, False]: + raise ValueError(_('{0}_params must have a boolean' + ' not a {0} for second argument' + ).format(type_, type( + force_permissive))) From a3e28392b0c73325f8d03943f8b7b1708d295228 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 26 Mar 2014 20:47:30 +0100 Subject: [PATCH 29/42] update translation --- tiramisu/option.py | 4 ++-- translations/fr/tiramisu.po | 19 +++++++++++++++---- translations/tiramisu.pot | 16 ++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index d8853df..eeab2f9 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1534,8 +1534,8 @@ def validate_callback(callback, callback_params, type_): 'tuple as 1 must only have ' 'None as first value')) elif len(callbk) != 2: - raise ValueError(_('{0}_params must only 1 or 2 as ' - 'length')) + raise ValueError(_('{0}_params must only have 1 or 2 ' + 'as length')) else: option, force_permissive = callbk if type_ == 'validator' and not force_permissive: diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 0e1b339..ab01ec6 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-24 19:54+CET\n" +"POT-Creation-Date: 2014-03-26 20:46+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -14,7 +14,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: tiramisu/autolib.py:161 +#: tiramisu/autolib.py:165 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -472,14 +472,25 @@ msgid "{0}_params must be tuple for key \"{1}\"" msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" #: tiramisu/option.py:1533 +msgid "{0}_params with length of tuple as 1 must only have None as first value" +msgstr "" +"{0}_params avec un tuple de longueur 1 doit seulement avoir None comme " +"première valeur" + +#: tiramisu/option.py:1537 +#, fuzzy +msgid "{0}_params must only have 1 or 2 as length" +msgstr "{0}_params doit seulement avoir une longueur de 1 ou 2" + +#: tiramisu/option.py:1542 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1536 +#: tiramisu/option.py:1545 msgid "{0}_params must have an option not a {0} for first argument" msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1540 +#: tiramisu/option.py:1549 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index eb41967..1bf9361 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-24 19:54+CET\n" +"POT-Creation-Date: 2014-03-26 20:46+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,7 +15,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:161 +#: tiramisu/autolib.py:165 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -441,14 +441,22 @@ msgid "{0}_params must be tuple for key \"{1}\"" msgstr "" #: tiramisu/option.py:1533 +msgid "{0}_params with length of tuple as 1 must only have None as first value" +msgstr "" + +#: tiramisu/option.py:1537 +msgid "{0}_params must only have 1 or 2 as length" +msgstr "" + +#: tiramisu/option.py:1542 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1536 +#: tiramisu/option.py:1545 msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1540 +#: tiramisu/option.py:1549 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" From 84f0095c2f3fc26ce696edcfa8e9b0d5a9a6971f Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 26 Mar 2014 20:47:30 +0100 Subject: [PATCH 30/42] update translation --- tiramisu/option.py | 4 ++-- translations/fr/tiramisu.po | 19 +++++++++++++++---- translations/tiramisu.pot | 16 ++++++++++++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index d8853df..eeab2f9 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1534,8 +1534,8 @@ def validate_callback(callback, callback_params, type_): 'tuple as 1 must only have ' 'None as first value')) elif len(callbk) != 2: - raise ValueError(_('{0}_params must only 1 or 2 as ' - 'length')) + raise ValueError(_('{0}_params must only have 1 or 2 ' + 'as length')) else: option, force_permissive = callbk if type_ == 'validator' and not force_permissive: diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index 0e1b339..ab01ec6 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-24 19:54+CET\n" +"POT-Creation-Date: 2014-03-26 20:46+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -14,7 +14,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Poedit-SourceCharset: UTF-8\n" -#: tiramisu/autolib.py:161 +#: tiramisu/autolib.py:165 msgid "" "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -472,14 +472,25 @@ msgid "{0}_params must be tuple for key \"{1}\"" msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" #: tiramisu/option.py:1533 +msgid "{0}_params with length of tuple as 1 must only have None as first value" +msgstr "" +"{0}_params avec un tuple de longueur 1 doit seulement avoir None comme " +"première valeur" + +#: tiramisu/option.py:1537 +#, fuzzy +msgid "{0}_params must only have 1 or 2 as length" +msgstr "{0}_params doit seulement avoir une longueur de 1 ou 2" + +#: tiramisu/option.py:1542 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1536 +#: tiramisu/option.py:1545 msgid "{0}_params must have an option not a {0} for first argument" msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1540 +#: tiramisu/option.py:1549 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index eb41967..1bf9361 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-24 19:54+CET\n" +"POT-Creation-Date: 2014-03-26 20:46+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -15,7 +15,7 @@ msgstr "" "Generated-By: pygettext.py 1.5\n" -#: tiramisu/autolib.py:161 +#: tiramisu/autolib.py:165 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}" msgstr "" @@ -441,14 +441,22 @@ msgid "{0}_params must be tuple for key \"{1}\"" msgstr "" #: tiramisu/option.py:1533 +msgid "{0}_params with length of tuple as 1 must only have None as first value" +msgstr "" + +#: tiramisu/option.py:1537 +msgid "{0}_params must only have 1 or 2 as length" +msgstr "" + +#: tiramisu/option.py:1542 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1536 +#: tiramisu/option.py:1545 msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1540 +#: tiramisu/option.py:1549 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" From 5fd62e2a9624a54e5b86c94f65ec73be91190a2c Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 28 Mar 2014 17:35:27 +0100 Subject: [PATCH 31/42] force_store_value works now with permissive --- test/test_freeze.py | 13 ++++++++++++- tiramisu/value.py | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/test/test_freeze.py b/test/test_freeze.py index cda1406..f279c47 100644 --- a/test/test_freeze.py +++ b/test/test_freeze.py @@ -22,13 +22,14 @@ def make_description_freeze(): boolop = BoolOption('boolop', 'Test boolean option op', default=[True], multi=True) wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=('force_store_value',), requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) + wantref2_option = BoolOption('wantref2', 'Test requires', default=False, properties=('force_store_value', 'hidden')) wantframework_option = BoolOption('wantframework', 'Test requires', default=False, requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption, - wantref_option, stroption, + wantref_option, wantref2_option, stroption, wantframework_option, intoption, boolop]) return descr @@ -153,3 +154,13 @@ def test_force_store_value_ro(): assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default' conf.wantref assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user' + + +def test_force_store_value_hidden(): + descr = make_description_freeze() + conf = Config(descr) + conf.cfgimpl_get_settings().setpermissive(('hidden',)) + conf.read_write() + assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'default' + conf._getattr('wantref2', force_permissive=True) + assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'user' diff --git a/tiramisu/value.py b/tiramisu/value.py index 968f0e4..d66f85d 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -243,7 +243,8 @@ class Values(object): opt.impl_validate(value, context, 'validator' in setting) if config_error is None and self._is_default_owner(path) and \ 'force_store_value' in setting[opt]: - self.setitem(opt, value, path, is_write=False) + self.setitem(opt, value, path, is_write=False, + force_permissive=force_permissive) if validate_properties: setting.validate_properties(opt, False, False, value=value, path=path, force_permissive=force_permissive, From 712db2875e0dac7c7e0d6c88b551d4bdff2992c6 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Fri, 28 Mar 2014 17:35:27 +0100 Subject: [PATCH 32/42] force_store_value works now with permissive --- test/test_freeze.py | 13 ++++++++++++- tiramisu/value.py | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/test/test_freeze.py b/test/test_freeze.py index cda1406..f279c47 100644 --- a/test/test_freeze.py +++ b/test/test_freeze.py @@ -22,13 +22,14 @@ def make_description_freeze(): boolop = BoolOption('boolop', 'Test boolean option op', default=[True], multi=True) wantref_option = BoolOption('wantref', 'Test requires', default=False, properties=('force_store_value',), requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) + wantref2_option = BoolOption('wantref2', 'Test requires', default=False, properties=('force_store_value', 'hidden')) wantframework_option = BoolOption('wantframework', 'Test requires', default=False, requires=({'option': booloption, 'expected': True, 'action': 'hidden'},)) gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption, - wantref_option, stroption, + wantref_option, wantref2_option, stroption, wantframework_option, intoption, boolop]) return descr @@ -153,3 +154,13 @@ def test_force_store_value_ro(): assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default' conf.wantref assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user' + + +def test_force_store_value_hidden(): + descr = make_description_freeze() + conf = Config(descr) + conf.cfgimpl_get_settings().setpermissive(('hidden',)) + conf.read_write() + assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'default' + conf._getattr('wantref2', force_permissive=True) + assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'user' diff --git a/tiramisu/value.py b/tiramisu/value.py index 968f0e4..d66f85d 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -243,7 +243,8 @@ class Values(object): opt.impl_validate(value, context, 'validator' in setting) if config_error is None and self._is_default_owner(path) and \ 'force_store_value' in setting[opt]: - self.setitem(opt, value, path, is_write=False) + self.setitem(opt, value, path, is_write=False, + force_permissive=force_permissive) if validate_properties: setting.validate_properties(opt, False, False, value=value, path=path, force_permissive=force_permissive, From ff5376a382f4fc48b16f695357bbe1de3b4cd021 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 29 Mar 2014 20:31:56 +0100 Subject: [PATCH 33/42] properties are check now in getowner get_modified_values works good with force_store_value --- test/test_freeze.py | 75 ++++++++++++++++++++++++++--- test/test_mandatory.py | 8 ++-- test/test_option_owner.py | 10 +++- tiramisu/config.py | 5 +- tiramisu/option.py | 14 ++++-- tiramisu/setting.py | 31 ++++++++---- tiramisu/value.py | 43 ++++++++++------- translations/fr/tiramisu.po | 96 ++++++++++++++++++++----------------- translations/tiramisu.pot | 92 ++++++++++++++++++----------------- 9 files changed, 242 insertions(+), 132 deletions(-) diff --git a/test/test_freeze.py b/test/test_freeze.py index f279c47..362f26f 100644 --- a/test/test_freeze.py +++ b/test/test_freeze.py @@ -142,18 +142,27 @@ def test_freeze_get_multi(): def test_force_store_value(): descr = make_description_freeze() conf = Config(descr) - assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} conf.wantref - assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)} + + +def test_force_store_value_no_requirement(): + booloption = BoolOption('bool', 'Test boolean option', default=True) + try: + BoolOption('wantref', 'Test requires', default=False, + requires=({'option': booloption, 'expected': True, 'action': 'force_store_value'},)) + except ValueError: + pass def test_force_store_value_ro(): descr = make_description_freeze() conf = Config(descr) conf.read_only() - assert conf.getowner(conf.unwrap_from_path('wantref')) == 'default' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} conf.wantref - assert conf.getowner(conf.unwrap_from_path('wantref')) == 'user' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)} def test_force_store_value_hidden(): @@ -161,6 +170,60 @@ def test_force_store_value_hidden(): conf = Config(descr) conf.cfgimpl_get_settings().setpermissive(('hidden',)) conf.read_write() - assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'default' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} conf._getattr('wantref2', force_permissive=True) - assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'user' + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref2': ('user', False)} + + +def test_force_store_value_owner(): + descr = make_description_freeze() + conf = Config(descr) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.getowner(conf.unwrap_from_path('wantref')) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)} + + +def test_force_store_value_owner_ro(): + descr = make_description_freeze() + conf = Config(descr) + conf.read_only() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.getowner(conf.unwrap_from_path('wantref')) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False)} + + +def test_force_store_value_owner_hidden(): + descr = make_description_freeze() + conf = Config(descr) + conf.cfgimpl_get_settings().setpermissive(('hidden',)) + conf.read_write() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.getowner(conf.unwrap_from_path('wantref2'), force_permissive=True) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref2': ('user', False)} + + +def test_force_store_value_modified(): + descr = make_description_freeze() + conf = Config(descr) + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.cfgimpl_get_values().get_modified_values() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False), 'wantref2': ('user', False)} + + +def test_force_store_value_modified_ro(): + descr = make_description_freeze() + conf = Config(descr) + conf.read_only() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.cfgimpl_get_values().get_modified_values() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False), 'wantref2': ('user', False)} + + +def test_force_store_value_modified_hidden(): + descr = make_description_freeze() + conf = Config(descr) + conf.cfgimpl_get_settings().setpermissive(('hidden',)) + conf.read_write() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {} + conf.cfgimpl_get_values().get_modified_values() + assert conf.cfgimpl_get_values()._p_.get_modified_values() == {'wantref': ('user', False), 'wantref2': ('user', False)} diff --git a/test/test_mandatory.py b/test/test_mandatory.py index 5b9878a..26c8e4b 100644 --- a/test/test_mandatory.py +++ b/test/test_mandatory.py @@ -99,8 +99,8 @@ def test_mandatory_multi_none(): descr = make_description() config = Config(descr) config.str3 = [None] - config.read_only() assert config.getowner(config.unwrap_from_path('str3')) == 'user' + config.read_only() prop = [] try: config.str3 @@ -109,8 +109,8 @@ def test_mandatory_multi_none(): assert 'mandatory' in prop config.read_write() config.str3 = ['yes', None] - config.read_only() assert config.getowner(config.unwrap_from_path('str3')) == 'user' + config.read_only() prop = [] try: config.str3 @@ -123,8 +123,8 @@ def test_mandatory_multi_empty(): descr = make_description() config = Config(descr) config.str3 = [''] - config.read_only() assert config.getowner(config.unwrap_from_path('str3')) == 'user' + config.read_only() prop = [] try: config.str3 @@ -133,8 +133,8 @@ def test_mandatory_multi_empty(): assert 'mandatory' in prop config.read_write() config.str3 = ['yes', ''] - config.read_only() assert config.getowner(config.unwrap_from_path('str3')) == 'user' + config.read_only() prop = [] try: config.str3 diff --git a/test/test_option_owner.py b/test/test_option_owner.py index d4c3f6b..1880bc4 100644 --- a/test/test_option_owner.py +++ b/test/test_option_owner.py @@ -5,7 +5,7 @@ from tiramisu.setting import owners from tiramisu.config import Config from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \ StrOption, OptionDescription -from tiramisu.error import ConfigError, ConstError +from tiramisu.error import ConfigError, ConstError, PropertiesOptionError def make_description(): @@ -41,6 +41,14 @@ def test_default_owner(): assert cfg.getowner(gcdummy) == owners.user +def test_hidden_owner(): + gcdummy = BoolOption('dummy', 'dummy', default=False, properties=('hidden',)) + descr = OptionDescription('tiramisu', '', [gcdummy]) + cfg = Config(descr) + cfg.read_write() + raises(PropertiesOptionError, "cfg.getowner(gcdummy)") + + def test_addowner(): gcdummy = BoolOption('dummy', 'dummy', default=False) descr = OptionDescription('tiramisu', '', [gcdummy]) diff --git a/tiramisu/config.py b/tiramisu/config.py index 2a882a1..8fc8e2d 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -483,14 +483,15 @@ class _CommonConfig(SubConfig): "read write is a global config's setting, see `settings.py`" self.cfgimpl_get_settings().read_write() - def getowner(self, opt): + def getowner(self, opt, force_permissive=False): """convenience method to retrieve an option's owner from the config itself """ if not isinstance(opt, Option) and not isinstance(opt, SymLinkOption): raise TypeError(_('opt in getowner must be an option not {0}' '').format(type(opt))) - return self.cfgimpl_get_values().getowner(opt) + return self.cfgimpl_get_values().getowner(opt, + force_permissive=force_permissive) def unwrap_from_path(self, path, force_permissive=False): """convenience method to extract and Option() object from the Config() diff --git a/tiramisu/option.py b/tiramisu/option.py index eeab2f9..f4a53aa 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -1461,6 +1461,10 @@ def validate_requires_arg(requires, name): raise ValueError(_("malformed requirements for option: {0}" " require must have option, expected and" " action keys").format(name)) + if action == 'force_store_value': + raise ValueError(_("malformed requirements for option: {0}" + " action cannot be force_store_value" + ).format(name)) inverse = require.get('inverse', False) if inverse not in [True, False]: raise ValueError(_('malformed requirements for option: {0}' @@ -1543,10 +1547,10 @@ def validate_callback(callback, callback_params, type_): if not isinstance(option, Option) and not \ isinstance(option, SymLinkOption): raise ValueError(_('{0}_params must have an option' - ' not a {0} for first argument' - ).format(type_, type(option))) + ' not a {0} for first argument' + ).format(type_, type(option))) if force_permissive not in [True, False]: raise ValueError(_('{0}_params must have a boolean' - ' not a {0} for second argument' - ).format(type_, type( - force_permissive))) + ' not a {0} for second argument' + ).format(type_, type( + force_permissive))) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 6ba84d7..8a7ae13 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -365,7 +365,10 @@ class Settings(object): self._p_.reset_properties(_path) self._getcontext().cfgimpl_reset_cache() - def _getproperties(self, opt=None, path=None, is_apply_req=True): + def _getproperties(self, opt=None, path=None, _is_apply_req=True): + """ + be careful, _is_apply_req doesn't copy properties + """ if opt is None: props = copy(self._p_.getproperties(path, default_properties)) else: @@ -379,15 +382,16 @@ class Settings(object): is_cached, props = self._p_.getcache(path, ntime) if is_cached: return copy(props) - props = copy(self._p_.getproperties(path, opt._properties)) - if is_apply_req: + props = self._p_.getproperties(path, opt._properties) + if _is_apply_req: + props = copy(props) props |= self.apply_requires(opt, path) - if 'cache' in self: - if 'expire' in self: - if ntime is None: - ntime = int(time()) - ntime = ntime + expires_time - self._p_.setcache(path, copy(props), ntime) + if 'cache' in self: + if 'expire' in self: + if ntime is None: + ntime = int(time()) + ntime = ntime + expires_time + self._p_.setcache(path, copy(props), ntime) return props def append(self, propname): @@ -640,6 +644,15 @@ class Settings(object): def get_modified_permissives(self): return self._p_.get_modified_permissives() + def get_with_property(self, propname): + opts, paths = self._getcontext().cfgimpl_get_description( + )._cache_paths + for index in range(0, len(paths)): + opt = opts[index] + path = paths[index] + if propname in self._getproperties(opt, path, False): + yield (opt, path) + def __getstate__(self): return {'_p_': self._p_, '_owner': str(self._owner)} diff --git a/tiramisu/value.py b/tiramisu/value.py index d66f85d..e5c6111 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -88,6 +88,11 @@ class Values(object): return value def get_modified_values(self): + context = self._getcontext() + if context._impl_descr is not None: + for opt, path in context.cfgimpl_get_settings( + ).get_with_property('force_store_value'): + self._getowner(opt, path, force_permissive=True) return self._p_.get_modified_values() def __contains__(self, opt): @@ -196,7 +201,7 @@ class Values(object): # if value has callback and is not set # or frozen with force_default_on_freeze if opt.impl_has_callback() and ( - self._is_default_owner(path) or + self._is_default_owner(opt, path, validate_properties=False) or (is_frozen and 'force_default_on_freeze' in setting[opt])): lenmaster = None no_value_slave = False @@ -241,7 +246,8 @@ class Values(object): value = Multi(value, self.context, opt, path, validate=validate) if config_error is None and validate: opt.impl_validate(value, context, 'validator' in setting) - if config_error is None and self._is_default_owner(path) and \ + if config_error is None and \ + self._is_default_owner(opt, path, validate_properties=False) and \ 'force_store_value' in setting[opt]: self.setitem(opt, value, path, is_write=False, force_permissive=force_permissive) @@ -303,23 +309,27 @@ class Values(object): value = list(value) self._p_.setvalue(path, value, owner) - def getowner(self, opt): + def getowner(self, opt, force_permissive=False): """ retrieves the option's owner :param opt: the `option.Option` object + :param force_permissive: behaves as if the permissive property + was present :returns: a `setting.owners.Owner` object """ if isinstance(opt, SymLinkOption): opt = opt._opt path = self._get_opt_path(opt) - return self._getowner(path) + return self._getowner(opt, path, force_permissive=force_permissive) - def _getowner(self, path): - owner = self._p_.getowner(path, owners.default) + def _getowner(self, opt, path, validate_properties=True, force_permissive=False): meta = self._getcontext().cfgimpl_get_meta() + if validate_properties: + self._getitem(opt, path, True, force_permissive, None, True) + owner = self._p_.getowner(path, owners.default) if owner is owners.default and meta is not None: - owner = meta.cfgimpl_get_values()._getowner(path) + owner = meta.cfgimpl_get_values()._getowner(opt, path) return owner def setowner(self, opt, owner): @@ -333,25 +343,25 @@ class Values(object): raise TypeError(_("invalid generic owner {0}").format(str(owner))) path = self._get_opt_path(opt) - self._setowner(path, owner) + self._setowner(opt, path, owner) - def _setowner(self, path, owner): - if self._getowner(path) == owners.default: + def _setowner(self, opt, path, owner): + if self._getowner(opt, path) == owners.default: raise ConfigError(_('no value for {0} cannot change owner to {1}' '').format(path, owner)) self._p_.setowner(path, owner) - def is_default_owner(self, opt): + def is_default_owner(self, opt, validate_properties=True): """ :param config: *must* be only the **parent** config (not the toplevel config) :return: boolean """ path = self._get_opt_path(opt) - return self._is_default_owner(path) + return self._is_default_owner(opt, path, validate_properties) - def _is_default_owner(self, path): - return self._getowner(path) == owners.default + def _is_default_owner(self, opt, path, validate_properties=True): + return self._getowner(opt, path, validate_properties) == owners.default def reset_cache(self, only_expired): """ @@ -550,7 +560,8 @@ class Multi(list): if not force and self.opt.impl_get_multitype() == multitypes.master: for slave in self.opt.impl_get_master_slaves(): path = values._get_opt_path(slave) - if not values._is_default_owner(path): + if not values._is_default_owner(slave, path, + validate_properties=False): if slave.impl_has_callback(): dvalue = values._getcallback_value(slave, index=index) else: @@ -631,7 +642,7 @@ class Multi(list): if self.opt.impl_get_multitype() == multitypes.master: for slave in self.opt.impl_get_master_slaves(): values = context.cfgimpl_get_values() - if not values.is_default_owner(slave): + if not values.is_default_owner(slave, validate_properties=False): #get multi without valid properties values.getitem(slave, validate=False, validate_properties=False diff --git a/translations/fr/tiramisu.po b/translations/fr/tiramisu.po index ab01ec6..eb14d72 100644 --- a/translations/fr/tiramisu.po +++ b/translations/fr/tiramisu.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Tiramisu\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-03-26 20:46+CET\n" +"POT-Creation-Date: 2014-03-29 19:01+CET\n" "PO-Revision-Date: \n" "Last-Translator: Emmanuel Garette \n" "Language-Team: Tiramisu's team \n" @@ -30,7 +30,7 @@ msgid "unknown group_type: {0}" msgstr "group_type inconnu: {0}" #: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 -#: tiramisu/value.py:483 +#: tiramisu/value.py:500 msgid "the context does not exist anymore" msgstr "le context n'existe plus" @@ -63,27 +63,27 @@ msgstr "chemin imprévu {0}, devrait commencer par {1}" msgid "opt in getowner must be an option not {0}" msgstr "opt dans getowner doit être une option pas {0}" -#: tiramisu/config.py:534 +#: tiramisu/config.py:535 msgid "cannot serialize Config with MetaConfig" msgstr "impossible de sérialiser une Config avec une MetaConfig" -#: tiramisu/config.py:548 +#: tiramisu/config.py:549 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "ce storage n'est sérialisable, devrait être une storage non persistant" -#: tiramisu/config.py:611 +#: tiramisu/config.py:612 msgid "metaconfig's children must be a list" msgstr "enfants d'une metaconfig doit être une liste" -#: tiramisu/config.py:705 +#: tiramisu/config.py:706 msgid "metaconfig's children should be config, not {0}" msgstr "enfants d'une metaconfig doit être une config, pas {0}" -#: tiramisu/config.py:709 +#: tiramisu/config.py:710 msgid "child has already a metaconfig's" msgstr "enfant a déjà une metaconfig" -#: tiramisu/config.py:713 +#: tiramisu/config.py:714 msgid "all config in metaconfig must have the same optiondescription" msgstr "" "toutes les configs d'une metaconfig doivent avoir la même optiondescription" @@ -100,7 +100,7 @@ msgstr "type des properties invalide {0} pour {1}, doit être un tuple" msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" -#: tiramisu/option.py:140 tiramisu/value.py:393 +#: tiramisu/option.py:140 tiramisu/value.py:410 msgid "information's item not found: {0}" msgstr "aucune config spécifiée alors que c'est nécessaire" @@ -420,77 +420,83 @@ msgstr "" "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "option, expected et action" -#: tiramisu/option.py:1466 +#: tiramisu/option.py:1465 +msgid "" +"malformed requirements for option: {0} action cannot be force_store_value" +msgstr "" +"requirements mal formés pour l'option : {0} action ne peut pas être " +"force_store_value" + +#: tiramisu/option.py:1470 msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" "requirements mal formés pour l'option : {0} inverse doit être un booléen" -#: tiramisu/option.py:1470 +#: tiramisu/option.py:1474 msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" "requirements mal formés pour l'option : {0} transitive doit être booléen" -#: tiramisu/option.py:1474 +#: tiramisu/option.py:1478 msgid "malformed requirements for option: {0} same_action must be boolean" msgstr "" "requirements mal formés pour l'option : {0} same_action doit être un booléen" -#: tiramisu/option.py:1478 +#: tiramisu/option.py:1482 msgid "malformed requirements must be an option in option {0}" msgstr "requirements mal formés doit être une option dans l'option {0}" -#: tiramisu/option.py:1481 +#: tiramisu/option.py:1485 msgid "malformed requirements option {0} must not be a multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi" -#: tiramisu/option.py:1487 +#: tiramisu/option.py:1491 msgid "" "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" "requirements mal formés deuxième argument doit être valide pour l'option " "{0} : {1}" -#: tiramisu/option.py:1492 +#: tiramisu/option.py:1496 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "incohérence dans les types action pour l'option : {0} action {1}" -#: tiramisu/option.py:1517 +#: tiramisu/option.py:1521 msgid "{0} must be a function" msgstr "{0} doit être une fonction" -#: tiramisu/option.py:1520 +#: tiramisu/option.py:1524 msgid "{0}_params must be a dict" msgstr "{0}_params doit être un dict" -#: tiramisu/option.py:1523 +#: tiramisu/option.py:1527 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" "{0}_params avec la clef {1} ne doit pas avoir une longueur différent de 1" -#: tiramisu/option.py:1527 +#: tiramisu/option.py:1531 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "{0}_params doit être un tuple pour la clef \"{1}\"" -#: tiramisu/option.py:1533 +#: tiramisu/option.py:1537 msgid "{0}_params with length of tuple as 1 must only have None as first value" msgstr "" "{0}_params avec un tuple de longueur 1 doit seulement avoir None comme " "première valeur" -#: tiramisu/option.py:1537 -#, fuzzy +#: tiramisu/option.py:1541 msgid "{0}_params must only have 1 or 2 as length" msgstr "{0}_params doit seulement avoir une longueur de 1 ou 2" -#: tiramisu/option.py:1542 +#: tiramisu/option.py:1546 msgid "validator not support tuple" msgstr "validator n'accepte pas de tuple" -#: tiramisu/option.py:1545 +#: tiramisu/option.py:1549 msgid "{0}_params must have an option not a {0} for first argument" msgstr "{0}_params doit avoir une option pas un {0} pour premier argument" -#: tiramisu/option.py:1549 +#: tiramisu/option.py:1553 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "{0}_params doit avoir un booléen pas un {0} pour second argument" @@ -512,29 +518,29 @@ msgstr "" msgid "opt and all_properties must not be set together in reset" msgstr "opt et all_properties ne doit pas être renseigné ensemble dans reset" -#: tiramisu/setting.py:373 +#: tiramisu/setting.py:376 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" "si opt n'est pas None, path devrait ne pas être à None dans _getproperties" -#: tiramisu/setting.py:482 +#: tiramisu/setting.py:486 msgid "cannot change the value for option {0} this option is frozen" msgstr "" "ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" -#: tiramisu/setting.py:488 +#: tiramisu/setting.py:492 msgid "trying to access to an option named: {0} with properties {1}" msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}" -#: tiramisu/setting.py:506 +#: tiramisu/setting.py:510 msgid "permissive must be a tuple" msgstr "permissive doit être un tuple" -#: tiramisu/setting.py:513 tiramisu/value.py:332 +#: tiramisu/setting.py:517 tiramisu/value.py:349 msgid "invalid generic owner {0}" msgstr "invalide owner générique {0}" -#: tiramisu/setting.py:601 +#: tiramisu/setting.py:605 msgid "" "malformed requirements imbrication detected for option: '{0}' with " "requirement on: '{1}'" @@ -542,7 +548,7 @@ msgstr "" "imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "requirement sur : '{1}'" -#: tiramisu/setting.py:612 +#: tiramisu/setting.py:616 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}" @@ -567,52 +573,52 @@ msgstr "session déjà utilisée" msgid "a dictionary cannot be persistent" msgstr "un espace de stockage dictionary ne peut être persistant" -#: tiramisu/value.py:339 +#: tiramisu/value.py:356 msgid "no value for {0} cannot change owner to {1}" msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}" -#: tiramisu/value.py:421 +#: tiramisu/value.py:438 msgid "can force cache only if cache is actived in config" msgstr "" "peut force la mise en cache seulement si le cache est activé dans la config" -#: tiramisu/value.py:460 +#: tiramisu/value.py:477 msgid "{0} is already a Multi " msgstr "{0} est déjà une Multi" -#: tiramisu/value.py:496 tiramisu/value.py:560 +#: tiramisu/value.py:513 tiramisu/value.py:577 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître" -#: tiramisu/value.py:532 +#: tiramisu/value.py:549 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave" -#: tiramisu/value.py:570 +#: tiramisu/value.py:587 msgid "cannot sort multi option {0} if master or slave" msgstr "ne peut trier une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:574 +#: tiramisu/value.py:591 msgid "cmp is not permitted in python v3 or greater" msgstr "cmp n'est pas permis en python v3 ou supérieure" -#: tiramisu/value.py:583 +#: tiramisu/value.py:600 msgid "cannot reverse multi option {0} if master or slave" msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:591 +#: tiramisu/value.py:608 msgid "cannot insert multi option {0} if master or slave" msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:599 +#: tiramisu/value.py:616 msgid "cannot extend multi option {0} if master or slave" msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave" -#: tiramisu/value.py:610 +#: tiramisu/value.py:627 msgid "invalid value {0} for option {1}: {2}" msgstr "valeur invalide {0} pour l'option {1} : {2}" -#: tiramisu/value.py:628 +#: tiramisu/value.py:645 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave" diff --git a/translations/tiramisu.pot b/translations/tiramisu.pot index 1bf9361..35ecafe 100644 --- a/translations/tiramisu.pot +++ b/translations/tiramisu.pot @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" -"POT-Creation-Date: 2014-03-26 20:46+CET\n" +"POT-Creation-Date: 2014-03-29 19:01+CET\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -28,7 +28,7 @@ msgid "unknown group_type: {0}" msgstr "" #: tiramisu/config.py:163 tiramisu/setting.py:334 tiramisu/value.py:55 -#: tiramisu/value.py:483 +#: tiramisu/value.py:500 msgid "the context does not exist anymore" msgstr "" @@ -60,27 +60,27 @@ msgstr "" msgid "opt in getowner must be an option not {0}" msgstr "" -#: tiramisu/config.py:534 +#: tiramisu/config.py:535 msgid "cannot serialize Config with MetaConfig" msgstr "" -#: tiramisu/config.py:548 +#: tiramisu/config.py:549 msgid "this storage is not serialisable, could be a none persistent storage" msgstr "" -#: tiramisu/config.py:611 +#: tiramisu/config.py:612 msgid "metaconfig's children must be a list" msgstr "" -#: tiramisu/config.py:705 +#: tiramisu/config.py:706 msgid "metaconfig's children should be config, not {0}" msgstr "" -#: tiramisu/config.py:709 +#: tiramisu/config.py:710 msgid "child has already a metaconfig's" msgstr "" -#: tiramisu/config.py:713 +#: tiramisu/config.py:714 msgid "all config in metaconfig must have the same optiondescription" msgstr "" @@ -96,7 +96,7 @@ msgstr "" msgid "'{0}' ({1}) object attribute '{2}' is read-only" msgstr "" -#: tiramisu/option.py:140 tiramisu/value.py:393 +#: tiramisu/option.py:140 tiramisu/value.py:410 msgid "information's item not found: {0}" msgstr "" @@ -396,67 +396,71 @@ msgstr "" msgid "malformed requirements for option: {0} require must have option, expected and action keys" msgstr "" -#: tiramisu/option.py:1466 -msgid "malformed requirements for option: {0} inverse must be boolean" +#: tiramisu/option.py:1465 +msgid "malformed requirements for option: {0} action cannot be force_store_value" msgstr "" #: tiramisu/option.py:1470 -msgid "malformed requirements for option: {0} transitive must be boolean" +msgid "malformed requirements for option: {0} inverse must be boolean" msgstr "" #: tiramisu/option.py:1474 -msgid "malformed requirements for option: {0} same_action must be boolean" +msgid "malformed requirements for option: {0} transitive must be boolean" msgstr "" #: tiramisu/option.py:1478 +msgid "malformed requirements for option: {0} same_action must be boolean" +msgstr "" + +#: tiramisu/option.py:1482 msgid "malformed requirements must be an option in option {0}" msgstr "" -#: tiramisu/option.py:1481 +#: tiramisu/option.py:1485 msgid "malformed requirements option {0} must not be a multi" msgstr "" -#: tiramisu/option.py:1487 +#: tiramisu/option.py:1491 msgid "malformed requirements second argument must be valid for option {0}: {1}" msgstr "" -#: tiramisu/option.py:1492 +#: tiramisu/option.py:1496 msgid "inconsistency in action types for option: {0} action: {1}" msgstr "" -#: tiramisu/option.py:1517 +#: tiramisu/option.py:1521 msgid "{0} must be a function" msgstr "" -#: tiramisu/option.py:1520 +#: tiramisu/option.py:1524 msgid "{0}_params must be a dict" msgstr "" -#: tiramisu/option.py:1523 +#: tiramisu/option.py:1527 msgid "{0}_params with key {1} mustn't have length different to 1" msgstr "" -#: tiramisu/option.py:1527 +#: tiramisu/option.py:1531 msgid "{0}_params must be tuple for key \"{1}\"" msgstr "" -#: tiramisu/option.py:1533 +#: tiramisu/option.py:1537 msgid "{0}_params with length of tuple as 1 must only have None as first value" msgstr "" -#: tiramisu/option.py:1537 +#: tiramisu/option.py:1541 msgid "{0}_params must only have 1 or 2 as length" msgstr "" -#: tiramisu/option.py:1542 +#: tiramisu/option.py:1546 msgid "validator not support tuple" msgstr "" -#: tiramisu/option.py:1545 +#: tiramisu/option.py:1549 msgid "{0}_params must have an option not a {0} for first argument" msgstr "" -#: tiramisu/option.py:1549 +#: tiramisu/option.py:1553 msgid "{0}_params must have a boolean not a {0} for second argument" msgstr "" @@ -476,31 +480,31 @@ msgstr "" msgid "opt and all_properties must not be set together in reset" msgstr "" -#: tiramisu/setting.py:373 +#: tiramisu/setting.py:376 msgid "if opt is not None, path should not be None in _getproperties" msgstr "" -#: tiramisu/setting.py:482 +#: tiramisu/setting.py:486 msgid "cannot change the value for option {0} this option is frozen" msgstr "" -#: tiramisu/setting.py:488 +#: tiramisu/setting.py:492 msgid "trying to access to an option named: {0} with properties {1}" msgstr "" -#: tiramisu/setting.py:506 +#: tiramisu/setting.py:510 msgid "permissive must be a tuple" msgstr "" -#: tiramisu/setting.py:513 tiramisu/value.py:332 +#: tiramisu/setting.py:517 tiramisu/value.py:349 msgid "invalid generic owner {0}" msgstr "" -#: tiramisu/setting.py:601 +#: tiramisu/setting.py:605 msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'" msgstr "" -#: tiramisu/setting.py:612 +#: tiramisu/setting.py:616 msgid "option '{0}' has requirement's property error: {1} {2}" msgstr "" @@ -524,51 +528,51 @@ msgstr "" msgid "a dictionary cannot be persistent" msgstr "" -#: tiramisu/value.py:339 +#: tiramisu/value.py:356 msgid "no value for {0} cannot change owner to {1}" msgstr "" -#: tiramisu/value.py:421 +#: tiramisu/value.py:438 msgid "can force cache only if cache is actived in config" msgstr "" -#: tiramisu/value.py:460 +#: tiramisu/value.py:477 msgid "{0} is already a Multi " msgstr "" -#: tiramisu/value.py:496 tiramisu/value.py:560 +#: tiramisu/value.py:513 tiramisu/value.py:577 msgid "invalid len for the slave: {0} which has {1} as master" msgstr "" -#: tiramisu/value.py:532 +#: tiramisu/value.py:549 msgid "cannot append a value on a multi option {0} which is a slave" msgstr "" -#: tiramisu/value.py:570 +#: tiramisu/value.py:587 msgid "cannot sort multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:574 +#: tiramisu/value.py:591 msgid "cmp is not permitted in python v3 or greater" msgstr "" -#: tiramisu/value.py:583 +#: tiramisu/value.py:600 msgid "cannot reverse multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:591 +#: tiramisu/value.py:608 msgid "cannot insert multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:599 +#: tiramisu/value.py:616 msgid "cannot extend multi option {0} if master or slave" msgstr "" -#: tiramisu/value.py:610 +#: tiramisu/value.py:627 msgid "invalid value {0} for option {1}: {2}" msgstr "" -#: tiramisu/value.py:628 +#: tiramisu/value.py:645 msgid "cannot pop a value on a multi option {0} which is a slave" msgstr "" From cd52729952a0f29e093813346fc1c04fa5d51d4f Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 31 Mar 2014 22:34:57 +0200 Subject: [PATCH 34/42] add force_permissive in config's method (iter_all, iter_group, find, find_first and make_dict) rename _getattr to getattr --- test/test_config.py | 13 +++++- test/test_config_api.py | 24 ++++++++++- test/test_freeze.py | 2 +- test/test_parsing_group.py | 15 ++++++- tiramisu/autolib.py | 4 +- tiramisu/config.py | 83 +++++++++++++++++++++++--------------- tiramisu/option.py | 2 +- tiramisu/setting.py | 2 +- tiramisu/value.py | 10 ++--- 9 files changed, 109 insertions(+), 46 deletions(-) diff --git a/test/test_config.py b/test/test_config.py index 8de8a57..ca2f4ef 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -9,7 +9,7 @@ from py.test import raises from tiramisu.config import Config, SubConfig from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ BoolOption, UnicodeOption, OptionDescription -from tiramisu.error import ConflictError, ConfigError +from tiramisu.error import ConflictError, ConfigError, PropertiesOptionError import weakref @@ -22,7 +22,7 @@ def make_description(): intoption = IntOption('int', 'Test int option', default=0) floatoption = FloatOption('float', 'Test float option', default=2.3) stroption = StrOption('str', 'Test string option', default="abc", properties=('mandatory', )) - boolop = BoolOption('boolop', 'Test boolean option op', default=True) + boolop = BoolOption('boolop', 'Test boolean option op', default=True, properties=('hidden',)) wantref_option = BoolOption('wantref', 'Test requires', default=False) wantframework_option = BoolOption('wantframework', 'Test requires', default=False) @@ -90,6 +90,15 @@ def test_base_config_and_groups(): #assert nm._name == 'name' +def test_base_config_force_permissive(): + descr = make_description() + config = Config(descr) + config.read_write() + config.cfgimpl_get_settings().setpermissive(('hidden',)) + raises(PropertiesOptionError, "config.getattr('boolop')") + assert config.getattr('boolop', force_permissive=True) is True + + def test_base_config_in_a_tree(): "how options are organized into a tree, see :ref:`tree`" descr = make_description() diff --git a/test/test_config_api.py b/test/test_config_api.py index 93f8c95..3471a23 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -101,9 +101,12 @@ def test_make_dict(): "serialization of the whole config to a dict" descr = OptionDescription("opt", "", [ OptionDescription("s1", "", [ - BoolOption("a", "", default=False)]), + BoolOption("a", "", default=False), + BoolOption("b", "", default=False, properties=('hidden',))]), IntOption("int", "", default=42)]) config = Config(descr) + config.read_write() + config.cfgimpl_get_settings().setpermissive(('hidden',)) d = config.make_dict() assert d == {"s1.a": False, "int": 42} config.int = 43 @@ -113,6 +116,8 @@ def test_make_dict(): d2 = config.make_dict(flatten=True) assert d2 == {'a': True, 'int': 43} raises(ValueError, 'd2 = config.make_dict(withvalue="3")') + d = config.make_dict(force_permissive=True) + assert d == {"s1.a": True, "s1.b": False, "int": 43} def test_make_dict_with_disabled(): @@ -132,6 +137,7 @@ def test_find_in_config(): descr = make_description() conf = Config(descr) conf.read_only() + conf.cfgimpl_get_settings().setpermissive(('hidden',)) assert conf.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')] assert conf.find(byname='float') == [conf.unwrap_from_path('gc.float'), conf.unwrap_from_path('float')] assert conf.find_first(byname='bool') == conf.unwrap_from_path('gc.gc2.bool') @@ -146,6 +152,8 @@ def test_find_in_config(): conf.read_write() raises(AttributeError, "assert conf.find(byname='prop')") assert conf.find(byname='prop', check_properties=False) == [conf.unwrap_from_path('gc.gc2.prop'), conf.unwrap_from_path('gc.prop')] + assert conf.find(byname='prop', force_permissive=True) == [conf.unwrap_from_path('gc.prop')] + assert conf.find_first(byname='prop', force_permissive=True) == conf.unwrap_from_path('gc.prop') #assert conf.find_first(byname='prop') == conf.unwrap_from_path('gc.prop') # combinaison of filters assert conf.find(bytype=BoolOption, byname='dummy') == [conf.unwrap_from_path('gc.dummy')] @@ -217,6 +225,20 @@ def test_iter_all(): break +def test_iter_all_force_permissive(): + s = StrOption("string", "", default="string") + s2 = StrOption("string2", "", default="string2") + s3 = StrOption("string3", "", default="string3", properties=('hidden',)) + descr = OptionDescription("options", "", [s, s2, s3]) + config = Config(descr) + config.read_write() + config.cfgimpl_get_settings().setpermissive(('hidden',)) + assert list(config.iter_all()) == [('string', 'string'), ('string2', 'string2')] + assert list(config.iter_all(force_permissive=True)) == [('string', 'string'), + ('string2', 'string2'), + ('string3', 'string3')] + + def test_iter_all_prop(): s = StrOption("string", "", default="string", properties=('disabled',)) s2 = StrOption("string2", "", default="string2") diff --git a/test/test_freeze.py b/test/test_freeze.py index f279c47..96c106c 100644 --- a/test/test_freeze.py +++ b/test/test_freeze.py @@ -162,5 +162,5 @@ def test_force_store_value_hidden(): conf.cfgimpl_get_settings().setpermissive(('hidden',)) conf.read_write() assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'default' - conf._getattr('wantref2', force_permissive=True) + conf.getattr('wantref2', force_permissive=True) assert conf.getowner(conf.unwrap_from_path('wantref2')) == 'user' diff --git a/test/test_parsing_group.py b/test/test_parsing_group.py index c3b6ffc..46bd82d 100644 --- a/test/test_parsing_group.py +++ b/test/test_parsing_group.py @@ -34,7 +34,9 @@ def make_description(): mode_conteneur_actif, adresse_serveur_ntp, time_zone]) general.impl_set_group_type(groups.family) - creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1]) + new = OptionDescription('new', '', [], properties=('hidden',)) + new.impl_set_group_type(groups.family) + creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1, new]) descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole]) return descr @@ -99,6 +101,17 @@ def test_iter_on_groups(): break +def test_iter_on_groups_force_permissive(): + descr = make_description() + config = Config(descr) + config.read_write() + config.cfgimpl_get_settings().setpermissive(('hidden',)) + result = list(config.creole.iter_groups(group_type=groups.family, + force_permissive=True)) + group_names = [res[0] for res in result] + assert group_names == ['general', 'interface1', 'new'] + + def test_iter_on_groups_props(): descr = make_description() config = Config(descr) diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index e837f79..26a39e4 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -154,8 +154,8 @@ def carry_out_calculation(option, config, callback, callback_params, ).impl_get_path_by_opt(opt) # get value try: - value = config._getattr(path, force_permissive=True, - validate=False) + value = config.getattr(path, force_permissive=True, + validate=False) # convert to list, not modifie this multi if value.__class__.__name__ == 'Multi': value = list(value) diff --git a/tiramisu/config.py b/tiramisu/config.py index 2a882a1..f008b64 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -67,9 +67,9 @@ class SubConfig(object): """:returns: tuple (config, name)""" path = path.split('.') for step in path[:-1]: - self = self._getattr(step, - force_permissive=force_permissive, - force_properties=force_properties) + self = self.getattr(step, + force_permissive=force_permissive, + force_properties=force_properties) return self, path[-1] def __hash__(self): @@ -101,18 +101,19 @@ class SubConfig(object): except PropertiesOptionError: pass # option with properties - def iter_all(self): + def iter_all(self, force_permissive=False): """A way of parsing options **and** groups. iteration on Options and OptionDescriptions.""" for child in self.cfgimpl_get_description().impl_getchildren(): try: - yield child._name, getattr(self, child._name) + yield child._name, self.getattr(child._name, + force_permissive=force_permissive) except GeneratorExit: raise StopIteration except PropertiesOptionError: pass # option with properties - def iter_groups(self, group_type=None): + def iter_groups(self, group_type=None, force_permissive=False): """iteration on groups objects only. All groups are returned if `group_type` is `None`, otherwise the groups can be filtered by categories (families, or whatever). @@ -130,7 +131,8 @@ class SubConfig(object): if group_type is None or (group_type is not None and child.impl_get_group_type() == group_type): - yield child._name, getattr(self, child._name) + yield child._name, self.getattr(child._name, + force_permissive=force_permissive) except GeneratorExit: raise StopIteration except PropertiesOptionError: @@ -210,10 +212,15 @@ class SubConfig(object): self.cfgimpl_get_values().__delitem__(child) def __getattr__(self, name): - return self._getattr(name) + return self.getattr(name) - def _getattr(self, name, force_permissive=False, force_properties=None, - validate=True): + def _getattr(self, name): + """use getattr instead of _getattr + """ + return self.getattr(name) + + def getattr(self, name, force_permissive=False, force_properties=None, + validate=True): """ attribute notation mechanism for accessing the value of an option :param name: attribute name @@ -226,9 +233,9 @@ class SubConfig(object): homeconfig, name = self.cfgimpl_get_home_by_path( name, force_permissive=force_permissive, force_properties=force_properties) - return homeconfig._getattr(name, force_permissive=force_permissive, - force_properties=force_properties, - validate=validate) + return homeconfig.getattr(name, force_permissive=force_permissive, + force_properties=force_properties, + validate=validate) opt_or_descr = getattr(self.cfgimpl_get_description(), name) if self._impl_path is None: subpath = name @@ -239,9 +246,9 @@ class SubConfig(object): context = self._cfgimpl_get_context() path = context.cfgimpl_get_description().impl_get_path_by_opt( opt_or_descr._opt) - return context._getattr(path, validate=validate, - force_properties=force_properties, - force_permissive=force_permissive) + return context.getattr(path, validate=validate, + force_properties=force_properties, + force_permissive=force_permissive) elif isinstance(opt_or_descr, OptionDescription): self.cfgimpl_get_settings().validate_properties( opt_or_descr, True, False, path=subpath, @@ -256,7 +263,7 @@ class SubConfig(object): force_permissive=force_permissive) def find(self, bytype=None, byname=None, byvalue=None, type_='option', - check_properties=True): + check_properties=True, force_permissive=False): """ finds a list of options recursively in the config @@ -269,10 +276,12 @@ class SubConfig(object): first=False, type_=type_, _subpath=self.cfgimpl_get_path(), - check_properties=check_properties) + check_properties=check_properties, + force_permissive=force_permissive) def find_first(self, bytype=None, byname=None, byvalue=None, - type_='option', display_error=True, check_properties=True): + type_='option', display_error=True, check_properties=True, + force_permissive=False): """ finds an option recursively in the config @@ -284,10 +293,12 @@ class SubConfig(object): return self._cfgimpl_get_context()._find( bytype, byname, byvalue, first=True, type_=type_, _subpath=self.cfgimpl_get_path(), display_error=display_error, - check_properties=check_properties) + check_properties=check_properties, + force_permissive=force_permissive) def _find(self, bytype, byname, byvalue, first, type_='option', - _subpath=None, check_properties=True, display_error=True): + _subpath=None, check_properties=True, display_error=True, + force_permissive=False): """ convenience method for finding an option that lives only in the subtree @@ -304,7 +315,7 @@ class SubConfig(object): if byvalue is None: return True try: - value = getattr(self, path) + value = self.getattr(path, force_permissive=force_permissive) if isinstance(value, Multi): return byvalue in value else: @@ -341,7 +352,8 @@ class SubConfig(object): #remove option with propertyerror, ... if byvalue is None and check_properties: try: - value = getattr(self, path) + value = self.getattr(path, + force_permissive=force_permissive) except PropertiesOptionError: # a property restricts the access of the value continue @@ -369,7 +381,7 @@ class SubConfig(object): return find_results def make_dict(self, flatten=False, _currpath=None, withoption=None, - withvalue=None): + withvalue=None, force_permissive=False): """exports the whole config into a `dict`, for example: >>> print cfg.make_dict() @@ -419,7 +431,8 @@ class SubConfig(object): byvalue=withvalue, first=False, type_='path', - _subpath=mypath): + _subpath=mypath, + force_permissive=force_permissive): path = '.'.join(path.split('.')[:-1]) opt = self._cfgimpl_get_context().cfgimpl_get_description( ).impl_get_opt_by_path(path) @@ -435,25 +448,31 @@ class SubConfig(object): 'should start with {1}' '').format(path, mypath)) path = path[len(tmypath):] - self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten) + self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten, + force_permissive=force_permissive) #withoption can be set to None below ! if withoption is None: for opt in self.cfgimpl_get_description().impl_getchildren(): path = opt._name - self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten) + self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten, + force_permissive=force_permissive) if _currpath == []: options = dict(pathsvalues) return options return pathsvalues - def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten): + def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten, + force_permissive=False): try: if isinstance(opt, OptionDescription): - pathsvalues += getattr(self, path).make_dict(flatten, - _currpath + - path.split('.')) + pathsvalues += self.getattr(path, + force_permissive=force_permissive).make_dict( + flatten, + _currpath + path.split('.'), + force_permissive=force_permissive) else: - value = self._getattr(opt._name) + value = self.getattr(opt._name, + force_permissive=force_permissive) if flatten: name = opt._name else: diff --git a/tiramisu/option.py b/tiramisu/option.py index eeab2f9..3c0ede1 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -364,7 +364,7 @@ class Option(BaseOption): else: #if context, calculate value, otherwise get default value if context is not None: - opt_value = context._getattr( + opt_value = context.getattr( descr.impl_get_path_by_opt(opt), validate=False, force_permissive=True) else: diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 6ba84d7..a945a2c 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -603,7 +603,7 @@ class Settings(object): " '{0}' with requirement on: " "'{1}'").format(path, reqpath)) try: - value = context._getattr(reqpath, force_permissive=True) + value = context.getattr(reqpath, force_permissive=True) except PropertiesOptionError as err: if not transitive: continue diff --git a/tiramisu/value.py b/tiramisu/value.py index d66f85d..b6f3b51 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -203,7 +203,7 @@ class Values(object): if (opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.slave): masterp = self._get_opt_path(opt.impl_get_master_slaves()) - mastervalue = context._getattr(masterp, validate=validate) + mastervalue = context.getattr(masterp, validate=validate) lenmaster = len(mastervalue) if lenmaster == 0: value = [] @@ -407,8 +407,8 @@ class Values(object): for path in context.cfgimpl_get_description().impl_getpaths( include_groups=True): try: - context._getattr(path, - force_properties=frozenset(('mandatory',))) + context.getattr(path, + force_properties=frozenset(('mandatory',))) except PropertiesOptionError as err: if err.proptype == ['mandatory']: yield path @@ -426,7 +426,7 @@ class Values(object): for path in context.cfgimpl_get_description().impl_getpaths( include_groups=True): try: - context._getattr(path) + context.getattr(path) except PropertiesOptionError: pass @@ -490,7 +490,7 @@ class Multi(list): values = context.cfgimpl_get_values() masterp = context.cfgimpl_get_description().impl_get_path_by_opt( self.opt.impl_get_master_slaves()) - mastervalue = context._getattr(masterp, validate=False) + mastervalue = context.getattr(masterp, validate=False) masterlen = len(mastervalue) valuelen = len(value) if valuelen > masterlen or (valuelen < masterlen and setitem): From 150b4902001f96ed1a81d6bfbe7d9b73d74897da Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 1 Apr 2014 09:29:07 +0200 Subject: [PATCH 35/42] config.mandatory_warnings return always None --- tiramisu/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tiramisu/config.py b/tiramisu/config.py index f008b64..af7266e 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -738,4 +738,4 @@ class MetaConfig(GroupConfig): def mandatory_warnings(config): #only for retro-compatibility - config.cfgimpl_get_values().mandatory_warnings() + return config.cfgimpl_get_values().mandatory_warnings() From 0b2e5f90e24585ef746eaf255eae3ef76f158109 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 1 Apr 2014 09:51:25 +0200 Subject: [PATCH 36/42] same arity for _getattr and getattr --- tiramisu/config.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tiramisu/config.py b/tiramisu/config.py index af7266e..d867a59 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -214,10 +214,11 @@ class SubConfig(object): def __getattr__(self, name): return self.getattr(name) - def _getattr(self, name): + def _getattr(self, name, force_permissive=False, force_properties=None, + validate=True): """use getattr instead of _getattr """ - return self.getattr(name) + return self.getattr(name, force_permissive, force_properties, validate) def getattr(self, name, force_permissive=False, force_properties=None, validate=True): From 463fc8e88ab0ebf2a63a1b8cd124e700f6d847df Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 1 Apr 2014 21:01:01 +0200 Subject: [PATCH 37/42] if opt is freeze with force_default_on_freeze, didn't remove store value --- tiramisu/value.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tiramisu/value.py b/tiramisu/value.py index b6f3b51..348f3ed 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -227,8 +227,6 @@ class Values(object): if config_error is None: if opt.impl_is_multi(): value = Multi(value, self.context, opt, path, validate) - # suppress value if already set - self.reset(opt, path) # frozen and force default elif is_frozen and 'force_default_on_freeze' in setting[opt]: value = self._getdefault(opt) From 76a43a7ff996fd5620b4086ddebb6777906375c5 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Wed, 2 Apr 2014 12:04:50 +0200 Subject: [PATCH 38/42] if slave has a callback with a slave that has a callback with a default_multi's slave, now it's works --- test/test_option_calculation.py | 26 ++++++++++++++++++++++++++ tiramisu/autolib.py | 15 +++++++++++---- tiramisu/value.py | 2 +- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index ad1b54f..de9c282 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -444,6 +444,22 @@ def test_callback_master_and_slaves_master(): assert cfg.val1.val2 == [None, None] +def test_callback_master_and_slaves_master2(): + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True, default_multi='val2') + val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)}) + val4 = StrOption('val4', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)}) + interface1 = OptionDescription('val1', '', [val1, val2, val3, val4]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(maconfig) + cfg.read_write() + cfg.val1.val1.append('val') + assert cfg.val1.val4 == ['val2'] + assert cfg.val1.val3 == ['val2'] + assert cfg.val1.val2 == ['val2'] + + def test_callback_master_and_slaves_master_list(): val1 = StrOption('val1', "", multi=True, callback=return_list) val2 = StrOption('val2', "", multi=True) @@ -499,6 +515,16 @@ def test_callback_master_and_slaves_slave(): assert cfg.val1.val2 == ['val2', 'val2', 'val'] +def test_callback_master_and_slaves(): + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True, callback=return_val) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(maconfig) + cfg.read_write() + + def test_callback_master_and_slaves_slave_cal(): val3 = StrOption('val3', "", multi=True) val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)}) diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 26a39e4..92b86c5 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -154,8 +154,15 @@ def carry_out_calculation(option, config, callback, callback_params, ).impl_get_path_by_opt(opt) # get value try: + if option.impl_is_multi() and \ + (option.impl_get_multitype() == multitypes.master or + (option.impl_get_multitype() == multitypes.slave and + option.impl_get_master_slaves() != opt)): + validate = True + else: + validate = False value = config.getattr(path, force_permissive=True, - validate=False) + validate=validate) # convert to list, not modifie this multi if value.__class__.__name__ == 'Multi': value = list(value) @@ -192,7 +199,7 @@ def carry_out_calculation(option, config, callback, callback_params, # if no index, return a list if one_is_multi: ret = [] - if index: + if index is not None: range_ = [index] else: range_ = range(len_multi) @@ -211,7 +218,7 @@ def carry_out_calculation(option, config, callback, callback_params, else: kwargs[key] = val calc = calculate(callback, args, kwargs) - if index: + if index is not None: ret = calc else: ret.append(calc) @@ -234,7 +241,7 @@ def carry_out_calculation(option, config, callback, callback_params, ret = ret[:max_len] if len(ret) < max_len: ret = ret + [None] * (max_len - len(ret)) - if isinstance(ret, list) and index: + if isinstance(ret, list) and index is not None: if len(ret) < index + 1: ret = None else: diff --git a/tiramisu/value.py b/tiramisu/value.py index 348f3ed..a584f9e 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -203,7 +203,7 @@ class Values(object): if (opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.slave): masterp = self._get_opt_path(opt.impl_get_master_slaves()) - mastervalue = context.getattr(masterp, validate=validate) + mastervalue = context.getattr(masterp, validate=False) lenmaster = len(mastervalue) if lenmaster == 0: value = [] From da434a42730ac5716b04ffc6197090402014b9a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 3 Apr 2014 22:15:41 +0200 Subject: [PATCH 39/42] add logger in validation --- tiramisu/option.py | 20 ++++++++++++++------ tiramisu/setting.py | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tiramisu/option.py b/tiramisu/option.py index 3c0ede1..c3caae3 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -27,7 +27,7 @@ from IPy import IP import warnings from tiramisu.error import ConfigError, ConflictError, ValueWarning -from tiramisu.setting import groups, multitypes +from tiramisu.setting import groups, multitypes, log from tiramisu.i18n import _ from tiramisu.autolib import carry_out_calculation @@ -430,10 +430,14 @@ class Option(BaseOption): val_validator(_value) self._second_level_validation(_value, self._warnings_only) except ValueError as error: + log.debug(_('do_validation for {0}: error in value').format( + self._name), exc_info=True) if self._warnings_only: warning = error error = None except ValueWarning as warning: + log.debug(_('do_validation for {0}: warning in value').format( + self._name), exc_info=True) pass if error is None and warning is None: try: @@ -441,8 +445,12 @@ class Option(BaseOption): if context is not None: descr._valid_consistency(self, _value, context, _index) except ValueError as error: + log.debug(_('do_validation for {0}: error in consistency').format( + self._name), exc_info=True) pass except ValueWarning as warning: + log.debug(_('do_validation for {0}: warning in consistency').format( + self._name), exc_info=True) pass if warning: msg = _("warning on the value of the option {0}: {1}").format( @@ -1543,10 +1551,10 @@ def validate_callback(callback, callback_params, type_): if not isinstance(option, Option) and not \ isinstance(option, SymLinkOption): raise ValueError(_('{0}_params must have an option' - ' not a {0} for first argument' - ).format(type_, type(option))) + ' not a {0} for first argument' + ).format(type_, type(option))) if force_permissive not in [True, False]: raise ValueError(_('{0}_params must have a boolean' - ' not a {0} for second argument' - ).format(type_, type( - force_permissive))) + ' not a {0} for second argument' + ).format(type_, type( + force_permissive))) diff --git a/tiramisu/setting.py b/tiramisu/setting.py index a945a2c..d7925fa 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -17,6 +17,7 @@ # ____________________________________________________________ from time import time from copy import copy +from logging import getLogger import weakref from tiramisu.error import (RequirementError, PropertiesOptionError, ConstError, ConfigError) @@ -99,6 +100,9 @@ rw_append = set(['frozen', 'disabled', 'validator', 'hidden']) rw_remove = set(['permissive', 'everything_frozen', 'mandatory']) +log = getLogger('tiramisu') + + # ____________________________________________________________ class _NameSpace(object): """convenient class that emulates a module From cd4d3527c79f5b6935540d14038540a05f4444de Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 12 Apr 2014 11:53:58 +0200 Subject: [PATCH 40/42] split tiramisu/option.py and add MasterSlaves object --- ChangeLog | 10 + test/test_option_calculation.py | 169 +++- test/test_option_consistency.py | 2 +- test/test_requires.py | 24 + tiramisu/autolib.py | 44 +- tiramisu/config.py | 5 +- tiramisu/option/__init__.py | 16 + tiramisu/{option.py => option/baseoption.py} | 948 ++----------------- tiramisu/option/masterslave.py | 187 ++++ tiramisu/option/option.py | 525 ++++++++++ tiramisu/option/optiondescription.py | 263 +++++ tiramisu/setting.py | 25 +- tiramisu/value.py | 436 ++++----- 13 files changed, 1478 insertions(+), 1176 deletions(-) create mode 100644 ChangeLog create mode 100644 tiramisu/option/__init__.py rename tiramisu/{option.py => option/baseoption.py} (51%) create mode 100644 tiramisu/option/masterslave.py create mode 100644 tiramisu/option/option.py create mode 100644 tiramisu/option/optiondescription.py diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..23913bc --- /dev/null +++ b/ChangeLog @@ -0,0 +1,10 @@ +Sat Apr 12 11:37:27 CEST 2014 Emmanuel Garette + + * behavior change in master/slave part of code: + if slave has a default value greater than master's one, it's raise + SlaveError, didn't try to reduce the slave's length + * tiramisu/option.py: split into tiramisu/option directory + * tiramisu/option/masterslave.py: master/slaves have no a special + object MasterSlaves for all code related to master/slaves options + * tiramisu/option/masterslave.py: master and slaves values (length, + consistency, ...) are now check every time diff --git a/test/test_option_calculation.py b/test/test_option_calculation.py index de9c282..567f854 100644 --- a/test/test_option_calculation.py +++ b/test/test_option_calculation.py @@ -1,8 +1,8 @@ import autopath from py.test import raises -from tiramisu.setting import groups from tiramisu.config import Config +from tiramisu.setting import groups, owners from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \ StrOption, OptionDescription, SymLinkOption from tiramisu.error import PropertiesOptionError, ConflictError, SlaveError, ConfigError @@ -430,6 +430,17 @@ def test_callback_multi_list_extend(): assert cfg.val1 == ['1', '2', '3', '4', '5'] +def test_callback_multi_callback(): + val1 = StrOption('val1', "", multi=True, callback=return_val) + interface1 = OptionDescription('val1', '', [val1]) + maconfig = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(maconfig) + cfg.read_write() + assert cfg.val1.val1 == ['val'] + cfg.val1.val1.append() + assert cfg.val1.val1 == ['val', 'val'] + + def test_callback_master_and_slaves_master(): val1 = StrOption('val1', "", multi=True, callback=return_val) val2 = StrOption('val2', "", multi=True) @@ -541,8 +552,6 @@ def test_callback_master_and_slaves_slave_cal(): cfg.val3 = ['val1'] assert cfg.val1.val1 == ['val1'] assert cfg.val1.val2 == ['val'] - assert cfg.val1.val1 == ['val1'] - assert cfg.val1.val2 == ['val'] del(cfg.val1.val1) cfg.val1.val2 = ['val'] cfg.val3 = ['val1', 'val2'] @@ -571,8 +580,8 @@ def test_callback_master_and_slaves_slave_cal2(): assert cfg.val1.val1 == ['val', 'val'] assert cfg.val1.val2 == ['val2', 'val2'] cfg.val3.pop(1) -# # cannot remove slave's value because master is calculated -# # so raise + # cannot remove slave's value because master is calculated + # so raise raises(SlaveError, "cfg.val1.val1") raises(SlaveError, "cfg.val1.val2") cfg.val3 = ['val', 'val'] @@ -585,6 +594,88 @@ def test_callback_master_and_slaves_slave_cal2(): assert cfg.val1.val2 == ['val2', 'val2'] +def test_callback_master_and_slaves_master_disabled(): + #properties must be transitive + val1 = StrOption('val1', "", multi=True, properties=('disabled',)) + val2 = StrOption('val2', "", multi=True) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(maconfig) + cfg.read_write() + raises(PropertiesOptionError, "cfg.val1.val1") + raises(PropertiesOptionError, "cfg.val1.val1.append('yes')") + raises(PropertiesOptionError, "cfg.val1.val2") + + +def test_callback_master_and_slaves_master_callback_disabled(): + val0 = StrOption('val0', "", multi=True, properties=('disabled',)) + val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val0, False),)}) + val2 = StrOption('val2', "", multi=True) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1, val0]) + cfg = Config(maconfig) + cfg.read_write() + raises(ConfigError, "cfg.val1.val1") + raises(ConfigError, "cfg.val1.val2") + cfg.cfgimpl_get_settings().remove('disabled') + cfg.val1.val1 = [] + cfg.cfgimpl_get_settings().append('disabled') + assert cfg.val1.val1 == [] + assert cfg.val1.val2 == [] + + +def test_callback_master_and_slaves_slave_disabled(): + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True, properties=('disabled',)) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1]) + cfg = Config(maconfig) + cfg.read_write() + assert cfg.val1.val1 == [] + raises(PropertiesOptionError, "cfg.val1.val2") + cfg.val1.val1.append('yes') + assert cfg.val1.val1 == ['yes'] + cfg.cfgimpl_get_settings().remove('disabled') + assert cfg.val1.val2 == [None] + cfg.val1.val2 = ['no'] + cfg.val1.val1.append('yes2') + cfg.val1.val1.append('yes3') + cfg.val1.val2[2] = 'no1' + assert cfg.val1.val2 == ['no', None, 'no1'] + cfg.cfgimpl_get_settings().append('disabled') + cfg.val1.val1.pop(0) + assert cfg.val1.val1 == ['yes2', 'yes3'] + cfg.cfgimpl_get_settings().remove('disabled') + assert cfg.val1.val2 == [None, 'no1'] + + +def test_callback_master_and_slaves_slave_callback_disabled(): + val0 = StrOption('val0', "", multi=True, properties=('disabled',)) + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val0, False),)}) + interface1 = OptionDescription('val1', '', [val1, val2]) + interface1.impl_set_group_type(groups.master) + maconfig = OptionDescription('rootconfig', '', [interface1, val0]) + cfg = Config(maconfig) + cfg.read_write() + assert cfg.val1.val1 == [] + raises(ConfigError, "cfg.val1.val2") + cfg.val1.val1.append('yes') + assert cfg.val1.val1 == ['yes'] + cfg.cfgimpl_get_settings().remove('disabled') + assert cfg.val1.val2 == [None] + cfg.val1.val2 = ['no'] + cfg.val1.val1.append('yes1') + cfg.val1.val2[1] = 'no1' + cfg.cfgimpl_get_settings().append('disabled') + cfg.val1.val1.pop(0) + assert cfg.val1.val1 == ['yes1'] + assert cfg.val1.val2 == ['no1'] + + def test_callback_master_and_slaves_slave_list(): val1 = StrOption('val1', "", multi=True) val2 = StrOption('val2', "", multi=True, callback=return_list) @@ -593,20 +684,20 @@ def test_callback_master_and_slaves_slave_list(): maconfig = OptionDescription('rootconfig', '', [interface1]) cfg = Config(maconfig) cfg.read_write() - assert cfg.val1.val2 == [] + #len is equal to 2 for slave and 0 for master + raises(SlaveError, "cfg.val1.val2") cfg.val1.val1 = ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val2 == ['val', 'val'] - cfg.val1.val1 = ['val1'] #wrong len - raises(SlaveError, 'cfg.val1.val2') + raises(SlaveError, "cfg.val1.val1 = ['val1']") def test_callback_master_and_slaves_value(): + val4 = StrOption('val4', '', multi=True, default=['val10', 'val11']) val1 = StrOption('val1', "", multi=True) val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)}) val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)}) - val4 = StrOption('val4', '', multi=True, default=['val10', 'val11']) val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)}) val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val5, False),)}) interface1 = OptionDescription('val1', '', [val1, val2, val3, val5, val6]) @@ -614,27 +705,24 @@ def test_callback_master_and_slaves_value(): maconfig = OptionDescription('rootconfig', '', [interface1, val4]) cfg = Config(maconfig) cfg.read_write() - assert cfg.val1.val1 == [] - assert cfg.val1.val2 == [] - assert cfg.val1.val3 == [] - assert cfg.val1.val5 == [] - assert cfg.val1.val6 == [] + cfg.val4 == ['val10', 'val11'] + raises(SlaveError, "cfg.val1.val1") + raises(SlaveError, "cfg.val1.val2") + raises(SlaveError, "cfg.val1.val3") + raises(SlaveError, "cfg.val1.val5") + raises(SlaveError, "cfg.val1.val6") # - cfg.val1.val1 = ['val1'] - assert cfg.val1.val1 == ['val1'] - assert cfg.val1.val2 == ['val1'] - assert cfg.val1.val3 == ['yes'] - assert cfg.val1.val5 == ['val10'] - assert cfg.val1.val6 == ['val10'] + #default calculation has greater length + raises(SlaveError, "cfg.val1.val1 = ['val1']") # - cfg.val1.val1.append('val2') + cfg.val1.val1 = ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val3 == ['yes', 'yes'] assert cfg.val1.val5 == ['val10', 'val11'] assert cfg.val1.val6 == ['val10', 'val11'] # - cfg.val1.val1 = ['val1', 'val2', 'val3'] + cfg.val1.val1.append('val3') assert cfg.val1.val1 == ['val1', 'val2', 'val3'] assert cfg.val1.val2 == ['val1', 'val2', 'val3'] assert cfg.val1.val3 == ['yes', 'yes', 'yes'] @@ -705,9 +793,16 @@ def test_callback_master_and_other_master_slave(): assert cfg.val4.val6 == ['no', None] cfg.val1.val1 = ['yes', 'yes', 'yes'] cfg.val1.val2 = ['no', 'no', 'no'] - assert cfg.val4.val4 == ['val10', 'val11'] - assert cfg.val4.val5 == ['yes', 'yes'] - assert cfg.val4.val6 == ['no', 'no'] + raises(SlaveError, "cfg.val4.val4") + raises(SlaveError, "cfg.val4.val5") + raises(SlaveError, "cfg.val4.val6") + cfg.val4.getattr('val4', validate=False).append('val12') + assert cfg.val4.val4 == ['val10', 'val11', 'val12'] + assert cfg.val4.val5 == ['yes', 'yes', 'yes'] + assert cfg.val4.val6 == ['no', 'no', 'no'] + + +#FIXME: slave est un symlink def test_callback_different_type(): @@ -757,6 +852,19 @@ def test_callback_two_disabled(): raises(PropertiesOptionError, 'cfg.od2.opt2') +def test_callback_two_disabled2(): + opt1 = BoolOption('opt1', '', properties=('hidden',)) + opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('hidden',)) + od1 = OptionDescription('od1', '', [opt1]) + od2 = OptionDescription('od2', '', [opt2]) + maconfig = OptionDescription('rootconfig', '', [od1, od2]) + cfg = Config(maconfig) + cfg.read_write() + cfg.cfgimpl_get_settings().setpermissive(('hidden',)) + raises(PropertiesOptionError, 'cfg.od2.opt2') + assert cfg.getowner(opt2, force_permissive=True) == owners.default + + def test_callback_calculating_disabled(): opt1 = BoolOption('opt1', '', properties=('disabled',)) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}) @@ -779,6 +887,17 @@ def test_callback_calculating_mandatory(): raises(ConfigError, 'cfg.od2.opt2') +def test_callback_calculating_mandatory_multi(): + opt1 = BoolOption('opt1', '', multi=True, properties=('disabled',)) + opt2 = BoolOption('opt2', '', multi=True, callback=return_value, callback_params={'': ((opt1, False),)}, properties=('mandatory',)) + od1 = OptionDescription('od1', '', [opt1]) + od2 = OptionDescription('od2', '', [opt2]) + maconfig = OptionDescription('rootconfig', '', [od1, od2]) + cfg = Config(maconfig) + cfg.read_only() + raises(ConfigError, 'cfg.od2.opt2') + + def test_callback_two_disabled_multi(): opt1 = BoolOption('opt1', '', properties=('disabled',)) opt2 = BoolOption('opt2', '', callback=return_value, callback_params={'': ((opt1, False),)}, properties=('disabled',), multi=True) diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index edb4f4a..5d2f9da 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -321,7 +321,7 @@ def test_consistency_broadcast_error(): c.impl_add_consistency('broadcast', a) c = Config(od) c.a = ['192.168.1.0'] - c.b = ['255.255.255.0'] + raises(ConfigError, "c.b = ['255.255.255.0']") raises(ConfigError, "c.c = ['192.168.1.255']") diff --git a/test/test_requires.py b/test/test_requires.py index ff9c2a6..c6d1032 100644 --- a/test/test_requires.py +++ b/test/test_requires.py @@ -242,6 +242,30 @@ def test_requires_transitive(): assert props == ['disabled'] +def test_requires_transitive_owner(): + a = BoolOption('activate_service', '', True) + b = BoolOption('activate_service_web', '', True, + requires=[{'option': a, 'expected': False, 'action': 'disabled'}]) + + d = IPOption('ip_address_service_web', '', + requires=[{'option': b, 'expected': False, 'action': 'disabled'}]) + od = OptionDescription('service', '', [a, b, d]) + c = Config(od) + c.read_write() + c.activate_service + c.activate_service_web + c.ip_address_service_web + #no more default value + c.ip_address_service_web = '1.1.1.1' + c.activate_service = False + props = [] + try: + c.ip_address_service_web + except PropertiesOptionError as err: + props = err.proptype + assert props == ['disabled'] + + def test_requires_transitive_bis(): a = BoolOption('activate_service', '', True) abis = BoolOption('activate_service_bis', '', True) diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 92b86c5..6d8ed6e 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -19,13 +19,13 @@ # ____________________________________________________________ "enables us to carry out a calculation and return an option's value" from tiramisu.error import PropertiesOptionError, ConfigError -from tiramisu.setting import multitypes from tiramisu.i18n import _ +from tiramisu.setting import undefined # ____________________________________________________________ def carry_out_calculation(option, config, callback, callback_params, - index=None, max_len=None): + index=undefined): """a function that carries out a calculation for an option's value :param name: the option @@ -38,8 +38,6 @@ def carry_out_calculation(option, config, callback, callback_params, :type callback_params: dict :param index: if an option is multi, only calculates the nth value :type index: int - :param max_len: max length for a multi - :type max_len: int The callback_params is a dict. Key is used to build args (if key is '') and kwargs (otherwise). Values are tuple of: @@ -129,7 +127,7 @@ def carry_out_calculation(option, config, callback, callback_params, * if callback_params={'value': ((opt1, False), (opt2, False))} => raises ValueError() - If index is not None, return a value, otherwise return: + If index is not undefined, return a value, otherwise return: * a list if one parameters have multi option * a value otherwise @@ -154,15 +152,8 @@ def carry_out_calculation(option, config, callback, callback_params, ).impl_get_path_by_opt(opt) # get value try: - if option.impl_is_multi() and \ - (option.impl_get_multitype() == multitypes.master or - (option.impl_get_multitype() == multitypes.slave and - option.impl_get_master_slaves() != opt)): - validate = True - else: - validate = False value = config.getattr(path, force_permissive=True, - validate=validate) + validate=False) # convert to list, not modifie this multi if value.__class__.__name__ == 'Multi': value = list(value) @@ -175,20 +166,13 @@ def carry_out_calculation(option, config, callback, callback_params, err.proptype, option._name)) - is_multi = False - if opt.impl_is_multi(): - #opt is master, search if option is a slave - if opt.impl_get_multitype() == multitypes.master: - if option in opt.impl_get_master_slaves(): - is_multi = True - #opt is slave, search if option is an other slaves - elif opt.impl_get_multitype() == multitypes.slave: - if option in opt.impl_get_master_slaves( - ).impl_get_master_slaves(): - is_multi = True - if is_multi: + if opt.impl_is_master_slaves() and \ + opt.impl_get_master_slaves().in_same_group(option): len_multi = len(value) one_is_multi = True + is_multi = True + else: + is_multi = False tcparams.setdefault(key, []).append((value, is_multi)) else: # callbk is a value and not a multi @@ -199,7 +183,7 @@ def carry_out_calculation(option, config, callback, callback_params, # if no index, return a list if one_is_multi: ret = [] - if index is not None: + if index is not undefined: range_ = [index] else: range_ = range(len_multi) @@ -218,7 +202,7 @@ def carry_out_calculation(option, config, callback, callback_params, else: kwargs[key] = val calc = calculate(callback, args, kwargs) - if index is not None: + if index is not undefined: ret = calc else: ret.append(calc) @@ -237,11 +221,7 @@ def carry_out_calculation(option, config, callback, callback_params, kwargs[key] = couple[0] ret = calculate(callback, args, kwargs) if callback_params != {}: - if isinstance(ret, list) and max_len: - ret = ret[:max_len] - if len(ret) < max_len: - ret = ret + [None] * (max_len - len(ret)) - if isinstance(ret, list) and index is not None: + if isinstance(ret, list) and index is not undefined: if len(ret) < index + 1: ret = None else: diff --git a/tiramisu/config.py b/tiramisu/config.py index 8356aaa..04c9cb9 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -228,6 +228,7 @@ class SubConfig(object): :return: option's value if name is an option name, OptionDescription otherwise """ + #FIXME force_properties vraiment utile maintenant ? # attribute access by passing a path, # for instance getattr(self, "creole.general.family.adresse_ip_eth0") if '.' in name: @@ -243,6 +244,8 @@ class SubConfig(object): else: subpath = self._impl_path + '.' + name # symlink options + #FIXME a gerer plutot dans l'option ca ... + #FIXME je n'en sais rien en fait ... :/ if isinstance(opt_or_descr, SymLinkOption): context = self._cfgimpl_get_context() path = context.cfgimpl_get_description().impl_get_path_by_opt( @@ -257,7 +260,7 @@ class SubConfig(object): force_properties=force_properties) return SubConfig(opt_or_descr, self._impl_context, subpath) else: - return self.cfgimpl_get_values().getitem( + return self.cfgimpl_get_values()._get_cached_item( opt_or_descr, path=subpath, validate=validate, force_properties=force_properties, diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py new file mode 100644 index 0000000..1a325f8 --- /dev/null +++ b/tiramisu/option/__init__.py @@ -0,0 +1,16 @@ +from .masterslave import MasterSlaves +from .optiondescription import OptionDescription +from .baseoption import Option, SymLinkOption +from .option import (ChoiceOption, BoolOption, IntOption, FloatOption, + StrOption, UnicodeOption, IPOption, PortOption, + NetworkOption, NetmaskOption, BroadcastOption, + DomainnameOption, EmailOption, URLOption, UsernameOption, + FilenameOption) + + +__all__ = (MasterSlaves, OptionDescription, Option, SymLinkOption, + ChoiceOption, BoolOption, IntOption, FloatOption, + StrOption, UnicodeOption, IPOption, PortOption, + NetworkOption, NetmaskOption, BroadcastOption, + DomainnameOption, EmailOption, URLOption, UsernameOption, + FilenameOption) diff --git a/tiramisu/option.py b/tiramisu/option/baseoption.py similarity index 51% rename from tiramisu/option.py rename to tiramisu/option/baseoption.py index 820908e..1e62e8f 100644 --- a/tiramisu/option.py +++ b/tiramisu/option/baseoption.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- -"option types and option description" -# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) +# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors) # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by the @@ -20,16 +19,14 @@ # the whole pypy projet is under MIT licence # ____________________________________________________________ import re -import sys from copy import copy, deepcopy from types import FunctionType -from IPy import IP import warnings -from tiramisu.error import ConfigError, ConflictError, ValueWarning -from tiramisu.setting import groups, multitypes, log from tiramisu.i18n import _ +from tiramisu.setting import log from tiramisu.autolib import carry_out_calculation +from tiramisu.error import ConfigError, ValueWarning name_regexp = re.compile(r'^\d+') forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first', @@ -48,6 +45,46 @@ def valid_name(name): return True else: return False + + +def validate_callback(callback, callback_params, type_): + if type(callback) != FunctionType: + raise ValueError(_('{0} must be a function').format(type_)) + if callback_params is not None: + if not isinstance(callback_params, dict): + raise ValueError(_('{0}_params must be a dict').format(type_)) + for key, callbacks in callback_params.items(): + if key != '' and len(callbacks) != 1: + raise ValueError(_("{0}_params with key {1} mustn't have " + "length different to 1").format(type_, + key)) + if not isinstance(callbacks, tuple): + raise ValueError(_('{0}_params must be tuple for key "{1}"' + ).format(type_, key)) + for callbk in callbacks: + if isinstance(callbk, tuple): + if len(callbk) == 1: + if callbk != (None,): + raise ValueError(_('{0}_params with length of ' + 'tuple as 1 must only have ' + 'None as first value')) + elif len(callbk) != 2: + raise ValueError(_('{0}_params must only have 1 or 2 ' + 'as length')) + else: + option, force_permissive = callbk + if type_ == 'validator' and not force_permissive: + raise ValueError(_('validator not support tuple')) + if not isinstance(option, Option) and not \ + isinstance(option, SymLinkOption): + raise ValueError(_('{0}_params must have an option' + ' not a {0} for first argument' + ).format(type_, type(option))) + if force_permissive not in [True, False]: + raise ValueError(_('{0}_params must have a boolean' + ' not a {0} for second argument' + ).format(type_, type( + force_permissive))) #____________________________________________________________ # @@ -264,9 +301,9 @@ class Option(BaseOption): Reminder: an Option object is **not** a container for the value. """ __slots__ = ('_multi', '_validator', '_default_multi', '_default', - '_state_callback', '_callback', '_multitype', - '_consistencies', '_warnings_only', '_master_slaves', - '_state_consistencies', '__weakref__') + '_state_callback', '_callback', '_consistencies', + '_warnings_only', '_master_slaves', '_state_consistencies', + '__weakref__') _empty = '' def __init__(self, name, doc, default=None, default_multi=None, @@ -327,7 +364,6 @@ class Option(BaseOption): if self._multi: if default is None: default = [] - self._multitype = multitypes.default self._default_multi = default_multi self._warnings_only = warnings_only self.impl_validate(default) @@ -390,9 +426,9 @@ class Option(BaseOption): :type context: :class:`tiramisu.config.Config` :param validate: if true enables ``self._validator`` validation :type validate: boolean - :param force_no_multi: if multi, value has to be a list - not if force_no_multi is True - :type force_no_multi: boolean + :param force_index: if multi, value has to be a list + not if force_index is not None + :type force_index: integer """ if not validate: return @@ -421,6 +457,8 @@ class Option(BaseOption): try: self._validate(_value) except ValueError as err: + log.debug('do_validation: value: {0} index: {1}'.format( + _value, _index), exc_info=True) raise ValueError(_('invalid value for option {0}: {1}' '').format(self._name, err)) error = None @@ -476,14 +514,28 @@ class Option(BaseOption): def impl_getdefault(self): "accessing the default value" + if isinstance(self._default, list): + return copy(self._default) return self._default def impl_getdefault_multi(self): "accessing the default value for a multi" return self._default_multi - def impl_get_multitype(self): - return self._multitype + def impl_is_master_slaves(self, type_='both'): + """FIXME + """ + try: + self._master_slaves + if type_ in ('both', 'master') and \ + self._master_slaves.is_master(self): + return True + if type_ in ('both', 'slave') and \ + not self._master_slaves.is_master(self): + return True + except: + pass + return False def impl_get_master_slaves(self): return self._master_slaves @@ -632,805 +684,6 @@ class Option(BaseOption): pass -class ChoiceOption(Option): - """represents a choice out of several objects. - - The option can also have the value ``None`` - """ - - __slots__ = ('_values', '_open_values') - _opt_type = 'string' - - def __init__(self, name, doc, values, default=None, default_multi=None, - requires=None, multi=False, callback=None, - callback_params=None, open_values=False, validator=None, - validator_params=None, properties=None, warnings_only=False): - """ - :param values: is a list of values the option can possibly take - """ - if not isinstance(values, tuple): - raise TypeError(_('values must be a tuple for {0}').format(name)) - self._values = values - if open_values not in (True, False): - raise TypeError(_('open_values must be a boolean for ' - '{0}').format(name)) - self._open_values = open_values - super(ChoiceOption, self).__init__(name, doc, default=default, - default_multi=default_multi, - callback=callback, - callback_params=callback_params, - requires=requires, - multi=multi, - validator=validator, - validator_params=validator_params, - properties=properties, - warnings_only=warnings_only) - - def impl_get_values(self): - return self._values - - def impl_is_openvalues(self): - return self._open_values - - def _validate(self, value): - if not self.impl_is_openvalues() and not value in self.impl_get_values(): - raise ValueError(_('value {0} is not permitted, ' - 'only {1} is allowed' - '').format(value, self._values)) - - -class BoolOption(Option): - "represents a choice between ``True`` and ``False``" - __slots__ = tuple() - _opt_type = 'bool' - - def _validate(self, value): - if not isinstance(value, bool): - raise ValueError(_('invalid boolean')) - - -class IntOption(Option): - "represents a choice of an integer" - __slots__ = tuple() - _opt_type = 'int' - - def _validate(self, value): - if not isinstance(value, int): - raise ValueError(_('invalid integer')) - - -class FloatOption(Option): - "represents a choice of a floating point number" - __slots__ = tuple() - _opt_type = 'float' - - def _validate(self, value): - if not isinstance(value, float): - raise ValueError(_('invalid float')) - - -class StrOption(Option): - "represents the choice of a string" - __slots__ = tuple() - _opt_type = 'string' - - def _validate(self, value): - if not isinstance(value, str): - raise ValueError(_('invalid string')) - - -if sys.version_info[0] >= 3: - #UnicodeOption is same as StrOption in python 3+ - class UnicodeOption(StrOption): - __slots__ = tuple() - pass -else: - class UnicodeOption(Option): - "represents the choice of a unicode string" - __slots__ = tuple() - _opt_type = 'unicode' - _empty = u'' - - def _validate(self, value): - if not isinstance(value, unicode): - raise ValueError(_('invalid unicode')) - - -class SymLinkOption(BaseOption): - __slots__ = ('_name', '_opt', '_state_opt') - _opt_type = 'symlink' - #not return _opt consistencies - _consistencies = None - - def __init__(self, name, opt): - self._name = name - if not isinstance(opt, Option): - raise ValueError(_('malformed symlinkoption ' - 'must be an option ' - 'for symlink {0}').format(name)) - self._opt = opt - self._readonly = True - - def __getattr__(self, name): - if name in ('_name', '_opt', '_opt_type', '_readonly'): - return object.__getattr__(self, name) - else: - return getattr(self._opt, name) - - def _impl_getstate(self, descr): - super(SymLinkOption, self)._impl_getstate(descr) - self._state_opt = descr.impl_get_path_by_opt(self._opt) - - def _impl_setstate(self, descr): - self._opt = descr.impl_get_opt_by_path(self._state_opt) - del(self._state_opt) - super(SymLinkOption, self)._impl_setstate(descr) - - -class IPOption(Option): - "represents the choice of an ip" - __slots__ = ('_private_only', '_allow_reserved') - _opt_type = 'ip' - - def __init__(self, name, doc, default=None, default_multi=None, - requires=None, multi=False, callback=None, - callback_params=None, validator=None, validator_params=None, - properties=None, private_only=False, allow_reserved=False, - warnings_only=False): - self._private_only = private_only - self._allow_reserved = allow_reserved - super(IPOption, self).__init__(name, doc, default=default, - default_multi=default_multi, - callback=callback, - callback_params=callback_params, - requires=requires, - multi=multi, - validator=validator, - validator_params=validator_params, - properties=properties, - warnings_only=warnings_only) - - def _validate(self, value): - # sometimes an ip term starts with a zero - # but this does not fit in some case, for example bind does not like it - try: - for val in value.split('.'): - if val.startswith("0") and len(val) > 1: - raise ValueError(_('invalid IP')) - except AttributeError: - #if integer for example - raise ValueError(_('invalid IP')) - # 'standard' validation - try: - IP('{0}/32'.format(value)) - except ValueError: - raise ValueError(_('invalid IP')) - - def _second_level_validation(self, value, warnings_only): - ip = IP('{0}/32'.format(value)) - if not self._allow_reserved and ip.iptype() == 'RESERVED': - if warnings_only: - msg = _("IP is in reserved class") - else: - msg = _("invalid IP, mustn't be in reserved class") - raise ValueError(msg) - if self._private_only and not ip.iptype() == 'PRIVATE': - if warnings_only: - msg = _("IP is not in private class") - else: - msg = _("invalid IP, must be in private class") - raise ValueError(msg) - - def _cons_in_network(self, opts, vals, warnings_only): - if len(vals) != 3: - raise ConfigError(_('invalid len for vals')) - if None in vals: - return - ip, network, netmask = vals - if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): - if warnings_only: - msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}' - ' ({5})') - else: - msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with ' - 'netmask {4} ({5})') - raise ValueError(msg.format(ip, opts[0]._name, network, - opts[1]._name, netmask, opts[2]._name)) - - -class PortOption(Option): - """represents the choice of a port - The port numbers are divided into three ranges: - the well-known ports, - the registered ports, - and the dynamic or private ports. - You can actived this three range. - Port number 0 is reserved and can't be used. - see: http://en.wikipedia.org/wiki/Port_numbers - """ - __slots__ = ('_allow_range', '_allow_zero', '_min_value', '_max_value') - _opt_type = 'port' - - def __init__(self, name, doc, default=None, default_multi=None, - requires=None, multi=False, callback=None, - callback_params=None, validator=None, validator_params=None, - properties=None, allow_range=False, allow_zero=False, - allow_wellknown=True, allow_registred=True, - allow_private=False, warnings_only=False): - self._allow_range = allow_range - self._min_value = None - self._max_value = None - ports_min = [0, 1, 1024, 49152] - ports_max = [0, 1023, 49151, 65535] - is_finally = False - for index, allowed in enumerate([allow_zero, - allow_wellknown, - allow_registred, - allow_private]): - if self._min_value is None: - if allowed: - self._min_value = ports_min[index] - elif not allowed: - is_finally = True - elif allowed and is_finally: - raise ValueError(_('inconsistency in allowed range')) - if allowed: - self._max_value = ports_max[index] - - if self._max_value is None: - raise ValueError(_('max value is empty')) - - super(PortOption, self).__init__(name, doc, default=default, - default_multi=default_multi, - callback=callback, - callback_params=callback_params, - requires=requires, - multi=multi, - validator=validator, - validator_params=validator_params, - properties=properties, - warnings_only=warnings_only) - - def _validate(self, value): - if self._allow_range and ":" in str(value): - value = str(value).split(':') - if len(value) != 2: - raise ValueError(_('invalid port, range must have two values ' - 'only')) - if not value[0] < value[1]: - raise ValueError(_('invalid port, first port in range must be' - ' smaller than the second one')) - else: - value = [value] - - for val in value: - try: - int(val) - except ValueError: - raise ValueError(_('invalid port')) - if not self._min_value <= int(val) <= self._max_value: - raise ValueError(_('invalid port, must be an between {0} ' - 'and {1}').format(self._min_value, - self._max_value)) - - -class NetworkOption(Option): - "represents the choice of a network" - __slots__ = tuple() - _opt_type = 'network' - - def _validate(self, value): - try: - IP(value) - except ValueError: - raise ValueError(_('invalid network address')) - - def _second_level_validation(self, value, warnings_only): - ip = IP(value) - if ip.iptype() == 'RESERVED': - if warnings_only: - msg = _("network address is in reserved class") - else: - msg = _("invalid network address, mustn't be in reserved class") - raise ValueError(msg) - - -class NetmaskOption(Option): - "represents the choice of a netmask" - __slots__ = tuple() - _opt_type = 'netmask' - - def _validate(self, value): - try: - IP('0.0.0.0/{0}'.format(value)) - except ValueError: - raise ValueError(_('invalid netmask address')) - - def _cons_network_netmask(self, opts, vals, warnings_only): - #opts must be (netmask, network) options - if None in vals: - return - self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only) - - def _cons_ip_netmask(self, opts, vals, warnings_only): - #opts must be (netmask, ip) options - if None in vals: - return - self.__cons_netmask(opts, vals[0], vals[1], True, warnings_only) - - def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net, - warnings_only): - if len(opts) != 2: - raise ConfigError(_('invalid len for opts')) - msg = None - try: - ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), - make_net=make_net) - #if cidr == 32, ip same has network - if ip.prefixlen() != 32: - try: - IP('{0}/{1}'.format(val_ipnetwork, val_netmask), - make_net=not make_net) - except ValueError: - pass - else: - if make_net: - msg = _("invalid IP {0} ({1}) with netmask {2}," - " this IP is a network") - - except ValueError: - if not make_net: - msg = _('invalid network {0} ({1}) with netmask {2}') - if msg is not None: - raise ValueError(msg.format(val_ipnetwork, opts[1]._name, - val_netmask)) - - -class BroadcastOption(Option): - __slots__ = tuple() - _opt_type = 'broadcast' - - def _validate(self, value): - try: - IP('{0}/32'.format(value)) - except ValueError: - raise ValueError(_('invalid broadcast address')) - - def _cons_broadcast(self, opts, vals, warnings_only): - if len(vals) != 3: - raise ConfigError(_('invalid len for vals')) - if None in vals: - return - broadcast, network, netmask = vals - if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast): - raise ValueError(_('invalid broadcast {0} ({1}) with network {2} ' - '({3}) and netmask {4} ({5})').format( - broadcast, opts[0]._name, network, - opts[1]._name, netmask, opts[2]._name)) - - -class DomainnameOption(Option): - """represents the choice of a domain name - netbios: for MS domain - hostname: to identify the device - domainname: - fqdn: with tld, not supported yet - """ - __slots__ = ('_type', '_allow_ip', '_allow_without_dot', '_domain_re') - _opt_type = 'domainname' - - def __init__(self, name, doc, default=None, default_multi=None, - requires=None, multi=False, callback=None, - callback_params=None, validator=None, validator_params=None, - properties=None, allow_ip=False, type_='domainname', - warnings_only=False, allow_without_dot=False): - if type_ not in ['netbios', 'hostname', 'domainname']: - raise ValueError(_('unknown type_ {0} for hostname').format(type_)) - self._type = type_ - if allow_ip not in [True, False]: - raise ValueError(_('allow_ip must be a boolean')) - if allow_without_dot not in [True, False]: - raise ValueError(_('allow_without_dot must be a boolean')) - self._allow_ip = allow_ip - self._allow_without_dot = allow_without_dot - end = '' - extrachar = '' - extrachar_mandatory = '' - if self._type != 'netbios': - allow_number = '\d' - else: - allow_number = '' - if self._type == 'netbios': - length = 14 - elif self._type == 'hostname': - length = 62 - elif self._type == 'domainname': - length = 62 - if allow_without_dot is False: - extrachar_mandatory = '\.' - else: - extrachar = '\.' - end = '+[a-z]*' - self._domain_re = re.compile(r'^(?:[a-z{0}][a-z\d\-{1}]{{,{2}}}{3}){4}$' - ''.format(allow_number, extrachar, length, - extrachar_mandatory, end)) - super(DomainnameOption, self).__init__(name, doc, default=default, - default_multi=default_multi, - callback=callback, - callback_params=callback_params, - requires=requires, - multi=multi, - validator=validator, - validator_params=validator_params, - properties=properties, - warnings_only=warnings_only) - - def _validate(self, value): - if self._allow_ip is True: - try: - IP('{0}/32'.format(value)) - return - except ValueError: - pass - if self._type == 'domainname' and not self._allow_without_dot and \ - '.' not in value: - raise ValueError(_("invalid domainname, must have dot")) - if len(value) > 255: - raise ValueError(_("invalid domainname's length (max 255)")) - if len(value) < 2: - raise ValueError(_("invalid domainname's length (min 2)")) - if not self._domain_re.search(value): - raise ValueError(_('invalid domainname')) - - -class EmailOption(DomainnameOption): - __slots__ = tuple() - _opt_type = 'email' - username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") - - def _validate(self, value): - splitted = value.split('@', 1) - try: - username, domain = splitted - except ValueError: - raise ValueError(_('invalid email address, must contains one @' - )) - if not self.username_re.search(username): - raise ValueError(_('invalid username in email address')) - super(EmailOption, self)._validate(domain) - - -class URLOption(DomainnameOption): - __slots__ = tuple() - _opt_type = 'url' - proto_re = re.compile(r'(http|https)://') - path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$") - - def _validate(self, value): - match = self.proto_re.search(value) - if not match: - raise ValueError(_('invalid url, must start with http:// or ' - 'https://')) - value = value[len(match.group(0)):] - # get domain/files - splitted = value.split('/', 1) - try: - domain, files = splitted - except ValueError: - domain = value - files = None - # if port in domain - splitted = domain.split(':', 1) - try: - domain, port = splitted - - except ValueError: - domain = splitted[0] - port = 0 - if not 0 <= int(port) <= 65535: - raise ValueError(_('invalid url, port must be an between 0 and ' - '65536')) - # validate domainname - super(URLOption, self)._validate(domain) - # validate file - if files is not None and files != '' and not self.path_re.search(files): - raise ValueError(_('invalid url, must ends with filename')) - - -class UsernameOption(Option): - __slots__ = tuple() - _opt_type = 'username' - #regexp build with 'man 8 adduser' informations - username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$") - - def _validate(self, value): - match = self.username_re.search(value) - if not match: - raise ValueError(_('invalid username')) - - -class FilenameOption(Option): - __slots__ = tuple() - _opt_type = 'file' - path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$") - - def _validate(self, value): - match = self.path_re.search(value) - if not match: - raise ValueError(_('invalid filename')) - - -class OptionDescription(BaseOption): - """Config's schema (organisation, group) and container of Options - The `OptionsDescription` objects lives in the `tiramisu.config.Config`. - """ - __slots__ = ('_name', '_requires', '_cache_paths', '_group_type', - '_state_group_type', '_properties', '_children', - '_cache_consistencies', '_calc_properties', '__weakref__', - '_readonly', '_impl_informations', '_state_requires', - '_stated', '_state_readonly') - _opt_type = 'optiondescription' - - def __init__(self, name, doc, children, requires=None, properties=None): - """ - :param children: a list of options (including optiondescriptions) - - """ - super(OptionDescription, self).__init__(name, doc, requires, properties) - child_names = [child._name for child in children] - #better performance like this - valid_child = copy(child_names) - valid_child.sort() - old = None - for child in valid_child: - if child == old: - raise ConflictError(_('duplicate option name: ' - '{0}').format(child)) - old = child - self._children = (tuple(child_names), tuple(children)) - self._cache_paths = None - self._cache_consistencies = None - # the group_type is useful for filtering OptionDescriptions in a config - self._group_type = groups.default - - def impl_getdoc(self): - return self.impl_get_information('doc') - - def __getattr__(self, name): - if name in self.__slots__: - return object.__getattribute__(self, name) - try: - return self._children[1][self._children[0].index(name)] - except ValueError: - raise AttributeError(_('unknown Option {0} ' - 'in OptionDescription {1}' - '').format(name, self._name)) - - def impl_getkey(self, config): - return tuple([child.impl_getkey(getattr(config, child._name)) - for child in self.impl_getchildren()]) - - def impl_getpaths(self, include_groups=False, _currpath=None): - """returns a list of all paths in self, recursively - _currpath should not be provided (helps with recursion) - """ - if _currpath is None: - _currpath = [] - paths = [] - for option in self.impl_getchildren(): - attr = option._name - if isinstance(option, OptionDescription): - if include_groups: - paths.append('.'.join(_currpath + [attr])) - paths += option.impl_getpaths(include_groups=include_groups, - _currpath=_currpath + [attr]) - else: - paths.append('.'.join(_currpath + [attr])) - return paths - - def impl_getchildren(self): - return self._children[1] - - def impl_build_cache(self, - cache_path=None, - cache_option=None, - _currpath=None, - _consistencies=None, - force_no_consistencies=False): - if _currpath is None and self._cache_paths is not None: - # cache already set - return - if _currpath is None: - save = True - _currpath = [] - if not force_no_consistencies: - _consistencies = {} - else: - save = False - if cache_path is None: - cache_path = [] - cache_option = [] - for option in self.impl_getchildren(): - attr = option._name - if option in cache_option: - raise ConflictError(_('duplicate option: {0}').format(option)) - - cache_option.append(option) - if not force_no_consistencies: - option._readonly = True - cache_path.append(str('.'.join(_currpath + [attr]))) - if not isinstance(option, OptionDescription): - if not force_no_consistencies and \ - option._consistencies is not None: - for consistency in option._consistencies: - func, all_cons_opts, params = consistency - for opt in all_cons_opts: - _consistencies.setdefault(opt, - []).append((func, - all_cons_opts, - params)) - else: - _currpath.append(attr) - option.impl_build_cache(cache_path, - cache_option, - _currpath, - _consistencies, - force_no_consistencies) - _currpath.pop() - if save: - self._cache_paths = (tuple(cache_option), tuple(cache_path)) - if not force_no_consistencies: - if _consistencies != {}: - self._cache_consistencies = {} - for opt, cons in _consistencies.items(): - if opt not in cache_option: - raise ConfigError(_('consistency with option {0} which is not in Config').format(opt._name)) - self._cache_consistencies[opt] = tuple(cons) - self._readonly = True - - def impl_get_opt_by_path(self, path): - try: - return self._cache_paths[0][self._cache_paths[1].index(path)] - except ValueError: - raise AttributeError(_('no option for path {0}').format(path)) - - def impl_get_path_by_opt(self, opt): - try: - return self._cache_paths[1][self._cache_paths[0].index(opt)] - except ValueError: - raise AttributeError(_('no option {0} found').format(opt)) - - # ____________________________________________________________ - def impl_set_group_type(self, group_type): - """sets a given group object to an OptionDescription - - :param group_type: an instance of `GroupType` or `MasterGroupType` - that lives in `setting.groups` - """ - if self._group_type != groups.default: - raise TypeError(_('cannot change group_type if already set ' - '(old {0}, new {1})').format(self._group_type, - group_type)) - if isinstance(group_type, groups.GroupType): - self._group_type = group_type - if isinstance(group_type, groups.MasterGroupType): - #if master (same name has group) is set - #for collect all slaves - slaves = [] - master = None - for child in self.impl_getchildren(): - if isinstance(child, OptionDescription): - raise ValueError(_("master group {0} shall not have " - "a subgroup").format(self._name)) - if isinstance(child, SymLinkOption): - raise ValueError(_("master group {0} shall not have " - "a symlinkoption").format(self._name)) - if not child.impl_is_multi(): - raise ValueError(_("not allowed option {0} " - "in group {1}" - ": this option is not a multi" - "").format(child._name, self._name)) - if child._name == self._name: - child._multitype = multitypes.master - master = child - else: - slaves.append(child) - if master is None: - raise ValueError(_('master group with wrong' - ' master name for {0}' - ).format(self._name)) - if master._callback is not None and master._callback[1] is not None: - for key, callbacks in master._callback[1].items(): - for callbk in callbacks: - if isinstance(callbk, tuple): - if callbk[0] in slaves: - raise ValueError(_("callback of master's option shall " - "not refered a slave's ones")) - master._master_slaves = tuple(slaves) - for child in self.impl_getchildren(): - if child != master: - child._master_slaves = master - child._multitype = multitypes.slave - else: - raise ValueError(_('group_type: {0}' - ' not allowed').format(group_type)) - - def impl_get_group_type(self): - return self._group_type - - def _valid_consistency(self, option, value, context, index): - if self._cache_consistencies is None: - return True - #consistencies is something like [('_cons_not_equal', (opt1, opt2))] - consistencies = self._cache_consistencies.get(option) - if consistencies is not None: - for func, all_cons_opts, params in consistencies: - warnings_only = params.get('warnings_only', False) - #all_cons_opts[0] is the option where func is set - try: - all_cons_opts[0]._launch_consistency(func, option, - value, - context, index, - all_cons_opts, - warnings_only) - except ValueError as err: - if warnings_only: - raise ValueWarning(err.message, option) - else: - raise err - - def _impl_getstate(self, descr=None): - """enables us to export into a dict - :param descr: parent :class:`tiramisu.option.OptionDescription` - """ - if descr is None: - self.impl_build_cache() - descr = self - super(OptionDescription, self)._impl_getstate(descr) - self._state_group_type = str(self._group_type) - for option in self.impl_getchildren(): - option._impl_getstate(descr) - - def __getstate__(self): - """special method to enable the serialization with pickle - """ - stated = True - try: - # the `_state` attribute is a flag that which tells us if - # the serialization can be performed - self._stated - except AttributeError: - # if cannot delete, _impl_getstate never launch - # launch it recursivement - # _stated prevent __getstate__ launch more than one time - # _stated is delete, if re-serialize, re-lauch _impl_getstate - self._impl_getstate() - stated = False - return super(OptionDescription, self).__getstate__(stated) - - def _impl_setstate(self, descr=None): - """enables us to import from a dict - :param descr: parent :class:`tiramisu.option.OptionDescription` - """ - if descr is None: - self._cache_paths = None - self._cache_consistencies = None - self.impl_build_cache(force_no_consistencies=True) - descr = self - self._group_type = getattr(groups, self._state_group_type) - del(self._state_group_type) - super(OptionDescription, self)._impl_setstate(descr) - for option in self.impl_getchildren(): - option._impl_setstate(descr) - - def __setstate__(self, state): - super(OptionDescription, self).__setstate__(state) - try: - self._stated - except AttributeError: - self._impl_setstate() - - def validate_requires_arg(requires, name): """check malformed requirements and tranform dict to internal tuple @@ -1524,41 +777,32 @@ def validate_requires_arg(requires, name): return frozenset(config_action.keys()), tuple(ret) -def validate_callback(callback, callback_params, type_): - if type(callback) != FunctionType: - raise ValueError(_('{0} must be a function').format(type_)) - if callback_params is not None: - if not isinstance(callback_params, dict): - raise ValueError(_('{0}_params must be a dict').format(type_)) - for key, callbacks in callback_params.items(): - if key != '' and len(callbacks) != 1: - raise ValueError(_("{0}_params with key {1} mustn't have " - "length different to 1").format(type_, - key)) - if not isinstance(callbacks, tuple): - raise ValueError(_('{0}_params must be tuple for key "{1}"' - ).format(type_, key)) - for callbk in callbacks: - if isinstance(callbk, tuple): - if len(callbk) == 1: - if callbk != (None,): - raise ValueError(_('{0}_params with length of ' - 'tuple as 1 must only have ' - 'None as first value')) - elif len(callbk) != 2: - raise ValueError(_('{0}_params must only have 1 or 2 ' - 'as length')) - else: - option, force_permissive = callbk - if type_ == 'validator' and not force_permissive: - raise ValueError(_('validator not support tuple')) - if not isinstance(option, Option) and not \ - isinstance(option, SymLinkOption): - raise ValueError(_('{0}_params must have an option' - ' not a {0} for first argument' - ).format(type_, type(option))) - if force_permissive not in [True, False]: - raise ValueError(_('{0}_params must have a boolean' - ' not a {0} for second argument' - ).format(type_, type( - force_permissive))) +class SymLinkOption(BaseOption): + __slots__ = ('_name', '_opt', '_state_opt') + _opt_type = 'symlink' + #not return _opt consistencies + _consistencies = None + + def __init__(self, name, opt): + self._name = name + if not isinstance(opt, Option): + raise ValueError(_('malformed symlinkoption ' + 'must be an option ' + 'for symlink {0}').format(name)) + self._opt = opt + self._readonly = True + + def __getattr__(self, name): + if name in ('_name', '_opt', '_opt_type', '_readonly'): + return object.__getattr__(self, name) + else: + return getattr(self._opt, name) + + def _impl_getstate(self, descr): + super(SymLinkOption, self)._impl_getstate(descr) + self._state_opt = descr.impl_get_path_by_opt(self._opt) + + def _impl_setstate(self, descr): + self._opt = descr.impl_get_opt_by_path(self._state_opt) + del(self._state_opt) + super(SymLinkOption, self)._impl_setstate(descr) diff --git a/tiramisu/option/masterslave.py b/tiramisu/option/masterslave.py new file mode 100644 index 0000000..9e0426d --- /dev/null +++ b/tiramisu/option/masterslave.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- +"master slave support" +# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +from tiramisu.i18n import _ +from tiramisu.setting import log +from tiramisu.error import SlaveError, ConfigError +from .baseoption import SymLinkOption, Option + + +class MasterSlaves(object): + __slots__ = ('master', 'slaves') + + def __init__(self, name, childs): + #if master (same name has group) is set + #for collect all slaves + self.master = None + slaves = [] + for child in childs: + if isinstance(child, SymLinkOption): + raise ValueError(_("master group {0} shall not have " + "a symlinkoption").format(name)) + if not isinstance(child, Option): + raise ValueError(_("master group {0} shall not have " + "a subgroup").format(name)) + if not child.impl_is_multi(): + raise ValueError(_("not allowed option {0} " + "in group {1}" + ": this option is not a multi" + "").format(child._name, name)) + if child._name == name: + self.master = child + else: + slaves.append(child) + if self.master is None: + raise ValueError(_('master group with wrong' + ' master name for {0}' + ).format(name)) + if self.master._callback is not None and self.master._callback[1] is not None: + for key, callbacks in self.master._callback[1].items(): + for callbk in callbacks: + if isinstance(callbk, tuple): + if callbk[0] in slaves: + raise ValueError(_("callback of master's option shall " + "not refered a slave's ones")) + #everything is ok, store references + self.slaves = tuple(slaves) + for child in childs: + child._master_slaves = self + + def is_master(self, opt): + return opt == self.master + + def in_same_group(self, opt): + return opt == self.master or opt in self.slaves + + def reset(self, values): + for slave in self.slaves: + values.reset(slave) + + def pop(self, values, index): + #FIXME pas test de meta ... + for slave in self.slaves: + if not values.is_default_owner(slave, validate_properties=False, + validate_meta=False): + values._get_cached_item(slave, validate=False, + validate_properties=False + ).pop(index, force=True) + pass + + def getitem(self, values, opt, path, validate, force_permissive, + force_properties, validate_properties): + if opt == self.master: + value = values._get_validated_value(opt, path, validate, + force_permissive, + force_properties, + validate_properties) + if validate is True: + masterlen = len(value) + for slave in self.slaves: + try: + slave_path = values._get_opt_path(slave) + slave_value = values._get_validated_value(slave, + slave_path, + False, + False, + None, False, + None) # not undefined + slavelen = len(slave_value) + self.validate_slave_length(masterlen, slavelen, slave._name) + except ConfigError: + pass + return value + else: + value = values._get_validated_value(opt, path, validate, + force_permissive, + force_properties, + validate_properties, + None) # not undefined + return self.get_slave_value(values, opt, value, validate, validate_properties) + + def setitem(self, values, opt, value, path): + if opt == self.master: + masterlen = len(value) + for slave in self.slaves: + slave_path = values._get_opt_path(slave) + slave_value = values._get_validated_value(slave, + slave_path, + False, + False, + None, False, + None) # not undefined + slavelen = len(slave_value) + self.validate_slave_length(masterlen, slavelen, slave._name) + else: + self.validate_slave_length(self.get_length(values), len(value), + opt._name, setitem=True) + + def get_length(self, values, validate=True): + masterp = values._get_opt_path(self.master) + return len(self.getitem(values, self.master, masterp, validate, False, + None, True)) + + def validate_slave_length(self, masterlen, valuelen, name, setitem=False): + if valuelen > masterlen or (valuelen < masterlen and setitem): + log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, ' + 'setitem: {2}'.format(masterlen, valuelen, setitem)) + raise SlaveError(_("invalid len for the slave: {0}" + " which has {1} as master").format( + name, self.master._name)) + + def get_slave_value(self, values, opt, value, validate=True, + validate_properties=True): + """ + if master has length 0: + return [] + if master has length bigger than 0: + if default owner: + if has callback: + if return a list: + list same length as master: return list + list is smaller than master: return list + None + list is greater than master: raise SlaveError + if has default value: + list same length as master: return list + list is smaller than master: return list + None + list is greater than master: raise SlaveError + if has default_multi value: + return default_multi * master's length + if has value: + list same length as master: return list + list is smaller than master: return list + None + list is greater than master: raise SlaveError + """ + #if slave, had values until master's one + masterlen = self.get_length(values, validate) + valuelen = len(value) + if validate: + self.validate_slave_length(masterlen, valuelen, opt._name) + path = values._get_opt_path(opt) + if valuelen < masterlen: + for num in range(0, masterlen - valuelen): + index = valuelen + num + value.append(values._get_validated_value(opt, path, True, + False, None, + validate_properties, + index=index), + setitem=False, + force=True) + return value diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py new file mode 100644 index 0000000..8a0cda6 --- /dev/null +++ b/tiramisu/option/option.py @@ -0,0 +1,525 @@ +# -*- coding: utf-8 -*- +"option types and option description" +# Copyright (C) 2012-2013 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +import re +import sys +from IPy import IP + +from tiramisu.error import ConfigError +from tiramisu.i18n import _ +from .baseoption import Option + + +class ChoiceOption(Option): + """represents a choice out of several objects. + + The option can also have the value ``None`` + """ + + __slots__ = ('_values', '_open_values') + _opt_type = 'string' + + def __init__(self, name, doc, values, default=None, default_multi=None, + requires=None, multi=False, callback=None, + callback_params=None, open_values=False, validator=None, + validator_params=None, properties=None, warnings_only=False): + """ + :param values: is a list of values the option can possibly take + """ + if not isinstance(values, tuple): + raise TypeError(_('values must be a tuple for {0}').format(name)) + self._values = values + if open_values not in (True, False): + raise TypeError(_('open_values must be a boolean for ' + '{0}').format(name)) + self._open_values = open_values + super(ChoiceOption, self).__init__(name, doc, default=default, + default_multi=default_multi, + callback=callback, + callback_params=callback_params, + requires=requires, + multi=multi, + validator=validator, + validator_params=validator_params, + properties=properties, + warnings_only=warnings_only) + + def impl_get_values(self): + return self._values + + def impl_is_openvalues(self): + return self._open_values + + def _validate(self, value): + if not self.impl_is_openvalues() and not value in self.impl_get_values(): + raise ValueError(_('value {0} is not permitted, ' + 'only {1} is allowed' + '').format(value, self._values)) + + +class BoolOption(Option): + "represents a choice between ``True`` and ``False``" + __slots__ = tuple() + _opt_type = 'bool' + + def _validate(self, value): + if not isinstance(value, bool): + raise ValueError(_('invalid boolean')) + + +class IntOption(Option): + "represents a choice of an integer" + __slots__ = tuple() + _opt_type = 'int' + + def _validate(self, value): + if not isinstance(value, int): + raise ValueError(_('invalid integer')) + + +class FloatOption(Option): + "represents a choice of a floating point number" + __slots__ = tuple() + _opt_type = 'float' + + def _validate(self, value): + if not isinstance(value, float): + raise ValueError(_('invalid float')) + + +class StrOption(Option): + "represents the choice of a string" + __slots__ = tuple() + _opt_type = 'string' + + def _validate(self, value): + if not isinstance(value, str): + raise ValueError(_('invalid string')) + + +if sys.version_info[0] >= 3: + #UnicodeOption is same as StrOption in python 3+ + class UnicodeOption(StrOption): + __slots__ = tuple() + pass +else: + class UnicodeOption(Option): + "represents the choice of a unicode string" + __slots__ = tuple() + _opt_type = 'unicode' + _empty = u'' + + def _validate(self, value): + if not isinstance(value, unicode): + raise ValueError(_('invalid unicode')) + + +class IPOption(Option): + "represents the choice of an ip" + __slots__ = ('_private_only', '_allow_reserved') + _opt_type = 'ip' + + def __init__(self, name, doc, default=None, default_multi=None, + requires=None, multi=False, callback=None, + callback_params=None, validator=None, validator_params=None, + properties=None, private_only=False, allow_reserved=False, + warnings_only=False): + self._private_only = private_only + self._allow_reserved = allow_reserved + super(IPOption, self).__init__(name, doc, default=default, + default_multi=default_multi, + callback=callback, + callback_params=callback_params, + requires=requires, + multi=multi, + validator=validator, + validator_params=validator_params, + properties=properties, + warnings_only=warnings_only) + + def _validate(self, value): + # sometimes an ip term starts with a zero + # but this does not fit in some case, for example bind does not like it + try: + for val in value.split('.'): + if val.startswith("0") and len(val) > 1: + raise ValueError(_('invalid IP')) + except AttributeError: + #if integer for example + raise ValueError(_('invalid IP')) + # 'standard' validation + try: + IP('{0}/32'.format(value)) + except ValueError: + raise ValueError(_('invalid IP')) + + def _second_level_validation(self, value, warnings_only): + ip = IP('{0}/32'.format(value)) + if not self._allow_reserved and ip.iptype() == 'RESERVED': + if warnings_only: + msg = _("IP is in reserved class") + else: + msg = _("invalid IP, mustn't be in reserved class") + raise ValueError(msg) + if self._private_only and not ip.iptype() == 'PRIVATE': + if warnings_only: + msg = _("IP is not in private class") + else: + msg = _("invalid IP, must be in private class") + raise ValueError(msg) + + def _cons_in_network(self, opts, vals, warnings_only): + if len(vals) != 3: + raise ConfigError(_('invalid len for vals')) + if None in vals: + return + ip, network, netmask = vals + if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): + if warnings_only: + msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}' + ' ({5})') + else: + msg = _('invalid IP {0} ({1}) not in network {2} ({3}) with ' + 'netmask {4} ({5})') + raise ValueError(msg.format(ip, opts[0]._name, network, + opts[1]._name, netmask, opts[2]._name)) + + +class PortOption(Option): + """represents the choice of a port + The port numbers are divided into three ranges: + the well-known ports, + the registered ports, + and the dynamic or private ports. + You can actived this three range. + Port number 0 is reserved and can't be used. + see: http://en.wikipedia.org/wiki/Port_numbers + """ + __slots__ = ('_allow_range', '_allow_zero', '_min_value', '_max_value') + _opt_type = 'port' + + def __init__(self, name, doc, default=None, default_multi=None, + requires=None, multi=False, callback=None, + callback_params=None, validator=None, validator_params=None, + properties=None, allow_range=False, allow_zero=False, + allow_wellknown=True, allow_registred=True, + allow_private=False, warnings_only=False): + self._allow_range = allow_range + self._min_value = None + self._max_value = None + ports_min = [0, 1, 1024, 49152] + ports_max = [0, 1023, 49151, 65535] + is_finally = False + for index, allowed in enumerate([allow_zero, + allow_wellknown, + allow_registred, + allow_private]): + if self._min_value is None: + if allowed: + self._min_value = ports_min[index] + elif not allowed: + is_finally = True + elif allowed and is_finally: + raise ValueError(_('inconsistency in allowed range')) + if allowed: + self._max_value = ports_max[index] + + if self._max_value is None: + raise ValueError(_('max value is empty')) + + super(PortOption, self).__init__(name, doc, default=default, + default_multi=default_multi, + callback=callback, + callback_params=callback_params, + requires=requires, + multi=multi, + validator=validator, + validator_params=validator_params, + properties=properties, + warnings_only=warnings_only) + + def _validate(self, value): + if self._allow_range and ":" in str(value): + value = str(value).split(':') + if len(value) != 2: + raise ValueError(_('invalid port, range must have two values ' + 'only')) + if not value[0] < value[1]: + raise ValueError(_('invalid port, first port in range must be' + ' smaller than the second one')) + else: + value = [value] + + for val in value: + try: + int(val) + except ValueError: + raise ValueError(_('invalid port')) + if not self._min_value <= int(val) <= self._max_value: + raise ValueError(_('invalid port, must be an between {0} ' + 'and {1}').format(self._min_value, + self._max_value)) + + +class NetworkOption(Option): + "represents the choice of a network" + __slots__ = tuple() + _opt_type = 'network' + + def _validate(self, value): + try: + IP(value) + except ValueError: + raise ValueError(_('invalid network address')) + + def _second_level_validation(self, value, warnings_only): + ip = IP(value) + if ip.iptype() == 'RESERVED': + if warnings_only: + msg = _("network address is in reserved class") + else: + msg = _("invalid network address, mustn't be in reserved class") + raise ValueError(msg) + + +class NetmaskOption(Option): + "represents the choice of a netmask" + __slots__ = tuple() + _opt_type = 'netmask' + + def _validate(self, value): + try: + IP('0.0.0.0/{0}'.format(value)) + except ValueError: + raise ValueError(_('invalid netmask address')) + + def _cons_network_netmask(self, opts, vals, warnings_only): + #opts must be (netmask, network) options + if None in vals: + return + self.__cons_netmask(opts, vals[0], vals[1], False, warnings_only) + + def _cons_ip_netmask(self, opts, vals, warnings_only): + #opts must be (netmask, ip) options + if None in vals: + return + self.__cons_netmask(opts, vals[0], vals[1], True, warnings_only) + + def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net, + warnings_only): + if len(opts) != 2: + raise ConfigError(_('invalid len for opts')) + msg = None + try: + ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask), + make_net=make_net) + #if cidr == 32, ip same has network + if ip.prefixlen() != 32: + try: + IP('{0}/{1}'.format(val_ipnetwork, val_netmask), + make_net=not make_net) + except ValueError: + pass + else: + if make_net: + msg = _("invalid IP {0} ({1}) with netmask {2}," + " this IP is a network") + + except ValueError: + if not make_net: + msg = _('invalid network {0} ({1}) with netmask {2}') + if msg is not None: + raise ValueError(msg.format(val_ipnetwork, opts[1]._name, + val_netmask)) + + +class BroadcastOption(Option): + __slots__ = tuple() + _opt_type = 'broadcast' + + def _validate(self, value): + try: + IP('{0}/32'.format(value)) + except ValueError: + raise ValueError(_('invalid broadcast address')) + + def _cons_broadcast(self, opts, vals, warnings_only): + if len(vals) != 3: + raise ConfigError(_('invalid len for vals')) + if None in vals: + return + broadcast, network, netmask = vals + if IP('{0}/{1}'.format(network, netmask)).broadcast() != IP(broadcast): + raise ValueError(_('invalid broadcast {0} ({1}) with network {2} ' + '({3}) and netmask {4} ({5})').format( + broadcast, opts[0]._name, network, + opts[1]._name, netmask, opts[2]._name)) + + +class DomainnameOption(Option): + """represents the choice of a domain name + netbios: for MS domain + hostname: to identify the device + domainname: + fqdn: with tld, not supported yet + """ + __slots__ = ('_type', '_allow_ip', '_allow_without_dot', '_domain_re') + _opt_type = 'domainname' + + def __init__(self, name, doc, default=None, default_multi=None, + requires=None, multi=False, callback=None, + callback_params=None, validator=None, validator_params=None, + properties=None, allow_ip=False, type_='domainname', + warnings_only=False, allow_without_dot=False): + if type_ not in ['netbios', 'hostname', 'domainname']: + raise ValueError(_('unknown type_ {0} for hostname').format(type_)) + self._type = type_ + if allow_ip not in [True, False]: + raise ValueError(_('allow_ip must be a boolean')) + if allow_without_dot not in [True, False]: + raise ValueError(_('allow_without_dot must be a boolean')) + self._allow_ip = allow_ip + self._allow_without_dot = allow_without_dot + end = '' + extrachar = '' + extrachar_mandatory = '' + if self._type != 'netbios': + allow_number = '\d' + else: + allow_number = '' + if self._type == 'netbios': + length = 14 + elif self._type == 'hostname': + length = 62 + elif self._type == 'domainname': + length = 62 + if allow_without_dot is False: + extrachar_mandatory = '\.' + else: + extrachar = '\.' + end = '+[a-z]*' + self._domain_re = re.compile(r'^(?:[a-z{0}][a-z\d\-{1}]{{,{2}}}{3}){4}$' + ''.format(allow_number, extrachar, length, + extrachar_mandatory, end)) + super(DomainnameOption, self).__init__(name, doc, default=default, + default_multi=default_multi, + callback=callback, + callback_params=callback_params, + requires=requires, + multi=multi, + validator=validator, + validator_params=validator_params, + properties=properties, + warnings_only=warnings_only) + + def _validate(self, value): + if self._allow_ip is True: + try: + IP('{0}/32'.format(value)) + return + except ValueError: + pass + if self._type == 'domainname' and not self._allow_without_dot and \ + '.' not in value: + raise ValueError(_("invalid domainname, must have dot")) + if len(value) > 255: + raise ValueError(_("invalid domainname's length (max 255)")) + if len(value) < 2: + raise ValueError(_("invalid domainname's length (min 2)")) + if not self._domain_re.search(value): + raise ValueError(_('invalid domainname')) + + +class EmailOption(DomainnameOption): + __slots__ = tuple() + _opt_type = 'email' + username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$") + + def _validate(self, value): + splitted = value.split('@', 1) + try: + username, domain = splitted + except ValueError: + raise ValueError(_('invalid email address, must contains one @' + )) + if not self.username_re.search(username): + raise ValueError(_('invalid username in email address')) + super(EmailOption, self)._validate(domain) + + +class URLOption(DomainnameOption): + __slots__ = tuple() + _opt_type = 'url' + proto_re = re.compile(r'(http|https)://') + path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$") + + def _validate(self, value): + match = self.proto_re.search(value) + if not match: + raise ValueError(_('invalid url, must start with http:// or ' + 'https://')) + value = value[len(match.group(0)):] + # get domain/files + splitted = value.split('/', 1) + try: + domain, files = splitted + except ValueError: + domain = value + files = None + # if port in domain + splitted = domain.split(':', 1) + try: + domain, port = splitted + + except ValueError: + domain = splitted[0] + port = 0 + if not 0 <= int(port) <= 65535: + raise ValueError(_('invalid url, port must be an between 0 and ' + '65536')) + # validate domainname + super(URLOption, self)._validate(domain) + # validate file + if files is not None and files != '' and not self.path_re.search(files): + raise ValueError(_('invalid url, must ends with filename')) + + +class UsernameOption(Option): + __slots__ = tuple() + _opt_type = 'username' + #regexp build with 'man 8 adduser' informations + username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$") + + def _validate(self, value): + match = self.username_re.search(value) + if not match: + raise ValueError(_('invalid username')) + + +class FilenameOption(Option): + __slots__ = tuple() + _opt_type = 'file' + path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$") + + def _validate(self, value): + match = self.path_re.search(value) + if not match: + raise ValueError(_('invalid filename')) diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py new file mode 100644 index 0000000..8c26f3b --- /dev/null +++ b/tiramisu/option/optiondescription.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2014 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +from copy import copy + +from tiramisu.i18n import _ +from tiramisu.setting import groups, log +from .baseoption import BaseOption +from . import MasterSlaves +from tiramisu.error import ConfigError, ConflictError, ValueWarning + + +class OptionDescription(BaseOption): + """Config's schema (organisation, group) and container of Options + The `OptionsDescription` objects lives in the `tiramisu.config.Config`. + """ + __slots__ = ('_name', '_requires', '_cache_paths', '_group_type', + '_state_group_type', '_properties', '_children', + '_cache_consistencies', '_calc_properties', '__weakref__', + '_readonly', '_impl_informations', '_state_requires', + '_stated', '_state_readonly') + _opt_type = 'optiondescription' + + def __init__(self, name, doc, children, requires=None, properties=None): + """ + :param children: a list of options (including optiondescriptions) + + """ + super(OptionDescription, self).__init__(name, doc, requires, properties) + child_names = [child._name for child in children] + #better performance like this + valid_child = copy(child_names) + valid_child.sort() + old = None + for child in valid_child: + if child == old: + raise ConflictError(_('duplicate option name: ' + '{0}').format(child)) + old = child + self._children = (tuple(child_names), tuple(children)) + self._cache_paths = None + self._cache_consistencies = None + # the group_type is useful for filtering OptionDescriptions in a config + self._group_type = groups.default + + def impl_getdoc(self): + return self.impl_get_information('doc') + + def __getattr__(self, name): + if name in self.__slots__: + return object.__getattribute__(self, name) + try: + return self._children[1][self._children[0].index(name)] + except ValueError: + log.debug('__getattr__', exc_info=True) + raise AttributeError(_('unknown Option {0} ' + 'in OptionDescription {1}' + '').format(name, self._name)) + + def impl_getkey(self, config): + return tuple([child.impl_getkey(getattr(config, child._name)) + for child in self.impl_getchildren()]) + + def impl_getpaths(self, include_groups=False, _currpath=None): + """returns a list of all paths in self, recursively + _currpath should not be provided (helps with recursion) + """ + if _currpath is None: + _currpath = [] + paths = [] + for option in self.impl_getchildren(): + attr = option._name + if isinstance(option, OptionDescription): + if include_groups: + paths.append('.'.join(_currpath + [attr])) + paths += option.impl_getpaths(include_groups=include_groups, + _currpath=_currpath + [attr]) + else: + paths.append('.'.join(_currpath + [attr])) + return paths + + def impl_getchildren(self): + return self._children[1] + + def impl_build_cache(self, + cache_path=None, + cache_option=None, + _currpath=None, + _consistencies=None, + force_no_consistencies=False): + if _currpath is None and self._cache_paths is not None: + # cache already set + return + if _currpath is None: + save = True + _currpath = [] + if not force_no_consistencies: + _consistencies = {} + else: + save = False + if cache_path is None: + cache_path = [] + cache_option = [] + for option in self.impl_getchildren(): + attr = option._name + if option in cache_option: + raise ConflictError(_('duplicate option: {0}').format(option)) + + cache_option.append(option) + if not force_no_consistencies: + option._readonly = True + cache_path.append(str('.'.join(_currpath + [attr]))) + if not isinstance(option, OptionDescription): + if not force_no_consistencies and \ + option._consistencies is not None: + for consistency in option._consistencies: + func, all_cons_opts, params = consistency + for opt in all_cons_opts: + _consistencies.setdefault(opt, + []).append((func, + all_cons_opts, + params)) + else: + _currpath.append(attr) + option.impl_build_cache(cache_path, + cache_option, + _currpath, + _consistencies, + force_no_consistencies) + _currpath.pop() + if save: + self._cache_paths = (tuple(cache_option), tuple(cache_path)) + if not force_no_consistencies: + if _consistencies != {}: + self._cache_consistencies = {} + for opt, cons in _consistencies.items(): + if opt not in cache_option: + raise ConfigError(_('consistency with option {0} which is not in Config').format(opt._name)) + self._cache_consistencies[opt] = tuple(cons) + self._readonly = True + + def impl_get_opt_by_path(self, path): + try: + return self._cache_paths[0][self._cache_paths[1].index(path)] + except ValueError: + raise AttributeError(_('no option for path {0}').format(path)) + + def impl_get_path_by_opt(self, opt): + try: + return self._cache_paths[1][self._cache_paths[0].index(opt)] + except ValueError: + raise AttributeError(_('no option {0} found').format(opt)) + + # ____________________________________________________________ + def impl_set_group_type(self, group_type): + """sets a given group object to an OptionDescription + + :param group_type: an instance of `GroupType` or `MasterGroupType` + that lives in `setting.groups` + """ + if self._group_type != groups.default: + raise TypeError(_('cannot change group_type if already set ' + '(old {0}, new {1})').format(self._group_type, + group_type)) + if isinstance(group_type, groups.GroupType): + self._group_type = group_type + if isinstance(group_type, groups.MasterGroupType): + MasterSlaves(self._name, self.impl_getchildren()) + else: + raise ValueError(_('group_type: {0}' + ' not allowed').format(group_type)) + + def impl_get_group_type(self): + return self._group_type + + def _valid_consistency(self, option, value, context, index): + if self._cache_consistencies is None: + return True + #consistencies is something like [('_cons_not_equal', (opt1, opt2))] + consistencies = self._cache_consistencies.get(option) + if consistencies is not None: + for func, all_cons_opts, params in consistencies: + warnings_only = params.get('warnings_only', False) + #all_cons_opts[0] is the option where func is set + try: + all_cons_opts[0]._launch_consistency(func, option, + value, + context, index, + all_cons_opts, + warnings_only) + except ValueError as err: + if warnings_only: + raise ValueWarning(err.message, option) + else: + raise err + + def _impl_getstate(self, descr=None): + """enables us to export into a dict + :param descr: parent :class:`tiramisu.option.OptionDescription` + """ + if descr is None: + self.impl_build_cache() + descr = self + super(OptionDescription, self)._impl_getstate(descr) + self._state_group_type = str(self._group_type) + for option in self.impl_getchildren(): + option._impl_getstate(descr) + + def __getstate__(self): + """special method to enable the serialization with pickle + """ + stated = True + try: + # the `_state` attribute is a flag that which tells us if + # the serialization can be performed + self._stated + except AttributeError: + # if cannot delete, _impl_getstate never launch + # launch it recursivement + # _stated prevent __getstate__ launch more than one time + # _stated is delete, if re-serialize, re-lauch _impl_getstate + self._impl_getstate() + stated = False + return super(OptionDescription, self).__getstate__(stated) + + def _impl_setstate(self, descr=None): + """enables us to import from a dict + :param descr: parent :class:`tiramisu.option.OptionDescription` + """ + if descr is None: + self._cache_paths = None + self._cache_consistencies = None + self.impl_build_cache(force_no_consistencies=True) + descr = self + self._group_type = getattr(groups, self._state_group_type) + del(self._state_group_type) + super(OptionDescription, self)._impl_setstate(descr) + for option in self.impl_getchildren(): + option._impl_setstate(descr) + + def __setstate__(self, state): + super(OptionDescription, self).__setstate__(state) + try: + self._stated + except AttributeError: + self._impl_setstate() diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 95cee47..ded4108 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -101,6 +101,9 @@ rw_remove = set(['permissive', 'everything_frozen', 'mandatory']) log = getLogger('tiramisu') +#FIXME +#import logging +#logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) # ____________________________________________________________ @@ -211,34 +214,12 @@ def populate_owners(): setattr(owners, 'addowner', addowner) -def populate_multitypes(): - """all multi option should have a type, this type is automaticly set do - not touch this - - default - default's multi option set if not master or slave - - master - master's option in a group with master's type, name of this option - should be the same name of the optiondescription - - slave - slave's option in a group with master's type - - """ - setattr(multitypes, 'default', multitypes.DefaultMultiType('default')) - setattr(multitypes, 'master', multitypes.MasterMultiType('master')) - setattr(multitypes, 'slave', multitypes.SlaveMultiType('slave')) - - # ____________________________________________________________ # populate groups, owners and multitypes with default attributes groups = GroupModule() populate_groups() owners = OwnerModule() populate_owners() -multitypes = MultiTypeModule() -populate_multitypes() # ____________________________________________________________ diff --git a/tiramisu/value.py b/tiramisu/value.py index 87b0acd..47e74b6 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -16,11 +16,10 @@ # along with this program. If not, see . # ____________________________________________________________ from time import time -from copy import copy import sys import weakref from tiramisu.error import ConfigError, SlaveError, PropertiesOptionError -from tiramisu.setting import owners, multitypes, expires_time, undefined +from tiramisu.setting import owners, expires_time, undefined from tiramisu.autolib import carry_out_calculation from tiramisu.i18n import _ from tiramisu.option import SymLinkOption @@ -55,36 +54,65 @@ class Values(object): raise ConfigError(_('the context does not exist anymore')) return context - def _getdefault(self, opt): - """ - actually retrieves the default value - - :param opt: the `option.Option()` object - """ - meta = self._getcontext().cfgimpl_get_meta() - if meta is not None: - value = meta.cfgimpl_get_values()[opt] - if isinstance(value, Multi): - value = list(value) - else: - value = opt.impl_getdefault() - if opt.impl_is_multi(): - return copy(value) - else: - return value - - def _getvalue(self, opt, path): + def _getvalue(self, opt, path, is_default, index=undefined): """actually retrieves the value :param opt: the `option.Option()` object :returns: the option's value (or the default value if not set) """ - if not self._p_.hasvalue(path): - # if there is no value - value = self._getdefault(opt) - else: - # if there is a value + setting = self._getcontext().cfgimpl_get_settings() + force_default = 'frozen' in setting[opt] and \ + 'force_default_on_freeze' in setting[opt] + if not is_default and not force_default: value = self._p_.getvalue(path) + if index is not undefined: + try: + return value[index] + except IndexError: + #value is smaller than expected + #so return default value + pass + else: + return value + #so default value + # if value has callback and is not set + if opt.impl_has_callback(): + callback, callback_params = opt._callback + if callback_params is None: + callback_params = {} + value = carry_out_calculation(opt, config=self._getcontext(), + callback=callback, + callback_params=callback_params, + index=index) + try: + if isinstance(value, list) and index is not undefined: + return value[index] + return value + except IndexError: + pass + meta = self._getcontext().cfgimpl_get_meta() + if meta is not None: + #FIXME : problème de longueur si meta + slave + #doit passer de meta à pas meta + #en plus il faut gérer la longueur avec les meta ! + #FIXME SymlinkOption + value = meta.cfgimpl_get_values()[opt] + if isinstance(value, Multi): + if index is not undefined: + value = value[index] + else: + value = list(value) + return value + # now try to get default value + value = opt.impl_getdefault() + if opt.impl_is_multi() and index is not undefined: + if value is None: + value = opt.impl_getdefault_multi() + else: + try: + value = value[index] + except IndexError: + value = opt.impl_getdefault_multi() return value def get_modified_values(self): @@ -121,44 +149,38 @@ class Values(object): opt.impl_validate(opt.impl_getdefault(), context, 'validator' in setting) context.cfgimpl_reset_cache() - if (opt.impl_is_multi() and - opt.impl_get_multitype() == multitypes.master): - for slave in opt.impl_get_master_slaves(): - self.reset(slave) + if opt.impl_is_master_slaves('master'): + opt.impl_get_master_slaves().reset(self) self._p_.resetvalue(path) def _isempty(self, opt, value): "convenience method to know if an option is empty" empty = opt._empty - if (not opt.impl_is_multi() and (value is None or value == empty)) or \ - (opt.impl_is_multi() and (value == [] or - None in value or empty in value)): - return True - return False - - def _getcallback_value(self, opt, index=None, max_len=None): - """ - retrieves a value for the options that have a callback - - :param opt: the `option.Option()` object - :param index: if an option is multi, only calculates the nth value - :type index: int - :returns: a calculated value - """ - callback, callback_params = opt._callback - if callback_params is None: - callback_params = {} - return carry_out_calculation(opt, config=self._getcontext(), - callback=callback, - callback_params=callback_params, - index=index, max_len=max_len) + if value is not undefined: + empty_not_multi = not opt.impl_is_multi() and (value is None or + value == empty) + empty_multi = opt.impl_is_multi() and (value == [] or + None in value or + empty in value) + else: + empty_multi = empty_not_multi = False + return empty_not_multi or empty_multi def __getitem__(self, opt): "enables us to use the pythonic dictionary-like access to values" return self.getitem(opt) - def getitem(self, opt, path=None, validate=True, force_permissive=False, - force_properties=None, validate_properties=True): + def getitem(self, opt, validate=True, force_permissive=False, + force_properties=None): + """ + """ + return self._get_cached_item(opt, validate=validate, + force_permissive=force_permissive, + force_properties=force_properties) + + def _get_cached_item(self, opt, path=None, validate=True, + force_permissive=False, force_properties=None, + validate_properties=True): if path is None: path = self._get_opt_path(opt) ntime = None @@ -170,7 +192,7 @@ class Values(object): if is_cached: if opt.impl_is_multi() and not isinstance(value, Multi): #load value so don't need to validate if is not a Multi - value = Multi(value, self.context, opt, path, validate=False) + value = Multi(value, self.context, opt, path) return value val = self._getitem(opt, path, validate, force_permissive, force_properties, validate_properties) @@ -181,85 +203,82 @@ class Values(object): ntime = int(time()) ntime = ntime + expires_time self._p_.setcache(path, val, ntime) - return val def _getitem(self, opt, path, validate, force_permissive, force_properties, validate_properties): - # options with callbacks + if opt.impl_is_master_slaves(): + return opt.impl_get_master_slaves().getitem(self, opt, path, + validate, + force_permissive, + force_properties, + validate_properties) + else: + return self._get_validated_value(opt, path, validate, + force_permissive, + force_properties, + validate_properties) + + def _get_validated_value(self, opt, path, validate, force_permissive, + force_properties, validate_properties, + index=undefined): + """same has getitem but don't touch the cache""" + #FIXME expliquer la différence entre index == undefined et index == None context = self._getcontext() setting = context.cfgimpl_get_settings() - is_frozen = 'frozen' in setting[opt] - # For calculating properties, we need value (ie for mandatory value). - # If value is calculating with a PropertiesOptionError's option - # _getcallback_value raise a ConfigError. - # We can not raise ConfigError if this option should raise - # PropertiesOptionError too. So we get config_error and raise - # ConfigError if properties did not raise. - config_error = None - force_permissives = None - # if value has callback and is not set - # or frozen with force_default_on_freeze - if opt.impl_has_callback() and ( - self._is_default_owner(opt, path, validate_properties=False) or - (is_frozen and 'force_default_on_freeze' in setting[opt])): - lenmaster = None - no_value_slave = False - if (opt.impl_is_multi() and - opt.impl_get_multitype() == multitypes.slave): - masterp = self._get_opt_path(opt.impl_get_master_slaves()) - mastervalue = context.getattr(masterp, validate=False) - lenmaster = len(mastervalue) - if lenmaster == 0: - value = [] - no_value_slave = True + is_default = self._is_default_owner(opt, path, + validate_properties=False, + validate_meta=False) + try: + if index is None: + gv_index = undefined + else: + gv_index = index + value = self._getvalue(opt, path, is_default, index=gv_index) + config_error = None + except ConfigError as err: + # For calculating properties, we need value (ie for mandatory + # value). + # If value is calculating with a PropertiesOptionError's option + # _getvalue raise a ConfigError. + # We can not raise ConfigError if this option should raise + # PropertiesOptionError too. So we get config_error and raise + # ConfigError if properties did not raise. + # cannot assign config_err directly in python 3.3 + config_error = err + # value is not set, for 'undefined' (cannot set None because of + # mandatory property) + value = undefined - if not no_value_slave: - try: - value = self._getcallback_value(opt, max_len=lenmaster) - except ConfigError as err: - # cannot assign config_err directly in python 3.3 - config_error = err - value = None - # should not raise PropertiesOptionError if option is - # mandatory - force_permissives = set(['mandatory']) - else: - if (opt.impl_is_multi() and - opt.impl_get_multitype() == multitypes.slave): - if not isinstance(value, list): - value = [value for i in range(lenmaster)] - if config_error is None: - if opt.impl_is_multi(): - value = Multi(value, self.context, opt, path, validate) - # frozen and force default - elif is_frozen and 'force_default_on_freeze' in setting[opt]: - value = self._getdefault(opt) + if config_error is None: + if index is undefined: + force_index = None + else: + force_index = index if opt.impl_is_multi(): - value = Multi(value, self.context, opt, path, validate) - else: - value = self._getvalue(opt, path) - if opt.impl_is_multi(): - # load value so don't need to validate if is not a Multi - value = Multi(value, self.context, opt, path, validate=validate) - if config_error is None and validate: - opt.impl_validate(value, context, 'validator' in setting) - if config_error is None and \ - self._is_default_owner(opt, path, validate_properties=False) and \ - 'force_store_value' in setting[opt]: - self.setitem(opt, value, path, is_write=False, - force_permissive=force_permissive) + if index is None and not isinstance(value, list): + value = [] + if force_index is None: + value = Multi(value, self.context, opt, path) + if validate: + opt.impl_validate(value, context, 'validator' in setting, + force_index=force_index) + #FIXME pas de test avec les metas ... + #FIXME et les symlinkoption ... + if is_default and 'force_store_value' in setting[opt]: + self.setitem(opt, value, path, is_write=False, + force_permissive=force_permissive) if validate_properties: - setting.validate_properties(opt, False, False, value=value, path=path, + setting.validate_properties(opt, False, False, value=value, + path=path, force_permissive=force_permissive, - force_properties=force_properties, - force_permissives=force_permissives) + force_properties=force_properties) if config_error is not None: raise config_error return value def __setitem__(self, opt, value): - raise ValueError('you should only set value with config') + raise ValueError(_('you should only set value with config')) def setitem(self, opt, value, path, force_permissive=False, is_write=True): @@ -270,26 +289,11 @@ class Values(object): opt.impl_validate(value, context, 'validator' in context.cfgimpl_get_settings()) if opt.impl_is_multi(): - value = Multi(value, self.context, opt, path, setitem=True) - # Save old value - if opt.impl_get_multitype() == multitypes.master and \ - self._p_.hasvalue(path): - old_value = self._p_.getvalue(path) - old_owner = self._p_.getowner(path, None) - else: - old_value = undefined - old_owner = undefined + value = Multi(value, self.context, opt, path) + if opt.impl_is_master_slaves(): + opt.impl_get_master_slaves().setitem(self, opt, value, path) self._setvalue(opt, path, value, force_permissive=force_permissive, is_write=is_write) - if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.master: - try: - value._valid_master() - except Exception, err: - if old_value is not undefined: - self._p_.setvalue(path, old_value, old_owner) - else: - self._p_.resetvalue(path) - raise err def _setvalue(self, opt, path, value, force_permissive=False, force_properties=None, @@ -321,13 +325,15 @@ class Values(object): path = self._get_opt_path(opt) return self._getowner(opt, path, force_permissive=force_permissive) - def _getowner(self, opt, path, validate_properties=True, force_permissive=False): - meta = self._getcontext().cfgimpl_get_meta() + def _getowner(self, opt, path, validate_properties=True, + force_permissive=False, validate_meta=True): if validate_properties: self._getitem(opt, path, True, force_permissive, None, True) owner = self._p_.getowner(path, owners.default) - if owner is owners.default and meta is not None: - owner = meta.cfgimpl_get_values()._getowner(opt, path) + if validate_meta: + meta = self._getcontext().cfgimpl_get_meta() + if owner is owners.default and meta is not None: + owner = meta.cfgimpl_get_values()._getowner(opt, path) return owner def setowner(self, opt, owner): @@ -349,17 +355,22 @@ class Values(object): '').format(path, owner)) self._p_.setowner(path, owner) - def is_default_owner(self, opt, validate_properties=True): + def is_default_owner(self, opt, validate_properties=True, + validate_meta=True): """ :param config: *must* be only the **parent** config (not the toplevel config) :return: boolean """ path = self._get_opt_path(opt) - return self._is_default_owner(opt, path, validate_properties) + return self._is_default_owner(opt, path, + validate_properties=validate_properties, + validate_meta=validate_meta) - def _is_default_owner(self, opt, path, validate_properties=True): - return self._getowner(opt, path, validate_properties) == owners.default + def _is_default_owner(self, opt, path, validate_properties=True, + validate_meta=True): + return self._getowner(opt, path, validate_properties, + validate_meta=validate_meta) == owners.default def reset_cache(self, only_expired): """ @@ -377,7 +388,8 @@ class Values(object): :param opt: the `option.Option` object :returns: a string with points like "gc.dummy.my_option" """ - return self._getcontext().cfgimpl_get_description().impl_get_path_by_opt(opt) + return self._getcontext().cfgimpl_get_description( + ).impl_get_path_by_opt(opt) # information def set_information(self, key, value): @@ -457,13 +469,11 @@ class Multi(list): that support item notation for the values of multi options""" __slots__ = ('opt', 'path', 'context') - def __init__(self, value, context, opt, path, validate=True, - setitem=False): + def __init__(self, value, context, opt, path): """ :param value: the Multi wraps a list value :param context: the home config that has the values :param opt: the option object that have this Multi value - :param setitem: only if set a value """ if isinstance(value, Multi): raise ValueError(_('{0} is already a Multi ').format(opt._name)) @@ -474,11 +484,6 @@ class Multi(list): self.context = context if not isinstance(value, list): value = [value] - if validate and self.opt.impl_get_multitype() == multitypes.slave: - value = self._valid_slave(value, setitem) - elif not setitem and validate and \ - self.opt.impl_get_multitype() == multitypes.master: - self._valid_master() super(Multi, self).__init__(value) def _getcontext(self): @@ -492,124 +497,73 @@ class Multi(list): raise ConfigError(_('the context does not exist anymore')) return context - def _valid_slave(self, value, setitem): - #if slave, had values until master's one - context = self._getcontext() - values = context.cfgimpl_get_values() - masterp = context.cfgimpl_get_description().impl_get_path_by_opt( - self.opt.impl_get_master_slaves()) - mastervalue = context.getattr(masterp, validate=False) - masterlen = len(mastervalue) - valuelen = len(value) - if valuelen > masterlen or (valuelen < masterlen and setitem): - raise SlaveError(_("invalid len for the slave: {0}" - " which has {1} as master").format( - self.opt._name, masterp)) - elif valuelen < masterlen: - for num in range(0, masterlen - valuelen): - if self.opt.impl_has_callback(): - # if callback add a value, but this value will not change - # anymore automaticly (because this value has owner) - index = value.__len__() - value.append(values._getcallback_value(self.opt, - index=index)) - else: - value.append(self.opt.impl_getdefault_multi()) - #else: same len so do nothing - return value - - def _valid_master(self): - #masterlen = len(value) - values = self._getcontext().cfgimpl_get_values() - for slave in self.opt._master_slaves: - path = values._get_opt_path(slave) - Multi(values._getvalue(slave, path), self.context, slave, path) - def __setitem__(self, index, value): self._validate(value, index) #assume not checking mandatory property super(Multi, self).__setitem__(index, value) - self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self) + self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, + self) - def append(self, value=undefined, force=False): + def append(self, value=undefined, force=False, setitem=True): """the list value can be updated (appened) only if the option is a master """ - context = self._getcontext() + values = self._getcontext().cfgimpl_get_values() if not force: - if self.opt.impl_get_multitype() == multitypes.slave: + if self.opt.impl_is_master_slaves('slave'): raise SlaveError(_("cannot append a value on a multi option {0}" " which is a slave").format(self.opt._name)) - elif self.opt.impl_get_multitype() == multitypes.master: - values = context.cfgimpl_get_values() - if value is undefined and self.opt.impl_has_callback(): - value = values._getcallback_value(self.opt) - #Force None il return a list - if isinstance(value, list): - value = None index = self.__len__() if value is undefined: - value = self.opt.impl_getdefault_multi() + try: + value = values._get_validated_value(self.opt, self.path, + True, False, None, True, + index=index) + except IndexError: + value = None self._validate(value, index) super(Multi, self).append(value) - context.cfgimpl_get_values()._setvalue(self.opt, self.path, - self, - validate_properties=not force) - if not force and self.opt.impl_get_multitype() == multitypes.master: - for slave in self.opt.impl_get_master_slaves(): - path = values._get_opt_path(slave) - if not values._is_default_owner(slave, path, - validate_properties=False): - if slave.impl_has_callback(): - dvalue = values._getcallback_value(slave, index=index) - else: - dvalue = slave.impl_getdefault_multi() - old_value = values.getitem(slave, path, validate=False, - validate_properties=False) - if len(old_value) + 1 != self.__len__(): - raise SlaveError(_("invalid len for the slave: {0}" - " which has {1} as master").format( - self.opt._name, self.__len__())) - values.getitem(slave, path, validate=False, - validate_properties=False).append( - dvalue, force=True) + if setitem: + values._setvalue(self.opt, self.path, self, + validate_properties=not force) def sort(self, cmp=None, key=None, reverse=False): - if self.opt.impl_get_multitype() in [multitypes.slave, - multitypes.master]: + if self.opt.impl_is_master_slaves(): raise SlaveError(_("cannot sort multi option {0} if master or slave" "").format(self.opt._name)) if sys.version_info[0] >= 3: if cmp is not None: - raise ValueError(_('cmp is not permitted in python v3 or greater')) + raise ValueError(_('cmp is not permitted in python v3 or ' + 'greater')) super(Multi, self).sort(key=key, reverse=reverse) else: super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse) - self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self) + self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, + self) def reverse(self): - if self.opt.impl_get_multitype() in [multitypes.slave, - multitypes.master]: + if self.opt.impl_is_master_slaves(): raise SlaveError(_("cannot reverse multi option {0} if master or " "slave").format(self.opt._name)) super(Multi, self).reverse() - self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self) + self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, + self) def insert(self, index, obj): - if self.opt.impl_get_multitype() in [multitypes.slave, - multitypes.master]: + if self.opt.impl_is_master_slaves(): raise SlaveError(_("cannot insert multi option {0} if master or " "slave").format(self.opt._name)) super(Multi, self).insert(index, obj) - self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self) + self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, + self) def extend(self, iterable): - if self.opt.impl_get_multitype() in [multitypes.slave, - multitypes.master]: + if self.opt.impl_is_master_slaves(): raise SlaveError(_("cannot extend multi option {0} if master or " "slave").format(self.opt._name)) super(Multi, self).extend(iterable) - self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self) + self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, + self) def _validate(self, value, force_index): if value is not None: @@ -634,18 +588,14 @@ class Multi(list): """ context = self._getcontext() if not force: - if self.opt.impl_get_multitype() == multitypes.slave: + if self.opt.impl_is_master_slaves('slave'): raise SlaveError(_("cannot pop a value on a multi option {0}" " which is a slave").format(self.opt._name)) - if self.opt.impl_get_multitype() == multitypes.master: - for slave in self.opt.impl_get_master_slaves(): - values = context.cfgimpl_get_values() - if not values.is_default_owner(slave, validate_properties=False): - #get multi without valid properties - values.getitem(slave, validate=False, - validate_properties=False - ).pop(index, force=True) + if self.opt.impl_is_master_slaves('master'): + self.opt.impl_get_master_slaves().pop( + context.cfgimpl_get_values(), index) #set value without valid properties ret = super(Multi, self).pop(index) - context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force) + context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, + validate_properties=not force) return ret From 3ab0688c46cbe82514199a09c0233db0c762ac20 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 12 Apr 2014 21:37:20 +0200 Subject: [PATCH 41/42] Arity change, remove force_properties: * tiramisu/config.py (in cfgimpl_get_home_by_path and getattr) * tiramisu/value.py (in getitem): --- ChangeLog | 10 ++++++---- test/test_mandatory.py | 21 +++++++++++++-------- tiramisu/config.py | 24 +++++++----------------- tiramisu/value.py | 40 ++++++++++++++++++++++------------------ 4 files changed, 48 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index 23913bc..8cb44d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,12 @@ Sat Apr 12 11:37:27 CEST 2014 Emmanuel Garette * behavior change in master/slave part of code: - if slave has a default value greater than master's one, it's raise - SlaveError, didn't try to reduce the slave's length + if slave has a default value greater than master's one, it's raise + SlaveError, didn't try to reduce the slave's length + * tiramisu/config.py (in cfgimpl_get_home_by_path and getattr) and + tiramisu/value.py (in getitem): arity change, remove force_properties * tiramisu/option.py: split into tiramisu/option directory * tiramisu/option/masterslave.py: master/slaves have no a special - object MasterSlaves for all code related to master/slaves options + object MasterSlaves for all code related to master/slaves options * tiramisu/option/masterslave.py: master and slaves values (length, - consistency, ...) are now check every time + consistency, ...) are now check every time diff --git a/test/test_mandatory.py b/test/test_mandatory.py index 26c8e4b..59da145 100644 --- a/test/test_mandatory.py +++ b/test/test_mandatory.py @@ -1,4 +1,5 @@ import autopath +from time import sleep #from py.test import raises from tiramisu.config import Config @@ -205,11 +206,12 @@ def test_mandatory_warnings_ro(): except PropertiesOptionError as err: proc = err.proptype assert proc == ['mandatory'] - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] config.read_write() config.str = 'a' config.read_only() - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3'] + sleep(.1) def test_mandatory_warnings_rw(): @@ -218,9 +220,10 @@ def test_mandatory_warnings_rw(): config.str = '' config.read_write() config.str - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] config.str = 'a' - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3'] + sleep(.1) def test_mandatory_warnings_disabled(): @@ -230,9 +233,10 @@ def test_mandatory_warnings_disabled(): setting = config.cfgimpl_get_settings() config.read_write() config.str - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('disabled') - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str1', 'unicode2', 'str3'] + sleep(.1) def test_mandatory_warnings_frozen(): @@ -242,7 +246,8 @@ def test_mandatory_warnings_frozen(): setting = config.cfgimpl_get_settings() config.read_write() config.str - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] setting[descr.str].append('frozen') config.read_only() - assert list(config.cfgimpl_get_values().mandatory_warnings()) == ['str', 'str1', 'unicode2', 'str3'] + assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3'] + sleep(.1) diff --git a/tiramisu/config.py b/tiramisu/config.py index 04c9cb9..b6e919b 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -62,14 +62,12 @@ class SubConfig(object): "remove cache (in context)" self._cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only) - def cfgimpl_get_home_by_path(self, path, force_permissive=False, - force_properties=None): + def cfgimpl_get_home_by_path(self, path, force_permissive=False): """:returns: tuple (config, name)""" path = path.split('.') for step in path[:-1]: self = self.getattr(step, - force_permissive=force_permissive, - force_properties=force_properties) + force_permissive=force_permissive) return self, path[-1] def __hash__(self): @@ -214,29 +212,24 @@ class SubConfig(object): def __getattr__(self, name): return self.getattr(name) - def _getattr(self, name, force_permissive=False, force_properties=None, - validate=True): + def _getattr(self, name, force_permissive=False, validate=True): """use getattr instead of _getattr """ - return self.getattr(name, force_permissive, force_properties, validate) + return self.getattr(name, force_permissive, validate) - def getattr(self, name, force_permissive=False, force_properties=None, - validate=True): + def getattr(self, name, force_permissive=False, validate=True): """ attribute notation mechanism for accessing the value of an option :param name: attribute name :return: option's value if name is an option name, OptionDescription otherwise """ - #FIXME force_properties vraiment utile maintenant ? # attribute access by passing a path, # for instance getattr(self, "creole.general.family.adresse_ip_eth0") if '.' in name: homeconfig, name = self.cfgimpl_get_home_by_path( - name, force_permissive=force_permissive, - force_properties=force_properties) + name, force_permissive=force_permissive) return homeconfig.getattr(name, force_permissive=force_permissive, - force_properties=force_properties, validate=validate) opt_or_descr = getattr(self.cfgimpl_get_description(), name) if self._impl_path is None: @@ -251,19 +244,16 @@ class SubConfig(object): path = context.cfgimpl_get_description().impl_get_path_by_opt( opt_or_descr._opt) return context.getattr(path, validate=validate, - force_properties=force_properties, force_permissive=force_permissive) elif isinstance(opt_or_descr, OptionDescription): self.cfgimpl_get_settings().validate_properties( opt_or_descr, True, False, path=subpath, - force_permissive=force_permissive, - force_properties=force_properties) + force_permissive=force_permissive) return SubConfig(opt_or_descr, self._impl_context, subpath) else: return self.cfgimpl_get_values()._get_cached_item( opt_or_descr, path=subpath, validate=validate, - force_properties=force_properties, force_permissive=force_permissive) def find(self, bytype=None, byname=None, byvalue=None, type_='option', diff --git a/tiramisu/value.py b/tiramisu/value.py index 47e74b6..9b954a5 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -22,7 +22,7 @@ from tiramisu.error import ConfigError, SlaveError, PropertiesOptionError from tiramisu.setting import owners, expires_time, undefined from tiramisu.autolib import carry_out_calculation from tiramisu.i18n import _ -from tiramisu.option import SymLinkOption +from tiramisu.option import SymLinkOption, OptionDescription class Values(object): @@ -170,13 +170,11 @@ class Values(object): "enables us to use the pythonic dictionary-like access to values" return self.getitem(opt) - def getitem(self, opt, validate=True, force_permissive=False, - force_properties=None): + def getitem(self, opt, validate=True, force_permissive=False): """ """ return self._get_cached_item(opt, validate=validate, - force_permissive=force_permissive, - force_properties=force_properties) + force_permissive=force_permissive) def _get_cached_item(self, opt, path=None, validate=True, force_permissive=False, force_properties=None, @@ -296,7 +294,6 @@ class Values(object): is_write=is_write) def _setvalue(self, opt, path, value, force_permissive=False, - force_properties=None, is_write=True, validate_properties=True): context = self._getcontext() context.cfgimpl_reset_cache() @@ -304,8 +301,7 @@ class Values(object): setting = context.cfgimpl_get_settings() setting.validate_properties(opt, False, is_write, value=value, path=path, - force_permissive=force_permissive, - force_properties=force_properties) + force_permissive=force_permissive) owner = context.cfgimpl_get_settings().getowner() if isinstance(value, Multi): value = list(value) @@ -421,18 +417,26 @@ class Values(object): :returns: generator of mandatory Option's path """ - #if value in cache, properties are not calculated + def _mandatory_warnings(description): + #if value in cache, properties are not calculated + for opt in description.impl_getchildren(): + if isinstance(opt, OptionDescription): + _mandatory_warnings(opt) + elif isinstance(opt, SymLinkOption): + pass + else: + path = self._get_opt_path(opt) + try: + self._get_cached_item(opt, path=path, + force_properties=frozenset(('mandatory',))) + except PropertiesOptionError as err: + if err.proptype == ['mandatory']: + yield path self.reset_cache(False) - context = self.context() - for path in context.cfgimpl_get_description().impl_getpaths( - include_groups=True): - try: - context.getattr(path, - force_properties=frozenset(('mandatory',))) - except PropertiesOptionError as err: - if err.proptype == ['mandatory']: - yield path + descr = self._getcontext().cfgimpl_get_description() + ret = list(_mandatory_warnings(descr)) self.reset_cache(False) + return ret def force_cache(self): """parse all option to force data in cache From aa0734591d171bd166a526ba9e2969f2a958a216 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 12 Apr 2014 21:55:22 +0200 Subject: [PATCH 42/42] change None to undefined when it's needed --- ChangeLog | 1 + tiramisu/config.py | 24 ++++++++++++------------ tiramisu/option/baseoption.py | 6 +++--- tiramisu/value.py | 4 ++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8cb44d7..e89d792 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,3 +10,4 @@ Sat Apr 12 11:37:27 CEST 2014 Emmanuel Garette object MasterSlaves for all code related to master/slaves options * tiramisu/option/masterslave.py: master and slaves values (length, consistency, ...) are now check every time + * change None to undefined when needed diff --git a/tiramisu/config.py b/tiramisu/config.py index b6e919b..b31e9d1 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -22,7 +22,7 @@ import weakref from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.option import OptionDescription, Option, SymLinkOption -from tiramisu.setting import groups, Settings, default_encoding +from tiramisu.setting import groups, Settings, default_encoding, undefined from tiramisu.storage import get_storages, get_storage, set_storage, \ _impl_getstate_setting from tiramisu.value import Values, Multi @@ -256,7 +256,7 @@ class SubConfig(object): validate=validate, force_permissive=force_permissive) - def find(self, bytype=None, byname=None, byvalue=None, type_='option', + def find(self, bytype=None, byname=None, byvalue=undefined, type_='option', check_properties=True, force_permissive=False): """ finds a list of options recursively in the config @@ -273,7 +273,7 @@ class SubConfig(object): check_properties=check_properties, force_permissive=force_permissive) - def find_first(self, bytype=None, byname=None, byvalue=None, + def find_first(self, bytype=None, byname=None, byvalue=undefined, type_='option', display_error=True, check_properties=True, force_permissive=False): """ @@ -306,7 +306,7 @@ class SubConfig(object): return False def _filter_by_value(): - if byvalue is None: + if byvalue is undefined: return True try: value = self.getattr(path, force_permissive=force_permissive) @@ -344,7 +344,7 @@ class SubConfig(object): if not _filter_by_type(): continue #remove option with propertyerror, ... - if byvalue is None and check_properties: + if byvalue is undefined and check_properties: try: value = self.getattr(path, force_permissive=force_permissive) @@ -375,7 +375,7 @@ class SubConfig(object): return find_results def make_dict(self, flatten=False, _currpath=None, withoption=None, - withvalue=None, force_permissive=False): + withvalue=undefined, force_permissive=False): """exports the whole config into a `dict`, for example: >>> print cfg.make_dict() @@ -415,7 +415,7 @@ class SubConfig(object): pathsvalues = [] if _currpath is None: _currpath = [] - if withoption is None and withvalue is not None: + if withoption is None and withvalue is not undefined: raise ValueError(_("make_dict can't filtering with value without " "option")) if withoption is not None: @@ -433,7 +433,7 @@ class SubConfig(object): if mypath is not None: if mypath == path: withoption = None - withvalue = None + withvalue = undefined break else: tmypath = mypath + '.' @@ -535,7 +535,7 @@ class _CommonConfig(SubConfig): """ self._impl_values.set_information(key, value) - def impl_get_information(self, key, default=None): + def impl_get_information(self, key, default=undefined): """retrieves one information's item :param key: the item string (ex: "help") @@ -661,7 +661,7 @@ class GroupConfig(_CommonConfig): except PropertiesOptionError: pass - def find_firsts(self, byname=None, bypath=None, byvalue=None, + def find_firsts(self, byname=None, bypath=None, byvalue=undefined, type_='path', display_error=True): """Find first not in current GroupConfig, but in each children """ @@ -671,7 +671,7 @@ class GroupConfig(_CommonConfig): try: if bypath is None and byname is not None and \ isinstance(self, MetaConfig): - bypath = self._find(bytype=None, byvalue=None, byname=byname, + bypath = self._find(bytype=None, byvalue=undefined, byname=byname, first=True, type_='path', check_properties=False, display_error=display_error) @@ -684,7 +684,7 @@ class GroupConfig(_CommonConfig): if bypath is not None: #if byvalue is None, try if not raise value = getattr(child, bypath) - if byvalue is not None: + if byvalue is not undefined: if isinstance(value, Multi): if byvalue in value: ret.append(child) diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 1e62e8f..68cd189 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -24,7 +24,7 @@ from types import FunctionType import warnings from tiramisu.i18n import _ -from tiramisu.setting import log +from tiramisu.setting import log, undefined from tiramisu.autolib import carry_out_calculation from tiramisu.error import ConfigError, ValueWarning @@ -164,14 +164,14 @@ class BaseOption(object): """ self._impl_informations[key] = value - def impl_get_information(self, key, default=None): + def impl_get_information(self, key, default=undefined): """retrieves one information's item :param key: the item string (ex: "help") """ if key in self._impl_informations: return self._impl_informations[key] - elif default is not None: + elif default is not undefined: return default else: raise ValueError(_("information's item not found: {0}").format( diff --git a/tiramisu/value.py b/tiramisu/value.py index 9b954a5..7e89e2c 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -396,7 +396,7 @@ class Values(object): """ self._p_.set_information(key, value) - def get_information(self, key, default=None): + def get_information(self, key, default=undefined): """retrieves one information's item :param key: the item string (ex: "help") @@ -404,7 +404,7 @@ class Values(object): try: return self._p_.get_information(key) except ValueError: - if default is not None: + if default is not undefined: return default else: raise ValueError(_("information's item"