mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 22:50:18 +00:00
Revendor packages and update patches
This commit is contained in:
@@ -1,7 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright 2017 Kenneth Reitz
|
||||
Copyright 2019 Matthew Peveler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,14 @@
|
||||
Copyright (C) 2008-2011 INADA Naoki <songofacandy@gmail.com>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
Copyright (c) 2012 by Simon Sapin.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -0,0 +1,23 @@
|
||||
Copyright (c) Donald Stufft and individual contributors.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,80 @@
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright (c) 2013-2018, Kim Davies. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
#. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
#. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided with
|
||||
the distribution.
|
||||
|
||||
#. Neither the name of the copyright holder nor the names of the
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
#. THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
|
||||
Portions of the codec implementation and unit tests are derived from the
|
||||
Python standard library, which carries the `Python Software Foundation
|
||||
License <https://docs.python.org/2/license.html>`_:
|
||||
|
||||
Copyright (c) 2001-2014 Python Software Foundation; All Rights Reserved
|
||||
|
||||
Portions of the unit tests are derived from the Unicode standard, which
|
||||
is subject to the Unicode, Inc. License Agreement:
|
||||
|
||||
Copyright (c) 1991-2014 Unicode, Inc. All rights reserved.
|
||||
Distributed under the Terms of Use in
|
||||
<http://www.unicode.org/copyright.html>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Unicode data files and any associated documentation
|
||||
(the "Data Files") or Unicode software and any associated documentation
|
||||
(the "Software") to deal in the Data Files or Software
|
||||
without restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
the Data Files or Software, and to permit persons to whom the Data Files
|
||||
or Software are furnished to do so, provided that
|
||||
|
||||
(a) this copyright and permission notice appear with all copies
|
||||
of the Data Files or Software,
|
||||
|
||||
(b) this copyright and permission notice appear in associated
|
||||
documentation, and
|
||||
|
||||
(c) there is clear notice in each modified Data File or in the Software
|
||||
as well as in the documentation associated with the Data File(s) or
|
||||
Software that the data or software has been modified.
|
||||
|
||||
THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder
|
||||
shall not be used in advertising or otherwise to promote the sale,
|
||||
use or other dealings in these Data Files or Software without prior
|
||||
written authorization of the copyright holder.
|
||||
@@ -1,20 +1,21 @@
|
||||
Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file)
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
Copyright (c) 2008-2019 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# This is the MIT license
|
||||
|
||||
Copyright (c) 2010 ActiveState Software Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,18 @@
|
||||
Copyright (c) 2010-2020 Benjamin Peterson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -141,13 +141,13 @@ def _requirement_to_str_lowercase_name(requirement):
|
||||
Formats a packaging.requirements.Requirement with a lowercase name.
|
||||
|
||||
This is simply a copy of
|
||||
https://github.com/pypa/pipenv/patched/packaging/blob/pipenv/patched/16.8/packaging/requirements.py#L109-L124
|
||||
https://github.com/pypa/pipenv/patched/pipenv/patched/packaging/blob/pipenv/patched/pipenv/patched/16.8/packaging/requirements.py#L109-L124
|
||||
modified to lowercase the dependency name.
|
||||
|
||||
Previously, we were invoking the original Requirement.__str__ method and
|
||||
lowercasing the entire result, which would lowercase the name, *and* other,
|
||||
important stuff that should not be lowercased (such as the marker). See
|
||||
this issue for more information: https://github.com/pypa/pipenv/patched/pipenv/issues/2113.
|
||||
this issue for more information: https://github.com/pypa/pipenv/patched/pipenv/patched/pipenv/issues/2113.
|
||||
"""
|
||||
parts = [requirement.name.lower()]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017-2020 Ingy döt Net
|
||||
Copyright (c) 2017-2021 Ingy döt Net
|
||||
Copyright (c) 2006-2016 Kirill Simonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
||||
@@ -8,7 +8,7 @@ from nodes import *
|
||||
from loader import *
|
||||
from dumper import *
|
||||
|
||||
__version__ = '5.3.1'
|
||||
__version__ = '5.4'
|
||||
|
||||
try:
|
||||
from cyaml import *
|
||||
|
||||
@@ -38,6 +38,12 @@ class timezone(datetime.tzinfo):
|
||||
def dst(self, dt=None):
|
||||
return datetime.timedelta(0)
|
||||
|
||||
def __copy__(self):
|
||||
return self.__deepcopy__()
|
||||
|
||||
def __deepcopy__(self, memodict={}):
|
||||
return self.__class__(self.utcoffset())
|
||||
|
||||
__repr__ = __str__ = tzname
|
||||
|
||||
|
||||
@@ -722,18 +728,6 @@ FullConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/name:',
|
||||
FullConstructor.construct_python_name)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/module:',
|
||||
FullConstructor.construct_python_module)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/object:',
|
||||
FullConstructor.construct_python_object)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/object/new:',
|
||||
FullConstructor.construct_python_object_new)
|
||||
|
||||
class UnsafeConstructor(FullConstructor):
|
||||
|
||||
def find_python_module(self, name, mark):
|
||||
@@ -750,6 +744,18 @@ class UnsafeConstructor(FullConstructor):
|
||||
return super(UnsafeConstructor, self).set_python_instance_state(
|
||||
instance, state, unsafe=True)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/module:',
|
||||
UnsafeConstructor.construct_python_module)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/object:',
|
||||
UnsafeConstructor.construct_python_object)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/object/new:',
|
||||
UnsafeConstructor.construct_python_object_new)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
u'tag:yaml.org,2002:python/object/apply:',
|
||||
UnsafeConstructor.construct_python_object_apply)
|
||||
|
||||
@@ -4,7 +4,7 @@ __all__ = [
|
||||
'CBaseDumper', 'CSafeDumper', 'CDumper'
|
||||
]
|
||||
|
||||
from _yaml import CParser, CEmitter
|
||||
from yaml._yaml import CParser, CEmitter
|
||||
|
||||
from constructor import *
|
||||
|
||||
|
||||
@@ -137,9 +137,14 @@ class Reader(object):
|
||||
self.update(1)
|
||||
|
||||
if has_ucs4:
|
||||
NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]')
|
||||
NON_PRINTABLE = u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]'
|
||||
elif sys.platform.startswith('java'):
|
||||
# Jython doesn't support lone surrogates https://bugs.jython.org/issue2048
|
||||
NON_PRINTABLE = u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD]'
|
||||
else:
|
||||
NON_PRINTABLE = re.compile(u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uFFFD]|(?:^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?:[^\uDC00-\uDFFF]|$)')
|
||||
# Need to use eval here due to the above Jython issue
|
||||
NON_PRINTABLE = eval(r"u'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uFFFD]|(?:^|[^\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uD800-\uDBFF](?:[^\uDC00-\uDFFF]|$)'")
|
||||
NON_PRINTABLE = re.compile(NON_PRINTABLE)
|
||||
def check_printable(self, data):
|
||||
match = self.NON_PRINTABLE.search(data)
|
||||
if match:
|
||||
|
||||
@@ -146,8 +146,8 @@ class BaseResolver(object):
|
||||
resolvers = self.yaml_implicit_resolvers.get(u'', [])
|
||||
else:
|
||||
resolvers = self.yaml_implicit_resolvers.get(value[0], [])
|
||||
resolvers += self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers:
|
||||
wildcard_resolvers = self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers + wildcard_resolvers:
|
||||
if regexp.match(value):
|
||||
return tag
|
||||
implicit = implicit[1]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017-2020 Ingy döt Net
|
||||
Copyright (c) 2017-2021 Ingy döt Net
|
||||
Copyright (c) 2006-2016 Kirill Simonov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
||||
@@ -8,7 +8,7 @@ from .nodes import *
|
||||
from .loader import *
|
||||
from .dumper import *
|
||||
|
||||
__version__ = '5.3.1'
|
||||
__version__ = '5.4'
|
||||
try:
|
||||
from .cyaml import *
|
||||
__with_libyaml__ = True
|
||||
|
||||
@@ -710,18 +710,6 @@ FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/name:',
|
||||
FullConstructor.construct_python_name)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/module:',
|
||||
FullConstructor.construct_python_module)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object:',
|
||||
FullConstructor.construct_python_object)
|
||||
|
||||
FullConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object/new:',
|
||||
FullConstructor.construct_python_object_new)
|
||||
|
||||
class UnsafeConstructor(FullConstructor):
|
||||
|
||||
def find_python_module(self, name, mark):
|
||||
@@ -738,6 +726,18 @@ class UnsafeConstructor(FullConstructor):
|
||||
return super(UnsafeConstructor, self).set_python_instance_state(
|
||||
instance, state, unsafe=True)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/module:',
|
||||
UnsafeConstructor.construct_python_module)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object:',
|
||||
UnsafeConstructor.construct_python_object)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object/new:',
|
||||
UnsafeConstructor.construct_python_object_new)
|
||||
|
||||
UnsafeConstructor.add_multi_constructor(
|
||||
'tag:yaml.org,2002:python/object/apply:',
|
||||
UnsafeConstructor.construct_python_object_apply)
|
||||
|
||||
@@ -4,7 +4,7 @@ __all__ = [
|
||||
'CBaseDumper', 'CSafeDumper', 'CDumper'
|
||||
]
|
||||
|
||||
from _yaml import CParser, CEmitter
|
||||
from yaml._yaml import CParser, CEmitter
|
||||
|
||||
from .constructor import *
|
||||
|
||||
|
||||
@@ -146,8 +146,8 @@ class BaseResolver:
|
||||
resolvers = self.yaml_implicit_resolvers.get('', [])
|
||||
else:
|
||||
resolvers = self.yaml_implicit_resolvers.get(value[0], [])
|
||||
resolvers += self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers:
|
||||
wildcard_resolvers = self.yaml_implicit_resolvers.get(None, [])
|
||||
for tag, regexp in resolvers + wildcard_resolvers:
|
||||
if regexp.match(value):
|
||||
return tag
|
||||
implicit = implicit[1]
|
||||
|
||||
Vendored
+237
@@ -0,0 +1,237 @@
|
||||
Release History
|
||||
===============
|
||||
|
||||
2.0.0 / 2021-05-25
|
||||
------------------
|
||||
|
||||
* Drop Python 2.7 and 3.5 support
|
||||
* Make ``termcolor`` an external dependency
|
||||
* Run CI tests under Ubuntu 20.04
|
||||
* Update dependencies
|
||||
|
||||
|
||||
1.5.0 / 2021-03-21
|
||||
------------------
|
||||
|
||||
* Update cli-spinners to ``v2.6.0``
|
||||
* Update dependencies
|
||||
|
||||
|
||||
1.4.1 / 2021-02-28
|
||||
------------------
|
||||
|
||||
* Fix timer round-up behavior (#118)
|
||||
|
||||
|
||||
1.4.0 / 2021-02-21
|
||||
------------------
|
||||
|
||||
* Add spinner timer (#99, #108)
|
||||
* fix(#107): use ``poetry_core`` as build backend
|
||||
* fix(#34): allow ``write()`` to print non-string objects
|
||||
* Update dependencies
|
||||
|
||||
|
||||
1.3.0 / 2021-01-17
|
||||
------------------
|
||||
|
||||
* Optimization: wait of stop event instead of sleep
|
||||
* Update dependencies
|
||||
|
||||
|
||||
1.2.0 / 2020-10-19
|
||||
------------------
|
||||
|
||||
* Update cli-spinners to ``v2.5.0``
|
||||
* Add support for Python 3.9
|
||||
|
||||
|
||||
1.1.0 / 2020-10-04
|
||||
------------------
|
||||
|
||||
* Add ``hidden()`` context manager #68
|
||||
* fix(#70): ``hidden()`` exceptions handling
|
||||
* Replace coveralls.io with codecov.io
|
||||
* Update dependencies
|
||||
|
||||
|
||||
1.0.0 / 2020-08-02
|
||||
------------------
|
||||
|
||||
* "Stabilize" yaspin; ``1.*`` branch will contain stable release with Python 2
|
||||
support. Drop Python 2 and switch to Python 3 completely is planned for versions
|
||||
``2.*``.
|
||||
|
||||
|
||||
0.18.0 / 2020-07-21
|
||||
-------------------
|
||||
|
||||
* Update cli-spinners to ``v2.4.0``
|
||||
* Update dependencies
|
||||
* fix(#59): remove ``tests/`` and ``examples/`` from wheels distribution
|
||||
|
||||
|
||||
0.17.0 / 2020-05-08
|
||||
-------------------
|
||||
|
||||
* Migrate to ``poetry`` for dependencies management, building and publishing project
|
||||
* Add tests for Python 3.8
|
||||
* Deprecate support for Python 3.4
|
||||
* Run tests under Ubuntu 18.04
|
||||
* Update dev dependencies to the most recent ones (compatible with Python 2.7)
|
||||
* Remove Tox from the project (use CI for tests under different versions of Python)
|
||||
|
||||
|
||||
0.16.0 / 2020-01-11
|
||||
-------------------
|
||||
|
||||
* Allow use inside zip bundled package
|
||||
* Code improvements
|
||||
|
||||
|
||||
0.15.0 / 2019-08-09
|
||||
-------------------
|
||||
|
||||
* Update cli-spinners to v2.2.0
|
||||
|
||||
|
||||
0.14.3 / 2019-05-12
|
||||
-------------------
|
||||
|
||||
* fix(#29): race condition between spinner thread and ``write()``
|
||||
|
||||
|
||||
0.14.2 / 2019-04-27
|
||||
-------------------
|
||||
|
||||
* fix: remove extra ``\b`` written to stdout. Fixes ``write()`` in rxvt terminal
|
||||
|
||||
|
||||
0.14.1 / 2019-01-28
|
||||
-------------------
|
||||
|
||||
* fix(#26): traceback on PYTHONOPTIMIZE=2
|
||||
|
||||
|
||||
0.14.0 / 2018-09-05
|
||||
-------------------
|
||||
|
||||
* Support for handling POSIX signals
|
||||
* New function in public API: ``kbi_safe_yaspin``
|
||||
|
||||
|
||||
0.13.0 / 2018-08-14
|
||||
-------------------
|
||||
|
||||
* API improvements: ``spinner``, ``color``, ``on_color``, ``attrs`` and ``side`` argument values are handled via ``__getattr__``
|
||||
* New ``yaspin`` arguments: ``on_color``, ``attrs``
|
||||
* ``right=False`` argument replaced with ``side="left"``
|
||||
* ``Yaspin.right`` replaced with ``Yaspin.side``
|
||||
* ``reverse`` argument replaced with ``reversal``
|
||||
* ``Yaspin.reverse`` replaced with ``Yaspin.reversal``
|
||||
* Remove default text stripping in ``Yaspin._freeze``
|
||||
|
||||
|
||||
0.12.0 / 2018-07-16
|
||||
-------------------
|
||||
|
||||
* Add support for Python 3.7
|
||||
* Drop support for Python 2.6 and 3.3
|
||||
|
||||
* dev: Migrate to Pipfile
|
||||
* dev: Speedup local unittests with pytest-xdist
|
||||
|
||||
|
||||
0.11.1 / 2018-07-10
|
||||
-------------------
|
||||
|
||||
* fix(#16): remove default text stripping in ``Yaspin.write`` to allow printing of the hierarchical text
|
||||
|
||||
|
||||
0.11.0 / 2018-06-23
|
||||
-------------------
|
||||
|
||||
* Update cli-spinners to v1.3.1
|
||||
|
||||
|
||||
0.10.0 / 2018-03-23
|
||||
-------------------
|
||||
|
||||
* New ``hide`` and ``show`` methods to toggle the display of the spinner
|
||||
|
||||
|
||||
0.9.0 / 2018-02-26
|
||||
------------------
|
||||
|
||||
* New ``write`` method for writing text into terminal without breaking the spinner
|
||||
|
||||
|
||||
0.8.0 / 2017-12-31
|
||||
------------------
|
||||
|
||||
* Speedup reading spinners collection with simplejson
|
||||
|
||||
|
||||
0.7.1 / 2017-12-02
|
||||
------------------
|
||||
|
||||
* fix(#7): handling bytes sequences in ``Spinner.frames``
|
||||
|
||||
|
||||
0.7.0 / 2017-11-28
|
||||
------------------
|
||||
|
||||
* Reverse spinner support
|
||||
|
||||
|
||||
0.6.0 / 2017-11-26
|
||||
------------------
|
||||
|
||||
* Right spinner support
|
||||
|
||||
|
||||
0.5.0 / 2017-11-24
|
||||
------------------
|
||||
|
||||
* Colors support
|
||||
|
||||
|
||||
0.4.2 / 2017-11-17
|
||||
------------------
|
||||
|
||||
* RST vs PyPI episode 2
|
||||
|
||||
|
||||
0.4.1 / 2017-11-17
|
||||
------------------
|
||||
|
||||
* RST vs PyPI episode 1
|
||||
|
||||
|
||||
0.4.0 / 2017-11-17
|
||||
------------------
|
||||
|
||||
* Support for success and failure finalizers
|
||||
|
||||
|
||||
0.3.0 / 2017-11-14
|
||||
------------------
|
||||
|
||||
* Support for changing spinner properties on the fly
|
||||
|
||||
|
||||
0.2.0 / 2017-11-10
|
||||
------------------
|
||||
|
||||
* Support all spinners from `cli-spinners`_
|
||||
* API changes:
|
||||
- ``yaspin.spinner`` -> ``yaspin.yaspin``
|
||||
|
||||
|
||||
0.1.0 / 2017-10-31
|
||||
------------------
|
||||
|
||||
* First version
|
||||
|
||||
|
||||
.. _cli-spinners: https://github.com/sindresorhus/cli-spinners
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Pavlo Dmytrenko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
:class:`zipfile.Path` now supports :attr:`zipfile.Path.stem`,
|
||||
:attr:`zipfile.Path.suffixes`, and :attr:`zipfile.Path.suffix` attributes.
|
||||
Vendored
+451
@@ -0,0 +1,451 @@
|
||||
|Logo|
|
||||
|
||||
=====================================================================
|
||||
``yaspin``: **Y**\ et **A**\ nother Terminal **Spin**\ ner for Python
|
||||
=====================================================================
|
||||
|
||||
|Build Status| |Coverage| |Codacy| |pyup| |black-fmt|
|
||||
|
||||
|pypi| |Versions| |Wheel| |Examples|
|
||||
|
||||
|DownloadsTot| |DownloadsW|
|
||||
|
||||
|
||||
``Yaspin`` provides a full-featured terminal spinner to show the progress during long-hanging operations.
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/demo.gif
|
||||
|
||||
It is easy to integrate into existing codebase by using it as a `context manager`_
|
||||
or as a function `decorator`_:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
# Context manager:
|
||||
with yaspin():
|
||||
time.sleep(3) # time consuming code
|
||||
|
||||
# Function decorator:
|
||||
@yaspin(text="Loading...")
|
||||
def some_operations():
|
||||
time.sleep(3) # time consuming code
|
||||
|
||||
some_operations()
|
||||
|
||||
|
||||
**Yaspin** also provides an intuitive and powerful API. For example, you can easily summon a shark:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
with yaspin().white.bold.shark.on_blue as sp:
|
||||
sp.text = "White bold shark in a blue sea"
|
||||
time.sleep(5)
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/shark.gif
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Runs at all major **CPython** versions (*3.6*, *3.7*, *3.8*, *3.9*), **PyPy**
|
||||
- Supports all (70+) spinners from `cli-spinners`_
|
||||
- Supports all *colors*, *highlights*, *attributes* and their mixes from `termcolor`_ library
|
||||
- Easy to combine with other command-line libraries, e.g. `prompt-toolkit`_
|
||||
- Flexible API, easy to integrate with existing code
|
||||
- User-friendly API for handling POSIX `signals`_
|
||||
- Safe **pipes** and **redirects**:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python script_that_uses_yaspin.py > script.log
|
||||
$ python script_that_uses_yaspin.py | grep ERROR
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
From `PyPI`_ using ``pip`` package manager:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install --upgrade yaspin
|
||||
|
||||
|
||||
Or install the latest sources from GitHub:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pip install https://github.com/pavdmyt/yaspin/archive/master.zip
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Basic Example
|
||||
/////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_example.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from random import randint
|
||||
from yaspin import yaspin
|
||||
|
||||
with yaspin(text="Loading", color="yellow") as spinner:
|
||||
time.sleep(2) # time consuming code
|
||||
|
||||
success = randint(0, 1)
|
||||
if success:
|
||||
spinner.ok("✅ ")
|
||||
else:
|
||||
spinner.fail("💥 ")
|
||||
|
||||
|
||||
It is also possible to control spinner manually:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
spinner = yaspin()
|
||||
spinner.start()
|
||||
|
||||
time.sleep(3) # time consuming tasks
|
||||
|
||||
spinner.stop()
|
||||
|
||||
|
||||
Run any spinner from `cli-spinners`_
|
||||
////////////////////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/cli_spinners.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
from yaspin.spinners import Spinners
|
||||
|
||||
with yaspin(Spinners.earth, text="Earth") as sp:
|
||||
time.sleep(2) # time consuming code
|
||||
|
||||
# change spinner
|
||||
sp.spinner = Spinners.moon
|
||||
sp.text = "Moon"
|
||||
|
||||
time.sleep(2) # time consuming code
|
||||
|
||||
|
||||
Any Colour You Like `🌈`_
|
||||
/////////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/basic_colors.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
with yaspin(text="Colors!") as sp:
|
||||
# Support all basic termcolor text colors
|
||||
colors = ("red", "green", "yellow", "blue", "magenta", "cyan", "white")
|
||||
|
||||
for color in colors:
|
||||
sp.color, sp.text = color, color
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
Advanced colors usage
|
||||
/////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/advanced_colors.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
from yaspin.spinners import Spinners
|
||||
|
||||
text = "Bold blink magenta spinner on cyan color"
|
||||
with yaspin().bold.blink.magenta.bouncingBall.on_cyan as sp:
|
||||
sp.text = text
|
||||
time.sleep(3)
|
||||
|
||||
# The same result can be achieved by passing arguments directly
|
||||
with yaspin(
|
||||
Spinners.bouncingBall,
|
||||
color="magenta",
|
||||
on_color="on_cyan",
|
||||
attrs=["bold", "blink"],
|
||||
) as sp:
|
||||
sp.text = text
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
Run any spinner you want
|
||||
////////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/custom_spinners.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin, Spinner
|
||||
|
||||
# Compose new spinners with custom frame sequence and interval value
|
||||
sp = Spinner(["😸", "😹", "😺", "😻", "😼", "😽", "😾", "😿", "🙀"], 200)
|
||||
|
||||
with yaspin(sp, text="Cat!"):
|
||||
time.sleep(3) # cat consuming code :)
|
||||
|
||||
|
||||
Change spinner properties on the fly
|
||||
////////////////////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/sp_properties.gif
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
from yaspin.spinners import Spinners
|
||||
|
||||
with yaspin(Spinners.noise, text="Noise spinner") as sp:
|
||||
time.sleep(2)
|
||||
|
||||
sp.spinner = Spinners.arc # spinner type
|
||||
sp.text = "Arc spinner" # text along with spinner
|
||||
sp.color = "green" # spinner color
|
||||
sp.side = "right" # put spinner to the right
|
||||
sp.reversal = True # reverse spin direction
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
Spinner with timer
|
||||
//////////////////
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
with yaspin(text="elapsed time", timer=True) as sp:
|
||||
time.sleep(3.1415)
|
||||
sp.ok()
|
||||
|
||||
|
||||
Writing messages
|
||||
////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/write_text.gif
|
||||
|
||||
You should not write any message in the terminal using ``print`` while spinner is open.
|
||||
To write messages in the terminal without any collision with ``yaspin`` spinner, a ``.write()`` method is provided:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
from yaspin import yaspin
|
||||
|
||||
with yaspin(text="Downloading images", color="cyan") as sp:
|
||||
# task 1
|
||||
time.sleep(1)
|
||||
sp.write("> image 1 download complete")
|
||||
|
||||
# task 2
|
||||
time.sleep(2)
|
||||
sp.write("> image 2 download complete")
|
||||
|
||||
# finalize
|
||||
sp.ok("✔")
|
||||
|
||||
|
||||
Integration with other libraries
|
||||
////////////////////////////////
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/gifs/hide_show.gif
|
||||
|
||||
Utilizing ``hidden`` context manager it is possible to toggle the display of
|
||||
the spinner in order to call custom methods that write to the terminal. This is
|
||||
helpful for allowing easy usage in other frameworks like `prompt-toolkit`_.
|
||||
Using the powerful ``print_formatted_text`` function allows you even to apply
|
||||
HTML formats and CSS styles to the output:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
from yaspin import yaspin
|
||||
from prompt_toolkit import HTML, print_formatted_text
|
||||
from prompt_toolkit.styles import Style
|
||||
|
||||
# override print with feature-rich ``print_formatted_text`` from prompt_toolkit
|
||||
print = print_formatted_text
|
||||
|
||||
# build a basic prompt_toolkit style for styling the HTML wrapped text
|
||||
style = Style.from_dict({
|
||||
'msg': '#4caf50 bold',
|
||||
'sub-msg': '#616161 italic'
|
||||
})
|
||||
|
||||
|
||||
with yaspin(text='Downloading images') as sp:
|
||||
# task 1
|
||||
time.sleep(1)
|
||||
with sp.hidden():
|
||||
print(HTML(
|
||||
u'<b>></b> <msg>image 1</msg> <sub-msg>download complete</sub-msg>'
|
||||
), style=style)
|
||||
|
||||
# task 2
|
||||
time.sleep(2)
|
||||
with sp.hidden():
|
||||
print(HTML(
|
||||
u'<b>></b> <msg>image 2</msg> <sub-msg>download complete</sub-msg>'
|
||||
), style=style)
|
||||
|
||||
# finalize
|
||||
sp.ok()
|
||||
|
||||
|
||||
Handling POSIX `signals`_
|
||||
/////////////////////////
|
||||
|
||||
Handling keyboard interrupts (pressing Control-C):
|
||||
|
||||
.. code:: python
|
||||
|
||||
import time
|
||||
|
||||
from yaspin import kbi_safe_yaspin
|
||||
|
||||
|
||||
with kbi_safe_yaspin(text="Press Control+C to send SIGINT (Keyboard Interrupt) signal"):
|
||||
time.sleep(5) # time consuming code
|
||||
|
||||
|
||||
Handling other types of signals:
|
||||
|
||||
.. code:: python
|
||||
|
||||
import os
|
||||
import time
|
||||
from signal import SIGTERM, SIGUSR1
|
||||
|
||||
from yaspin import yaspin
|
||||
from yaspin.signal_handlers import default_handler, fancy_handler
|
||||
|
||||
|
||||
sigmap = {SIGUSR1: default_handler, SIGTERM: fancy_handler}
|
||||
with yaspin(sigmap=sigmap, text="Handling SIGUSR1 and SIGTERM signals") as sp:
|
||||
sp.write("Send signals using `kill` command")
|
||||
sp.write("E.g. $ kill -USR1 {0}".format(os.getpid()))
|
||||
time.sleep(20) # time consuming code
|
||||
|
||||
|
||||
More `examples`_.
|
||||
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
Clone the repository:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/pavdmyt/yaspin.git
|
||||
|
||||
|
||||
Install dev dependencies:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
poetry install
|
||||
|
||||
# if you don't have poetry installed:
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
Lint code:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make lint
|
||||
|
||||
|
||||
Format code:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make black-fmt
|
||||
|
||||
|
||||
Run tests:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make test
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
1. Fork it!
|
||||
2. Create your feature branch: ``git checkout -b my-new-feature``
|
||||
3. Commit your changes: ``git commit -m 'Add some feature'``
|
||||
4. Push to the branch: ``git push origin my-new-feature``
|
||||
5. Submit a pull request
|
||||
6. Make sure tests are passing
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
* MIT - Pavlo Dmytrenko; https://twitter.com/pavdmyt
|
||||
* Contains data from `cli-spinners`_: MIT License, Copyright (c) Sindre Sorhus sindresorhus@gmail.com (sindresorhus.com)
|
||||
|
||||
|
||||
.. |Logo| image:: https://raw.githubusercontent.com/pavdmyt/yaspin/master/static/logo_80.png
|
||||
:alt: yaspin Logo
|
||||
.. |Build Status| image:: https://travis-ci.org/pavdmyt/yaspin.svg?branch=master
|
||||
:target: https://travis-ci.org/pavdmyt/yaspin
|
||||
.. |Coverage| image:: https://codecov.io/gh/pavdmyt/yaspin/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/pavdmyt/yaspin
|
||||
.. |Codacy| image:: https://api.codacy.com/project/badge/Grade/797c7772d0d3467c88a5e2e9dc79ec98
|
||||
:target: https://www.codacy.com/app/pavdmyt/yaspin?utm_source=github.com&utm_medium=referral&utm_content=pavdmyt/yaspin&utm_campaign=Badge_Grade
|
||||
.. |pypi| image:: https://img.shields.io/pypi/v/yaspin.svg
|
||||
:target: https://pypi.org/project/yaspin/
|
||||
.. |Versions| image:: https://img.shields.io/pypi/pyversions/yaspin.svg
|
||||
:target: https://pypi.org/project/yaspin/
|
||||
.. |Wheel| image:: https://img.shields.io/pypi/wheel/yaspin.svg
|
||||
:target: https://pypi.org/project/yaspin/
|
||||
.. |Examples| image:: https://img.shields.io/badge/learn%20by-examples-0077b3.svg
|
||||
:target: https://github.com/pavdmyt/yaspin/tree/master/examples
|
||||
.. |pyup| image:: https://pyup.io/repos/github/pavdmyt/yaspin/shield.svg
|
||||
:target: https://pyup.io/repos/github/pavdmyt/yaspin/
|
||||
.. |black-fmt| image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:target: https://github.com/ambv/black
|
||||
.. |DownloadsTot| image:: https://pepy.tech/badge/yaspin
|
||||
:target: https://pepy.tech/project/yaspin
|
||||
.. |DownloadsW| image:: https://pepy.tech/badge/yaspin/week
|
||||
:target: https://pepy.tech/project/yaspin
|
||||
|
||||
|
||||
.. _context manager: https://docs.python.org/3/reference/datamodel.html#context-managers
|
||||
.. _decorator: https://www.thecodeship.com/patterns/guide-to-python-function-decorators/
|
||||
.. _cli-spinners: https://github.com/sindresorhus/cli-spinners
|
||||
.. _termcolor: https://pypi.org/project/termcolor/
|
||||
.. _PyPI: https://pypi.org/
|
||||
.. _🌈: https://en.wikipedia.org/wiki/Any_Colour_You_Like
|
||||
.. _examples: https://github.com/pavdmyt/yaspin/tree/master/examples
|
||||
.. _prompt-toolkit: https://github.com/jonathanslenders/python-prompt-toolkit/
|
||||
.. _signals: https://www.computerhope.com/unix/signals.htm
|
||||
Vendored
+3
-1
@@ -5,6 +5,7 @@ import sys
|
||||
from functools import partial
|
||||
|
||||
from . import converters, exceptions, filters, setters, validators
|
||||
from ._cmp import cmp_using
|
||||
from ._config import get_run_validators, set_run_validators
|
||||
from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
|
||||
from ._make import (
|
||||
@@ -21,7 +22,7 @@ from ._make import (
|
||||
from ._version_info import VersionInfo
|
||||
|
||||
|
||||
__version__ = "20.3.0"
|
||||
__version__ = "21.2.0"
|
||||
__version_info__ = VersionInfo._from_version_string(__version__)
|
||||
|
||||
__title__ = "attrs"
|
||||
@@ -52,6 +53,7 @@ __all__ = [
|
||||
"attrib",
|
||||
"attributes",
|
||||
"attrs",
|
||||
"cmp_using",
|
||||
"converters",
|
||||
"evolve",
|
||||
"exceptions",
|
||||
|
||||
Vendored
+84
-42
@@ -1,12 +1,14 @@
|
||||
import sys
|
||||
|
||||
from typing import (
|
||||
Any,
|
||||
Callable,
|
||||
Dict,
|
||||
Generic,
|
||||
List,
|
||||
Mapping,
|
||||
Optional,
|
||||
Sequence,
|
||||
Mapping,
|
||||
Tuple,
|
||||
Type,
|
||||
TypeVar,
|
||||
@@ -15,14 +17,14 @@ from typing import (
|
||||
)
|
||||
|
||||
# `import X as X` is required to make these public
|
||||
from . import converters as converters
|
||||
from . import exceptions as exceptions
|
||||
from . import filters as filters
|
||||
from . import converters as converters
|
||||
from . import setters as setters
|
||||
from . import validators as validators
|
||||
|
||||
from ._version_info import VersionInfo
|
||||
|
||||
|
||||
__version__: str
|
||||
__version_info__: VersionInfo
|
||||
__title__: str
|
||||
@@ -37,6 +39,7 @@ __copyright__: str
|
||||
_T = TypeVar("_T")
|
||||
_C = TypeVar("_C", bound=type)
|
||||
|
||||
_EqOrderType = Union[bool, Callable[[Any], Any]]
|
||||
_ValidatorType = Callable[[Any, Attribute[_T], _T], Any]
|
||||
_ConverterType = Callable[[Any], Any]
|
||||
_FilterType = Callable[[Attribute[_T], _T], bool]
|
||||
@@ -46,7 +49,7 @@ _OnSetAttrType = Callable[[Any, Attribute[Any], Any], Any]
|
||||
_OnSetAttrArgType = Union[
|
||||
_OnSetAttrType, List[_OnSetAttrType], setters._NoOpType
|
||||
]
|
||||
_FieldTransformer = Callable[[type, List[Attribute]], List[Attribute]]
|
||||
_FieldTransformer = Callable[[type, List[Attribute[Any]]], List[Attribute[Any]]]
|
||||
# FIXME: in reality, if multiple validators are passed they must be in a list
|
||||
# or tuple, but those are invariant and so would prevent subtypes of
|
||||
# _ValidatorType from working when passed in a list or tuple.
|
||||
@@ -59,22 +62,54 @@ NOTHING: object
|
||||
# NOTE: Factory lies about its return type to make this possible:
|
||||
# `x: List[int] # = Factory(list)`
|
||||
# Work around mypy issue #4554 in the common case by using an overload.
|
||||
@overload
|
||||
def Factory(factory: Callable[[], _T]) -> _T: ...
|
||||
@overload
|
||||
def Factory(
|
||||
factory: Union[Callable[[Any], _T], Callable[[], _T]],
|
||||
takes_self: bool = ...,
|
||||
) -> _T: ...
|
||||
if sys.version_info >= (3, 8):
|
||||
from typing import Literal
|
||||
|
||||
@overload
|
||||
def Factory(factory: Callable[[], _T]) -> _T: ...
|
||||
@overload
|
||||
def Factory(
|
||||
factory: Callable[[Any], _T],
|
||||
takes_self: Literal[True],
|
||||
) -> _T: ...
|
||||
@overload
|
||||
def Factory(
|
||||
factory: Callable[[], _T],
|
||||
takes_self: Literal[False],
|
||||
) -> _T: ...
|
||||
else:
|
||||
@overload
|
||||
def Factory(factory: Callable[[], _T]) -> _T: ...
|
||||
@overload
|
||||
def Factory(
|
||||
factory: Union[Callable[[Any], _T], Callable[[], _T]],
|
||||
takes_self: bool = ...,
|
||||
) -> _T: ...
|
||||
|
||||
# Static type inference support via __dataclass_transform__ implemented as per:
|
||||
# https://github.com/microsoft/pyright/blob/1.1.135/specs/dataclass_transforms.md
|
||||
# This annotation must be applied to all overloads of "define" and "attrs"
|
||||
#
|
||||
# NOTE: This is a typing construct and does not exist at runtime. Extensions
|
||||
# wrapping attrs decorators should declare a separate __dataclass_transform__
|
||||
# signature in the extension module using the specification linked above to
|
||||
# provide pyright support.
|
||||
def __dataclass_transform__(
|
||||
*,
|
||||
eq_default: bool = True,
|
||||
order_default: bool = False,
|
||||
kw_only_default: bool = False,
|
||||
field_descriptors: Tuple[Union[type, Callable[..., Any]], ...] = (()),
|
||||
) -> Callable[[_T], _T]: ...
|
||||
|
||||
class Attribute(Generic[_T]):
|
||||
name: str
|
||||
default: Optional[_T]
|
||||
validator: Optional[_ValidatorType[_T]]
|
||||
repr: _ReprArgType
|
||||
cmp: bool
|
||||
eq: bool
|
||||
order: bool
|
||||
cmp: _EqOrderType
|
||||
eq: _EqOrderType
|
||||
order: _EqOrderType
|
||||
hash: Optional[bool]
|
||||
init: bool
|
||||
converter: Optional[_ConverterType]
|
||||
@@ -83,6 +118,8 @@ class Attribute(Generic[_T]):
|
||||
kw_only: bool
|
||||
on_setattr: _OnSetAttrType
|
||||
|
||||
def evolve(self, **changes: Any) -> "Attribute[Any]": ...
|
||||
|
||||
# NOTE: We had several choices for the annotation to use for type arg:
|
||||
# 1) Type[_T]
|
||||
# - Pros: Handles simple cases correctly
|
||||
@@ -112,7 +149,7 @@ def attrib(
|
||||
default: None = ...,
|
||||
validator: None = ...,
|
||||
repr: _ReprArgType = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
metadata: Optional[Mapping[Any, Any]] = ...,
|
||||
@@ -120,8 +157,8 @@ def attrib(
|
||||
converter: None = ...,
|
||||
factory: None = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> Any: ...
|
||||
|
||||
@@ -132,7 +169,7 @@ def attrib(
|
||||
default: None = ...,
|
||||
validator: Optional[_ValidatorArgType[_T]] = ...,
|
||||
repr: _ReprArgType = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
metadata: Optional[Mapping[Any, Any]] = ...,
|
||||
@@ -140,8 +177,8 @@ def attrib(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> _T: ...
|
||||
|
||||
@@ -151,7 +188,7 @@ def attrib(
|
||||
default: _T,
|
||||
validator: Optional[_ValidatorArgType[_T]] = ...,
|
||||
repr: _ReprArgType = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
metadata: Optional[Mapping[Any, Any]] = ...,
|
||||
@@ -159,8 +196,8 @@ def attrib(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> _T: ...
|
||||
|
||||
@@ -170,7 +207,7 @@ def attrib(
|
||||
default: Optional[_T] = ...,
|
||||
validator: Optional[_ValidatorArgType[_T]] = ...,
|
||||
repr: _ReprArgType = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
metadata: Optional[Mapping[Any, Any]] = ...,
|
||||
@@ -178,8 +215,8 @@ def attrib(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> Any: ...
|
||||
@overload
|
||||
@@ -213,8 +250,8 @@ def field(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> _T: ...
|
||||
|
||||
@@ -231,8 +268,8 @@ def field(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> _T: ...
|
||||
|
||||
@@ -249,17 +286,18 @@ def field(
|
||||
converter: Optional[_ConverterType] = ...,
|
||||
factory: Optional[Callable[[], _T]] = ...,
|
||||
kw_only: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
) -> Any: ...
|
||||
@overload
|
||||
@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
|
||||
def attrs(
|
||||
maybe_cls: _C,
|
||||
these: Optional[Dict[str, Any]] = ...,
|
||||
repr_ns: Optional[str] = ...,
|
||||
repr: bool = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
slots: bool = ...,
|
||||
@@ -270,8 +308,8 @@ def attrs(
|
||||
kw_only: bool = ...,
|
||||
cache_hash: bool = ...,
|
||||
auto_exc: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
auto_detect: bool = ...,
|
||||
collect_by_mro: bool = ...,
|
||||
getstate_setstate: Optional[bool] = ...,
|
||||
@@ -279,12 +317,13 @@ def attrs(
|
||||
field_transformer: Optional[_FieldTransformer] = ...,
|
||||
) -> _C: ...
|
||||
@overload
|
||||
@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))
|
||||
def attrs(
|
||||
maybe_cls: None = ...,
|
||||
these: Optional[Dict[str, Any]] = ...,
|
||||
repr_ns: Optional[str] = ...,
|
||||
repr: bool = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
slots: bool = ...,
|
||||
@@ -295,8 +334,8 @@ def attrs(
|
||||
kw_only: bool = ...,
|
||||
cache_hash: bool = ...,
|
||||
auto_exc: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
auto_detect: bool = ...,
|
||||
collect_by_mro: bool = ...,
|
||||
getstate_setstate: Optional[bool] = ...,
|
||||
@@ -304,6 +343,7 @@ def attrs(
|
||||
field_transformer: Optional[_FieldTransformer] = ...,
|
||||
) -> Callable[[_C], _C]: ...
|
||||
@overload
|
||||
@__dataclass_transform__(field_descriptors=(attrib, field))
|
||||
def define(
|
||||
maybe_cls: _C,
|
||||
*,
|
||||
@@ -327,6 +367,7 @@ def define(
|
||||
field_transformer: Optional[_FieldTransformer] = ...,
|
||||
) -> _C: ...
|
||||
@overload
|
||||
@__dataclass_transform__(field_descriptors=(attrib, field))
|
||||
def define(
|
||||
maybe_cls: None = ...,
|
||||
*,
|
||||
@@ -364,6 +405,7 @@ def resolve_types(
|
||||
cls: _C,
|
||||
globalns: Optional[Dict[str, Any]] = ...,
|
||||
localns: Optional[Dict[str, Any]] = ...,
|
||||
attribs: Optional[List[Attribute[Any]]] = ...,
|
||||
) -> _C: ...
|
||||
|
||||
# TODO: add support for returning a proper attrs class from the mypy plugin
|
||||
@@ -375,7 +417,7 @@ def make_class(
|
||||
bases: Tuple[type, ...] = ...,
|
||||
repr_ns: Optional[str] = ...,
|
||||
repr: bool = ...,
|
||||
cmp: Optional[bool] = ...,
|
||||
cmp: Optional[_EqOrderType] = ...,
|
||||
hash: Optional[bool] = ...,
|
||||
init: bool = ...,
|
||||
slots: bool = ...,
|
||||
@@ -386,8 +428,8 @@ def make_class(
|
||||
kw_only: bool = ...,
|
||||
cache_hash: bool = ...,
|
||||
auto_exc: bool = ...,
|
||||
eq: Optional[bool] = ...,
|
||||
order: Optional[bool] = ...,
|
||||
eq: Optional[_EqOrderType] = ...,
|
||||
order: Optional[_EqOrderType] = ...,
|
||||
collect_by_mro: bool = ...,
|
||||
on_setattr: Optional[_OnSetAttrArgType] = ...,
|
||||
field_transformer: Optional[_FieldTransformer] = ...,
|
||||
@@ -406,7 +448,7 @@ def asdict(
|
||||
filter: Optional[_FilterType[Any]] = ...,
|
||||
dict_factory: Type[Mapping[Any, Any]] = ...,
|
||||
retain_collection_types: bool = ...,
|
||||
value_serializer: Optional[Callable[[type, Attribute, Any], Any]] = ...,
|
||||
value_serializer: Optional[Callable[[type, Attribute[Any], Any], Any]] = ...,
|
||||
) -> Dict[str, Any]: ...
|
||||
|
||||
# TODO: add support for returning NamedTuple from the mypy plugin
|
||||
|
||||
Vendored
+152
@@ -0,0 +1,152 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import functools
|
||||
|
||||
from ._compat import new_class
|
||||
from ._make import _make_ne
|
||||
|
||||
|
||||
_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
|
||||
|
||||
|
||||
def cmp_using(
|
||||
eq=None,
|
||||
lt=None,
|
||||
le=None,
|
||||
gt=None,
|
||||
ge=None,
|
||||
require_same_type=True,
|
||||
class_name="Comparable",
|
||||
):
|
||||
"""
|
||||
Create a class that can be passed into `attr.ib`'s ``eq``, ``order``, and
|
||||
``cmp`` arguments to customize field comparison.
|
||||
|
||||
The resulting class will have a full set of ordering methods if
|
||||
at least one of ``{lt, le, gt, ge}`` and ``eq`` are provided.
|
||||
|
||||
:param Optional[callable] eq: `callable` used to evaluate equality
|
||||
of two objects.
|
||||
:param Optional[callable] lt: `callable` used to evaluate whether
|
||||
one object is less than another object.
|
||||
:param Optional[callable] le: `callable` used to evaluate whether
|
||||
one object is less than or equal to another object.
|
||||
:param Optional[callable] gt: `callable` used to evaluate whether
|
||||
one object is greater than another object.
|
||||
:param Optional[callable] ge: `callable` used to evaluate whether
|
||||
one object is greater than or equal to another object.
|
||||
|
||||
:param bool require_same_type: When `True`, equality and ordering methods
|
||||
will return `NotImplemented` if objects are not of the same type.
|
||||
|
||||
:param Optional[str] class_name: Name of class. Defaults to 'Comparable'.
|
||||
|
||||
See `comparison` for more details.
|
||||
|
||||
.. versionadded:: 21.1.0
|
||||
"""
|
||||
|
||||
body = {
|
||||
"__slots__": ["value"],
|
||||
"__init__": _make_init(),
|
||||
"_requirements": [],
|
||||
"_is_comparable_to": _is_comparable_to,
|
||||
}
|
||||
|
||||
# Add operations.
|
||||
num_order_functions = 0
|
||||
has_eq_function = False
|
||||
|
||||
if eq is not None:
|
||||
has_eq_function = True
|
||||
body["__eq__"] = _make_operator("eq", eq)
|
||||
body["__ne__"] = _make_ne()
|
||||
|
||||
if lt is not None:
|
||||
num_order_functions += 1
|
||||
body["__lt__"] = _make_operator("lt", lt)
|
||||
|
||||
if le is not None:
|
||||
num_order_functions += 1
|
||||
body["__le__"] = _make_operator("le", le)
|
||||
|
||||
if gt is not None:
|
||||
num_order_functions += 1
|
||||
body["__gt__"] = _make_operator("gt", gt)
|
||||
|
||||
if ge is not None:
|
||||
num_order_functions += 1
|
||||
body["__ge__"] = _make_operator("ge", ge)
|
||||
|
||||
type_ = new_class(class_name, (object,), {}, lambda ns: ns.update(body))
|
||||
|
||||
# Add same type requirement.
|
||||
if require_same_type:
|
||||
type_._requirements.append(_check_same_type)
|
||||
|
||||
# Add total ordering if at least one operation was defined.
|
||||
if 0 < num_order_functions < 4:
|
||||
if not has_eq_function:
|
||||
# functools.total_ordering requires __eq__ to be defined,
|
||||
# so raise early error here to keep a nice stack.
|
||||
raise ValueError(
|
||||
"eq must be define is order to complete ordering from "
|
||||
"lt, le, gt, ge."
|
||||
)
|
||||
type_ = functools.total_ordering(type_)
|
||||
|
||||
return type_
|
||||
|
||||
|
||||
def _make_init():
|
||||
"""
|
||||
Create __init__ method.
|
||||
"""
|
||||
|
||||
def __init__(self, value):
|
||||
"""
|
||||
Initialize object with *value*.
|
||||
"""
|
||||
self.value = value
|
||||
|
||||
return __init__
|
||||
|
||||
|
||||
def _make_operator(name, func):
|
||||
"""
|
||||
Create operator method.
|
||||
"""
|
||||
|
||||
def method(self, other):
|
||||
if not self._is_comparable_to(other):
|
||||
return NotImplemented
|
||||
|
||||
result = func(self.value, other.value)
|
||||
if result is NotImplemented:
|
||||
return NotImplemented
|
||||
|
||||
return result
|
||||
|
||||
method.__name__ = "__%s__" % (name,)
|
||||
method.__doc__ = "Return a %s b. Computed by attrs." % (
|
||||
_operation_names[name],
|
||||
)
|
||||
|
||||
return method
|
||||
|
||||
|
||||
def _is_comparable_to(self, other):
|
||||
"""
|
||||
Check whether `other` is comparable to `self`.
|
||||
"""
|
||||
for func in self._requirements:
|
||||
if not func(self, other):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _check_same_type(self, other):
|
||||
"""
|
||||
Return True if *self* and *other* are of the same type, False otherwise.
|
||||
"""
|
||||
return other.value.__class__ is self.value.__class__
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
from typing import Type
|
||||
|
||||
from . import _CompareWithType
|
||||
|
||||
|
||||
def cmp_using(
|
||||
eq: Optional[_CompareWithType],
|
||||
lt: Optional[_CompareWithType],
|
||||
le: Optional[_CompareWithType],
|
||||
gt: Optional[_CompareWithType],
|
||||
ge: Optional[_CompareWithType],
|
||||
require_same_type: bool,
|
||||
class_name: str,
|
||||
) -> Type: ...
|
||||
Vendored
+11
@@ -28,6 +28,15 @@ if PY2:
|
||||
def isclass(klass):
|
||||
return isinstance(klass, (type, types.ClassType))
|
||||
|
||||
def new_class(name, bases, kwds, exec_body):
|
||||
"""
|
||||
A minimal stub of types.new_class that we need for make_class.
|
||||
"""
|
||||
ns = {}
|
||||
exec_body(ns)
|
||||
|
||||
return type(name, bases, ns)
|
||||
|
||||
# TYPE is used in exceptions, repr(int) is different on Python 2 and 3.
|
||||
TYPE = "type"
|
||||
|
||||
@@ -122,6 +131,8 @@ else: # Python 3 and later.
|
||||
def iteritems(d):
|
||||
return d.items()
|
||||
|
||||
new_class = types.new_class
|
||||
|
||||
def metadata_proxy(d):
|
||||
return types.MappingProxyType(dict(d))
|
||||
|
||||
|
||||
Vendored
+8
-3
@@ -343,7 +343,7 @@ def evolve(inst, **changes):
|
||||
return cls(**changes)
|
||||
|
||||
|
||||
def resolve_types(cls, globalns=None, localns=None):
|
||||
def resolve_types(cls, globalns=None, localns=None, attribs=None):
|
||||
"""
|
||||
Resolve any strings and forward annotations in type annotations.
|
||||
|
||||
@@ -360,10 +360,13 @@ def resolve_types(cls, globalns=None, localns=None):
|
||||
:param type cls: Class to resolve.
|
||||
:param Optional[dict] globalns: Dictionary containing global variables.
|
||||
:param Optional[dict] localns: Dictionary containing local variables.
|
||||
:param Optional[list] attribs: List of attribs for the given class.
|
||||
This is necessary when calling from inside a ``field_transformer``
|
||||
since *cls* is not an ``attrs`` class yet.
|
||||
|
||||
:raise TypeError: If *cls* is not a class.
|
||||
:raise attr.exceptions.NotAnAttrsClassError: If *cls* is not an ``attrs``
|
||||
class.
|
||||
class and you didn't pass any attribs.
|
||||
:raise NameError: If types cannot be resolved because of missing variables.
|
||||
|
||||
:returns: *cls* so you can use this function also as a class decorator.
|
||||
@@ -371,6 +374,8 @@ def resolve_types(cls, globalns=None, localns=None):
|
||||
the decorator has to come in the line **before** `attr.s`.
|
||||
|
||||
.. versionadded:: 20.1.0
|
||||
.. versionadded:: 21.1.0 *attribs*
|
||||
|
||||
"""
|
||||
try:
|
||||
# Since calling get_type_hints is expensive we cache whether we've
|
||||
@@ -380,7 +385,7 @@ def resolve_types(cls, globalns=None, localns=None):
|
||||
import typing
|
||||
|
||||
hints = typing.get_type_hints(cls, globalns=globalns, localns=localns)
|
||||
for field in fields(cls):
|
||||
for field in fields(cls) if attribs is None else attribs:
|
||||
if field.name in hints:
|
||||
# Since fields have been frozen we must work around it.
|
||||
_obj_setattr(field, "type", hints[field.name])
|
||||
|
||||
Vendored
+381
-94
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import copy
|
||||
import inspect
|
||||
import linecache
|
||||
import sys
|
||||
import threading
|
||||
@@ -16,6 +17,7 @@ from ._compat import (
|
||||
isclass,
|
||||
iteritems,
|
||||
metadata_proxy,
|
||||
new_class,
|
||||
ordered_dict,
|
||||
set_closure_cell,
|
||||
)
|
||||
@@ -28,6 +30,10 @@ from .exceptions import (
|
||||
)
|
||||
|
||||
|
||||
if not PY2:
|
||||
import typing
|
||||
|
||||
|
||||
# This is used at least twice, so cache it here.
|
||||
_obj_setattr = object.__setattr__
|
||||
_init_converter_pat = "__attr_converter_%s"
|
||||
@@ -35,7 +41,12 @@ _init_factory_pat = "__attr_factory_{}"
|
||||
_tuple_property_pat = (
|
||||
" {attr_name} = _attrs_property(_attrs_itemgetter({index}))"
|
||||
)
|
||||
_classvar_prefixes = ("typing.ClassVar", "t.ClassVar", "ClassVar")
|
||||
_classvar_prefixes = (
|
||||
"typing.ClassVar",
|
||||
"t.ClassVar",
|
||||
"ClassVar",
|
||||
"typing_extensions.ClassVar",
|
||||
)
|
||||
# we don't use a double-underscore prefix because that triggers
|
||||
# name mangling when trying to create a slot for the field
|
||||
# (when slots=True)
|
||||
@@ -52,6 +63,8 @@ class _Nothing(object):
|
||||
Sentinel class to indicate the lack of a value when ``None`` is ambiguous.
|
||||
|
||||
``_Nothing`` is a singleton. There is only ever one of it.
|
||||
|
||||
.. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.
|
||||
"""
|
||||
|
||||
_singleton = None
|
||||
@@ -64,6 +77,12 @@ class _Nothing(object):
|
||||
def __repr__(self):
|
||||
return "NOTHING"
|
||||
|
||||
def __bool__(self):
|
||||
return False
|
||||
|
||||
def __len__(self):
|
||||
return 0 # __bool__ for Python 2
|
||||
|
||||
|
||||
NOTHING = _Nothing()
|
||||
"""
|
||||
@@ -165,13 +184,25 @@ def attrib(
|
||||
as-is, i.e. it will be used directly *instead* of calling ``repr()``
|
||||
(the default).
|
||||
:type repr: a `bool` or a `callable` to use a custom function.
|
||||
:param bool eq: If ``True`` (default), include this attribute in the
|
||||
|
||||
:param eq: If ``True`` (default), include this attribute in the
|
||||
generated ``__eq__`` and ``__ne__`` methods that check two instances
|
||||
for equality.
|
||||
:param bool order: If ``True`` (default), include this attributes in the
|
||||
for equality. To override how the attribute value is compared,
|
||||
pass a ``callable`` that takes a single value and returns the value
|
||||
to be compared.
|
||||
:type eq: a `bool` or a `callable`.
|
||||
|
||||
:param order: If ``True`` (default), include this attributes in the
|
||||
generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods.
|
||||
:param bool cmp: Setting to ``True`` is equivalent to setting ``eq=True,
|
||||
order=True``. Deprecated in favor of *eq* and *order*.
|
||||
To override how the attribute value is ordered,
|
||||
pass a ``callable`` that takes a single value and returns the value
|
||||
to be ordered.
|
||||
:type order: a `bool` or a `callable`.
|
||||
|
||||
:param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the
|
||||
same value. Must not be mixed with *eq* or *order*.
|
||||
:type cmp: a `bool` or a `callable`.
|
||||
|
||||
:param Optional[bool] hash: Include this attribute in the generated
|
||||
``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This
|
||||
is the correct behavior according the Python spec. Setting this value
|
||||
@@ -219,14 +250,19 @@ def attrib(
|
||||
.. versionadded:: 18.1.0
|
||||
``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
|
||||
.. versionadded:: 18.2.0 *kw_only*
|
||||
.. versionchanged:: 19.2.0 *convert* keyword argument removed
|
||||
.. versionchanged:: 19.2.0 *convert* keyword argument removed.
|
||||
.. versionchanged:: 19.2.0 *repr* also accepts a custom callable.
|
||||
.. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
|
||||
.. versionadded:: 19.2.0 *eq* and *order*
|
||||
.. versionadded:: 20.1.0 *on_setattr*
|
||||
.. versionchanged:: 20.3.0 *kw_only* backported to Python 2
|
||||
.. versionchanged:: 21.1.0
|
||||
*eq*, *order*, and *cmp* also accept a custom callable
|
||||
.. versionchanged:: 21.1.0 *cmp* undeprecated
|
||||
"""
|
||||
eq, order = _determine_eq_order(cmp, eq, order, True)
|
||||
eq, eq_key, order, order_key = _determine_attrib_eq_order(
|
||||
cmp, eq, order, True
|
||||
)
|
||||
|
||||
if hash is not None and hash is not True and hash is not False:
|
||||
raise TypeError(
|
||||
@@ -268,11 +304,43 @@ def attrib(
|
||||
type=type,
|
||||
kw_only=kw_only,
|
||||
eq=eq,
|
||||
eq_key=eq_key,
|
||||
order=order,
|
||||
order_key=order_key,
|
||||
on_setattr=on_setattr,
|
||||
)
|
||||
|
||||
|
||||
def _compile_and_eval(script, globs, locs=None, filename=""):
|
||||
"""
|
||||
"Exec" the script with the given global (globs) and local (locs) variables.
|
||||
"""
|
||||
bytecode = compile(script, filename, "exec")
|
||||
eval(bytecode, globs, locs)
|
||||
|
||||
|
||||
def _make_method(name, script, filename, globs=None):
|
||||
"""
|
||||
Create the method with the script given and return the method object.
|
||||
"""
|
||||
locs = {}
|
||||
if globs is None:
|
||||
globs = {}
|
||||
|
||||
_compile_and_eval(script, globs, locs, filename)
|
||||
|
||||
# In order of debuggers like PDB being able to step through the code,
|
||||
# we add a fake linecache entry.
|
||||
linecache.cache[filename] = (
|
||||
len(script),
|
||||
None,
|
||||
script.splitlines(True),
|
||||
filename,
|
||||
)
|
||||
|
||||
return locs[name]
|
||||
|
||||
|
||||
def _make_attr_tuple_class(cls_name, attr_names):
|
||||
"""
|
||||
Create a tuple subclass to hold `Attribute`s for an `attrs` class.
|
||||
@@ -296,8 +364,7 @@ def _make_attr_tuple_class(cls_name, attr_names):
|
||||
else:
|
||||
attr_class_template.append(" pass")
|
||||
globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
|
||||
eval(compile("\n".join(attr_class_template), "", "exec"), globs)
|
||||
|
||||
_compile_and_eval("\n".join(attr_class_template), globs)
|
||||
return globs[attr_class_name]
|
||||
|
||||
|
||||
@@ -324,7 +391,13 @@ def _is_class_var(annot):
|
||||
annotations which would put attrs-based classes at a performance
|
||||
disadvantage compared to plain old classes.
|
||||
"""
|
||||
return str(annot).startswith(_classvar_prefixes)
|
||||
annot = str(annot)
|
||||
|
||||
# Annotation can be quoted.
|
||||
if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):
|
||||
annot = annot[1:-1]
|
||||
|
||||
return annot.startswith(_classvar_prefixes)
|
||||
|
||||
|
||||
def _has_own_attribute(cls, attrib_name):
|
||||
@@ -575,6 +648,7 @@ class _ClassBuilder(object):
|
||||
"_cls_dict",
|
||||
"_delete_attribs",
|
||||
"_frozen",
|
||||
"_has_pre_init",
|
||||
"_has_post_init",
|
||||
"_is_exc",
|
||||
"_on_setattr",
|
||||
@@ -620,6 +694,7 @@ class _ClassBuilder(object):
|
||||
self._frozen = frozen
|
||||
self._weakref_slot = weakref_slot
|
||||
self._cache_hash = cache_hash
|
||||
self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
|
||||
self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
|
||||
self._delete_attribs = not bool(these)
|
||||
self._is_exc = is_exc
|
||||
@@ -698,7 +773,6 @@ class _ClassBuilder(object):
|
||||
"""
|
||||
Build and return a new class with a `__slots__` attribute.
|
||||
"""
|
||||
base_names = self._base_names
|
||||
cd = {
|
||||
k: v
|
||||
for k, v in iteritems(self._cls_dict)
|
||||
@@ -722,12 +796,21 @@ class _ClassBuilder(object):
|
||||
cd["__setattr__"] = object.__setattr__
|
||||
break
|
||||
|
||||
# Traverse the MRO to check for an existing __weakref__.
|
||||
# Traverse the MRO to collect existing slots
|
||||
# and check for an existing __weakref__.
|
||||
existing_slots = dict()
|
||||
weakref_inherited = False
|
||||
for base_cls in self._cls.__mro__[1:-1]:
|
||||
if base_cls.__dict__.get("__weakref__", None) is not None:
|
||||
weakref_inherited = True
|
||||
break
|
||||
existing_slots.update(
|
||||
{
|
||||
name: getattr(base_cls, name)
|
||||
for name in getattr(base_cls, "__slots__", [])
|
||||
}
|
||||
)
|
||||
|
||||
base_names = set(self._base_names)
|
||||
|
||||
names = self._attr_names
|
||||
if (
|
||||
@@ -741,6 +824,17 @@ class _ClassBuilder(object):
|
||||
# We only add the names of attributes that aren't inherited.
|
||||
# Setting __slots__ to inherited attributes wastes memory.
|
||||
slot_names = [name for name in names if name not in base_names]
|
||||
# There are slots for attributes from current class
|
||||
# that are defined in parent classes.
|
||||
# As their descriptors may be overriden by a child class,
|
||||
# we collect them here and update the class dict
|
||||
reused_slots = {
|
||||
slot: slot_descriptor
|
||||
for slot, slot_descriptor in iteritems(existing_slots)
|
||||
if slot in slot_names
|
||||
}
|
||||
slot_names = [name for name in slot_names if name not in reused_slots]
|
||||
cd.update(reused_slots)
|
||||
if self._cache_hash:
|
||||
slot_names.append(_hash_cache_field)
|
||||
cd["__slots__"] = tuple(slot_names)
|
||||
@@ -763,6 +857,10 @@ class _ClassBuilder(object):
|
||||
# Class- and staticmethods hide their functions inside.
|
||||
# These might need to be rewritten as well.
|
||||
closure_cells = getattr(item.__func__, "__closure__", None)
|
||||
elif isinstance(item, property):
|
||||
# Workaround for property `super()` shortcut (PY3-only).
|
||||
# There is no universal way for other descriptors.
|
||||
closure_cells = getattr(item.fget, "__closure__", None)
|
||||
else:
|
||||
closure_cells = getattr(item, "__closure__", None)
|
||||
|
||||
@@ -853,6 +951,7 @@ class _ClassBuilder(object):
|
||||
_make_init(
|
||||
self._cls,
|
||||
self._attrs,
|
||||
self._has_pre_init,
|
||||
self._has_post_init,
|
||||
self._frozen,
|
||||
self._slots,
|
||||
@@ -861,6 +960,27 @@ class _ClassBuilder(object):
|
||||
self._is_exc,
|
||||
self._on_setattr is not None
|
||||
and self._on_setattr is not setters.NO_OP,
|
||||
attrs_init=False,
|
||||
)
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
def add_attrs_init(self):
|
||||
self._cls_dict["__attrs_init__"] = self._add_method_dunders(
|
||||
_make_init(
|
||||
self._cls,
|
||||
self._attrs,
|
||||
self._has_pre_init,
|
||||
self._has_post_init,
|
||||
self._frozen,
|
||||
self._slots,
|
||||
self._cache_hash,
|
||||
self._base_attr_map,
|
||||
self._is_exc,
|
||||
self._on_setattr is not None
|
||||
and self._on_setattr is not setters.NO_OP,
|
||||
attrs_init=True,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -954,7 +1074,7 @@ _CMP_DEPRECATION = (
|
||||
)
|
||||
|
||||
|
||||
def _determine_eq_order(cmp, eq, order, default_eq):
|
||||
def _determine_attrs_eq_order(cmp, eq, order, default_eq):
|
||||
"""
|
||||
Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
|
||||
values of eq and order. If *eq* is None, set it to *default_eq*.
|
||||
@@ -964,8 +1084,6 @@ def _determine_eq_order(cmp, eq, order, default_eq):
|
||||
|
||||
# cmp takes precedence due to bw-compatibility.
|
||||
if cmp is not None:
|
||||
warnings.warn(_CMP_DEPRECATION, DeprecationWarning, stacklevel=3)
|
||||
|
||||
return cmp, cmp
|
||||
|
||||
# If left None, equality is set to the specified default and ordering
|
||||
@@ -982,6 +1100,47 @@ def _determine_eq_order(cmp, eq, order, default_eq):
|
||||
return eq, order
|
||||
|
||||
|
||||
def _determine_attrib_eq_order(cmp, eq, order, default_eq):
|
||||
"""
|
||||
Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
|
||||
values of eq and order. If *eq* is None, set it to *default_eq*.
|
||||
"""
|
||||
if cmp is not None and any((eq is not None, order is not None)):
|
||||
raise ValueError("Don't mix `cmp` with `eq' and `order`.")
|
||||
|
||||
def decide_callable_or_boolean(value):
|
||||
"""
|
||||
Decide whether a key function is used.
|
||||
"""
|
||||
if callable(value):
|
||||
value, key = True, value
|
||||
else:
|
||||
key = None
|
||||
return value, key
|
||||
|
||||
# cmp takes precedence due to bw-compatibility.
|
||||
if cmp is not None:
|
||||
cmp, cmp_key = decide_callable_or_boolean(cmp)
|
||||
return cmp, cmp_key, cmp, cmp_key
|
||||
|
||||
# If left None, equality is set to the specified default and ordering
|
||||
# mirrors equality.
|
||||
if eq is None:
|
||||
eq, eq_key = default_eq, None
|
||||
else:
|
||||
eq, eq_key = decide_callable_or_boolean(eq)
|
||||
|
||||
if order is None:
|
||||
order, order_key = eq, eq_key
|
||||
else:
|
||||
order, order_key = decide_callable_or_boolean(order)
|
||||
|
||||
if eq is False and order is True:
|
||||
raise ValueError("`order` can only be True if `eq` is True too.")
|
||||
|
||||
return eq, eq_key, order, order_key
|
||||
|
||||
|
||||
def _determine_whether_to_implement(
|
||||
cls, flag, auto_detect, dunders, default=True
|
||||
):
|
||||
@@ -1064,7 +1223,7 @@ def attrs(
|
||||
inherited from some base class).
|
||||
|
||||
So for example by implementing ``__eq__`` on a class yourself,
|
||||
``attrs`` will deduce ``eq=False`` and won't create *neither*
|
||||
``attrs`` will deduce ``eq=False`` and will create *neither*
|
||||
``__eq__`` *nor* ``__ne__`` (but Python classes come with a sensible
|
||||
``__ne__`` by default, so it *should* be enough to only implement
|
||||
``__eq__`` in most cases).
|
||||
@@ -1097,10 +1256,8 @@ def attrs(
|
||||
``__gt__``, and ``__ge__`` methods that behave like *eq* above and
|
||||
allow instances to be ordered. If ``None`` (default) mirror value of
|
||||
*eq*.
|
||||
:param Optional[bool] cmp: Setting to ``True`` is equivalent to setting
|
||||
``eq=True, order=True``. Deprecated in favor of *eq* and *order*, has
|
||||
precedence over them for backward-compatibility though. Must not be
|
||||
mixed with *eq* or *order*.
|
||||
:param Optional[bool] cmp: Setting *cmp* is equivalent to setting *eq*
|
||||
and *order* to the same value. Must not be mixed with *eq* or *order*.
|
||||
:param Optional[bool] hash: If ``None`` (default), the ``__hash__`` method
|
||||
is generated according how *eq* and *frozen* are set.
|
||||
|
||||
@@ -1121,9 +1278,16 @@ def attrs(
|
||||
behavior <https://github.com/python-attrs/attrs/issues/136>`_ for more
|
||||
details.
|
||||
:param bool init: Create a ``__init__`` method that initializes the
|
||||
``attrs`` attributes. Leading underscores are stripped for the
|
||||
argument name. If a ``__attrs_post_init__`` method exists on the
|
||||
class, it will be called after the class is fully initialized.
|
||||
``attrs`` attributes. Leading underscores are stripped for the argument
|
||||
name. If a ``__attrs_pre_init__`` method exists on the class, it will
|
||||
be called before the class is initialized. If a ``__attrs_post_init__``
|
||||
method exists on the class, it will be called after the class is fully
|
||||
initialized.
|
||||
|
||||
If ``init`` is ``False``, an ``__attrs_init__`` method will be
|
||||
injected instead. This allows you to define a custom ``__init__``
|
||||
method that can do pre-init work such as ``super().__init__()``,
|
||||
and then call ``__attrs_init__()`` and ``__attrs_post_init__()``.
|
||||
:param bool slots: Create a `slotted class <slotted classes>` that's more
|
||||
memory-efficient. Slotted classes are generally superior to the default
|
||||
dict classes, but have some gotchas you should know about, so we
|
||||
@@ -1164,11 +1328,20 @@ def attrs(
|
||||
If you assign a value to those attributes (e.g. ``x: int = 42``), that
|
||||
value becomes the default value like if it were passed using
|
||||
``attr.ib(default=42)``. Passing an instance of `Factory` also
|
||||
works as expected.
|
||||
works as expected in most cases (see warning below).
|
||||
|
||||
Attributes annotated as `typing.ClassVar`, and attributes that are
|
||||
neither annotated nor set to an `attr.ib` are **ignored**.
|
||||
|
||||
.. warning::
|
||||
For features that use the attribute name to create decorators (e.g.
|
||||
`validators <validators>`), you still *must* assign `attr.ib` to
|
||||
them. Otherwise Python will either not find the name or try to use
|
||||
the default value to call e.g. ``validator`` on it.
|
||||
|
||||
These errors can be quite confusing and probably the most common bug
|
||||
report on our bug tracker.
|
||||
|
||||
.. _`PEP 526`: https://www.python.org/dev/peps/pep-0526/
|
||||
:param bool kw_only: Make all attributes keyword-only (Python 3+)
|
||||
in the generated ``__init__`` (if ``init`` is ``False``, this
|
||||
@@ -1263,13 +1436,17 @@ def attrs(
|
||||
.. versionadded:: 20.1.0 *getstate_setstate*
|
||||
.. versionadded:: 20.1.0 *on_setattr*
|
||||
.. versionadded:: 20.3.0 *field_transformer*
|
||||
.. versionchanged:: 21.1.0
|
||||
``init=False`` injects ``__attrs_init__``
|
||||
.. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``
|
||||
.. versionchanged:: 21.1.0 *cmp* undeprecated
|
||||
"""
|
||||
if auto_detect and PY2:
|
||||
raise PythonTooOldError(
|
||||
"auto_detect only works on Python 3 and later."
|
||||
)
|
||||
|
||||
eq_, order_ = _determine_eq_order(cmp, eq, order, None)
|
||||
eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)
|
||||
hash_ = hash # work around the lack of nonlocal
|
||||
|
||||
if isinstance(on_setattr, (list, tuple)):
|
||||
@@ -1372,6 +1549,7 @@ def attrs(
|
||||
):
|
||||
builder.add_init()
|
||||
else:
|
||||
builder.add_attrs_init()
|
||||
if cache_hash:
|
||||
raise TypeError(
|
||||
"Invalid value for cache_hash. To use hash caching,"
|
||||
@@ -1419,13 +1597,6 @@ else:
|
||||
return cls.__setattr__ == _frozen_setattrs
|
||||
|
||||
|
||||
def _attrs_to_tuple(obj, attrs):
|
||||
"""
|
||||
Create a tuple of all values of *obj*'s *attrs*.
|
||||
"""
|
||||
return tuple(getattr(obj, a.name) for a in attrs)
|
||||
|
||||
|
||||
def _generate_unique_filename(cls, func_name):
|
||||
"""
|
||||
Create a "filename" suitable for a function being generated.
|
||||
@@ -1519,21 +1690,7 @@ def _make_hash(cls, attrs, frozen, cache_hash):
|
||||
append_hash_computation_lines("return ", tab)
|
||||
|
||||
script = "\n".join(method_lines)
|
||||
globs = {}
|
||||
locs = {}
|
||||
bytecode = compile(script, unique_filename, "exec")
|
||||
eval(bytecode, globs, locs)
|
||||
|
||||
# In order of debuggers like PDB being able to step through the code,
|
||||
# we add a fake linecache entry.
|
||||
linecache.cache[unique_filename] = (
|
||||
len(script),
|
||||
None,
|
||||
script.splitlines(True),
|
||||
unique_filename,
|
||||
)
|
||||
|
||||
return locs["__hash__"]
|
||||
return _make_method("__hash__", script, unique_filename)
|
||||
|
||||
|
||||
def _add_hash(cls, attrs):
|
||||
@@ -1575,34 +1732,44 @@ def _make_eq(cls, attrs):
|
||||
" if other.__class__ is not self.__class__:",
|
||||
" return NotImplemented",
|
||||
]
|
||||
|
||||
# We can't just do a big self.x = other.x and... clause due to
|
||||
# irregularities like nan == nan is false but (nan,) == (nan,) is true.
|
||||
globs = {}
|
||||
if attrs:
|
||||
lines.append(" return (")
|
||||
others = [" ) == ("]
|
||||
for a in attrs:
|
||||
lines.append(" self.%s," % (a.name,))
|
||||
others.append(" other.%s," % (a.name,))
|
||||
if a.eq_key:
|
||||
cmp_name = "_%s_key" % (a.name,)
|
||||
# Add the key function to the global namespace
|
||||
# of the evaluated function.
|
||||
globs[cmp_name] = a.eq_key
|
||||
lines.append(
|
||||
" %s(self.%s),"
|
||||
% (
|
||||
cmp_name,
|
||||
a.name,
|
||||
)
|
||||
)
|
||||
others.append(
|
||||
" %s(other.%s),"
|
||||
% (
|
||||
cmp_name,
|
||||
a.name,
|
||||
)
|
||||
)
|
||||
else:
|
||||
lines.append(" self.%s," % (a.name,))
|
||||
others.append(" other.%s," % (a.name,))
|
||||
|
||||
lines += others + [" )"]
|
||||
else:
|
||||
lines.append(" return True")
|
||||
|
||||
script = "\n".join(lines)
|
||||
globs = {}
|
||||
locs = {}
|
||||
bytecode = compile(script, unique_filename, "exec")
|
||||
eval(bytecode, globs, locs)
|
||||
|
||||
# In order of debuggers like PDB being able to step through the code,
|
||||
# we add a fake linecache entry.
|
||||
linecache.cache[unique_filename] = (
|
||||
len(script),
|
||||
None,
|
||||
script.splitlines(True),
|
||||
unique_filename,
|
||||
)
|
||||
return locs["__eq__"]
|
||||
return _make_method("__eq__", script, unique_filename, globs)
|
||||
|
||||
|
||||
def _make_order(cls, attrs):
|
||||
@@ -1615,7 +1782,12 @@ def _make_order(cls, attrs):
|
||||
"""
|
||||
Save us some typing.
|
||||
"""
|
||||
return _attrs_to_tuple(obj, attrs)
|
||||
return tuple(
|
||||
key(value) if key else value
|
||||
for value, key in (
|
||||
(getattr(obj, a.name), a.order_key) for a in attrs
|
||||
)
|
||||
)
|
||||
|
||||
def __lt__(self, other):
|
||||
"""
|
||||
@@ -1829,6 +2001,7 @@ def _is_slot_attr(a_name, base_attr_map):
|
||||
def _make_init(
|
||||
cls,
|
||||
attrs,
|
||||
pre_init,
|
||||
post_init,
|
||||
frozen,
|
||||
slots,
|
||||
@@ -1836,6 +2009,7 @@ def _make_init(
|
||||
base_attr_map,
|
||||
is_exc,
|
||||
has_global_on_setattr,
|
||||
attrs_init,
|
||||
):
|
||||
if frozen and has_global_on_setattr:
|
||||
raise ValueError("Frozen classes can't use on_setattr.")
|
||||
@@ -1866,15 +2040,19 @@ def _make_init(
|
||||
filtered_attrs,
|
||||
frozen,
|
||||
slots,
|
||||
pre_init,
|
||||
post_init,
|
||||
cache_hash,
|
||||
base_attr_map,
|
||||
is_exc,
|
||||
needs_cached_setattr,
|
||||
has_global_on_setattr,
|
||||
attrs_init,
|
||||
)
|
||||
locs = {}
|
||||
bytecode = compile(script, unique_filename, "exec")
|
||||
if cls.__module__ in sys.modules:
|
||||
# This makes typing.get_type_hints(CLS.__init__) resolve string types.
|
||||
globs.update(sys.modules[cls.__module__].__dict__)
|
||||
|
||||
globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
|
||||
|
||||
if needs_cached_setattr:
|
||||
@@ -1882,21 +2060,15 @@ def _make_init(
|
||||
# setattr hooks.
|
||||
globs["_cached_setattr"] = _obj_setattr
|
||||
|
||||
eval(bytecode, globs, locs)
|
||||
|
||||
# In order of debuggers like PDB being able to step through the code,
|
||||
# we add a fake linecache entry.
|
||||
linecache.cache[unique_filename] = (
|
||||
len(script),
|
||||
None,
|
||||
script.splitlines(True),
|
||||
init = _make_method(
|
||||
"__attrs_init__" if attrs_init else "__init__",
|
||||
script,
|
||||
unique_filename,
|
||||
globs,
|
||||
)
|
||||
init.__annotations__ = annotations
|
||||
|
||||
__init__ = locs["__init__"]
|
||||
__init__.__annotations__ = annotations
|
||||
|
||||
return __init__
|
||||
return init
|
||||
|
||||
|
||||
def _setattr(attr_name, value_var, has_on_setattr):
|
||||
@@ -2005,12 +2177,14 @@ def _attrs_to_init_script(
|
||||
attrs,
|
||||
frozen,
|
||||
slots,
|
||||
pre_init,
|
||||
post_init,
|
||||
cache_hash,
|
||||
base_attr_map,
|
||||
is_exc,
|
||||
needs_cached_setattr,
|
||||
has_global_on_setattr,
|
||||
attrs_init,
|
||||
):
|
||||
"""
|
||||
Return a script of an initializer for *attrs* and a dict of globals.
|
||||
@@ -2021,6 +2195,9 @@ def _attrs_to_init_script(
|
||||
a cached ``object.__setattr__``.
|
||||
"""
|
||||
lines = []
|
||||
if pre_init:
|
||||
lines.append("self.__attrs_pre_init__()")
|
||||
|
||||
if needs_cached_setattr:
|
||||
lines.append(
|
||||
# Circumvent the __setattr__ descriptor to save one lookup per
|
||||
@@ -2210,8 +2387,24 @@ def _attrs_to_init_script(
|
||||
else:
|
||||
lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
|
||||
|
||||
if a.init is True and a.converter is None and a.type is not None:
|
||||
annotations[arg_name] = a.type
|
||||
if a.init is True:
|
||||
if a.type is not None and a.converter is None:
|
||||
annotations[arg_name] = a.type
|
||||
elif a.converter is not None and not PY2:
|
||||
# Try to get the type from the converter.
|
||||
sig = None
|
||||
try:
|
||||
sig = inspect.signature(a.converter)
|
||||
except (ValueError, TypeError): # inspect failed
|
||||
pass
|
||||
if sig:
|
||||
sig_params = list(sig.parameters.values())
|
||||
if (
|
||||
sig_params
|
||||
and sig_params[0].annotation
|
||||
is not inspect.Parameter.empty
|
||||
):
|
||||
annotations[arg_name] = sig_params[0].annotation
|
||||
|
||||
if attrs_to_validate: # we can skip this if there are no validators.
|
||||
names_for_globals["_config"] = _config
|
||||
@@ -2265,10 +2458,12 @@ def _attrs_to_init_script(
|
||||
)
|
||||
return (
|
||||
"""\
|
||||
def __init__(self, {args}):
|
||||
def {init_name}(self, {args}):
|
||||
{lines}
|
||||
""".format(
|
||||
args=args, lines="\n ".join(lines) if lines else "pass"
|
||||
init_name=("__attrs_init__" if attrs_init else "__init__"),
|
||||
args=args,
|
||||
lines="\n ".join(lines) if lines else "pass",
|
||||
),
|
||||
names_for_globals,
|
||||
annotations,
|
||||
@@ -2297,6 +2492,7 @@ class Attribute(object):
|
||||
.. versionadded:: 20.1.0 *on_setattr*
|
||||
.. versionchanged:: 20.2.0 *inherited* is not taken into account for
|
||||
equality checks and hashing anymore.
|
||||
.. versionadded:: 21.1.0 *eq_key* and *order_key*
|
||||
|
||||
For the full version history of the fields, see `attr.ib`.
|
||||
"""
|
||||
@@ -2307,7 +2503,9 @@ class Attribute(object):
|
||||
"validator",
|
||||
"repr",
|
||||
"eq",
|
||||
"eq_key",
|
||||
"order",
|
||||
"order_key",
|
||||
"hash",
|
||||
"init",
|
||||
"metadata",
|
||||
@@ -2333,10 +2531,14 @@ class Attribute(object):
|
||||
converter=None,
|
||||
kw_only=False,
|
||||
eq=None,
|
||||
eq_key=None,
|
||||
order=None,
|
||||
order_key=None,
|
||||
on_setattr=None,
|
||||
):
|
||||
eq, order = _determine_eq_order(cmp, eq, order, True)
|
||||
eq, eq_key, order, order_key = _determine_attrib_eq_order(
|
||||
cmp, eq_key or eq, order_key or order, True
|
||||
)
|
||||
|
||||
# Cache this descriptor here to speed things up later.
|
||||
bound_setattr = _obj_setattr.__get__(self, Attribute)
|
||||
@@ -2348,7 +2550,9 @@ class Attribute(object):
|
||||
bound_setattr("validator", validator)
|
||||
bound_setattr("repr", repr)
|
||||
bound_setattr("eq", eq)
|
||||
bound_setattr("eq_key", eq_key)
|
||||
bound_setattr("order", order)
|
||||
bound_setattr("order_key", order_key)
|
||||
bound_setattr("hash", hash)
|
||||
bound_setattr("init", init)
|
||||
bound_setattr("converter", converter)
|
||||
@@ -2495,7 +2699,9 @@ class _CountingAttr(object):
|
||||
"_default",
|
||||
"repr",
|
||||
"eq",
|
||||
"eq_key",
|
||||
"order",
|
||||
"order_key",
|
||||
"hash",
|
||||
"init",
|
||||
"metadata",
|
||||
@@ -2516,7 +2722,9 @@ class _CountingAttr(object):
|
||||
init=True,
|
||||
kw_only=False,
|
||||
eq=True,
|
||||
eq_key=None,
|
||||
order=False,
|
||||
order_key=None,
|
||||
inherited=False,
|
||||
on_setattr=None,
|
||||
)
|
||||
@@ -2541,7 +2749,9 @@ class _CountingAttr(object):
|
||||
init=True,
|
||||
kw_only=False,
|
||||
eq=True,
|
||||
eq_key=None,
|
||||
order=False,
|
||||
order_key=None,
|
||||
inherited=False,
|
||||
on_setattr=None,
|
||||
),
|
||||
@@ -2553,7 +2763,7 @@ class _CountingAttr(object):
|
||||
default,
|
||||
validator,
|
||||
repr,
|
||||
cmp, # XXX: unused, remove along with cmp
|
||||
cmp,
|
||||
hash,
|
||||
init,
|
||||
converter,
|
||||
@@ -2561,7 +2771,9 @@ class _CountingAttr(object):
|
||||
type,
|
||||
kw_only,
|
||||
eq,
|
||||
eq_key,
|
||||
order,
|
||||
order_key,
|
||||
on_setattr,
|
||||
):
|
||||
_CountingAttr.cls_counter += 1
|
||||
@@ -2571,7 +2783,9 @@ class _CountingAttr(object):
|
||||
self.converter = converter
|
||||
self.repr = repr
|
||||
self.eq = eq
|
||||
self.eq_key = eq_key
|
||||
self.order = order
|
||||
self.order_key = order_key
|
||||
self.hash = hash
|
||||
self.init = init
|
||||
self.metadata = metadata
|
||||
@@ -2614,7 +2828,6 @@ class _CountingAttr(object):
|
||||
_CountingAttr = _add_eq(_add_repr(_CountingAttr))
|
||||
|
||||
|
||||
@attrs(slots=True, init=False, hash=True)
|
||||
class Factory(object):
|
||||
"""
|
||||
Stores a factory callable.
|
||||
@@ -2630,8 +2843,7 @@ class Factory(object):
|
||||
.. versionadded:: 17.1.0 *takes_self*
|
||||
"""
|
||||
|
||||
factory = attrib()
|
||||
takes_self = attrib()
|
||||
__slots__ = ("factory", "takes_self")
|
||||
|
||||
def __init__(self, factory, takes_self=False):
|
||||
"""
|
||||
@@ -2641,6 +2853,38 @@ class Factory(object):
|
||||
self.factory = factory
|
||||
self.takes_self = takes_self
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Play nice with pickle.
|
||||
"""
|
||||
return tuple(getattr(self, name) for name in self.__slots__)
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Play nice with pickle.
|
||||
"""
|
||||
for name, value in zip(self.__slots__, state):
|
||||
setattr(self, name, value)
|
||||
|
||||
|
||||
_f = [
|
||||
Attribute(
|
||||
name=name,
|
||||
default=NOTHING,
|
||||
validator=None,
|
||||
repr=True,
|
||||
cmp=None,
|
||||
eq=True,
|
||||
order=False,
|
||||
hash=True,
|
||||
init=True,
|
||||
inherited=False,
|
||||
)
|
||||
for name in Factory.__slots__
|
||||
]
|
||||
|
||||
Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
|
||||
|
||||
|
||||
def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
||||
"""
|
||||
@@ -2674,12 +2918,20 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
||||
else:
|
||||
raise TypeError("attrs argument must be a dict or a list.")
|
||||
|
||||
pre_init = cls_dict.pop("__attrs_pre_init__", None)
|
||||
post_init = cls_dict.pop("__attrs_post_init__", None)
|
||||
type_ = type(
|
||||
name,
|
||||
bases,
|
||||
{} if post_init is None else {"__attrs_post_init__": post_init},
|
||||
)
|
||||
user_init = cls_dict.pop("__init__", None)
|
||||
|
||||
body = {}
|
||||
if pre_init is not None:
|
||||
body["__attrs_pre_init__"] = pre_init
|
||||
if post_init is not None:
|
||||
body["__attrs_post_init__"] = post_init
|
||||
if user_init is not None:
|
||||
body["__init__"] = user_init
|
||||
|
||||
type_ = new_class(name, bases, {}, lambda ns: ns.update(body))
|
||||
|
||||
# For pickling to work, the __module__ variable needs to be set to the
|
||||
# frame where the class is created. Bypass this step in environments where
|
||||
# sys._getframe is not defined (Jython for example) or sys._getframe is not
|
||||
@@ -2696,7 +2948,7 @@ def make_class(name, attrs, bases=(object,), **attributes_arguments):
|
||||
(
|
||||
attributes_arguments["eq"],
|
||||
attributes_arguments["order"],
|
||||
) = _determine_eq_order(
|
||||
) = _determine_attrs_eq_order(
|
||||
cmp,
|
||||
attributes_arguments.get("eq"),
|
||||
attributes_arguments.get("order"),
|
||||
@@ -2751,6 +3003,9 @@ def pipe(*converters):
|
||||
When called on a value, it runs all wrapped converters, returning the
|
||||
*last* value.
|
||||
|
||||
Type annotations will be inferred from the wrapped converters', if
|
||||
they have any.
|
||||
|
||||
:param callables converters: Arbitrary number of converters.
|
||||
|
||||
.. versionadded:: 20.1.0
|
||||
@@ -2762,4 +3017,36 @@ def pipe(*converters):
|
||||
|
||||
return val
|
||||
|
||||
if not PY2:
|
||||
if not converters:
|
||||
# If the converter list is empty, pipe_converter is the identity.
|
||||
A = typing.TypeVar("A")
|
||||
pipe_converter.__annotations__ = {"val": A, "return": A}
|
||||
else:
|
||||
# Get parameter type.
|
||||
sig = None
|
||||
try:
|
||||
sig = inspect.signature(converters[0])
|
||||
except (ValueError, TypeError): # inspect failed
|
||||
pass
|
||||
if sig:
|
||||
params = list(sig.parameters.values())
|
||||
if (
|
||||
params
|
||||
and params[0].annotation is not inspect.Parameter.empty
|
||||
):
|
||||
pipe_converter.__annotations__["val"] = params[
|
||||
0
|
||||
].annotation
|
||||
# Get return type.
|
||||
sig = None
|
||||
try:
|
||||
sig = inspect.signature(converters[-1])
|
||||
except (ValueError, TypeError): # inspect failed
|
||||
pass
|
||||
if sig and sig.return_annotation is not inspect.Signature().empty:
|
||||
pipe_converter.__annotations__[
|
||||
"return"
|
||||
] = sig.return_annotation
|
||||
|
||||
return pipe_converter
|
||||
|
||||
Vendored
+4
-6
@@ -1,8 +1,6 @@
|
||||
"""
|
||||
This is a Python 3.6 and later-only, keyword-only, and **provisional** API that
|
||||
calls `attr.s` with different default values.
|
||||
|
||||
Provisional APIs that shall become "import attrs" one glorious day.
|
||||
These are Python 3.6+-only and keyword-only APIs that call `attr.s` and
|
||||
`attr.ib` with different default values.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
@@ -42,8 +40,8 @@ def define(
|
||||
:param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves
|
||||
exactly like `attr.s`. If left `None`, `attr.s` will try to guess:
|
||||
|
||||
1. If all attributes are annotated and no `attr.ib` is found, it assumes
|
||||
*auto_attribs=True*.
|
||||
1. If any attributes are annotated and no unannotated `attr.ib`\ s
|
||||
are found, it assumes *auto_attribs=True*.
|
||||
2. Otherwise it assumes *auto_attribs=False* and tries to collect
|
||||
`attr.ib`\ s.
|
||||
|
||||
|
||||
Vendored
+27
-1
@@ -4,9 +4,15 @@ Commonly useful converters.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from ._compat import PY2
|
||||
from ._make import NOTHING, Factory, pipe
|
||||
|
||||
|
||||
if not PY2:
|
||||
import inspect
|
||||
import typing
|
||||
|
||||
|
||||
__all__ = [
|
||||
"pipe",
|
||||
"optional",
|
||||
@@ -19,6 +25,9 @@ def optional(converter):
|
||||
A converter that allows an attribute to be optional. An optional attribute
|
||||
is one which can be set to ``None``.
|
||||
|
||||
Type annotations will be inferred from the wrapped converter's, if it
|
||||
has any.
|
||||
|
||||
:param callable converter: the converter that is used for non-``None``
|
||||
values.
|
||||
|
||||
@@ -30,6 +39,23 @@ def optional(converter):
|
||||
return None
|
||||
return converter(val)
|
||||
|
||||
if not PY2:
|
||||
sig = None
|
||||
try:
|
||||
sig = inspect.signature(converter)
|
||||
except (ValueError, TypeError): # inspect failed
|
||||
pass
|
||||
if sig:
|
||||
params = list(sig.parameters.values())
|
||||
if params and params[0].annotation is not inspect.Parameter.empty:
|
||||
optional_converter.__annotations__["val"] = typing.Optional[
|
||||
params[0].annotation
|
||||
]
|
||||
if sig.return_annotation is not inspect.Signature.empty:
|
||||
optional_converter.__annotations__["return"] = typing.Optional[
|
||||
sig.return_annotation
|
||||
]
|
||||
|
||||
return optional_converter
|
||||
|
||||
|
||||
@@ -41,7 +67,7 @@ def default_if_none(default=NOTHING, factory=None):
|
||||
:param default: Value to be used if ``None`` is passed. Passing an instance
|
||||
of `attr.Factory` is supported, however the ``takes_self`` option
|
||||
is *not*.
|
||||
:param callable factory: A callable that takes not parameters whose result
|
||||
:param callable factory: A callable that takes no parameters whose result
|
||||
is used if ``None`` is passed.
|
||||
|
||||
:raises TypeError: If **neither** *default* or *factory* is passed.
|
||||
|
||||
Vendored
+3
-1
@@ -1,6 +1,8 @@
|
||||
from typing import TypeVar, Optional, Callable, overload
|
||||
from typing import Callable, Optional, TypeVar, overload
|
||||
|
||||
from . import _ConverterType
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
def pipe(*validators: _ConverterType) -> _ConverterType: ...
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ from __future__ import absolute_import, division, print_function
|
||||
|
||||
class FrozenError(AttributeError):
|
||||
"""
|
||||
A frozen/immutable instance or attribute haave been attempted to be
|
||||
A frozen/immutable instance or attribute have been attempted to be
|
||||
modified.
|
||||
|
||||
It mirrors the behavior of ``namedtuples`` by using the same error message
|
||||
|
||||
Vendored
+1
@@ -1,5 +1,6 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
class FrozenError(AttributeError):
|
||||
msg: str = ...
|
||||
|
||||
|
||||
Vendored
+3
-1
@@ -1,5 +1,7 @@
|
||||
from typing import Union, Any
|
||||
from typing import Any, Union
|
||||
|
||||
from . import Attribute, _FilterType
|
||||
|
||||
|
||||
def include(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
|
||||
def exclude(*what: Union[type, Attribute[Any]]) -> _FilterType[Any]: ...
|
||||
|
||||
Vendored
+5
-3
@@ -1,10 +1,12 @@
|
||||
from . import _OnSetAttrType, Attribute
|
||||
from typing import TypeVar, Any, NewType, NoReturn, cast
|
||||
from typing import Any, NewType, NoReturn, TypeVar, cast
|
||||
|
||||
from . import Attribute, _OnSetAttrType
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
def frozen(
|
||||
instance: Any, attribute: Attribute, new_value: Any
|
||||
instance: Any, attribute: Attribute[Any], new_value: Any
|
||||
) -> NoReturn: ...
|
||||
def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ...
|
||||
def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ...
|
||||
|
||||
Vendored
+12
-10
@@ -1,21 +1,23 @@
|
||||
from typing import (
|
||||
Container,
|
||||
List,
|
||||
Union,
|
||||
TypeVar,
|
||||
Type,
|
||||
Any,
|
||||
AnyStr,
|
||||
Callable,
|
||||
Container,
|
||||
Iterable,
|
||||
List,
|
||||
Mapping,
|
||||
Match,
|
||||
Optional,
|
||||
Tuple,
|
||||
Iterable,
|
||||
Mapping,
|
||||
Callable,
|
||||
Match,
|
||||
AnyStr,
|
||||
Type,
|
||||
TypeVar,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
|
||||
from . import _ValidatorType
|
||||
|
||||
|
||||
_T = TypeVar("_T")
|
||||
_T1 = TypeVar("_T1")
|
||||
_T2 = TypeVar("_T2")
|
||||
|
||||
Vendored
+3
-3
@@ -1,5 +1,5 @@
|
||||
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
|
||||
from . import shutil_get_terminal_size
|
||||
from . import weakref
|
||||
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
||||
from . import enum
|
||||
from . import functools_lru_cache
|
||||
from . import shutil_get_terminal_size
|
||||
from . import weakref
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
Copyright Jason R. Coombs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+4
-4
@@ -4,7 +4,7 @@ import functools
|
||||
from collections import namedtuple
|
||||
from threading import RLock
|
||||
|
||||
_CacheInfo = namedtuple("CacheInfo", ["hits", "misses", "maxsize", "currsize"])
|
||||
_CacheInfo = namedtuple("_CacheInfo", ["hits", "misses", "maxsize", "currsize"])
|
||||
|
||||
|
||||
@functools.wraps(functools.update_wrapper)
|
||||
@@ -63,7 +63,7 @@ def _make_key(
|
||||
return _HashedSeq(key)
|
||||
|
||||
|
||||
def lru_cache(maxsize=100, typed=False):
|
||||
def lru_cache(maxsize=100, typed=False): # noqa: C901
|
||||
"""Least-recently-used cache decorator.
|
||||
|
||||
If *maxsize* is set to None, the LRU features are disabled and the cache
|
||||
@@ -136,7 +136,7 @@ def lru_cache(maxsize=100, typed=False):
|
||||
if link is not None:
|
||||
# record recent use of the key by moving it
|
||||
# to the front of the list
|
||||
root, = nonlocal_root
|
||||
(root,) = nonlocal_root
|
||||
link_prev, link_next, key, result = link
|
||||
link_prev[NEXT] = link_next
|
||||
link_next[PREV] = link_prev
|
||||
@@ -148,7 +148,7 @@ def lru_cache(maxsize=100, typed=False):
|
||||
return result
|
||||
result = user_function(*args, **kwds)
|
||||
with lock:
|
||||
root, = nonlocal_root
|
||||
(root,) = nonlocal_root
|
||||
if key in cache:
|
||||
# getting here means that this same key was added to the
|
||||
# cache while the lock was released. since the link
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
Copyright (c) 2015, Daniel Greenfeld
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of cached-property nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
Vendored
+2
-2
@@ -1,10 +1,10 @@
|
||||
"""
|
||||
Extensible validation for Python dictionaries.
|
||||
|
||||
:copyright: 2012-2016 by Nicola Iarocci.
|
||||
:copyright: 2012-2021 by Nicola Iarocci.
|
||||
:license: ISC, see LICENSE for more details.
|
||||
|
||||
Full documentation is available at http://python-cerberus.org/
|
||||
Full documentation is available at https://python-cerberus.org/
|
||||
|
||||
"""
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
DOCUMENTS_PATH = Path(__file__).parent / "documents"
|
||||
@@ -0,0 +1,212 @@
|
||||
"""
|
||||
some notes regarding this test suite:
|
||||
- results are only comparable using the semantically equal schema against and
|
||||
identical set of documents in the same execution environment
|
||||
- the module can be executed to generate a new set of test documents
|
||||
- it is intended to detect *significant* changes in validation time
|
||||
- benchmarks should run with as few other processes running on the system as
|
||||
possible (e.g. an Alpine Linux on bare metal w/o a Desktop environment)
|
||||
"""
|
||||
|
||||
import json
|
||||
from collections import Counter
|
||||
from pathlib import Path
|
||||
from random import choice, randrange
|
||||
from typing import Callable, List
|
||||
|
||||
from pytest import mark
|
||||
|
||||
from cerberus import rules_set_registry, schema_registry, TypeDefinition, Validator
|
||||
from cerberus.benchmarks import DOCUMENTS_PATH
|
||||
|
||||
|
||||
rules_set_registry.add("path_rules", {"coerce": Path, "type": "path"})
|
||||
|
||||
|
||||
schema_registry.add(
|
||||
"field_3_schema",
|
||||
{
|
||||
# an outer rule requires all fields' values to be a list
|
||||
"field_31": {"contains": 0, "empty": False},
|
||||
"field_32": {
|
||||
"default": [None, None, None],
|
||||
"items": [
|
||||
{"type": "integer"},
|
||||
{"type": "string"},
|
||||
{"type": ["integer", "string"]},
|
||||
],
|
||||
"schema": {"nullable": True},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def schema_1_field_3_allow_unknown_check_with(field, value, error):
|
||||
if len(value) > 9:
|
||||
error(field, "Requires a smaller list.")
|
||||
|
||||
|
||||
schema_1 = {
|
||||
"field_1": {
|
||||
"type": "dict",
|
||||
"required": True,
|
||||
"allow_unknown": True,
|
||||
"keysrules": {"regex": r"field_1[12345]"},
|
||||
"minlength": 3,
|
||||
"maxlength": 5,
|
||||
"schema": {
|
||||
"field_11": {
|
||||
"type": "integer",
|
||||
"allowed": list(range(100)),
|
||||
"dependencies": {"field_12": 0, "^field_1.field_13": 0},
|
||||
},
|
||||
"field_12": {
|
||||
"type": "integer",
|
||||
"default_setter": lambda _: 1,
|
||||
"forbidden": (1,),
|
||||
},
|
||||
"field_13": {"type": "integer"},
|
||||
"field_14": {"rename": "field_13"},
|
||||
},
|
||||
},
|
||||
"field_2": {
|
||||
"type": "dict",
|
||||
"allow_unknown": False,
|
||||
"schema": {
|
||||
"field_21": {
|
||||
"type": "integer",
|
||||
"coerce": [str.strip, int],
|
||||
"min": 9,
|
||||
"max": 89,
|
||||
"anyof": [{"dependencies": "field_22"}, {"dependencies": "field_23"}],
|
||||
},
|
||||
"field_22": {"excludes": "field_23", "nullable": True},
|
||||
"field_23": {"nullable": True},
|
||||
},
|
||||
},
|
||||
"field_3": {
|
||||
"allow_unknown": {"check_with": schema_1_field_3_allow_unknown_check_with},
|
||||
"valuesrules": {"type": "list"},
|
||||
"require_all": True,
|
||||
"schema": "field_3_schema",
|
||||
},
|
||||
"field_4": "path_rules",
|
||||
}
|
||||
|
||||
|
||||
def init_validator():
|
||||
class TestValidator(Validator):
|
||||
types_mapping = {
|
||||
**Validator.types_mapping,
|
||||
"path": TypeDefinition("path", (Path,), ()),
|
||||
}
|
||||
|
||||
return TestValidator(schema_1, purge_unknown=True)
|
||||
|
||||
|
||||
def load_documents():
|
||||
with (DOCUMENTS_PATH / "overall_documents_1.json").open() as f:
|
||||
documents = json.load(f)
|
||||
return documents
|
||||
|
||||
|
||||
def validate_documents(init_validator: Callable, documents: List[dict]):
|
||||
doc_count = failed_count = 0
|
||||
error_paths = Counter()
|
||||
validator = init_validator()
|
||||
|
||||
def count_errors(errors):
|
||||
if errors is None:
|
||||
return
|
||||
for error in errors:
|
||||
if error.is_group_error:
|
||||
count_errors(error.child_errors)
|
||||
else:
|
||||
error_paths[error.schema_path] += 1
|
||||
|
||||
for document in documents:
|
||||
if validator.validated(document) is None:
|
||||
failed_count += 1
|
||||
count_errors(validator._errors)
|
||||
doc_count += 1
|
||||
|
||||
print(
|
||||
f"{failed_count} out of {doc_count} documents failed with "
|
||||
f"{len(error_paths)} different error leafs."
|
||||
)
|
||||
print("Top 3 errors, excluding container errors:")
|
||||
for path, count in error_paths.most_common(3):
|
||||
print(f"{count}: {path}")
|
||||
|
||||
|
||||
@mark.benchmark(group="overall-1")
|
||||
def test_overall_performance_1(benchmark):
|
||||
benchmark.pedantic(validate_documents, (init_validator, load_documents()), rounds=5)
|
||||
|
||||
|
||||
#
|
||||
|
||||
|
||||
def generate_sample_document_1() -> dict:
|
||||
result = {}
|
||||
for i in (1, 2, 3, 4, 5):
|
||||
if randrange(100):
|
||||
result[f"field_{i}"] = globals()[f"generate_document_1_field_{i}"]()
|
||||
return result
|
||||
|
||||
|
||||
def generate_document_1_field_1() -> dict:
|
||||
result = {"field_11": randrange(100), "field_13": 0}
|
||||
if randrange(100):
|
||||
result["field_12"] = 0
|
||||
if not randrange(100):
|
||||
result["field_14"] = None
|
||||
if randrange(100):
|
||||
result["field_15"] = None
|
||||
return result
|
||||
|
||||
|
||||
def generate_document_1_field_2() -> dict:
|
||||
x = "*" if not randrange(50) else " "
|
||||
result = {"field_21": x + str(randrange(100)) + x}
|
||||
|
||||
if randrange(100):
|
||||
result["field_22"] = None
|
||||
if "field_22" in result and not randrange(100):
|
||||
result["field_23"] = None
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def generate_document_1_field_3() -> dict:
|
||||
result = {}
|
||||
if randrange(100):
|
||||
result["field_31"] = [randrange(2) for _ in range(randrange(20))]
|
||||
else:
|
||||
result["field_31"] = None
|
||||
if randrange(100):
|
||||
result["field_32"] = [
|
||||
choice((0, 0, 0, 0, 0, 0, 0, 0, "", None)),
|
||||
choice(("", "", "", "", "", "", "", "", 0, None)),
|
||||
choice((0, 0, 0, 0, "", "", "", "", None)),
|
||||
]
|
||||
if not randrange(10):
|
||||
result["3_unknown"] = [0] * (randrange(10) + 1)
|
||||
return result
|
||||
|
||||
|
||||
def generate_document_1_field_4():
|
||||
return "/foo/bar" if randrange(100) else 0
|
||||
|
||||
|
||||
def generate_document_1_field_5():
|
||||
return None
|
||||
|
||||
|
||||
def write_sample_documents():
|
||||
with (DOCUMENTS_PATH / "overall_documents_1.json").open("wt") as f:
|
||||
json.dump([generate_sample_document_1() for _ in range(10_000)], f)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
write_sample_documents()
|
||||
@@ -0,0 +1,54 @@
|
||||
import json
|
||||
from collections import Counter
|
||||
from typing import Callable, List
|
||||
from typing import Counter as CounterType
|
||||
|
||||
from pytest import mark
|
||||
|
||||
from cerberus import Validator
|
||||
from cerberus.benchmarks.schemas.overalll_schema_2 import product_schema
|
||||
from cerberus.benchmarks import DOCUMENTS_PATH
|
||||
|
||||
|
||||
def init_validator():
|
||||
return Validator(product_schema, purge_unknown=True)
|
||||
|
||||
|
||||
def load_documents():
|
||||
with (DOCUMENTS_PATH / "overall_documents_2.json").open() as f:
|
||||
documents = json.load(f)
|
||||
return documents
|
||||
|
||||
|
||||
def validate_documents(init_validator: Callable, documents: List[dict]) -> None:
|
||||
doc_count = failed_count = 0
|
||||
error_paths: CounterType[tuple] = Counter()
|
||||
validator = init_validator()
|
||||
|
||||
def count_errors(errors):
|
||||
if errors is None:
|
||||
return
|
||||
for error in errors:
|
||||
if error.is_group_error:
|
||||
count_errors(error.child_errors)
|
||||
else:
|
||||
error_paths[error.schema_path] += 1
|
||||
|
||||
for document in documents:
|
||||
if validator.validated(document) is None:
|
||||
failed_count += 1
|
||||
count_errors(validator._errors)
|
||||
doc_count += 1
|
||||
|
||||
print(
|
||||
f"{failed_count} out of {doc_count} documents failed with "
|
||||
f"{len(error_paths)} different error leafs."
|
||||
)
|
||||
print("Top 3 errors, excluding container errors:")
|
||||
for path, count in error_paths.most_common(3):
|
||||
print(f"{count}: {path}")
|
||||
|
||||
|
||||
@mark.benchmark(group="overall-2")
|
||||
def test_overall_performance_2(benchmark):
|
||||
benchmark.pedantic(validate_documents, (init_validator, load_documents()), rounds=5)
|
||||
Vendored
+59
-39
@@ -89,7 +89,7 @@ SCHEMA_ERROR_MISSING = "validation schema missing"
|
||||
|
||||
|
||||
class ValidationError(object):
|
||||
""" A simple class to store and query basic error information. """
|
||||
"""A simple class to store and query basic error information."""
|
||||
|
||||
def __init__(self, document_path, schema_path, code, rule, constraint, value, info):
|
||||
self.document_path = document_path
|
||||
@@ -111,11 +111,11 @@ class ValidationError(object):
|
||||
Type: :class:`tuple` """
|
||||
|
||||
def __eq__(self, other):
|
||||
""" Assumes the errors relate to the same document and schema. """
|
||||
"""Assumes the errors relate to the same document and schema."""
|
||||
return hash(self) == hash(other)
|
||||
|
||||
def __hash__(self):
|
||||
""" Expects that all other properties are transitively determined. """
|
||||
"""Expects that all other properties are transitively determined."""
|
||||
return hash(self.document_path) ^ hash(self.schema_path) ^ hash(self.code)
|
||||
|
||||
def __lt__(self, other):
|
||||
@@ -153,9 +153,10 @@ class ValidationError(object):
|
||||
|
||||
@property
|
||||
def definitions_errors(self):
|
||||
""" Dictionary with errors of an *of-rule mapped to the index of the
|
||||
definition it occurred in. Returns :obj:`None` if not applicable.
|
||||
"""
|
||||
"""
|
||||
Dictionary with errors of an \*of-rule mapped to the index of the definition it
|
||||
occurred in. Returns :obj:`None` if not applicable.
|
||||
"""
|
||||
if not self.is_logic_error:
|
||||
return None
|
||||
|
||||
@@ -167,7 +168,7 @@ class ValidationError(object):
|
||||
|
||||
@property
|
||||
def field(self):
|
||||
""" Field of the contextual mapping, possibly :obj:`None`. """
|
||||
"""Field of the contextual mapping, possibly :obj:`None`."""
|
||||
if self.document_path:
|
||||
return self.document_path[-1]
|
||||
else:
|
||||
@@ -175,25 +176,27 @@ class ValidationError(object):
|
||||
|
||||
@property
|
||||
def is_group_error(self):
|
||||
""" ``True`` for errors of bulk validations. """
|
||||
"""``True`` for errors of bulk validations."""
|
||||
return bool(self.code & ERROR_GROUP.code)
|
||||
|
||||
@property
|
||||
def is_logic_error(self):
|
||||
""" ``True`` for validation errors against different schemas with
|
||||
*of-rules. """
|
||||
"""
|
||||
``True`` for validation errors against different schemas with \*of-rules.
|
||||
"""
|
||||
return bool(self.code & LOGICAL.code - ERROR_GROUP.code)
|
||||
|
||||
@property
|
||||
def is_normalization_error(self):
|
||||
""" ``True`` for normalization errors. """
|
||||
"""``True`` for normalization errors."""
|
||||
return bool(self.code & NORMALIZATION.code)
|
||||
|
||||
|
||||
class ErrorList(list):
|
||||
""" A list for :class:`~cerberus.errors.ValidationError` instances that
|
||||
can be queried with the ``in`` keyword for a particular
|
||||
:class:`~cerberus.errors.ErrorDefinition`. """
|
||||
"""
|
||||
A list for :class:`~cerberus.errors.ValidationError` instances that can be queried
|
||||
with the ``in`` keyword for a particular :class:`~cerberus.errors.ErrorDefinition`.
|
||||
"""
|
||||
|
||||
def __contains__(self, error_definition):
|
||||
if not isinstance(error_definition, ErrorDefinition):
|
||||
@@ -277,8 +280,10 @@ class ErrorTreeNode(MutableMapping):
|
||||
|
||||
|
||||
class ErrorTree(ErrorTreeNode):
|
||||
""" Base class for :class:`~cerberus.errors.DocumentErrorTree` and
|
||||
:class:`~cerberus.errors.SchemaErrorTree`. """
|
||||
"""
|
||||
Base class for :class:`~cerberus.errors.DocumentErrorTree` and
|
||||
:class:`~cerberus.errors.SchemaErrorTree`.
|
||||
"""
|
||||
|
||||
def __init__(self, errors=()):
|
||||
self.parent_node = None
|
||||
@@ -290,7 +295,8 @@ class ErrorTree(ErrorTreeNode):
|
||||
self.add(error)
|
||||
|
||||
def add(self, error):
|
||||
""" Add an error to the tree.
|
||||
"""
|
||||
Add an error to the tree.
|
||||
|
||||
:param error: :class:`~cerberus.errors.ValidationError`
|
||||
"""
|
||||
@@ -301,7 +307,8 @@ class ErrorTree(ErrorTreeNode):
|
||||
super(ErrorTree, self).add(error)
|
||||
|
||||
def fetch_errors_from(self, path):
|
||||
""" Returns all errors for a particular path.
|
||||
"""
|
||||
Returns all errors for a particular path.
|
||||
|
||||
:param path: :class:`tuple` of :term:`hashable` s.
|
||||
:rtype: :class:`~cerberus.errors.ErrorList`
|
||||
@@ -313,7 +320,8 @@ class ErrorTree(ErrorTreeNode):
|
||||
return ErrorList()
|
||||
|
||||
def fetch_node_from(self, path):
|
||||
""" Returns a node for a path.
|
||||
"""
|
||||
Returns a node for a path.
|
||||
|
||||
:param path: Tuple of :term:`hashable` s.
|
||||
:rtype: :class:`~cerberus.errors.ErrorTreeNode` or :obj:`None`
|
||||
@@ -327,29 +335,34 @@ class ErrorTree(ErrorTreeNode):
|
||||
|
||||
|
||||
class DocumentErrorTree(ErrorTree):
|
||||
""" Implements a dict-like class to query errors by indexes following the
|
||||
structure of a validated document. """
|
||||
"""
|
||||
Implements a dict-like class to query errors by indexes following the structure of a
|
||||
validated document.
|
||||
"""
|
||||
|
||||
tree_type = 'document'
|
||||
|
||||
|
||||
class SchemaErrorTree(ErrorTree):
|
||||
""" Implements a dict-like class to query errors by indexes following the
|
||||
structure of the used schema. """
|
||||
"""
|
||||
Implements a dict-like class to query errors by indexes following the structure of
|
||||
the used schema.
|
||||
"""
|
||||
|
||||
tree_type = 'schema'
|
||||
|
||||
|
||||
class BaseErrorHandler(object):
|
||||
""" Base class for all error handlers.
|
||||
Subclasses are identified as error-handlers with an instance-test. """
|
||||
"""Base class for all error handlers.
|
||||
Subclasses are identified as error-handlers with an instance-test."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" Optionally initialize a new instance. """
|
||||
"""Optionally initialize a new instance."""
|
||||
pass
|
||||
|
||||
def __call__(self, errors):
|
||||
""" Returns errors in a handler-specific format.
|
||||
"""
|
||||
Returns errors in a handler-specific format.
|
||||
|
||||
:param errors: An object containing the errors.
|
||||
:type errors: :term:`iterable` of
|
||||
@@ -359,11 +372,12 @@ class BaseErrorHandler(object):
|
||||
raise NotImplementedError
|
||||
|
||||
def __iter__(self):
|
||||
""" Be a superhero and implement an iterator over errors. """
|
||||
"""Be a superhero and implement an iterator over errors."""
|
||||
raise NotImplementedError
|
||||
|
||||
def add(self, error):
|
||||
""" Add an error to the errors' container object of a handler.
|
||||
"""
|
||||
Add an error to the errors' container object of a handler.
|
||||
|
||||
:param error: The error to add.
|
||||
:type error: :class:`~cerberus.errors.ValidationError`
|
||||
@@ -371,8 +385,9 @@ class BaseErrorHandler(object):
|
||||
raise NotImplementedError
|
||||
|
||||
def emit(self, error):
|
||||
""" Optionally emits an error in the handler's format to a stream.
|
||||
Or light a LED, or even shut down a power plant.
|
||||
"""
|
||||
Optionally emits an error in the handler's format to a stream. Or light a LED,
|
||||
or even shut down a power plant.
|
||||
|
||||
:param error: The error to emit.
|
||||
:type error: :class:`~cerberus.errors.ValidationError`
|
||||
@@ -380,14 +395,17 @@ class BaseErrorHandler(object):
|
||||
pass
|
||||
|
||||
def end(self, validator):
|
||||
""" Gets called when a validation ends.
|
||||
"""
|
||||
Gets called when a validation ends.
|
||||
|
||||
:param validator: The calling validator.
|
||||
:type validator: :class:`~cerberus.Validator` """
|
||||
:type validator: :class:`~cerberus.Validator`
|
||||
"""
|
||||
pass
|
||||
|
||||
def extend(self, errors):
|
||||
""" Adds all errors to the handler's container object.
|
||||
"""
|
||||
Adds all errors to the handler's container object.
|
||||
|
||||
:param errors: The errors to add.
|
||||
:type errors: :term:`iterable` of
|
||||
@@ -397,7 +415,8 @@ class BaseErrorHandler(object):
|
||||
self.add(error)
|
||||
|
||||
def start(self, validator):
|
||||
""" Gets called when a validation starts.
|
||||
"""
|
||||
Gets called when a validation starts.
|
||||
|
||||
:param validator: The calling validator.
|
||||
:type validator: :class:`~cerberus.Validator`
|
||||
@@ -441,9 +460,9 @@ def encode_unicode(f):
|
||||
|
||||
|
||||
class BasicErrorHandler(BaseErrorHandler):
|
||||
""" Models cerberus' legacy. Returns a :class:`dict`. When mangled
|
||||
through :class:`str` a pretty-formatted representation of that
|
||||
tree is returned.
|
||||
"""
|
||||
Models cerberus' legacy. Returns a :class:`dict`. When mangled through :class:`str`
|
||||
a pretty-formatted representation of that tree is returned.
|
||||
"""
|
||||
|
||||
messages = {
|
||||
@@ -532,7 +551,8 @@ class BasicErrorHandler(BaseErrorHandler):
|
||||
)
|
||||
|
||||
def _insert_error(self, path, node):
|
||||
""" Adds an error or sub-tree to :attr:tree.
|
||||
"""
|
||||
Adds an error or sub-tree to :attr:tree.
|
||||
|
||||
:param path: Path to the error.
|
||||
:type path: Tuple of strings and integers.
|
||||
|
||||
Vendored
+3
@@ -2,6 +2,9 @@
|
||||
|
||||
import sys
|
||||
|
||||
if sys.flags.optimize == 2:
|
||||
raise RuntimeError("Cerberus can't be run with Python's optimization level 2.")
|
||||
|
||||
|
||||
PYTHON_VERSION = float(sys.version_info[0]) + float(sys.version_info[1]) / 10
|
||||
|
||||
|
||||
Vendored
+59
-39
@@ -1,6 +1,5 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from copy import copy
|
||||
from warnings import warn
|
||||
|
||||
from cerberus import errors
|
||||
@@ -25,14 +24,15 @@ class _Abort(Exception):
|
||||
|
||||
|
||||
class SchemaError(Exception):
|
||||
""" Raised when the validation schema is missing, has the wrong format or
|
||||
contains errors. """
|
||||
"""
|
||||
Raised when the validation schema is missing, has the wrong format or contains
|
||||
errors."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class DefinitionSchema(MutableMapping):
|
||||
""" A dict-subclass for caching of validated schemas. """
|
||||
"""A dict-subclass for caching of validated schemas."""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if 'SchemaValidator' not in globals():
|
||||
@@ -134,7 +134,8 @@ class DefinitionSchema(MutableMapping):
|
||||
|
||||
@classmethod
|
||||
def _expand_logical_shortcuts(cls, schema):
|
||||
""" Expand agglutinated rules in a definition-schema.
|
||||
"""
|
||||
Expand agglutinated rules in a definition-schema.
|
||||
|
||||
:param schema: The schema-definition to expand.
|
||||
:return: The expanded schema-definition.
|
||||
@@ -160,8 +161,10 @@ class DefinitionSchema(MutableMapping):
|
||||
return isinstance(schema[field], Mapping) and 'schema' in schema[field]
|
||||
|
||||
def has_mapping_schema():
|
||||
""" Tries to determine heuristically if the schema-constraints are
|
||||
aimed to mappings. """
|
||||
"""
|
||||
Tries to determine heuristically if the schema-constraints are aimed to
|
||||
mappings.
|
||||
"""
|
||||
try:
|
||||
return all(
|
||||
isinstance(x, Mapping) for x in schema[field]['schema'].values()
|
||||
@@ -249,12 +252,14 @@ class DefinitionSchema(MutableMapping):
|
||||
self.validation_schema = SchemaValidationSchema(self.validator)
|
||||
|
||||
def validate(self, schema=None):
|
||||
""" Validates a schema that defines rules against supported rules.
|
||||
"""
|
||||
Validates a schema that defines rules against supported rules.
|
||||
|
||||
:param schema: The schema to be validated as a legal cerberus schema
|
||||
according to the rules of the assigned Validator object.
|
||||
Raises a :class:`~cerberus.base.SchemaError` when an invalid
|
||||
schema is encountered. """
|
||||
schema is encountered.
|
||||
"""
|
||||
if schema is None:
|
||||
schema = self.schema
|
||||
_hash = (mapping_hash(schema), mapping_hash(self.validator.types_mapping))
|
||||
@@ -266,15 +271,17 @@ class DefinitionSchema(MutableMapping):
|
||||
if isinstance(schema, _str_type):
|
||||
schema = self.validator.schema_registry.get(schema, schema)
|
||||
|
||||
if schema is None:
|
||||
raise SchemaError(errors.SCHEMA_ERROR_MISSING)
|
||||
test_schema = {}
|
||||
for field, rules in schema.items():
|
||||
if isinstance(rules, _str_type):
|
||||
test_schema[field] = rules_set_registry.get(rules, rules)
|
||||
else:
|
||||
test_rules = {}
|
||||
for rule, constraint in rules.items():
|
||||
test_rules[rule.replace(" ", "_")] = constraint
|
||||
test_schema[field] = test_rules
|
||||
|
||||
schema = copy(schema)
|
||||
for field in schema:
|
||||
if isinstance(schema[field], _str_type):
|
||||
schema[field] = rules_set_registry.get(schema[field], schema[field])
|
||||
|
||||
if not self.schema_validator(schema, normalize=False):
|
||||
if not self.schema_validator(test_schema, normalize=False):
|
||||
raise SchemaError(self.schema_validator.errors)
|
||||
|
||||
|
||||
@@ -303,8 +310,10 @@ class SchemaValidationSchema(UnvalidatedSchema):
|
||||
|
||||
|
||||
class SchemaValidatorMixin(object):
|
||||
""" This validator mixin provides mechanics to validate schemas passed to a Cerberus
|
||||
validator. """
|
||||
"""
|
||||
This validator mixin provides mechanics to validate schemas passed to a Cerberus
|
||||
validator.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('known_rules_set_refs', set())
|
||||
@@ -313,22 +322,22 @@ class SchemaValidatorMixin(object):
|
||||
|
||||
@property
|
||||
def known_rules_set_refs(self):
|
||||
""" The encountered references to rules set registry items. """
|
||||
"""The encountered references to rules set registry items."""
|
||||
return self._config['known_rules_set_refs']
|
||||
|
||||
@property
|
||||
def known_schema_refs(self):
|
||||
""" The encountered references to schema registry items. """
|
||||
"""The encountered references to schema registry items."""
|
||||
return self._config['known_schema_refs']
|
||||
|
||||
@property
|
||||
def target_schema(self):
|
||||
""" The schema that is being validated. """
|
||||
"""The schema that is being validated."""
|
||||
return self._config['target_schema']
|
||||
|
||||
@property
|
||||
def target_validator(self):
|
||||
""" The validator whose schema is being validated. """
|
||||
"""The validator whose schema is being validated."""
|
||||
return self._config['target_validator']
|
||||
|
||||
def _check_with_bulk_schema(self, field, value):
|
||||
@@ -434,7 +443,7 @@ class SchemaValidatorMixin(object):
|
||||
return definition
|
||||
|
||||
def _validate_logical(self, rule, field, value):
|
||||
""" {'allowed': ('allof', 'anyof', 'noneof', 'oneof')} """
|
||||
"""{'allowed': ('allof', 'anyof', 'noneof', 'oneof')}"""
|
||||
if not isinstance(value, Sequence):
|
||||
self._error(field, errors.BAD_TYPE)
|
||||
return
|
||||
@@ -464,59 +473,70 @@ class SchemaValidatorMixin(object):
|
||||
|
||||
|
||||
class Registry(object):
|
||||
""" A registry to store and retrieve schemas and parts of it by a name
|
||||
that can be used in validation schemas.
|
||||
"""
|
||||
A registry to store and retrieve schemas and parts of it by a name that can be used
|
||||
in validation schemas.
|
||||
|
||||
:param definitions: Optional, initial definitions.
|
||||
:type definitions: any :term:`mapping` """
|
||||
:type definitions: any :term:`mapping`
|
||||
"""
|
||||
|
||||
def __init__(self, definitions={}):
|
||||
self._storage = {}
|
||||
self.extend(definitions)
|
||||
|
||||
def add(self, name, definition):
|
||||
""" Register a definition to the registry. Existing definitions are
|
||||
replaced silently.
|
||||
"""
|
||||
Register a definition to the registry. Existing definitions are replaced
|
||||
silently.
|
||||
|
||||
:param name: The name which can be used as reference in a validation
|
||||
schema.
|
||||
:type name: :class:`str`
|
||||
:param definition: The definition.
|
||||
:type definition: any :term:`mapping` """
|
||||
:type definition: any :term:`mapping`
|
||||
"""
|
||||
self._storage[name] = self._expand_definition(definition)
|
||||
|
||||
def all(self):
|
||||
""" Returns a :class:`dict` with all registered definitions mapped to
|
||||
their name. """
|
||||
"""
|
||||
Returns a :class:`dict` with all registered definitions mapped to their name.
|
||||
"""
|
||||
return self._storage
|
||||
|
||||
def clear(self):
|
||||
""" Purge all definitions in the registry. """
|
||||
"""Purge all definitions in the registry."""
|
||||
self._storage.clear()
|
||||
|
||||
def extend(self, definitions):
|
||||
""" Add several definitions at once. Existing definitions are
|
||||
"""
|
||||
Add several definitions at once. Existing definitions are
|
||||
replaced silently.
|
||||
|
||||
:param definitions: The names and definitions.
|
||||
:type definitions: a :term:`mapping` or an :term:`iterable` with
|
||||
two-value :class:`tuple` s """
|
||||
two-value :class:`tuple` s
|
||||
"""
|
||||
for name, definition in dict(definitions).items():
|
||||
self.add(name, definition)
|
||||
|
||||
def get(self, name, default=None):
|
||||
""" Retrieve a definition from the registry.
|
||||
"""
|
||||
Retrieve a definition from the registry.
|
||||
|
||||
:param name: The reference that points to the definition.
|
||||
:type name: :class:`str`
|
||||
:param default: Return value if the reference isn't registered. """
|
||||
:param default: Return value if the reference isn't registered.
|
||||
"""
|
||||
return self._storage.get(name, default)
|
||||
|
||||
def remove(self, *names):
|
||||
""" Unregister definitions from the registry.
|
||||
"""
|
||||
Unregister definitions from the registry.
|
||||
|
||||
:param names: The names of the definitions that are to be
|
||||
unregistered. """
|
||||
unregistered.
|
||||
"""
|
||||
for name in names:
|
||||
self._storage.pop(name, None)
|
||||
|
||||
|
||||
+8
-8
@@ -9,8 +9,10 @@ from cerberus.tests.conftest import sample_schema
|
||||
|
||||
|
||||
def assert_exception(exception, document={}, schema=None, validator=None, msg=None):
|
||||
""" Tests whether a specific exception is raised. Optionally also tests
|
||||
whether the exception message is as expected. """
|
||||
"""
|
||||
Tests whether a specific exception is raised. Optionally also tests whether the
|
||||
exception message is as expected.
|
||||
"""
|
||||
if validator is None:
|
||||
validator = Validator()
|
||||
if msg is None:
|
||||
@@ -22,14 +24,12 @@ def assert_exception(exception, document={}, schema=None, validator=None, msg=No
|
||||
|
||||
|
||||
def assert_schema_error(*args):
|
||||
""" Tests whether a validation raises an exception due to a malformed
|
||||
schema. """
|
||||
"""Tests whether a validation raises an exception due to a malformed schema."""
|
||||
assert_exception(SchemaError, *args)
|
||||
|
||||
|
||||
def assert_document_error(*args):
|
||||
""" Tests whether a validation raises an exception due to a malformed
|
||||
document. """
|
||||
"""Tests whether a validation raises an exception due to a malformed document."""
|
||||
assert_exception(DocumentError, *args)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ def assert_fail(
|
||||
errors=None,
|
||||
child_errors=None,
|
||||
):
|
||||
""" Tests whether a validation fails. """
|
||||
"""Tests whether a validation fails."""
|
||||
if validator is None:
|
||||
validator = Validator(sample_schema)
|
||||
result = validator(document, schema, update)
|
||||
@@ -72,7 +72,7 @@ def assert_fail(
|
||||
|
||||
|
||||
def assert_success(document, schema=None, validator=None, update=False):
|
||||
""" Tests whether a validation succeeds. """
|
||||
"""Tests whether a validation succeeds."""
|
||||
if validator is None:
|
||||
validator = Validator(sample_schema)
|
||||
result = validator(document, schema, update)
|
||||
|
||||
+3
-2
@@ -28,11 +28,12 @@ def test_contextual_data_preservation():
|
||||
def test_docstring_parsing():
|
||||
class CustomValidator(cerberus.Validator):
|
||||
def _validate_foo(self, argument, field, value):
|
||||
""" {'type': 'zap'} """
|
||||
"""{'type': 'zap'}"""
|
||||
pass
|
||||
|
||||
def _validate_bar(self, value):
|
||||
""" Test the barreness of a value.
|
||||
"""
|
||||
Test the barreness of a value.
|
||||
|
||||
The rule's arguments are validated against this schema:
|
||||
{'type': 'boolean'}
|
||||
|
||||
+80
-51
@@ -101,6 +101,16 @@ def test_error_tree_from_anyof(validator):
|
||||
|
||||
|
||||
def test_nested_error_paths(validator):
|
||||
# interpreters of the same version on some platforms showed different sort results
|
||||
# over various runs:
|
||||
def assert_has_all_errors(errors, *ref_errs):
|
||||
for ref_err in ref_errs:
|
||||
for error in errors:
|
||||
if error == ref_err:
|
||||
break
|
||||
else:
|
||||
raise AssertionError
|
||||
|
||||
schema = {
|
||||
'a_dict': {
|
||||
'keysrules': {'type': 'integer'},
|
||||
@@ -114,27 +124,27 @@ def test_nested_error_paths(validator):
|
||||
}
|
||||
assert_fail(document, schema, validator=validator)
|
||||
|
||||
_det = validator.document_error_tree
|
||||
_set = validator.schema_error_tree
|
||||
det = validator.document_error_tree
|
||||
set = validator.schema_error_tree
|
||||
|
||||
assert len(_det.errors) == 0
|
||||
assert len(_set.errors) == 0
|
||||
assert len(det.errors) == 0
|
||||
assert len(set.errors) == 0
|
||||
|
||||
assert len(_det['a_dict'].errors) == 2
|
||||
assert len(_set['a_dict'].errors) == 0
|
||||
assert len(det['a_dict'].errors) == 2
|
||||
assert len(set['a_dict'].errors) == 0
|
||||
|
||||
assert _det['a_dict'][0] is None
|
||||
assert len(_det['a_dict']['one'].errors) == 1
|
||||
assert len(_det['a_dict'][2].errors) == 1
|
||||
assert len(_det['a_dict']['three'].errors) == 2
|
||||
assert det['a_dict'][0] is None
|
||||
assert len(det['a_dict']['one'].errors) == 1
|
||||
assert len(det['a_dict'][2].errors) == 1
|
||||
assert len(det['a_dict']['three'].errors) == 2
|
||||
|
||||
assert len(_set['a_dict']['keysrules'].errors) == 1
|
||||
assert len(_set['a_dict']['valuesrules'].errors) == 1
|
||||
assert len(set['a_dict']['keysrules'].errors) == 1
|
||||
assert len(set['a_dict']['valuesrules'].errors) == 1
|
||||
|
||||
assert len(_set['a_dict']['keysrules']['type'].errors) == 2
|
||||
assert len(_set['a_dict']['valuesrules']['regex'].errors) == 2
|
||||
assert len(set['a_dict']['keysrules']['type'].errors) == 2
|
||||
assert len(set['a_dict']['valuesrules']['regex'].errors) == 2
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err1 = ValidationError(
|
||||
('a_dict', 'one'),
|
||||
('a_dict', 'keysrules', 'type'),
|
||||
errors.BAD_TYPE.code,
|
||||
@@ -143,10 +153,8 @@ def test_nested_error_paths(validator):
|
||||
'one',
|
||||
(),
|
||||
)
|
||||
assert _det['a_dict']['one'].errors[0] == _ref_err
|
||||
assert _set['a_dict']['keysrules']['type'].errors[0] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err2 = ValidationError(
|
||||
('a_dict', 2),
|
||||
('a_dict', 'valuesrules', 'regex'),
|
||||
errors.REGEX_MISMATCH.code,
|
||||
@@ -155,10 +163,8 @@ def test_nested_error_paths(validator):
|
||||
'aBc',
|
||||
(),
|
||||
)
|
||||
assert _det['a_dict'][2].errors[0] == _ref_err
|
||||
assert _set['a_dict']['valuesrules']['regex'].errors[0] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err3 = ValidationError(
|
||||
('a_dict', 'three'),
|
||||
('a_dict', 'keysrules', 'type'),
|
||||
errors.BAD_TYPE.code,
|
||||
@@ -167,10 +173,7 @@ def test_nested_error_paths(validator):
|
||||
'three',
|
||||
(),
|
||||
)
|
||||
assert _det['a_dict']['three'].errors[0] == _ref_err
|
||||
assert _set['a_dict']['keysrules']['type'].errors[1] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err4 = ValidationError(
|
||||
('a_dict', 'three'),
|
||||
('a_dict', 'valuesrules', 'regex'),
|
||||
errors.REGEX_MISMATCH.code,
|
||||
@@ -179,20 +182,25 @@ def test_nested_error_paths(validator):
|
||||
'abC',
|
||||
(),
|
||||
)
|
||||
assert _det['a_dict']['three'].errors[1] == _ref_err
|
||||
assert _set['a_dict']['valuesrules']['regex'].errors[1] == _ref_err
|
||||
assert det['a_dict'][2].errors[0] == ref_err2
|
||||
assert det['a_dict']['one'].errors[0] == ref_err1
|
||||
assert_has_all_errors(det['a_dict']['three'].errors, ref_err3, ref_err4)
|
||||
assert_has_all_errors(set['a_dict']['keysrules']['type'].errors, ref_err1, ref_err3)
|
||||
assert_has_all_errors(
|
||||
set['a_dict']['valuesrules']['regex'].errors, ref_err2, ref_err4
|
||||
)
|
||||
|
||||
assert len(_det['a_list'].errors) == 1
|
||||
assert len(_det['a_list'][0].errors) == 1
|
||||
assert _det['a_list'][1] is None
|
||||
assert len(_det['a_list'][2].errors) == 3
|
||||
assert len(_set['a_list'].errors) == 0
|
||||
assert len(_set['a_list']['schema'].errors) == 1
|
||||
assert len(_set['a_list']['schema']['type'].errors) == 1
|
||||
assert len(_set['a_list']['schema']['oneof'][0]['regex'].errors) == 1
|
||||
assert len(_set['a_list']['schema']['oneof'][1]['regex'].errors) == 1
|
||||
assert len(det['a_list'].errors) == 1
|
||||
assert len(det['a_list'][0].errors) == 1
|
||||
assert det['a_list'][1] is None
|
||||
assert len(det['a_list'][2].errors) == 3
|
||||
assert len(set['a_list'].errors) == 0
|
||||
assert len(set['a_list']['schema'].errors) == 1
|
||||
assert len(set['a_list']['schema']['type'].errors) == 1
|
||||
assert len(set['a_list']['schema']['oneof'][0]['regex'].errors) == 1
|
||||
assert len(set['a_list']['schema']['oneof'][1]['regex'].errors) == 1
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err5 = ValidationError(
|
||||
('a_list', 0),
|
||||
('a_list', 'schema', 'type'),
|
||||
errors.BAD_TYPE.code,
|
||||
@@ -201,10 +209,7 @@ def test_nested_error_paths(validator):
|
||||
0,
|
||||
(),
|
||||
)
|
||||
assert _det['a_list'][0].errors[0] == _ref_err
|
||||
assert _set['a_list']['schema']['type'].errors[0] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err6 = ValidationError(
|
||||
('a_list', 2),
|
||||
('a_list', 'schema', 'oneof'),
|
||||
errors.ONEOF.code,
|
||||
@@ -213,10 +218,7 @@ def test_nested_error_paths(validator):
|
||||
'abC',
|
||||
(),
|
||||
)
|
||||
assert _det['a_list'][2].errors[0] == _ref_err
|
||||
assert _set['a_list']['schema']['oneof'].errors[0] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err7 = ValidationError(
|
||||
('a_list', 2),
|
||||
('a_list', 'schema', 'oneof', 0, 'regex'),
|
||||
errors.REGEX_MISMATCH.code,
|
||||
@@ -225,10 +227,7 @@ def test_nested_error_paths(validator):
|
||||
'abC',
|
||||
(),
|
||||
)
|
||||
assert _det['a_list'][2].errors[1] == _ref_err
|
||||
assert _set['a_list']['schema']['oneof'][0]['regex'].errors[0] == _ref_err
|
||||
|
||||
_ref_err = ValidationError(
|
||||
ref_err8 = ValidationError(
|
||||
('a_list', 2),
|
||||
('a_list', 'schema', 'oneof', 1, 'regex'),
|
||||
errors.REGEX_MISMATCH.code,
|
||||
@@ -237,8 +236,38 @@ def test_nested_error_paths(validator):
|
||||
'abC',
|
||||
(),
|
||||
)
|
||||
assert _det['a_list'][2].errors[2] == _ref_err
|
||||
assert _set['a_list']['schema']['oneof'][1]['regex'].errors[0] == _ref_err
|
||||
|
||||
assert det['a_list'][0].errors[0] == ref_err5
|
||||
assert_has_all_errors(det['a_list'][2].errors, ref_err6, ref_err7, ref_err8)
|
||||
assert set['a_list']['schema']['oneof'].errors[0] == ref_err6
|
||||
assert set['a_list']['schema']['oneof'][0]['regex'].errors[0] == ref_err7
|
||||
assert set['a_list']['schema']['oneof'][1]['regex'].errors[0] == ref_err8
|
||||
assert set['a_list']['schema']['type'].errors[0] == ref_err5
|
||||
|
||||
|
||||
def test_path_resolution_for_registry_references():
|
||||
class CustomValidator(Validator):
|
||||
def _normalize_coerce_custom(self, value):
|
||||
raise Exception("Failed coerce")
|
||||
|
||||
validator = CustomValidator()
|
||||
validator.schema_registry.add(
|
||||
"schema1", {"child": {"type": "boolean", "coerce": "custom"}}
|
||||
)
|
||||
validator.schema = {"parent": {"schema": "schema1"}}
|
||||
validator.validate({"parent": {"child": "["}})
|
||||
|
||||
expected = {
|
||||
'parent': [
|
||||
{
|
||||
'child': [
|
||||
"must be of boolean type",
|
||||
"field 'child' cannot be coerced: Failed coerce",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
assert validator.errors == expected
|
||||
|
||||
|
||||
def test_queries():
|
||||
|
||||
+5
-1
@@ -88,7 +88,7 @@ def test_validated_schema_cache():
|
||||
v = Validator({'foozifix': {'coerce': int}})
|
||||
assert len(v._valid_schemas) == cache_size
|
||||
|
||||
max_cache_size = 161
|
||||
max_cache_size = 163
|
||||
assert cache_size <= max_cache_size, (
|
||||
"There's an unexpected high amount (%s) of cached valid "
|
||||
"definition schemas. Unless you added further tests, "
|
||||
@@ -172,3 +172,7 @@ def test_anyof_check_with():
|
||||
assert validator.schema == {
|
||||
'field': {'anyof': [{'check_with': foo}, {'check_with': bar}]}
|
||||
}
|
||||
|
||||
|
||||
def test_rulename_space_is_normalized():
|
||||
Validator(schema={"field": {"default setter": lambda x: x, "type": "string"}})
|
||||
|
||||
+39
-12
@@ -479,7 +479,7 @@ def test_array_unallowed():
|
||||
(field, 'allowed'),
|
||||
errors.UNALLOWED_VALUES,
|
||||
['agent', 'client', 'vendor'],
|
||||
['profit'],
|
||||
(('profit',),),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -596,6 +596,11 @@ def test_regex(validator):
|
||||
)
|
||||
|
||||
|
||||
def test_regex_with_flag():
|
||||
assert_success({"item": "hOly grAil"}, {"item": {"regex": "(?i)holy grail"}})
|
||||
assert_fail({"item": "hOly grAil"}, {"item": {"regex": "holy grail"}})
|
||||
|
||||
|
||||
def test_a_list_of_dicts():
|
||||
assert_success(
|
||||
{
|
||||
@@ -742,7 +747,7 @@ def test_custom_datatype():
|
||||
def test_custom_datatype_rule():
|
||||
class MyValidator(Validator):
|
||||
def _validate_min_number(self, min_number, field, value):
|
||||
""" {'type': 'number'} """
|
||||
"""{'type': 'number'}"""
|
||||
if value < min_number:
|
||||
self._error(field, 'Below the min')
|
||||
|
||||
@@ -769,7 +774,7 @@ def test_custom_datatype_rule():
|
||||
def test_custom_validator():
|
||||
class MyValidator(Validator):
|
||||
def _validate_isodd(self, isodd, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
if isodd and not bool(value & 1):
|
||||
self._error(field, 'Not an odd number')
|
||||
|
||||
@@ -1114,15 +1119,15 @@ def test_options_passed_to_nested_validators(validator):
|
||||
|
||||
|
||||
def test_self_root_document():
|
||||
""" Make sure self.root_document is always the root document.
|
||||
See:
|
||||
"""
|
||||
Make sure self.root_document is always the root document. See:
|
||||
* https://github.com/pyeve/cerberus/pull/42
|
||||
* https://github.com/pyeve/eve/issues/295
|
||||
"""
|
||||
|
||||
class MyValidator(Validator):
|
||||
def _validate_root_doc(self, root_doc, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
if 'sub' not in self.root_document or len(self.root_document['sub']) != 2:
|
||||
self._error(field, 'self.context is not the root doc!')
|
||||
|
||||
@@ -1251,8 +1256,10 @@ def test_unicode_allowed():
|
||||
|
||||
@mark.skipif(sys.version_info[0] < 3, reason='requires python 3.x')
|
||||
def test_unicode_allowed_py3():
|
||||
""" All strings are unicode in Python 3.x. Input doc and schema
|
||||
have equal strings and validation yield success."""
|
||||
"""
|
||||
All strings are unicode in Python 3.x. Input doc and schema have equal strings and
|
||||
validation yield success.
|
||||
"""
|
||||
|
||||
# issue 280
|
||||
doc = {'letters': u'♄εℓł☺'}
|
||||
@@ -1262,9 +1269,11 @@ def test_unicode_allowed_py3():
|
||||
|
||||
@mark.skipif(sys.version_info[0] > 2, reason='requires python 2.x')
|
||||
def test_unicode_allowed_py2():
|
||||
""" Python 2.x encodes value of allowed using default encoding if
|
||||
the string includes characters outside ASCII range. Produced string
|
||||
does not match input which is an unicode string."""
|
||||
"""
|
||||
Python 2.x encodes value of allowed using default encoding if the string includes
|
||||
characters outside ASCII range. Produced string does not match input which is an
|
||||
unicode string.
|
||||
"""
|
||||
|
||||
# issue 280
|
||||
doc = {'letters': u'♄εℓł☺'}
|
||||
@@ -1646,7 +1655,7 @@ def test_dependencies_on_boolean_field_with_value_in_list():
|
||||
def test_document_path():
|
||||
class DocumentPathTester(Validator):
|
||||
def _validate_trail(self, constraint, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
test_doc = self.root_document
|
||||
for crumb in self.document_path:
|
||||
test_doc = test_doc[crumb]
|
||||
@@ -1946,3 +1955,21 @@ def test_require_all_and_exclude():
|
||||
assert_success({'foo': 'value'}, schema, validator)
|
||||
assert_success({'bar': 'value'}, schema, validator)
|
||||
assert_fail({'foo': 'value', 'bar': 'value'}, schema, validator)
|
||||
|
||||
|
||||
def test_allowed_when_passing_list_of_dicts():
|
||||
# https://github.com/pyeve/cerberus/issues/524
|
||||
doc = {'letters': [{'some': 'dict'}]}
|
||||
schema = {'letters': {'type': 'list', 'allowed': ['a', 'b', 'c']}}
|
||||
|
||||
assert_fail(
|
||||
doc,
|
||||
schema,
|
||||
error=(
|
||||
'letters',
|
||||
('letters', 'allowed'),
|
||||
errors.UNALLOWED_VALUES,
|
||||
['a', 'b', 'c'],
|
||||
(({'some': 'dict'},),),
|
||||
),
|
||||
)
|
||||
|
||||
Vendored
+9
-7
@@ -59,10 +59,11 @@ def mapping_hash(schema):
|
||||
|
||||
|
||||
def mapping_to_frozenset(mapping):
|
||||
""" Be aware that this treats any sequence type with the equal members as
|
||||
equal. As it is used to identify equality of schemas, this can be
|
||||
considered okay as definitions are semantically equal regardless the
|
||||
container type. """
|
||||
"""
|
||||
Be aware that this treats any sequence type with the equal members as equal. As it
|
||||
is used to identify equality of schemas, this can be considered okay as definitions
|
||||
are semantically equal regardless the container type.
|
||||
"""
|
||||
|
||||
aggregation = {}
|
||||
|
||||
@@ -102,9 +103,10 @@ class readonly_classproperty(property):
|
||||
|
||||
|
||||
def validator_factory(name, bases=None, namespace={}):
|
||||
""" Dynamically create a :class:`~cerberus.Validator` subclass.
|
||||
Docstrings of mixin-classes will be added to the resulting
|
||||
class' one if ``__doc__`` is not in :obj:`namespace`.
|
||||
"""
|
||||
Dynamically create a :class:`~cerberus.Validator` subclass.
|
||||
Docstrings of mixin-classes will be added to the resulting class' one if ``__doc__``
|
||||
is not in :obj:`namespace`.
|
||||
|
||||
:param name: The name of the new class.
|
||||
:type name: :class:`str`
|
||||
|
||||
Vendored
+209
-142
@@ -52,20 +52,23 @@ def dummy_for_rule_validation(rule_constraints):
|
||||
|
||||
|
||||
class DocumentError(Exception):
|
||||
""" Raised when the target document is missing or has the wrong format """
|
||||
"""Raised when the target document is missing or has the wrong format"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class _SchemaRuleTypeError(Exception):
|
||||
""" Raised when a schema (list) validation encounters a mapping.
|
||||
Not supposed to be used outside this module. """
|
||||
"""
|
||||
Raised when a schema (list) validation encounters a mapping.
|
||||
Not supposed to be used outside this module.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class BareValidator(object):
|
||||
""" Validator class. Normalizes and/or validates any mapping against a
|
||||
"""
|
||||
Validator class. Normalizes and/or validates any mapping against a
|
||||
validation-schema which is provided as an argument at class instantiation
|
||||
or upon calling the :meth:`~cerberus.Validator.validate`,
|
||||
:meth:`~cerberus.Validator.validated` or
|
||||
@@ -112,12 +115,16 @@ class BareValidator(object):
|
||||
""" # noqa: E501
|
||||
|
||||
mandatory_validations = ('nullable',)
|
||||
""" Rules that are evaluated on any field, regardless whether defined in
|
||||
the schema or not.
|
||||
Type: :class:`tuple` """
|
||||
"""
|
||||
Rules that are evaluated on any field, regardless whether defined in the schema or
|
||||
not.
|
||||
Type: :class:`tuple`
|
||||
"""
|
||||
priority_validations = ('nullable', 'readonly', 'type', 'empty')
|
||||
""" Rules that will be processed in that order before any other.
|
||||
Type: :class:`tuple` """
|
||||
"""
|
||||
Rules that will be processed in that order before any other.
|
||||
Type: :class:`tuple`
|
||||
"""
|
||||
types_mapping = {
|
||||
'binary': TypeDefinition('binary', (bytes, bytearray), ()),
|
||||
'boolean': TypeDefinition('boolean', (bool,), ()),
|
||||
@@ -130,16 +137,21 @@ class BareValidator(object):
|
||||
'list': TypeDefinition('list', (Sequence,), (_str_type,)),
|
||||
'number': TypeDefinition('number', (_int_types, float), (bool,)),
|
||||
'set': TypeDefinition('set', (set,), ()),
|
||||
'string': TypeDefinition('string', (_str_type), ()),
|
||||
'string': TypeDefinition('string', (_str_type,), ()),
|
||||
}
|
||||
""" This mapping holds all available constraints for the type rule and
|
||||
their assigned :class:`~cerberus.TypeDefinition`. """
|
||||
"""
|
||||
This mapping holds all available constraints for the type rule and their assigned
|
||||
:class:`~cerberus.TypeDefinition`.
|
||||
"""
|
||||
_valid_schemas = set()
|
||||
""" A :class:`set` of hashes derived from validation schemas that are
|
||||
legit for a particular ``Validator`` class. """
|
||||
"""
|
||||
A :class:`set` of hashes derived from validation schemas that are legit for a
|
||||
particular ``Validator`` class.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
""" The arguments will be treated as with this signature:
|
||||
"""
|
||||
The arguments will be treated as with this signature:
|
||||
|
||||
__init__(self, schema=None, ignore_none_values=False,
|
||||
allow_unknown=False, require_all=False,
|
||||
@@ -205,7 +217,7 @@ class BareValidator(object):
|
||||
raise RuntimeError('Invalid error_handler.')
|
||||
|
||||
def __store_config(self, args, kwargs):
|
||||
""" Assign args to kwargs and store configuration. """
|
||||
"""Assign args to kwargs and store configuration."""
|
||||
signature = (
|
||||
'schema',
|
||||
'ignore_none_values',
|
||||
@@ -226,11 +238,12 @@ class BareValidator(object):
|
||||
|
||||
@classmethod
|
||||
def clear_caches(cls):
|
||||
""" Purge the cache of known valid schemas. """
|
||||
"""Purge the cache of known valid schemas."""
|
||||
cls._valid_schemas.clear()
|
||||
|
||||
def _error(self, *args):
|
||||
""" Creates and adds one or multiple errors.
|
||||
"""
|
||||
Creates and adds one or multiple errors.
|
||||
|
||||
:param args: Accepts different argument's signatures.
|
||||
|
||||
@@ -290,15 +303,17 @@ class BareValidator(object):
|
||||
if not rule:
|
||||
constraint = None
|
||||
else:
|
||||
field_definitions = self._resolve_rules_set(self.schema[field])
|
||||
rules_set = self._resolve_rules_set(
|
||||
self._resolve_schema(self.schema)[field]
|
||||
)
|
||||
if rule == 'nullable':
|
||||
constraint = field_definitions.get(rule, False)
|
||||
constraint = rules_set.get(rule, False)
|
||||
elif rule == 'required':
|
||||
constraint = field_definitions.get(rule, self.require_all)
|
||||
if rule not in field_definitions:
|
||||
constraint = rules_set.get(rule, self.require_all)
|
||||
if rule not in rules_set:
|
||||
schema_path = "__require_all__"
|
||||
else:
|
||||
constraint = field_definitions[rule]
|
||||
constraint = rules_set[rule]
|
||||
|
||||
value = self.document.get(field)
|
||||
|
||||
@@ -308,9 +323,10 @@ class BareValidator(object):
|
||||
self._error([self.recent_error])
|
||||
|
||||
def _get_child_validator(self, document_crumb=None, schema_crumb=None, **kwargs):
|
||||
""" Creates a new instance of Validator-(sub-)class. All initial
|
||||
parameters of the parent are passed to the initialization, unless
|
||||
a parameter is given as an explicit *keyword*-parameter.
|
||||
"""
|
||||
Creates a new instance of Validator-(sub-)class. All initial parameters of the
|
||||
parent are passed to the initialization, unless a parameter is given as an
|
||||
explicit *keyword*-parameter.
|
||||
|
||||
:param document_crumb: Extends the
|
||||
:attr:`~cerberus.Validator.document_path`
|
||||
@@ -364,8 +380,8 @@ class BareValidator(object):
|
||||
return result
|
||||
|
||||
def _drop_nodes_from_errorpaths(self, _errors, dp_items, sp_items):
|
||||
""" Removes nodes by index from an errorpath, relatively to the
|
||||
basepaths of self.
|
||||
"""
|
||||
Removes nodes by index from an errorpath, relatively to the basepaths of self.
|
||||
|
||||
:param errors: A list of :class:`errors.ValidationError` instances.
|
||||
:param dp_items: A list of integers, pointing at the nodes to drop from
|
||||
@@ -387,8 +403,9 @@ class BareValidator(object):
|
||||
self._drop_nodes_from_errorpaths(error.child_errors, dp_items, sp_items)
|
||||
|
||||
def _lookup_field(self, path):
|
||||
""" Searches for a field as defined by path. This method is used by the
|
||||
``dependency`` evaluation logic.
|
||||
"""
|
||||
Searches for a field as defined by path. This method is used by the
|
||||
``dependency`` evaluation logic.
|
||||
|
||||
:param path: Path elements are separated by a ``.``. A leading ``^``
|
||||
indicates that the path relates to the document root,
|
||||
@@ -433,11 +450,12 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def allow_unknown(self):
|
||||
""" If ``True`` unknown fields that are not defined in the schema will
|
||||
be ignored. If a mapping with a validation schema is given, any
|
||||
undefined field will be validated against its rules.
|
||||
Also see :ref:`allowing-the-unknown`.
|
||||
Type: :class:`bool` or any :term:`mapping` """
|
||||
"""
|
||||
If ``True`` unknown fields that are not defined in the schema will be ignored.
|
||||
If a mapping with a validation schema is given, any undefined field will be
|
||||
validated against its rules. Also see :ref:`allowing-the-unknown`.
|
||||
Type: :class:`bool` or any :term:`mapping`
|
||||
"""
|
||||
return self._config.get('allow_unknown', False)
|
||||
|
||||
@allow_unknown.setter
|
||||
@@ -448,9 +466,10 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def require_all(self):
|
||||
""" If ``True`` known fields that are defined in the schema will
|
||||
be required.
|
||||
Type: :class:`bool` """
|
||||
"""
|
||||
If ``True`` known fields that are defined in the schema will be required.
|
||||
Type: :class:`bool`
|
||||
"""
|
||||
return self._config.get('require_all', False)
|
||||
|
||||
@require_all.setter
|
||||
@@ -459,14 +478,18 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def errors(self):
|
||||
""" The errors of the last processing formatted by the handler that is
|
||||
bound to :attr:`~cerberus.Validator.error_handler`. """
|
||||
"""
|
||||
The errors of the last processing formatted by the handler that is bound to
|
||||
:attr:`~cerberus.Validator.error_handler`.
|
||||
"""
|
||||
return self.error_handler(self._errors)
|
||||
|
||||
@property
|
||||
def ignore_none_values(self):
|
||||
""" Whether to not process :obj:`None`-values in a document or not.
|
||||
Type: :class:`bool` """
|
||||
"""
|
||||
Whether to not process :obj:`None`-values in a document or not.
|
||||
Type: :class:`bool`
|
||||
"""
|
||||
return self._config.get('ignore_none_values', False)
|
||||
|
||||
@ignore_none_values.setter
|
||||
@@ -475,14 +498,16 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def is_child(self):
|
||||
""" ``True`` for child-validators obtained with
|
||||
"""
|
||||
``True`` for child-validators obtained with
|
||||
:meth:`~cerberus.Validator._get_child_validator`.
|
||||
Type: :class:`bool` """
|
||||
Type: :class:`bool`
|
||||
"""
|
||||
return self._config.get('is_child', False)
|
||||
|
||||
@property
|
||||
def _is_normalized(self):
|
||||
""" ``True`` if the document is already normalized. """
|
||||
"""``True`` if the document is already normalized."""
|
||||
return self._config.get('_is_normalized', False)
|
||||
|
||||
@_is_normalized.setter
|
||||
@@ -491,9 +516,12 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def purge_unknown(self):
|
||||
""" If ``True``, unknown fields will be deleted from the document
|
||||
unless a validation is called with disabled normalization.
|
||||
Also see :ref:`purging-unknown-fields`. Type: :class:`bool` """
|
||||
"""
|
||||
If ``True``, unknown fields will be deleted from the document unless a
|
||||
validation is called with disabled normalization. Also see
|
||||
:ref:`purging-unknown-fields`.
|
||||
Type: :class:`bool`
|
||||
"""
|
||||
return self._config.get('purge_unknown', False)
|
||||
|
||||
@purge_unknown.setter
|
||||
@@ -502,9 +530,11 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def purge_readonly(self):
|
||||
""" If ``True``, fields declared as readonly will be deleted from the
|
||||
document unless a validation is called with disabled normalization.
|
||||
Type: :class:`bool` """
|
||||
"""
|
||||
If ``True``, fields declared as readonly will be deleted from the document
|
||||
unless a validation is called with disabled normalization.
|
||||
Type: :class:`bool`
|
||||
"""
|
||||
return self._config.get('purge_readonly', False)
|
||||
|
||||
@purge_readonly.setter
|
||||
@@ -513,26 +543,34 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def root_allow_unknown(self):
|
||||
""" The :attr:`~cerberus.Validator.allow_unknown` attribute of the
|
||||
first level ancestor of a child validator. """
|
||||
"""
|
||||
The :attr:`~cerberus.Validator.allow_unknown` attribute of the first level
|
||||
ancestor of a child validator.
|
||||
"""
|
||||
return self._config.get('root_allow_unknown', self.allow_unknown)
|
||||
|
||||
@property
|
||||
def root_require_all(self):
|
||||
""" The :attr:`~cerberus.Validator.require_all` attribute of
|
||||
the first level ancestor of a child validator. """
|
||||
"""
|
||||
The :attr:`~cerberus.Validator.require_all` attribute of the first level
|
||||
ancestor of a child validator.
|
||||
"""
|
||||
return self._config.get('root_require_all', self.require_all)
|
||||
|
||||
@property
|
||||
def root_document(self):
|
||||
""" The :attr:`~cerberus.Validator.document` attribute of the
|
||||
first level ancestor of a child validator. """
|
||||
"""
|
||||
The :attr:`~cerberus.Validator.document` attribute of the first level ancestor
|
||||
of a child validator.
|
||||
"""
|
||||
return self._config.get('root_document', self.document)
|
||||
|
||||
@property
|
||||
def rules_set_registry(self):
|
||||
""" The registry that holds referenced rules sets.
|
||||
Type: :class:`~cerberus.Registry` """
|
||||
"""
|
||||
The registry that holds referenced rules sets.
|
||||
Type: :class:`~cerberus.Registry`
|
||||
"""
|
||||
return self._config.get('rules_set_registry', rules_set_registry)
|
||||
|
||||
@rules_set_registry.setter
|
||||
@@ -541,15 +579,19 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def root_schema(self):
|
||||
""" The :attr:`~cerberus.Validator.schema` attribute of the
|
||||
first level ancestor of a child validator. """
|
||||
"""
|
||||
The :attr:`~cerberus.Validator.schema` attribute of the first level ancestor of
|
||||
a child validator.
|
||||
"""
|
||||
return self._config.get('root_schema', self.schema)
|
||||
|
||||
@property
|
||||
def schema(self):
|
||||
""" The validation schema of a validator. When a schema is passed to
|
||||
a method, it replaces this attribute.
|
||||
Type: any :term:`mapping` or :obj:`None` """
|
||||
"""
|
||||
The validation schema of a validator. When a schema is passed to a method, it
|
||||
replaces this attribute.
|
||||
Type: any :term:`mapping` or :obj:`None`
|
||||
"""
|
||||
return self._schema
|
||||
|
||||
@schema.setter
|
||||
@@ -563,8 +605,10 @@ class BareValidator(object):
|
||||
|
||||
@property
|
||||
def schema_registry(self):
|
||||
""" The registry that holds referenced schemas.
|
||||
Type: :class:`~cerberus.Registry` """
|
||||
"""
|
||||
The registry that holds referenced schemas.
|
||||
Type: :class:`~cerberus.Registry`
|
||||
"""
|
||||
return self._config.get('schema_registry', schema_registry)
|
||||
|
||||
@schema_registry.setter
|
||||
@@ -575,8 +619,10 @@ class BareValidator(object):
|
||||
# in the API docs
|
||||
@readonly_classproperty
|
||||
def types(cls):
|
||||
""" The constraints that can be used for the 'type' rule.
|
||||
Type: A tuple of strings. """
|
||||
"""
|
||||
The constraints that can be used for the 'type' rule.
|
||||
Type: A tuple of strings.
|
||||
"""
|
||||
redundant_types = set(cls.types_mapping) & set(cls._types_from_methods)
|
||||
if redundant_types:
|
||||
warn(
|
||||
@@ -611,9 +657,10 @@ class BareValidator(object):
|
||||
self.error_handler.start(self)
|
||||
|
||||
def _drop_remaining_rules(self, *rules):
|
||||
""" Drops rules from the queue of the rules that still need to be
|
||||
evaluated for the currently processed field.
|
||||
If no arguments are given, the whole queue is emptied.
|
||||
"""
|
||||
Drops rules from the queue of the rules that still need to be evaluated for the
|
||||
currently processed field. If no arguments are given, the whole queue is
|
||||
emptied.
|
||||
"""
|
||||
if rules:
|
||||
for rule in rules:
|
||||
@@ -627,8 +674,8 @@ class BareValidator(object):
|
||||
# # Normalizing
|
||||
|
||||
def normalized(self, document, schema=None, always_return_document=False):
|
||||
""" Returns the document normalized according to the specified rules
|
||||
of a schema.
|
||||
"""
|
||||
Returns the document normalized according to the specified rules of a schema.
|
||||
|
||||
:param document: The document to normalize.
|
||||
:type document: any :term:`mapping`
|
||||
@@ -673,13 +720,15 @@ class BareValidator(object):
|
||||
return mapping
|
||||
|
||||
def _normalize_coerce(self, mapping, schema):
|
||||
""" {'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]} """
|
||||
"""
|
||||
{'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]}
|
||||
"""
|
||||
|
||||
error = errors.COERCION_FAILED
|
||||
for field in mapping:
|
||||
@@ -853,7 +902,7 @@ class BareValidator(object):
|
||||
|
||||
@staticmethod
|
||||
def _normalize_purge_unknown(mapping, schema):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
for field in [x for x in mapping if x not in schema]:
|
||||
mapping.pop(field)
|
||||
return mapping
|
||||
@@ -873,19 +922,21 @@ class BareValidator(object):
|
||||
return mapping
|
||||
|
||||
def _normalize_rename(self, mapping, schema, field):
|
||||
""" {'type': 'hashable'} """
|
||||
"""{'type': 'hashable'}"""
|
||||
if 'rename' in schema[field]:
|
||||
mapping[schema[field]['rename']] = mapping[field]
|
||||
del mapping[field]
|
||||
|
||||
def _normalize_rename_handler(self, mapping, schema, field):
|
||||
""" {'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]} """
|
||||
"""
|
||||
{'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]}
|
||||
"""
|
||||
if 'rename_handler' not in schema[field]:
|
||||
return
|
||||
new_name = self.__normalize_coerce(
|
||||
@@ -947,14 +998,16 @@ class BareValidator(object):
|
||||
known_fields_states.add(fields_processing_state)
|
||||
|
||||
def _normalize_default(self, mapping, schema, field):
|
||||
""" {'nullable': True} """
|
||||
"""{'nullable': True}"""
|
||||
mapping[field] = schema[field]['default']
|
||||
|
||||
def _normalize_default_setter(self, mapping, schema, field):
|
||||
""" {'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'string'}
|
||||
]} """
|
||||
"""
|
||||
{'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'string'}
|
||||
]}
|
||||
"""
|
||||
if 'default_setter' in schema[field]:
|
||||
setter = schema[field]['default_setter']
|
||||
if isinstance(setter, _str_type):
|
||||
@@ -964,8 +1017,8 @@ class BareValidator(object):
|
||||
# # Validating
|
||||
|
||||
def validate(self, document, schema=None, update=False, normalize=True):
|
||||
""" Normalizes and validates a mapping against a validation-schema of
|
||||
defined rules.
|
||||
"""
|
||||
Normalizes and validates a mapping against a validation-schema of defined rules.
|
||||
|
||||
:param document: The document to normalize.
|
||||
:type document: any :term:`mapping`
|
||||
@@ -1008,9 +1061,10 @@ class BareValidator(object):
|
||||
__call__ = validate
|
||||
|
||||
def validated(self, *args, **kwargs):
|
||||
""" Wrapper around :meth:`~cerberus.Validator.validate` that returns
|
||||
the normalized and validated document or :obj:`None` if validation
|
||||
failed. """
|
||||
"""
|
||||
Wrapper around :meth:`~cerberus.Validator.validate` that returns the normalized
|
||||
and validated document or :obj:`None` if validation failed.
|
||||
"""
|
||||
always_return_document = kwargs.pop('always_return_document', False)
|
||||
self.validate(*args, **kwargs)
|
||||
if self._errors and not always_return_document:
|
||||
@@ -1034,7 +1088,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.UNKNOWN_FIELD)
|
||||
|
||||
def __validate_definitions(self, definitions, field):
|
||||
""" Validate a field's value against its defined rules. """
|
||||
"""Validate a field's value against its defined rules."""
|
||||
|
||||
def validate_rule(rule):
|
||||
validator = self.__get_rule_handler('validate', rule)
|
||||
@@ -1082,23 +1136,25 @@ class BareValidator(object):
|
||||
)
|
||||
|
||||
def _validate_allowed(self, allowed_values, field, value):
|
||||
""" {'type': 'container'} """
|
||||
"""{'type': 'container'}"""
|
||||
if isinstance(value, Iterable) and not isinstance(value, _str_type):
|
||||
unallowed = set(value) - set(allowed_values)
|
||||
unallowed = tuple(x for x in value if x not in allowed_values)
|
||||
if unallowed:
|
||||
self._error(field, errors.UNALLOWED_VALUES, list(unallowed))
|
||||
self._error(field, errors.UNALLOWED_VALUES, unallowed)
|
||||
else:
|
||||
if value not in allowed_values:
|
||||
self._error(field, errors.UNALLOWED_VALUE, value)
|
||||
|
||||
def _validate_check_with(self, checks, field, value):
|
||||
""" {'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]} """
|
||||
"""
|
||||
{'oneof': [
|
||||
{'type': 'callable'},
|
||||
{'type': 'list',
|
||||
'schema': {'oneof': [{'type': 'callable'},
|
||||
{'type': 'string'}]}},
|
||||
{'type': 'string'}
|
||||
]}
|
||||
"""
|
||||
if isinstance(checks, _str_type):
|
||||
try:
|
||||
value_checker = self.__get_rule_handler('check_with', checks)
|
||||
@@ -1118,7 +1174,7 @@ class BareValidator(object):
|
||||
checks(field, value, self._error)
|
||||
|
||||
def _validate_contains(self, expected_values, field, value):
|
||||
""" {'empty': False } """
|
||||
"""{'empty': False }"""
|
||||
if not isinstance(value, Iterable):
|
||||
return
|
||||
|
||||
@@ -1134,8 +1190,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.MISSING_MEMBERS, missing_values)
|
||||
|
||||
def _validate_dependencies(self, dependencies, field, value):
|
||||
""" {'type': ('dict', 'hashable', 'list'),
|
||||
'check_with': 'dependencies'} """
|
||||
"""{'type': ('dict', 'hashable', 'list'), 'check_with': 'dependencies'}"""
|
||||
if isinstance(dependencies, _str_type) or not isinstance(
|
||||
dependencies, (Iterable, Mapping)
|
||||
):
|
||||
@@ -1178,7 +1233,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.DEPENDENCIES_FIELD, dependency)
|
||||
|
||||
def _validate_empty(self, empty, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
if isinstance(value, Sized) and len(value) == 0:
|
||||
self._drop_remaining_rules(
|
||||
'allowed',
|
||||
@@ -1193,8 +1248,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.EMPTY_NOT_ALLOWED)
|
||||
|
||||
def _validate_excludes(self, excluded_fields, field, value):
|
||||
""" {'type': ('hashable', 'list'),
|
||||
'schema': {'type': 'hashable'}} """
|
||||
"""{'type': ('hashable', 'list'), 'schema': {'type': 'hashable'}}"""
|
||||
if isinstance(excluded_fields, Hashable):
|
||||
excluded_fields = [excluded_fields]
|
||||
|
||||
@@ -1217,7 +1271,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.EXCLUDES_FIELD, exclusion_str)
|
||||
|
||||
def _validate_forbidden(self, forbidden_values, field, value):
|
||||
""" {'type': 'list'} """
|
||||
"""{'type': 'list'}"""
|
||||
if isinstance(value, Sequence) and not isinstance(value, _str_type):
|
||||
forbidden = set(value) & set(forbidden_values)
|
||||
if forbidden:
|
||||
@@ -1227,7 +1281,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.FORBIDDEN_VALUE, value)
|
||||
|
||||
def _validate_items(self, items, field, values):
|
||||
""" {'type': 'list', 'check_with': 'items'} """
|
||||
"""{'type': 'list', 'check_with': 'items'}"""
|
||||
if len(items) != len(values):
|
||||
self._error(field, errors.ITEMS_LENGTH, len(items), len(values))
|
||||
else:
|
||||
@@ -1247,8 +1301,10 @@ class BareValidator(object):
|
||||
self._error(field, errors.BAD_ITEMS, validator._errors)
|
||||
|
||||
def __validate_logical(self, operator, definitions, field, value):
|
||||
""" Validates value against all definitions and logs errors according
|
||||
to the operator. """
|
||||
"""
|
||||
Validates value against all definitions and logs errors according to the
|
||||
operator.
|
||||
"""
|
||||
valid_counter = 0
|
||||
_errors = errors.ErrorList()
|
||||
|
||||
@@ -1272,31 +1328,31 @@ class BareValidator(object):
|
||||
return valid_counter, _errors
|
||||
|
||||
def _validate_anyof(self, definitions, field, value):
|
||||
""" {'type': 'list', 'logical': 'anyof'} """
|
||||
"""{'type': 'list', 'logical': 'anyof'}"""
|
||||
valids, _errors = self.__validate_logical('anyof', definitions, field, value)
|
||||
if valids < 1:
|
||||
self._error(field, errors.ANYOF, _errors, valids, len(definitions))
|
||||
|
||||
def _validate_allof(self, definitions, field, value):
|
||||
""" {'type': 'list', 'logical': 'allof'} """
|
||||
"""{'type': 'list', 'logical': 'allof'}"""
|
||||
valids, _errors = self.__validate_logical('allof', definitions, field, value)
|
||||
if valids < len(definitions):
|
||||
self._error(field, errors.ALLOF, _errors, valids, len(definitions))
|
||||
|
||||
def _validate_noneof(self, definitions, field, value):
|
||||
""" {'type': 'list', 'logical': 'noneof'} """
|
||||
"""{'type': 'list', 'logical': 'noneof'}"""
|
||||
valids, _errors = self.__validate_logical('noneof', definitions, field, value)
|
||||
if valids > 0:
|
||||
self._error(field, errors.NONEOF, _errors, valids, len(definitions))
|
||||
|
||||
def _validate_oneof(self, definitions, field, value):
|
||||
""" {'type': 'list', 'logical': 'oneof'} """
|
||||
"""{'type': 'list', 'logical': 'oneof'}"""
|
||||
valids, _errors = self.__validate_logical('oneof', definitions, field, value)
|
||||
if valids != 1:
|
||||
self._error(field, errors.ONEOF, _errors, valids, len(definitions))
|
||||
|
||||
def _validate_max(self, max_value, field, value):
|
||||
""" {'nullable': False } """
|
||||
"""{'nullable': False }"""
|
||||
try:
|
||||
if value > max_value:
|
||||
self._error(field, errors.MAX_VALUE)
|
||||
@@ -1304,7 +1360,7 @@ class BareValidator(object):
|
||||
pass
|
||||
|
||||
def _validate_min(self, min_value, field, value):
|
||||
""" {'nullable': False } """
|
||||
"""{'nullable': False }"""
|
||||
try:
|
||||
if value < min_value:
|
||||
self._error(field, errors.MIN_VALUE)
|
||||
@@ -1312,19 +1368,19 @@ class BareValidator(object):
|
||||
pass
|
||||
|
||||
def _validate_maxlength(self, max_length, field, value):
|
||||
""" {'type': 'integer'} """
|
||||
"""{'type': 'integer'}"""
|
||||
if isinstance(value, Iterable) and len(value) > max_length:
|
||||
self._error(field, errors.MAX_LENGTH, len(value))
|
||||
|
||||
_validate_meta = dummy_for_rule_validation('')
|
||||
|
||||
def _validate_minlength(self, min_length, field, value):
|
||||
""" {'type': 'integer'} """
|
||||
"""{'type': 'integer'}"""
|
||||
if isinstance(value, Iterable) and len(value) < min_length:
|
||||
self._error(field, errors.MIN_LENGTH, len(value))
|
||||
|
||||
def _validate_nullable(self, nullable, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
if value is None:
|
||||
if not nullable:
|
||||
self._error(field, errors.NOT_NULLABLE)
|
||||
@@ -1345,8 +1401,11 @@ class BareValidator(object):
|
||||
)
|
||||
|
||||
def _validate_keysrules(self, schema, field, value):
|
||||
""" {'type': ['dict', 'string'], 'check_with': 'bulk_schema',
|
||||
'forbidden': ['rename', 'rename_handler']} """
|
||||
"""
|
||||
{'type': ['dict', 'string'],
|
||||
'check_with': 'bulk_schema',
|
||||
'forbidden': ['rename', 'rename_handler']}
|
||||
"""
|
||||
if isinstance(value, Mapping):
|
||||
validator = self._get_child_validator(
|
||||
document_crumb=field,
|
||||
@@ -1358,7 +1417,7 @@ class BareValidator(object):
|
||||
self._error(field, errors.KEYSRULES, validator._errors)
|
||||
|
||||
def _validate_readonly(self, readonly, field, value):
|
||||
""" {'type': 'boolean'} """
|
||||
"""{'type': 'boolean'}"""
|
||||
if readonly:
|
||||
if not self._is_normalized:
|
||||
self._error(field, errors.READONLY_FIELD)
|
||||
@@ -1375,7 +1434,7 @@ class BareValidator(object):
|
||||
self._drop_remaining_rules()
|
||||
|
||||
def _validate_regex(self, pattern, field, value):
|
||||
""" {'type': 'string'} """
|
||||
"""{'type': 'string'}"""
|
||||
if not isinstance(value, _str_type):
|
||||
return
|
||||
if not pattern.endswith('$'):
|
||||
@@ -1389,7 +1448,8 @@ class BareValidator(object):
|
||||
_validate_require_all = dummy_for_rule_validation(""" {'type': 'boolean'} """)
|
||||
|
||||
def __validate_required_fields(self, document):
|
||||
""" Validates that required fields are not missing.
|
||||
"""
|
||||
Validates that required fields are not missing.
|
||||
|
||||
:param document: The document being validated.
|
||||
"""
|
||||
@@ -1424,9 +1484,11 @@ class BareValidator(object):
|
||||
self._error(field, errors.REQUIRED_FIELD)
|
||||
|
||||
def _validate_schema(self, schema, field, value):
|
||||
""" {'type': ['dict', 'string'],
|
||||
'anyof': [{'check_with': 'schema'},
|
||||
{'check_with': 'bulk_schema'}]} """
|
||||
"""
|
||||
{'type': ['dict', 'string'],
|
||||
'anyof': [{'check_with': 'schema'},
|
||||
{'check_with': 'bulk_schema'}]}
|
||||
"""
|
||||
if schema is None:
|
||||
return
|
||||
|
||||
@@ -1472,8 +1534,10 @@ class BareValidator(object):
|
||||
self._error(field, errors.SEQUENCE_SCHEMA, validator._errors)
|
||||
|
||||
def _validate_type(self, data_type, field, value):
|
||||
""" {'type': ['string', 'list'],
|
||||
'check_with': 'type'} """
|
||||
"""
|
||||
{'type': ['string', 'list'],
|
||||
'check_with': 'type'}
|
||||
"""
|
||||
if not data_type:
|
||||
return
|
||||
|
||||
@@ -1504,8 +1568,11 @@ class BareValidator(object):
|
||||
self._drop_remaining_rules()
|
||||
|
||||
def _validate_valuesrules(self, schema, field, value):
|
||||
""" {'type': ['dict', 'string'], 'check_with': 'bulk_schema',
|
||||
'forbidden': ['rename', 'rename_handler']} """
|
||||
"""
|
||||
{'type': ['dict', 'string'],
|
||||
'check_with': 'bulk_schema',
|
||||
'forbidden': ['rename', 'rename_handler']}
|
||||
"""
|
||||
schema_crumb = (field, 'valuesrules')
|
||||
if isinstance(value, Mapping):
|
||||
validator = self._get_child_validator(
|
||||
@@ -1523,7 +1590,7 @@ RULE_SCHEMA_SEPARATOR = "The rule's arguments are validated against this schema:
|
||||
|
||||
|
||||
class InspectedValidator(type):
|
||||
""" Metaclass for all validators """
|
||||
"""Metaclass for all validators"""
|
||||
|
||||
def __new__(cls, *args):
|
||||
if '__doc__' not in args[2]:
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
This packge contains a modified version of ca-bundle.crt:
|
||||
This package contains a modified version of ca-bundle.crt:
|
||||
|
||||
ca-bundle.crt -- Bundle of CA Root Certificates
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,3 +1,3 @@
|
||||
from .core import contents, where
|
||||
|
||||
__version__ = "2020.11.08"
|
||||
__version__ = "2021.05.30"
|
||||
|
||||
Vendored
+271
-620
@@ -155,112 +155,6 @@ eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
|
||||
0vdXcDazv/wor3ElhVsT/h5/WrQ8
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc.
|
||||
# Subject: CN=GeoTrust Global CA O=GeoTrust Inc.
|
||||
# Label: "GeoTrust Global CA"
|
||||
# Serial: 144470
|
||||
# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5
|
||||
# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12
|
||||
# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
|
||||
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
|
||||
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
|
||||
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
|
||||
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
|
||||
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
|
||||
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
|
||||
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
|
||||
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
|
||||
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
|
||||
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
|
||||
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
|
||||
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
|
||||
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
|
||||
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
|
||||
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
|
||||
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc.
|
||||
# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc.
|
||||
# Label: "GeoTrust Universal CA"
|
||||
# Serial: 1
|
||||
# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48
|
||||
# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79
|
||||
# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
|
||||
MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
|
||||
c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
|
||||
BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
|
||||
IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
|
||||
VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
|
||||
cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
|
||||
QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
|
||||
F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
|
||||
c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
|
||||
mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
|
||||
VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
|
||||
teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
|
||||
f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
|
||||
Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
|
||||
nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
|
||||
/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
|
||||
MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
|
||||
9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
|
||||
aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
|
||||
IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
|
||||
ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
|
||||
uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
|
||||
Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
|
||||
QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
|
||||
koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
|
||||
ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
|
||||
DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
|
||||
bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
|
||||
# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc.
|
||||
# Label: "GeoTrust Universal CA 2"
|
||||
# Serial: 1
|
||||
# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7
|
||||
# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79
|
||||
# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
|
||||
MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
|
||||
c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
|
||||
VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
|
||||
c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
|
||||
AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
|
||||
WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
|
||||
FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
|
||||
XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
|
||||
se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
|
||||
KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
|
||||
IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
|
||||
y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
|
||||
hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
|
||||
QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
|
||||
Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
|
||||
HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
||||
KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
|
||||
dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
|
||||
L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
|
||||
Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
|
||||
ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
|
||||
T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
|
||||
GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
|
||||
1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
|
||||
OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
|
||||
6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
|
||||
QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Subject: CN=AAA Certificate Services O=Comodo CA Limited
|
||||
# Label: "Comodo AAA Services root"
|
||||
@@ -294,48 +188,6 @@ l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
|
||||
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
|
||||
# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority
|
||||
# Label: "QuoVadis Root CA"
|
||||
# Serial: 985026699
|
||||
# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24
|
||||
# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9
|
||||
# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
|
||||
TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
|
||||
aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
|
||||
aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
|
||||
MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
|
||||
IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
|
||||
dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
|
||||
li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
|
||||
rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
|
||||
WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
|
||||
F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
|
||||
xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
|
||||
Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
|
||||
dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
|
||||
ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
|
||||
IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
|
||||
c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
|
||||
ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
|
||||
Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
|
||||
KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
|
||||
KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
|
||||
y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
|
||||
dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
|
||||
VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
|
||||
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
|
||||
fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
|
||||
7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
|
||||
cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
|
||||
mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
|
||||
xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
|
||||
SnQ2+Q==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited
|
||||
# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited
|
||||
# Label: "QuoVadis Root CA 2"
|
||||
@@ -451,33 +303,6 @@ JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
|
||||
RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Sonera Class2 CA O=Sonera
|
||||
# Subject: CN=Sonera Class2 CA O=Sonera
|
||||
# Label: "Sonera Class 2 Root CA"
|
||||
# Serial: 29
|
||||
# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb
|
||||
# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27
|
||||
# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
|
||||
MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
|
||||
MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
|
||||
BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
|
||||
hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
|
||||
Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
|
||||
5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
|
||||
3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
|
||||
vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
|
||||
8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
|
||||
DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
|
||||
MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
|
||||
zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
|
||||
3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
|
||||
FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
|
||||
Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
|
||||
ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
|
||||
# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
|
||||
# Label: "XRamp Global CA Root"
|
||||
@@ -776,104 +601,6 @@ hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
|
||||
tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
|
||||
# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc.
|
||||
# Label: "GeoTrust Primary Certification Authority"
|
||||
# Serial: 32798226551256963324313806436981982369
|
||||
# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf
|
||||
# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96
|
||||
# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
|
||||
MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
|
||||
R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
|
||||
MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
|
||||
Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
|
||||
ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
|
||||
AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
|
||||
AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
|
||||
ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
|
||||
7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
|
||||
kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
|
||||
mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
|
||||
A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
|
||||
KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
|
||||
6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
|
||||
4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
|
||||
oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
|
||||
UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
|
||||
AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
|
||||
# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only
|
||||
# Label: "thawte Primary Root CA"
|
||||
# Serial: 69529181992039203566298953787712940909
|
||||
# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12
|
||||
# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81
|
||||
# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
|
||||
qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
|
||||
Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
|
||||
MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
|
||||
BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
|
||||
NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
|
||||
LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
|
||||
A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
|
||||
IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
|
||||
W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
|
||||
3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
|
||||
6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
|
||||
Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
|
||||
NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
|
||||
r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
|
||||
DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
|
||||
YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
|
||||
xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
|
||||
/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
|
||||
LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
|
||||
jVaMaA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
|
||||
# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only
|
||||
# Label: "VeriSign Class 3 Public Primary Certification Authority - G5"
|
||||
# Serial: 33037644167568058970164719475676101450
|
||||
# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c
|
||||
# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5
|
||||
# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
|
||||
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
|
||||
ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
|
||||
aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
|
||||
nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
|
||||
t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
|
||||
SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
|
||||
BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
|
||||
rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
|
||||
NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
|
||||
BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
|
||||
BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
|
||||
aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
|
||||
MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
|
||||
p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
|
||||
5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
|
||||
WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
|
||||
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
|
||||
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=SecureTrust CA O=SecureTrust Corporation
|
||||
# Subject: CN=SecureTrust CA O=SecureTrust Corporation
|
||||
# Label: "SecureTrust CA"
|
||||
@@ -1151,185 +878,6 @@ i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
|
||||
9u6wWk5JRFRYX0KD
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
|
||||
# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only
|
||||
# Label: "GeoTrust Primary Certification Authority - G3"
|
||||
# Serial: 28809105769928564313984085209975885599
|
||||
# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05
|
||||
# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd
|
||||
# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
|
||||
mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
|
||||
MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
|
||||
eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
|
||||
BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
|
||||
MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
|
||||
BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
|
||||
LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
|
||||
+uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
|
||||
hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
|
||||
5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
|
||||
JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
|
||||
DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
|
||||
huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
|
||||
HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
|
||||
zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
|
||||
kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
|
||||
AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
|
||||
SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
|
||||
spki4cErx5z481+oghLrGREt
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
|
||||
# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only
|
||||
# Label: "thawte Primary Root CA - G2"
|
||||
# Serial: 71758320672825410020661621085256472406
|
||||
# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f
|
||||
# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12
|
||||
# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
|
||||
MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
|
||||
IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
|
||||
BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
|
||||
MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
|
||||
d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
|
||||
YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
|
||||
dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
|
||||
BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
|
||||
papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
|
||||
BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
|
||||
DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
|
||||
KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
|
||||
XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
|
||||
# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only
|
||||
# Label: "thawte Primary Root CA - G3"
|
||||
# Serial: 127614157056681299805556476275995414779
|
||||
# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31
|
||||
# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2
|
||||
# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
|
||||
rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
|
||||
Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
|
||||
MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
|
||||
BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
|
||||
Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
|
||||
LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
|
||||
MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
|
||||
ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
|
||||
gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
|
||||
YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
|
||||
b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
|
||||
9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
|
||||
zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
|
||||
OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
|
||||
HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
|
||||
2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
|
||||
oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
|
||||
t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
|
||||
KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
|
||||
m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
|
||||
MdRAGmI0Nj81Aa6sY6A=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
|
||||
# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only
|
||||
# Label: "GeoTrust Primary Certification Authority - G2"
|
||||
# Serial: 80682863203381065782177908751794619243
|
||||
# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a
|
||||
# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0
|
||||
# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
|
||||
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
|
||||
KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
|
||||
MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
|
||||
eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
|
||||
BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
|
||||
NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
|
||||
BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
|
||||
MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
|
||||
So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
|
||||
tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
|
||||
BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
|
||||
CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
|
||||
qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
|
||||
rD6ogRLQy7rQkgu2npaqBA+K
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
|
||||
# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only
|
||||
# Label: "VeriSign Universal Root Certification Authority"
|
||||
# Serial: 85209574734084581917763752644031726877
|
||||
# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19
|
||||
# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54
|
||||
# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
|
||||
vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
|
||||
ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
|
||||
U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
|
||||
ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
|
||||
Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
|
||||
MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
|
||||
IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
|
||||
IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
|
||||
bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
|
||||
9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
|
||||
H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
|
||||
LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
|
||||
/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
|
||||
rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
|
||||
WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
|
||||
exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
|
||||
DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
|
||||
sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
|
||||
seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
|
||||
4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
|
||||
BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
|
||||
lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
|
||||
7M2CYfE45k+XmCpajQ==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
|
||||
# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only
|
||||
# Label: "VeriSign Class 3 Public Primary Certification Authority - G4"
|
||||
# Serial: 63143484348153506665311985501458640051
|
||||
# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41
|
||||
# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a
|
||||
# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
|
||||
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
|
||||
ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
|
||||
biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
|
||||
U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
|
||||
aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
|
||||
A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
|
||||
U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
|
||||
SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
|
||||
biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
|
||||
IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
|
||||
GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
|
||||
fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
|
||||
AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
|
||||
aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
|
||||
aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
|
||||
kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
|
||||
4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
|
||||
FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services)
|
||||
# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services)
|
||||
# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny"
|
||||
@@ -1565,105 +1113,6 @@ naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
|
||||
QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A.
|
||||
# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A.
|
||||
# Label: "Chambers of Commerce Root - 2008"
|
||||
# Serial: 11806822484801597146
|
||||
# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7
|
||||
# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c
|
||||
# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
|
||||
VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
|
||||
IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
|
||||
MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz
|
||||
IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz
|
||||
MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj
|
||||
dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw
|
||||
EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp
|
||||
MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G
|
||||
CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9
|
||||
28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq
|
||||
VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q
|
||||
DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR
|
||||
5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL
|
||||
ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a
|
||||
Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl
|
||||
UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s
|
||||
+12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5
|
||||
Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
|
||||
ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx
|
||||
hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV
|
||||
HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1
|
||||
+HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN
|
||||
YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t
|
||||
L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy
|
||||
ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt
|
||||
IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV
|
||||
HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w
|
||||
DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW
|
||||
PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF
|
||||
5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1
|
||||
glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH
|
||||
FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2
|
||||
pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD
|
||||
xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG
|
||||
tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq
|
||||
jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De
|
||||
fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
|
||||
OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ
|
||||
d0jQ
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A.
|
||||
# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A.
|
||||
# Label: "Global Chambersign Root - 2008"
|
||||
# Serial: 14541511773111788494
|
||||
# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3
|
||||
# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c
|
||||
# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
|
||||
VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
|
||||
IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
|
||||
MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
|
||||
aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx
|
||||
MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy
|
||||
cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG
|
||||
A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl
|
||||
BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI
|
||||
hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed
|
||||
KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7
|
||||
G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2
|
||||
zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4
|
||||
ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG
|
||||
HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2
|
||||
Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V
|
||||
yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e
|
||||
beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r
|
||||
6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
|
||||
wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog
|
||||
zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW
|
||||
BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr
|
||||
ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp
|
||||
ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk
|
||||
cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt
|
||||
YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC
|
||||
CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow
|
||||
KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI
|
||||
hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ
|
||||
UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz
|
||||
X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x
|
||||
fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz
|
||||
a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd
|
||||
Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd
|
||||
SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O
|
||||
AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso
|
||||
M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge
|
||||
v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
|
||||
09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
|
||||
# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
|
||||
# Label: "Go Daddy Root Certificate Authority - G2"
|
||||
@@ -2075,35 +1524,6 @@ LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
|
||||
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: O=Trustis Limited OU=Trustis FPS Root CA
|
||||
# Subject: O=Trustis Limited OU=Trustis FPS Root CA
|
||||
# Label: "Trustis FPS Root CA"
|
||||
# Serial: 36053640375399034304724988975563710553
|
||||
# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d
|
||||
# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04
|
||||
# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
|
||||
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
|
||||
ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx
|
||||
MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc
|
||||
MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
|
||||
ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+
|
||||
AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH
|
||||
iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj
|
||||
vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA
|
||||
0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB
|
||||
OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/
|
||||
BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E
|
||||
FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01
|
||||
GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW
|
||||
zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4
|
||||
1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE
|
||||
f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
|
||||
jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
|
||||
ZetX2fNXlrtIzYE=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
|
||||
# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
|
||||
# Label: "Buypass Class 2 Root CA"
|
||||
@@ -2965,46 +2385,6 @@ KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
|
||||
xwy8p2Fp8fc74SrL+SvzZpA3
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden
|
||||
# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden
|
||||
# Label: "Staat der Nederlanden Root CA - G3"
|
||||
# Serial: 10003001
|
||||
# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37
|
||||
# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc
|
||||
# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
|
||||
TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
|
||||
dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX
|
||||
DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
|
||||
ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
|
||||
b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP
|
||||
cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW
|
||||
IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX
|
||||
xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy
|
||||
KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR
|
||||
9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az
|
||||
5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8
|
||||
6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7
|
||||
Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP
|
||||
bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt
|
||||
BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt
|
||||
XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd
|
||||
INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD
|
||||
U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp
|
||||
LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8
|
||||
Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp
|
||||
gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh
|
||||
/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw
|
||||
0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A
|
||||
fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq
|
||||
4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR
|
||||
1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/
|
||||
QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM
|
||||
94B7IWcnMFk=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden
|
||||
# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden
|
||||
# Label: "Staat der Nederlanden EV Root CA"
|
||||
@@ -4604,3 +3984,274 @@ AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC
|
||||
MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu
|
||||
Sw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp.
|
||||
# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp.
|
||||
# Label: "NAVER Global Root Certification Authority"
|
||||
# Serial: 9013692873798656336226253319739695165984492813
|
||||
# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b
|
||||
# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1
|
||||
# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM
|
||||
BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG
|
||||
T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0
|
||||
aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx
|
||||
CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD
|
||||
b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB
|
||||
dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA
|
||||
iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH
|
||||
38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE
|
||||
HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz
|
||||
kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP
|
||||
szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq
|
||||
vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf
|
||||
nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG
|
||||
YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo
|
||||
0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a
|
||||
CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K
|
||||
AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I
|
||||
36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
|
||||
Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN
|
||||
qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj
|
||||
cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm
|
||||
+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL
|
||||
hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe
|
||||
lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7
|
||||
p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8
|
||||
piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR
|
||||
LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX
|
||||
5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO
|
||||
dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul
|
||||
9XXeifdy
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres
|
||||
# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres
|
||||
# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS"
|
||||
# Serial: 131542671362353147877283741781055151509
|
||||
# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb
|
||||
# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a
|
||||
# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
|
||||
CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
|
||||
FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
|
||||
Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5
|
||||
MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL
|
||||
DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS
|
||||
QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB
|
||||
BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH
|
||||
sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK
|
||||
Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
|
||||
VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu
|
||||
SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC
|
||||
MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy
|
||||
v+c=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa
|
||||
# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa
|
||||
# Label: "GlobalSign Root R46"
|
||||
# Serial: 1552617688466950547958867513931858518042577
|
||||
# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef
|
||||
# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90
|
||||
# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
|
||||
MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
|
||||
VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
|
||||
MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt
|
||||
c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ
|
||||
OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG
|
||||
vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud
|
||||
316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo
|
||||
0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE
|
||||
y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF
|
||||
zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE
|
||||
+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN
|
||||
I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs
|
||||
x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa
|
||||
ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC
|
||||
4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
|
||||
HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4
|
||||
7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
|
||||
JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti
|
||||
2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk
|
||||
pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF
|
||||
FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt
|
||||
rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk
|
||||
ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5
|
||||
u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP
|
||||
4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6
|
||||
N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
|
||||
vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa
|
||||
# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa
|
||||
# Label: "GlobalSign Root E46"
|
||||
# Serial: 1552617690338932563915843282459653771421763
|
||||
# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f
|
||||
# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84
|
||||
# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
|
||||
CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
|
||||
ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
|
||||
MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
|
||||
HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
|
||||
IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq
|
||||
R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd
|
||||
yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
|
||||
7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
|
||||
+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH
|
||||
# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH
|
||||
# Label: "GLOBALTRUST 2020"
|
||||
# Serial: 109160994242082918454945253
|
||||
# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8
|
||||
# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2
|
||||
# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG
|
||||
A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw
|
||||
FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx
|
||||
MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u
|
||||
aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b
|
||||
RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z
|
||||
YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3
|
||||
QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw
|
||||
yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+
|
||||
BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ
|
||||
SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH
|
||||
r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0
|
||||
4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me
|
||||
dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw
|
||||
q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2
|
||||
nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
|
||||
AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu
|
||||
H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA
|
||||
VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC
|
||||
XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd
|
||||
6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf
|
||||
+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi
|
||||
kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7
|
||||
wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB
|
||||
TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C
|
||||
MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn
|
||||
4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I
|
||||
aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy
|
||||
qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
|
||||
# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
|
||||
# Label: "ANF Secure Server Root CA"
|
||||
# Serial: 996390341000653745
|
||||
# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96
|
||||
# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74
|
||||
# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
|
||||
BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
|
||||
YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
|
||||
BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN
|
||||
MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF
|
||||
UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD
|
||||
VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v
|
||||
dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj
|
||||
cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q
|
||||
yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH
|
||||
2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX
|
||||
H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL
|
||||
zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR
|
||||
p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz
|
||||
W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/
|
||||
SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn
|
||||
LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3
|
||||
n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B
|
||||
u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
|
||||
o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO
|
||||
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
|
||||
AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L
|
||||
9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej
|
||||
rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK
|
||||
pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0
|
||||
vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq
|
||||
OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ
|
||||
/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9
|
||||
2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI
|
||||
+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2
|
||||
MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo
|
||||
tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
|
||||
# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
|
||||
# Label: "Certum EC-384 CA"
|
||||
# Serial: 160250656287871593594747141429395092468
|
||||
# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1
|
||||
# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed
|
||||
# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
|
||||
CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
|
||||
JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
|
||||
EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0
|
||||
WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT
|
||||
LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX
|
||||
BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE
|
||||
KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm
|
||||
Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj
|
||||
QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8
|
||||
EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J
|
||||
UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn
|
||||
nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
|
||||
# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
|
||||
# Label: "Certum Trusted Root CA"
|
||||
# Serial: 40870380103424195783807378461123655149
|
||||
# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29
|
||||
# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5
|
||||
# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
|
||||
MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
|
||||
MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
|
||||
BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw
|
||||
MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
|
||||
U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo
|
||||
b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG
|
||||
SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ
|
||||
n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q
|
||||
p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq
|
||||
NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF
|
||||
8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3
|
||||
HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa
|
||||
mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi
|
||||
7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF
|
||||
ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P
|
||||
qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ
|
||||
v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6
|
||||
Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
|
||||
vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD
|
||||
ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4
|
||||
WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo
|
||||
zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR
|
||||
5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ
|
||||
GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf
|
||||
5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq
|
||||
0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D
|
||||
P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM
|
||||
qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
|
||||
0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
|
||||
E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Vendored
+46
-2
@@ -16,11 +16,14 @@
|
||||
######################### END LICENSE BLOCK #########################
|
||||
|
||||
|
||||
from .compat import PY2, PY3
|
||||
from .universaldetector import UniversalDetector
|
||||
from .enums import InputState
|
||||
from .version import __version__, VERSION
|
||||
|
||||
|
||||
__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION']
|
||||
|
||||
|
||||
def detect(byte_str):
|
||||
"""
|
||||
Detect the encoding of the given byte string.
|
||||
@@ -31,9 +34,50 @@ def detect(byte_str):
|
||||
if not isinstance(byte_str, bytearray):
|
||||
if not isinstance(byte_str, bytes):
|
||||
raise TypeError('Expected object of type bytes or bytearray, got: '
|
||||
'{0}'.format(type(byte_str)))
|
||||
'{}'.format(type(byte_str)))
|
||||
else:
|
||||
byte_str = bytearray(byte_str)
|
||||
detector = UniversalDetector()
|
||||
detector.feed(byte_str)
|
||||
return detector.close()
|
||||
|
||||
|
||||
def detect_all(byte_str):
|
||||
"""
|
||||
Detect all the possible encodings of the given byte string.
|
||||
|
||||
:param byte_str: The byte sequence to examine.
|
||||
:type byte_str: ``bytes`` or ``bytearray``
|
||||
"""
|
||||
if not isinstance(byte_str, bytearray):
|
||||
if not isinstance(byte_str, bytes):
|
||||
raise TypeError('Expected object of type bytes or bytearray, got: '
|
||||
'{}'.format(type(byte_str)))
|
||||
else:
|
||||
byte_str = bytearray(byte_str)
|
||||
|
||||
detector = UniversalDetector()
|
||||
detector.feed(byte_str)
|
||||
detector.close()
|
||||
|
||||
if detector._input_state == InputState.HIGH_BYTE:
|
||||
results = []
|
||||
for prober in detector._charset_probers:
|
||||
if prober.get_confidence() > detector.MINIMUM_THRESHOLD:
|
||||
charset_name = prober.charset_name
|
||||
lower_charset_name = prober.charset_name.lower()
|
||||
# Use Windows encoding name instead of ISO-8859 if we saw any
|
||||
# extra Windows-specific bytes
|
||||
if lower_charset_name.startswith('iso-8859'):
|
||||
if detector._has_win_bytes:
|
||||
charset_name = detector.ISO_WIN_MAP.get(lower_charset_name,
|
||||
charset_name)
|
||||
results.append({
|
||||
'encoding': charset_name,
|
||||
'confidence': prober.get_confidence(),
|
||||
'language': prober.language,
|
||||
})
|
||||
if len(results) > 0:
|
||||
return sorted(results, key=lambda result: -result['confidence'])
|
||||
|
||||
return [detector.result]
|
||||
|
||||
+1
@@ -73,6 +73,7 @@ class CharSetGroupProber(CharSetProber):
|
||||
continue
|
||||
if state == ProbingState.FOUND_IT:
|
||||
self._best_guess_prober = prober
|
||||
self._state = ProbingState.FOUND_IT
|
||||
return self.state
|
||||
elif state == ProbingState.NOT_ME:
|
||||
prober.active = False
|
||||
|
||||
+3
-4
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Script which takes one or more file paths and reports on their detected
|
||||
encodings
|
||||
@@ -45,10 +44,10 @@ def description_of(lines, name='stdin'):
|
||||
if PY2:
|
||||
name = name.decode(sys.getfilesystemencoding(), 'ignore')
|
||||
if result['encoding']:
|
||||
return '{0}: {1} with confidence {2}'.format(name, result['encoding'],
|
||||
return '{}: {} with confidence {}'.format(name, result['encoding'],
|
||||
result['confidence'])
|
||||
else:
|
||||
return '{0}: no result'.format(name)
|
||||
return '{}: no result'.format(name)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
@@ -69,7 +68,7 @@ def main(argv=None):
|
||||
type=argparse.FileType('rb'), nargs='*',
|
||||
default=[sys.stdin if PY2 else sys.stdin.buffer])
|
||||
parser.add_argument('--version', action='version',
|
||||
version='%(prog)s {0}'.format(__version__))
|
||||
version='%(prog)s {}'.format(__version__))
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
for f in args.input:
|
||||
|
||||
Vendored
+4
-2
@@ -25,10 +25,12 @@ import sys
|
||||
if sys.version_info < (3, 0):
|
||||
PY2 = True
|
||||
PY3 = False
|
||||
base_str = (str, unicode)
|
||||
string_types = (str, unicode)
|
||||
text_type = unicode
|
||||
iteritems = dict.iteritems
|
||||
else:
|
||||
PY2 = False
|
||||
PY3 = True
|
||||
base_str = (bytes, str)
|
||||
string_types = (bytes, str)
|
||||
text_type = str
|
||||
iteritems = dict.items
|
||||
|
||||
+4642
-220
File diff suppressed because it is too large
Load Diff
-333
@@ -1,333 +0,0 @@
|
||||
######################## BEGIN LICENSE BLOCK ########################
|
||||
# The Original Code is Mozilla Communicator client code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 1998
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Mark Pilgrim - port to Python
|
||||
#
|
||||
# This library 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 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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 library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
# 02110-1301 USA
|
||||
######################### END LICENSE BLOCK #########################
|
||||
|
||||
# KOI8-R language model
|
||||
# Character Mapping Table:
|
||||
KOI8R_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80
|
||||
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90
|
||||
223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0
|
||||
238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0
|
||||
27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0
|
||||
15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0
|
||||
59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0
|
||||
35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0
|
||||
)
|
||||
|
||||
win1251_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
|
||||
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,
|
||||
223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,
|
||||
239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253,
|
||||
37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35,
|
||||
45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43,
|
||||
3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15,
|
||||
9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16,
|
||||
)
|
||||
|
||||
latin5_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
|
||||
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,
|
||||
223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,
|
||||
37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35,
|
||||
45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43,
|
||||
3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15,
|
||||
9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16,
|
||||
239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255,
|
||||
)
|
||||
|
||||
macCyrillic_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35,
|
||||
45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43,
|
||||
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
|
||||
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,
|
||||
223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,
|
||||
239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16,
|
||||
3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15,
|
||||
9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255,
|
||||
)
|
||||
|
||||
IBM855_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205,
|
||||
206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70,
|
||||
3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219,
|
||||
220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229,
|
||||
230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243,
|
||||
8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248,
|
||||
43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249,
|
||||
250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255,
|
||||
)
|
||||
|
||||
IBM866_char_to_order_map = (
|
||||
255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10
|
||||
253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20
|
||||
252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30
|
||||
253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40
|
||||
155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50
|
||||
253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60
|
||||
67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70
|
||||
37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35,
|
||||
45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43,
|
||||
3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15,
|
||||
191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
|
||||
207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,
|
||||
223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,
|
||||
9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16,
|
||||
239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255,
|
||||
)
|
||||
|
||||
# Model Table:
|
||||
# total sequences: 100%
|
||||
# first 512 sequences: 97.6601%
|
||||
# first 1024 sequences: 2.3389%
|
||||
# rest sequences: 0.1237%
|
||||
# negative sequences: 0.0009%
|
||||
RussianLangModel = (
|
||||
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2,
|
||||
3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1,
|
||||
0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1,
|
||||
0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0,
|
||||
0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,
|
||||
2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
|
||||
3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0,
|
||||
0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1,
|
||||
1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1,
|
||||
1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0,
|
||||
2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1,
|
||||
1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0,
|
||||
3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1,
|
||||
1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0,
|
||||
2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2,
|
||||
1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1,
|
||||
1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1,
|
||||
1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,
|
||||
2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1,
|
||||
1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,
|
||||
3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2,
|
||||
1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,
|
||||
2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1,
|
||||
1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0,
|
||||
2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0,
|
||||
0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1,
|
||||
1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0,
|
||||
1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1,
|
||||
1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0,
|
||||
3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1,
|
||||
2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1,
|
||||
3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1,
|
||||
1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,
|
||||
1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1,
|
||||
0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,
|
||||
2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1,
|
||||
1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0,
|
||||
1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1,
|
||||
0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1,
|
||||
1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
|
||||
2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2,
|
||||
2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1,
|
||||
1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0,
|
||||
1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0,
|
||||
2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,
|
||||
1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,
|
||||
0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,
|
||||
2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1,
|
||||
1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1,
|
||||
1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,
|
||||
0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
|
||||
0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1,
|
||||
0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1,
|
||||
0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,
|
||||
0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,
|
||||
1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1,
|
||||
0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,
|
||||
2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,
|
||||
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
|
||||
1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0,
|
||||
0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
|
||||
)
|
||||
|
||||
Koi8rModel = {
|
||||
'char_to_order_map': KOI8R_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "KOI8-R",
|
||||
'language': 'Russian',
|
||||
}
|
||||
|
||||
Win1251CyrillicModel = {
|
||||
'char_to_order_map': win1251_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "windows-1251",
|
||||
'language': 'Russian',
|
||||
}
|
||||
|
||||
Latin5CyrillicModel = {
|
||||
'char_to_order_map': latin5_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "ISO-8859-5",
|
||||
'language': 'Russian',
|
||||
}
|
||||
|
||||
MacCyrillicModel = {
|
||||
'char_to_order_map': macCyrillic_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "MacCyrillic",
|
||||
'language': 'Russian',
|
||||
}
|
||||
|
||||
Ibm866Model = {
|
||||
'char_to_order_map': IBM866_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "IBM866",
|
||||
'language': 'Russian',
|
||||
}
|
||||
|
||||
Ibm855Model = {
|
||||
'char_to_order_map': IBM855_char_to_order_map,
|
||||
'precedence_matrix': RussianLangModel,
|
||||
'typical_positive_ratio': 0.976601,
|
||||
'keep_english_letter': False,
|
||||
'charset_name': "IBM855",
|
||||
'language': 'Russian',
|
||||
}
|
||||
+4390
-217
File diff suppressed because it is too large
Load Diff
+4377
-194
File diff suppressed because it is too large
Load Diff
+4642
-217
File diff suppressed because it is too large
Load Diff
+5718
File diff suppressed because it is too large
Load Diff
+4377
-193
File diff suppressed because it is too large
Load Diff
+4376
-186
File diff suppressed because it is too large
Load Diff
Vendored
+310
@@ -0,0 +1,310 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Metadata about languages used by our model training code for our
|
||||
SingleByteCharSetProbers. Could be used for other things in the future.
|
||||
|
||||
This code is based on the language metadata from the uchardet project.
|
||||
"""
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
from string import ascii_letters
|
||||
|
||||
|
||||
# TODO: Add Ukranian (KOI8-U)
|
||||
|
||||
class Language(object):
|
||||
"""Metadata about a language useful for training models
|
||||
|
||||
:ivar name: The human name for the language, in English.
|
||||
:type name: str
|
||||
:ivar iso_code: 2-letter ISO 639-1 if possible, 3-letter ISO code otherwise,
|
||||
or use another catalog as a last resort.
|
||||
:type iso_code: str
|
||||
:ivar use_ascii: Whether or not ASCII letters should be included in trained
|
||||
models.
|
||||
:type use_ascii: bool
|
||||
:ivar charsets: The charsets we want to support and create data for.
|
||||
:type charsets: list of str
|
||||
:ivar alphabet: The characters in the language's alphabet. If `use_ascii` is
|
||||
`True`, you only need to add those not in the ASCII set.
|
||||
:type alphabet: str
|
||||
:ivar wiki_start_pages: The Wikipedia pages to start from if we're crawling
|
||||
Wikipedia for training data.
|
||||
:type wiki_start_pages: list of str
|
||||
"""
|
||||
def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None,
|
||||
alphabet=None, wiki_start_pages=None):
|
||||
super(Language, self).__init__()
|
||||
self.name = name
|
||||
self.iso_code = iso_code
|
||||
self.use_ascii = use_ascii
|
||||
self.charsets = charsets
|
||||
if self.use_ascii:
|
||||
if alphabet:
|
||||
alphabet += ascii_letters
|
||||
else:
|
||||
alphabet = ascii_letters
|
||||
elif not alphabet:
|
||||
raise ValueError('Must supply alphabet if use_ascii is False')
|
||||
self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None
|
||||
self.wiki_start_pages = wiki_start_pages
|
||||
|
||||
def __repr__(self):
|
||||
return '{}({})'.format(self.__class__.__name__,
|
||||
', '.join('{}={!r}'.format(k, v)
|
||||
for k, v in self.__dict__.items()
|
||||
if not k.startswith('_')))
|
||||
|
||||
|
||||
LANGUAGES = {'Arabic': Language(name='Arabic',
|
||||
iso_code='ar',
|
||||
use_ascii=False,
|
||||
# We only support encodings that use isolated
|
||||
# forms, because the current recommendation is
|
||||
# that the rendering system handles presentation
|
||||
# forms. This means we purposefully skip IBM864.
|
||||
charsets=['ISO-8859-6', 'WINDOWS-1256',
|
||||
'CP720', 'CP864'],
|
||||
alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ',
|
||||
wiki_start_pages=[u'الصفحة_الرئيسية']),
|
||||
'Belarusian': Language(name='Belarusian',
|
||||
iso_code='be',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-5', 'WINDOWS-1251',
|
||||
'IBM866', 'MacCyrillic'],
|
||||
alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ'
|
||||
u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'),
|
||||
wiki_start_pages=[u'Галоўная_старонка']),
|
||||
'Bulgarian': Language(name='Bulgarian',
|
||||
iso_code='bg',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-5', 'WINDOWS-1251',
|
||||
'IBM855'],
|
||||
alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ'
|
||||
u'абвгдежзийклмнопрстуфхцчшщъьюя'),
|
||||
wiki_start_pages=[u'Начална_страница']),
|
||||
'Czech': Language(name='Czech',
|
||||
iso_code='cz',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ',
|
||||
wiki_start_pages=[u'Hlavní_strana']),
|
||||
'Danish': Language(name='Danish',
|
||||
iso_code='da',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'æøåÆØÅ',
|
||||
wiki_start_pages=[u'Forside']),
|
||||
'German': Language(name='German',
|
||||
iso_code='de',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'WINDOWS-1252'],
|
||||
alphabet=u'äöüßÄÖÜ',
|
||||
wiki_start_pages=[u'Wikipedia:Hauptseite']),
|
||||
'Greek': Language(name='Greek',
|
||||
iso_code='el',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-7', 'WINDOWS-1253'],
|
||||
alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ'
|
||||
u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'),
|
||||
wiki_start_pages=[u'Πύλη:Κύρια']),
|
||||
'English': Language(name='English',
|
||||
iso_code='en',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'WINDOWS-1252'],
|
||||
wiki_start_pages=[u'Main_Page']),
|
||||
'Esperanto': Language(name='Esperanto',
|
||||
iso_code='eo',
|
||||
# Q, W, X, and Y not used at all
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-3'],
|
||||
alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz'
|
||||
u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'),
|
||||
wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']),
|
||||
'Spanish': Language(name='Spanish',
|
||||
iso_code='es',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ',
|
||||
wiki_start_pages=[u'Wikipedia:Portada']),
|
||||
'Estonian': Language(name='Estonian',
|
||||
iso_code='et',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-4', 'ISO-8859-13',
|
||||
'WINDOWS-1257'],
|
||||
# C, F, Š, Q, W, X, Y, Z, Ž are only for
|
||||
# loanwords
|
||||
alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ'
|
||||
u'abdeghijklmnoprstuvõäöü'),
|
||||
wiki_start_pages=[u'Esileht']),
|
||||
'Finnish': Language(name='Finnish',
|
||||
iso_code='fi',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'ÅÄÖŠŽåäöšž',
|
||||
wiki_start_pages=[u'Wikipedia:Etusivu']),
|
||||
'French': Language(name='French',
|
||||
iso_code='fr',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ',
|
||||
wiki_start_pages=[u'Wikipédia:Accueil_principal',
|
||||
u'Bœuf (animal)']),
|
||||
'Hebrew': Language(name='Hebrew',
|
||||
iso_code='he',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-8', 'WINDOWS-1255'],
|
||||
alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ',
|
||||
wiki_start_pages=[u'עמוד_ראשי']),
|
||||
'Croatian': Language(name='Croatian',
|
||||
iso_code='hr',
|
||||
# Q, W, X, Y are only used for foreign words.
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=(u'abcčćdđefghijklmnoprsštuvzž'
|
||||
u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'),
|
||||
wiki_start_pages=[u'Glavna_stranica']),
|
||||
'Hungarian': Language(name='Hungarian',
|
||||
iso_code='hu',
|
||||
# Q, W, X, Y are only used for foreign words.
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű'
|
||||
u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'),
|
||||
wiki_start_pages=[u'Kezdőlap']),
|
||||
'Italian': Language(name='Italian',
|
||||
iso_code='it',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'ÀÈÉÌÒÓÙàèéìòóù',
|
||||
wiki_start_pages=[u'Pagina_principale']),
|
||||
'Lithuanian': Language(name='Lithuanian',
|
||||
iso_code='lt',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-13', 'WINDOWS-1257',
|
||||
'ISO-8859-4'],
|
||||
# Q, W, and X not used at all
|
||||
alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ'
|
||||
u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'),
|
||||
wiki_start_pages=[u'Pagrindinis_puslapis']),
|
||||
'Latvian': Language(name='Latvian',
|
||||
iso_code='lv',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-13', 'WINDOWS-1257',
|
||||
'ISO-8859-4'],
|
||||
# Q, W, X, Y are only for loanwords
|
||||
alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ'
|
||||
u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'),
|
||||
wiki_start_pages=[u'Sākumlapa']),
|
||||
'Macedonian': Language(name='Macedonian',
|
||||
iso_code='mk',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-5', 'WINDOWS-1251',
|
||||
'MacCyrillic', 'IBM855'],
|
||||
alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ'
|
||||
u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'),
|
||||
wiki_start_pages=[u'Главна_страница']),
|
||||
'Dutch': Language(name='Dutch',
|
||||
iso_code='nl',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'WINDOWS-1252'],
|
||||
wiki_start_pages=[u'Hoofdpagina']),
|
||||
'Polish': Language(name='Polish',
|
||||
iso_code='pl',
|
||||
# Q and X are only used for foreign words.
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ'
|
||||
u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'),
|
||||
wiki_start_pages=[u'Wikipedia:Strona_główna']),
|
||||
'Portuguese': Language(name='Portuguese',
|
||||
iso_code='pt',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-1', 'ISO-8859-15',
|
||||
'WINDOWS-1252'],
|
||||
alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú',
|
||||
wiki_start_pages=[u'Wikipédia:Página_principal']),
|
||||
'Romanian': Language(name='Romanian',
|
||||
iso_code='ro',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=u'ăâîșțĂÂÎȘȚ',
|
||||
wiki_start_pages=[u'Pagina_principală']),
|
||||
'Russian': Language(name='Russian',
|
||||
iso_code='ru',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-5', 'WINDOWS-1251',
|
||||
'KOI8-R', 'MacCyrillic', 'IBM866',
|
||||
'IBM855'],
|
||||
alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'
|
||||
u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'),
|
||||
wiki_start_pages=[u'Заглавная_страница']),
|
||||
'Slovak': Language(name='Slovak',
|
||||
iso_code='sk',
|
||||
use_ascii=True,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ',
|
||||
wiki_start_pages=[u'Hlavná_stránka']),
|
||||
'Slovene': Language(name='Slovene',
|
||||
iso_code='sl',
|
||||
# Q, W, X, Y are only used for foreign words.
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-2', 'WINDOWS-1250'],
|
||||
alphabet=(u'abcčdefghijklmnoprsštuvzž'
|
||||
u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'),
|
||||
wiki_start_pages=[u'Glavna_stran']),
|
||||
# Serbian can be written in both Latin and Cyrillic, but there's no
|
||||
# simple way to get the Latin alphabet pages from Wikipedia through
|
||||
# the API, so for now we just support Cyrillic.
|
||||
'Serbian': Language(name='Serbian',
|
||||
iso_code='sr',
|
||||
alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ'
|
||||
u'абвгдђежзијклљмнњопрстћуфхцчџш'),
|
||||
charsets=['ISO-8859-5', 'WINDOWS-1251',
|
||||
'MacCyrillic', 'IBM855'],
|
||||
wiki_start_pages=[u'Главна_страна']),
|
||||
'Thai': Language(name='Thai',
|
||||
iso_code='th',
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-11', 'TIS-620', 'CP874'],
|
||||
alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛',
|
||||
wiki_start_pages=[u'หน้าหลัก']),
|
||||
'Turkish': Language(name='Turkish',
|
||||
iso_code='tr',
|
||||
# Q, W, and X are not used by Turkish
|
||||
use_ascii=False,
|
||||
charsets=['ISO-8859-3', 'ISO-8859-9',
|
||||
'WINDOWS-1254'],
|
||||
alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû'
|
||||
u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'),
|
||||
wiki_start_pages=[u'Ana_Sayfa']),
|
||||
'Vietnamese': Language(name='Vietnamese',
|
||||
iso_code='vi',
|
||||
use_ascii=False,
|
||||
# Windows-1258 is the only common 8-bit
|
||||
# Vietnamese encoding supported by Python.
|
||||
# From Wikipedia:
|
||||
# For systems that lack support for Unicode,
|
||||
# dozens of 8-bit Vietnamese code pages are
|
||||
# available.[1] The most common are VISCII
|
||||
# (TCVN 5712:1993), VPS, and Windows-1258.[3]
|
||||
# Where ASCII is required, such as when
|
||||
# ensuring readability in plain text e-mail,
|
||||
# Vietnamese letters are often encoded
|
||||
# according to Vietnamese Quoted-Readable
|
||||
# (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4]
|
||||
# though usage of either variable-width
|
||||
# scheme has declined dramatically following
|
||||
# the adoption of Unicode on the World Wide
|
||||
# Web.
|
||||
charsets=['WINDOWS-1258'],
|
||||
alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy'
|
||||
u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'),
|
||||
wiki_start_pages=[u'Chữ_Quốc_ngữ']),
|
||||
}
|
||||
+29
-16
@@ -26,10 +26,22 @@
|
||||
# 02110-1301 USA
|
||||
######################### END LICENSE BLOCK #########################
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from .charsetprober import CharSetProber
|
||||
from .enums import CharacterCategory, ProbingState, SequenceLikelihood
|
||||
|
||||
|
||||
SingleByteCharSetModel = namedtuple('SingleByteCharSetModel',
|
||||
['charset_name',
|
||||
'language',
|
||||
'char_to_order_map',
|
||||
'language_model',
|
||||
'typical_positive_ratio',
|
||||
'keep_ascii_letters',
|
||||
'alphabet'])
|
||||
|
||||
|
||||
class SingleByteCharSetProber(CharSetProber):
|
||||
SAMPLE_SIZE = 64
|
||||
SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2
|
||||
@@ -65,25 +77,25 @@ class SingleByteCharSetProber(CharSetProber):
|
||||
if self._name_prober:
|
||||
return self._name_prober.charset_name
|
||||
else:
|
||||
return self._model['charset_name']
|
||||
return self._model.charset_name
|
||||
|
||||
@property
|
||||
def language(self):
|
||||
if self._name_prober:
|
||||
return self._name_prober.language
|
||||
else:
|
||||
return self._model.get('language')
|
||||
return self._model.language
|
||||
|
||||
def feed(self, byte_str):
|
||||
if not self._model['keep_english_letter']:
|
||||
# TODO: Make filter_international_words keep things in self.alphabet
|
||||
if not self._model.keep_ascii_letters:
|
||||
byte_str = self.filter_international_words(byte_str)
|
||||
if not byte_str:
|
||||
return self.state
|
||||
char_to_order_map = self._model['char_to_order_map']
|
||||
for i, c in enumerate(byte_str):
|
||||
# XXX: Order is in range 1-64, so one would think we want 0-63 here,
|
||||
# but that leads to 27 more test failures than before.
|
||||
order = char_to_order_map[c]
|
||||
char_to_order_map = self._model.char_to_order_map
|
||||
language_model = self._model.language_model
|
||||
for char in byte_str:
|
||||
order = char_to_order_map.get(char, CharacterCategory.UNDEFINED)
|
||||
# XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but
|
||||
# CharacterCategory.SYMBOL is actually 253, so we use CONTROL
|
||||
# to make it closer to the original intent. The only difference
|
||||
@@ -91,20 +103,21 @@ class SingleByteCharSetProber(CharSetProber):
|
||||
# _total_char purposes.
|
||||
if order < CharacterCategory.CONTROL:
|
||||
self._total_char += 1
|
||||
# TODO: Follow uchardet's lead and discount confidence for frequent
|
||||
# control characters.
|
||||
# See https://github.com/BYVoid/uchardet/commit/55b4f23971db61
|
||||
if order < self.SAMPLE_SIZE:
|
||||
self._freq_char += 1
|
||||
if self._last_order < self.SAMPLE_SIZE:
|
||||
self._total_seqs += 1
|
||||
if not self._reversed:
|
||||
i = (self._last_order * self.SAMPLE_SIZE) + order
|
||||
model = self._model['precedence_matrix'][i]
|
||||
else: # reverse the order of the letters in the lookup
|
||||
i = (order * self.SAMPLE_SIZE) + self._last_order
|
||||
model = self._model['precedence_matrix'][i]
|
||||
self._seq_counters[model] += 1
|
||||
lm_cat = language_model[self._last_order][order]
|
||||
else:
|
||||
lm_cat = language_model[order][self._last_order]
|
||||
self._seq_counters[lm_cat] += 1
|
||||
self._last_order = order
|
||||
|
||||
charset_name = self._model['charset_name']
|
||||
charset_name = self._model.charset_name
|
||||
if self.state == ProbingState.DETECTING:
|
||||
if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD:
|
||||
confidence = self.get_confidence()
|
||||
@@ -125,7 +138,7 @@ class SingleByteCharSetProber(CharSetProber):
|
||||
r = 0.01
|
||||
if self._total_seqs > 0:
|
||||
r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) /
|
||||
self._total_seqs / self._model['typical_positive_ratio'])
|
||||
self._total_seqs / self._model.typical_positive_ratio)
|
||||
r = r * self._freq_char / self._total_char
|
||||
if r >= 1.0:
|
||||
r = 0.99
|
||||
|
||||
+43
-33
@@ -27,47 +27,57 @@
|
||||
######################### END LICENSE BLOCK #########################
|
||||
|
||||
from .charsetgroupprober import CharSetGroupProber
|
||||
from .sbcharsetprober import SingleByteCharSetProber
|
||||
from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel,
|
||||
Latin5CyrillicModel, MacCyrillicModel,
|
||||
Ibm866Model, Ibm855Model)
|
||||
from .langgreekmodel import Latin7GreekModel, Win1253GreekModel
|
||||
from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel
|
||||
# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel
|
||||
from .langthaimodel import TIS620ThaiModel
|
||||
from .langhebrewmodel import Win1255HebrewModel
|
||||
from .hebrewprober import HebrewProber
|
||||
from .langturkishmodel import Latin5TurkishModel
|
||||
from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL,
|
||||
WINDOWS_1251_BULGARIAN_MODEL)
|
||||
from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL
|
||||
from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL
|
||||
# from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL,
|
||||
# WINDOWS_1250_HUNGARIAN_MODEL)
|
||||
from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL,
|
||||
ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL,
|
||||
MACCYRILLIC_RUSSIAN_MODEL,
|
||||
WINDOWS_1251_RUSSIAN_MODEL)
|
||||
from .langthaimodel import TIS_620_THAI_MODEL
|
||||
from .langturkishmodel import ISO_8859_9_TURKISH_MODEL
|
||||
from .sbcharsetprober import SingleByteCharSetProber
|
||||
|
||||
|
||||
class SBCSGroupProber(CharSetGroupProber):
|
||||
def __init__(self):
|
||||
super(SBCSGroupProber, self).__init__()
|
||||
hebrew_prober = HebrewProber()
|
||||
logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL,
|
||||
False, hebrew_prober)
|
||||
# TODO: See if using ISO-8859-8 Hebrew model works better here, since
|
||||
# it's actually the visual one
|
||||
visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL,
|
||||
True, hebrew_prober)
|
||||
hebrew_prober.set_model_probers(logical_hebrew_prober,
|
||||
visual_hebrew_prober)
|
||||
# TODO: ORDER MATTERS HERE. I changed the order vs what was in master
|
||||
# and several tests failed that did not before. Some thought
|
||||
# should be put into the ordering, and we should consider making
|
||||
# order not matter here, because that is very counter-intuitive.
|
||||
self.probers = [
|
||||
SingleByteCharSetProber(Win1251CyrillicModel),
|
||||
SingleByteCharSetProber(Koi8rModel),
|
||||
SingleByteCharSetProber(Latin5CyrillicModel),
|
||||
SingleByteCharSetProber(MacCyrillicModel),
|
||||
SingleByteCharSetProber(Ibm866Model),
|
||||
SingleByteCharSetProber(Ibm855Model),
|
||||
SingleByteCharSetProber(Latin7GreekModel),
|
||||
SingleByteCharSetProber(Win1253GreekModel),
|
||||
SingleByteCharSetProber(Latin5BulgarianModel),
|
||||
SingleByteCharSetProber(Win1251BulgarianModel),
|
||||
SingleByteCharSetProber(WINDOWS_1251_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(KOI8_R_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(ISO_8859_5_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(MACCYRILLIC_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(IBM866_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(IBM855_RUSSIAN_MODEL),
|
||||
SingleByteCharSetProber(ISO_8859_7_GREEK_MODEL),
|
||||
SingleByteCharSetProber(WINDOWS_1253_GREEK_MODEL),
|
||||
SingleByteCharSetProber(ISO_8859_5_BULGARIAN_MODEL),
|
||||
SingleByteCharSetProber(WINDOWS_1251_BULGARIAN_MODEL),
|
||||
# TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250)
|
||||
# after we retrain model.
|
||||
# SingleByteCharSetProber(Latin2HungarianModel),
|
||||
# SingleByteCharSetProber(Win1250HungarianModel),
|
||||
SingleByteCharSetProber(TIS620ThaiModel),
|
||||
SingleByteCharSetProber(Latin5TurkishModel),
|
||||
# SingleByteCharSetProber(ISO_8859_2_HUNGARIAN_MODEL),
|
||||
# SingleByteCharSetProber(WINDOWS_1250_HUNGARIAN_MODEL),
|
||||
SingleByteCharSetProber(TIS_620_THAI_MODEL),
|
||||
SingleByteCharSetProber(ISO_8859_9_TURKISH_MODEL),
|
||||
hebrew_prober,
|
||||
logical_hebrew_prober,
|
||||
visual_hebrew_prober,
|
||||
]
|
||||
hebrew_prober = HebrewProber()
|
||||
logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel,
|
||||
False, hebrew_prober)
|
||||
visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True,
|
||||
hebrew_prober)
|
||||
hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober)
|
||||
self.probers.extend([hebrew_prober, logical_hebrew_prober,
|
||||
visual_hebrew_prober])
|
||||
|
||||
self.reset()
|
||||
|
||||
+4
-4
@@ -266,7 +266,7 @@ class UniversalDetector(object):
|
||||
'language': max_prober.language}
|
||||
|
||||
# Log all prober confidences if none met MINIMUM_THRESHOLD
|
||||
if self.logger.getEffectiveLevel() == logging.DEBUG:
|
||||
if self.logger.getEffectiveLevel() <= logging.DEBUG:
|
||||
if self.result['encoding'] is None:
|
||||
self.logger.debug('no probers hit minimum threshold')
|
||||
for group_prober in self._charset_probers:
|
||||
@@ -280,7 +280,7 @@ class UniversalDetector(object):
|
||||
prober.get_confidence())
|
||||
else:
|
||||
self.logger.debug('%s %s confidence = %s',
|
||||
prober.charset_name,
|
||||
prober.language,
|
||||
prober.get_confidence())
|
||||
group_prober.charset_name,
|
||||
group_prober.language,
|
||||
group_prober.get_confidence())
|
||||
return self.result
|
||||
|
||||
Vendored
+1
-1
@@ -5,5 +5,5 @@ from within setup.py and from chardet subpackages.
|
||||
:author: Dan Blanchard (dan.blanchard@gmail.com)
|
||||
"""
|
||||
|
||||
__version__ = "3.0.4"
|
||||
__version__ = "4.0.0"
|
||||
VERSION = __version__.split('.')
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 TAHRI Ahmed R.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Charset-Normalizer
|
||||
~~~~~~~~~~~~~~
|
||||
The Real First Universal Charset Detector.
|
||||
A library that helps you read text from an unknown charset encoding.
|
||||
Motivated by chardet, This package is trying to resolve the issue by taking a new approach.
|
||||
All IANA character set names for which the Python core library provides codecs are supported.
|
||||
|
||||
Basic usage:
|
||||
>>> from charset_normalizer import from_bytes
|
||||
>>> results = from_bytes('Bсеки човек има право на образование. Oбразованието трябва да бъде безплатно, поне що се отнася до началното и основното образование.'.encode('utf_8'))
|
||||
>>> "utf_8" in results
|
||||
True
|
||||
>>> best_result = results.best()
|
||||
>>> str(best_result)
|
||||
'Bсеки човек има право на образование. Oбразованието трябва да бъде безплатно, поне що се отнася до началното и основното образование.'
|
||||
|
||||
Others methods and usages are available - see the full documentation
|
||||
at <https://github.com/Ousret/charset_normalizer>.
|
||||
:copyright: (c) 2021 by Ahmed TAHRI
|
||||
:license: MIT, see LICENSE for more details.
|
||||
"""
|
||||
from charset_normalizer.api import from_fp, from_path, from_bytes, normalize
|
||||
from charset_normalizer.legacy import detect
|
||||
from charset_normalizer.version import __version__, VERSION
|
||||
from charset_normalizer.models import CharsetMatch, CharsetMatches
|
||||
|
||||
# Backward-compatible v1 imports
|
||||
from charset_normalizer.models import CharsetNormalizerMatch
|
||||
import charset_normalizer.api as CharsetDetector
|
||||
CharsetNormalizerMatches = CharsetDetector
|
||||
+421
@@ -0,0 +1,421 @@
|
||||
from os.path import splitext, basename
|
||||
from typing import List, BinaryIO, Optional, Set, Union
|
||||
|
||||
try:
|
||||
from os import PathLike
|
||||
except ImportError:
|
||||
PathLike = Union[str, 'os.PathLike[str]'] # type: ignore
|
||||
|
||||
from charset_normalizer.constant import TOO_SMALL_SEQUENCE, TOO_BIG_SEQUENCE, IANA_SUPPORTED
|
||||
from charset_normalizer.md import mess_ratio
|
||||
from charset_normalizer.models import CharsetMatches, CharsetMatch
|
||||
from warnings import warn
|
||||
import logging
|
||||
|
||||
from charset_normalizer.utils import any_specified_encoding, is_multi_byte_encoding, identify_sig_or_bom, \
|
||||
should_strip_sig_or_bom, is_cp_similar, iana_name
|
||||
from charset_normalizer.cd import coherence_ratio, encoding_languages, mb_encoding_languages, merge_coherence_ratios
|
||||
|
||||
logger = logging.getLogger("charset_normalizer")
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter('%(asctime)s | %(levelname)s | %(message)s'))
|
||||
logger.addHandler(handler)
|
||||
|
||||
|
||||
def from_bytes(
|
||||
sequences: bytes,
|
||||
steps: int = 5,
|
||||
chunk_size: int = 512,
|
||||
threshold: float = 0.2,
|
||||
cp_isolation: List[str] = None,
|
||||
cp_exclusion: List[str] = None,
|
||||
preemptive_behaviour: bool = True,
|
||||
explain: bool = False
|
||||
) -> CharsetMatches:
|
||||
"""
|
||||
Given a raw bytes sequence, return the best possibles charset usable to render str objects.
|
||||
If there is no results, it is a strong indicator that the source is binary/not text.
|
||||
By default, the process will extract 5 blocs of 512o each to assess the mess and coherence of a given sequence.
|
||||
And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will.
|
||||
|
||||
The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page
|
||||
but never take it for granted. Can improve the performance.
|
||||
|
||||
You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that
|
||||
purpose.
|
||||
|
||||
This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32.
|
||||
"""
|
||||
|
||||
if not explain:
|
||||
logger.setLevel(logging.CRITICAL)
|
||||
else:
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
length = len(sequences) # type: int
|
||||
|
||||
if length == 0:
|
||||
logger.warning("Given content is empty, stopping the process very early, returning empty utf_8 str match")
|
||||
return CharsetMatches(
|
||||
[
|
||||
CharsetMatch(
|
||||
sequences,
|
||||
"utf_8",
|
||||
0.,
|
||||
False,
|
||||
[],
|
||||
""
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
if cp_isolation is not None:
|
||||
logger.warning('cp_isolation is set. use this flag for debugging purpose. '
|
||||
'limited list of encoding allowed : %s.',
|
||||
', '.join(cp_isolation))
|
||||
cp_isolation = [iana_name(cp, False) for cp in cp_isolation]
|
||||
else:
|
||||
cp_isolation = []
|
||||
|
||||
if cp_exclusion is not None:
|
||||
logger.warning(
|
||||
'cp_exclusion is set. use this flag for debugging purpose. '
|
||||
'limited list of encoding excluded : %s.',
|
||||
', '.join(cp_exclusion))
|
||||
cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion]
|
||||
else:
|
||||
cp_exclusion = []
|
||||
|
||||
if length <= (chunk_size * steps):
|
||||
logger.warning(
|
||||
'override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.',
|
||||
steps, chunk_size, length)
|
||||
steps = 1
|
||||
chunk_size = length
|
||||
|
||||
if steps > 1 and length / steps < chunk_size:
|
||||
chunk_size = int(length / steps)
|
||||
|
||||
is_too_small_sequence = len(sequences) < TOO_SMALL_SEQUENCE # type: bool
|
||||
is_too_large_sequence = len(sequences) >= TOO_BIG_SEQUENCE # type: bool
|
||||
|
||||
if is_too_small_sequence:
|
||||
warn('Trying to detect encoding from a tiny portion of ({}) byte(s).'.format(length))
|
||||
|
||||
prioritized_encodings = [] # type: List[str]
|
||||
|
||||
specified_encoding = any_specified_encoding(sequences) if preemptive_behaviour is True else None # type: Optional[str]
|
||||
|
||||
if specified_encoding is not None:
|
||||
prioritized_encodings.append(specified_encoding)
|
||||
logger.info('Detected declarative mark in sequence. Priority +1 given for %s.', specified_encoding)
|
||||
|
||||
tested = set() # type: Set[str]
|
||||
tested_but_hard_failure = [] # type: List[str]
|
||||
tested_but_soft_failure = [] # type: List[str]
|
||||
|
||||
fallback_ascii = None # type: Optional[CharsetMatch]
|
||||
fallback_u8 = None # type: Optional[CharsetMatch]
|
||||
|
||||
single_byte_hard_failure_count = 0 # type: int
|
||||
single_byte_soft_failure_count = 0 # type: int
|
||||
|
||||
results = CharsetMatches() # type: CharsetMatches
|
||||
|
||||
sig_encoding, sig_payload = identify_sig_or_bom(sequences)
|
||||
|
||||
if sig_encoding is not None:
|
||||
prioritized_encodings.append(sig_encoding)
|
||||
logger.info('Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.', len(sig_payload), sig_encoding)
|
||||
|
||||
prioritized_encodings.append("ascii")
|
||||
|
||||
if "utf_8" not in prioritized_encodings:
|
||||
prioritized_encodings.append("utf_8")
|
||||
|
||||
for encoding_iana in prioritized_encodings+IANA_SUPPORTED:
|
||||
|
||||
if cp_isolation and encoding_iana not in cp_isolation:
|
||||
continue
|
||||
|
||||
if cp_exclusion and encoding_iana in cp_exclusion:
|
||||
continue
|
||||
|
||||
if encoding_iana in tested:
|
||||
continue
|
||||
|
||||
tested.add(encoding_iana)
|
||||
|
||||
decoded_payload = None # type: Optional[str]
|
||||
bom_or_sig_available = sig_encoding == encoding_iana # type: bool
|
||||
strip_sig_or_bom = bom_or_sig_available and should_strip_sig_or_bom(encoding_iana) # type: bool
|
||||
|
||||
if encoding_iana in {"utf_16", "utf_32"} and bom_or_sig_available is False:
|
||||
logger.info("Encoding %s wont be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", encoding_iana)
|
||||
continue
|
||||
|
||||
try:
|
||||
is_multi_byte_decoder = is_multi_byte_encoding(encoding_iana) # type: bool
|
||||
except (ModuleNotFoundError, ImportError):
|
||||
logger.debug("Encoding %s does not provide an IncrementalDecoder", encoding_iana)
|
||||
continue
|
||||
|
||||
try:
|
||||
if is_too_large_sequence and is_multi_byte_decoder is False:
|
||||
str(
|
||||
sequences[:int(50e4)] if strip_sig_or_bom is False else sequences[len(sig_payload):int(50e4)],
|
||||
encoding=encoding_iana
|
||||
)
|
||||
else:
|
||||
decoded_payload = str(
|
||||
sequences if strip_sig_or_bom is False else sequences[len(sig_payload):],
|
||||
encoding=encoding_iana
|
||||
)
|
||||
except UnicodeDecodeError as e:
|
||||
logger.warning('Code page %s does not fit given bytes sequence at ALL. %s', encoding_iana, str(e))
|
||||
tested_but_hard_failure.append(encoding_iana)
|
||||
if not is_multi_byte_decoder:
|
||||
single_byte_hard_failure_count += 1
|
||||
continue
|
||||
except LookupError:
|
||||
tested_but_hard_failure.append(encoding_iana)
|
||||
if not is_multi_byte_decoder:
|
||||
single_byte_hard_failure_count += 1
|
||||
continue
|
||||
|
||||
similar_soft_failure_test = False # type: bool
|
||||
|
||||
for encoding_soft_failed in tested_but_soft_failure:
|
||||
if is_cp_similar(encoding_iana, encoding_soft_failed):
|
||||
similar_soft_failure_test = True
|
||||
break
|
||||
|
||||
if similar_soft_failure_test:
|
||||
logger.warning("%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", encoding_iana, encoding_soft_failed)
|
||||
continue
|
||||
|
||||
r_ = range(
|
||||
0 if bom_or_sig_available is False else len(sig_payload),
|
||||
length,
|
||||
int(length / steps)
|
||||
)
|
||||
|
||||
multi_byte_bonus = is_multi_byte_decoder and decoded_payload is not None and len(decoded_payload) < length # type: bool
|
||||
|
||||
if multi_byte_bonus:
|
||||
logger.info('Code page %s is a multi byte encoding table and it appear that at least one character was encoded using n-bytes. Should not be a coincidence. Priority +1 given.', encoding_iana)
|
||||
|
||||
max_chunk_gave_up = int(len(r_) / 4) # type: int
|
||||
|
||||
if max_chunk_gave_up < 2:
|
||||
max_chunk_gave_up = 2
|
||||
|
||||
early_stop_count = 0 # type: int
|
||||
|
||||
md_chunks = [] # type: List[str]
|
||||
md_ratios = []
|
||||
|
||||
for i in r_:
|
||||
cut_sequence = sequences[i:i + chunk_size]
|
||||
|
||||
if bom_or_sig_available and strip_sig_or_bom is False:
|
||||
cut_sequence = sig_payload+cut_sequence
|
||||
|
||||
chunk = cut_sequence.decode(encoding_iana, errors="ignore") # type: str
|
||||
|
||||
md_chunks.append(chunk)
|
||||
|
||||
md_ratios.append(
|
||||
mess_ratio(
|
||||
chunk,
|
||||
threshold
|
||||
)
|
||||
)
|
||||
|
||||
if md_ratios[-1] >= threshold:
|
||||
early_stop_count += 1
|
||||
|
||||
if (early_stop_count >= max_chunk_gave_up) or (bom_or_sig_available and strip_sig_or_bom is False):
|
||||
break
|
||||
|
||||
if md_ratios:
|
||||
mean_mess_ratio = sum(md_ratios) / len(md_ratios) # type: float
|
||||
else:
|
||||
mean_mess_ratio = 0.
|
||||
|
||||
if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up:
|
||||
tested_but_soft_failure.append(encoding_iana)
|
||||
if not is_multi_byte_decoder:
|
||||
single_byte_soft_failure_count += 1
|
||||
logger.warning('%s was excluded because of initial chaos probing. Gave up %i time(s). '
|
||||
'Computed mean chaos is %f %%.',
|
||||
encoding_iana,
|
||||
early_stop_count,
|
||||
round(mean_mess_ratio * 100, ndigits=3))
|
||||
# Preparing those fallbacks in case we got nothing.
|
||||
if encoding_iana in ["ascii", "utf_8"]:
|
||||
fallback_entry = CharsetMatch(
|
||||
sequences,
|
||||
encoding_iana,
|
||||
threshold,
|
||||
False,
|
||||
[],
|
||||
decoded_payload
|
||||
)
|
||||
if encoding_iana == "ascii":
|
||||
fallback_ascii = fallback_entry
|
||||
else:
|
||||
fallback_u8 = fallback_entry
|
||||
continue
|
||||
|
||||
logger.info(
|
||||
'%s passed initial chaos probing. Mean measured chaos is %f %%',
|
||||
encoding_iana,
|
||||
round(mean_mess_ratio * 100, ndigits=3)
|
||||
)
|
||||
|
||||
if not is_multi_byte_decoder:
|
||||
target_languages = encoding_languages(encoding_iana) # type: List[str]
|
||||
else:
|
||||
target_languages = mb_encoding_languages(encoding_iana)
|
||||
|
||||
if target_languages:
|
||||
logger.info("{} should target any language(s) of {}".format(encoding_iana, str(target_languages)))
|
||||
|
||||
cd_ratios = []
|
||||
|
||||
for chunk in md_chunks:
|
||||
chunk_languages = coherence_ratio(chunk, 0.1, ",".join(target_languages) if target_languages else None)
|
||||
|
||||
cd_ratios.append(
|
||||
chunk_languages
|
||||
)
|
||||
|
||||
cd_ratios_merged = merge_coherence_ratios(cd_ratios)
|
||||
|
||||
if cd_ratios_merged:
|
||||
logger.info("We detected language {} using {}".format(cd_ratios_merged, encoding_iana))
|
||||
|
||||
results.append(
|
||||
CharsetMatch(
|
||||
sequences,
|
||||
encoding_iana,
|
||||
mean_mess_ratio,
|
||||
bom_or_sig_available,
|
||||
cd_ratios_merged,
|
||||
decoded_payload
|
||||
)
|
||||
)
|
||||
|
||||
if encoding_iana in [specified_encoding, "ascii", "utf_8"] and mean_mess_ratio < 0.1:
|
||||
logger.info("%s is most likely the one. Stopping the process.", encoding_iana)
|
||||
return CharsetMatches(
|
||||
[results[encoding_iana]]
|
||||
)
|
||||
|
||||
if encoding_iana == sig_encoding:
|
||||
logger.info(
|
||||
"%s is most likely the one as we detected a BOM or SIG within the beginning of the sequence.",
|
||||
encoding_iana
|
||||
)
|
||||
return CharsetMatches(
|
||||
[results[encoding_iana]]
|
||||
)
|
||||
|
||||
if results[-1].languages:
|
||||
logger.info(
|
||||
"Using %s code page we detected the following languages: %s",
|
||||
encoding_iana,
|
||||
results[-1]._languages
|
||||
)
|
||||
|
||||
if len(results) == 0:
|
||||
if fallback_u8 or fallback_ascii:
|
||||
logger.warning("Nothing got out of the detection process. Using ASCII/UTF-8 fallback.")
|
||||
|
||||
if (fallback_u8 and fallback_ascii is None) or (fallback_u8 and fallback_u8.fingerprint != fallback_ascii.fingerprint):
|
||||
logger.warning("utf_8 will be used as a fallback match")
|
||||
results.append(fallback_u8)
|
||||
elif fallback_ascii:
|
||||
logger.warning("ascii will be used as a fallback match")
|
||||
results.append(fallback_ascii)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def from_fp(
|
||||
fp: BinaryIO,
|
||||
steps: int = 5,
|
||||
chunk_size: int = 512,
|
||||
threshold: float = 0.20,
|
||||
cp_isolation: List[str] = None,
|
||||
cp_exclusion: List[str] = None,
|
||||
preemptive_behaviour: bool = True,
|
||||
explain: bool = False
|
||||
) -> CharsetMatches:
|
||||
"""
|
||||
Same thing than the function from_bytes but using a file pointer that is already ready.
|
||||
Will not close the file pointer.
|
||||
"""
|
||||
return from_bytes(
|
||||
fp.read(),
|
||||
steps,
|
||||
chunk_size,
|
||||
threshold,
|
||||
cp_isolation,
|
||||
cp_exclusion,
|
||||
preemptive_behaviour,
|
||||
explain
|
||||
)
|
||||
|
||||
|
||||
def from_path(
|
||||
path: PathLike,
|
||||
steps: int = 5,
|
||||
chunk_size: int = 512,
|
||||
threshold: float = 0.20,
|
||||
cp_isolation: List[str] = None,
|
||||
cp_exclusion: List[str] = None,
|
||||
preemptive_behaviour: bool = True,
|
||||
explain: bool = False
|
||||
) -> CharsetMatches:
|
||||
"""
|
||||
Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode.
|
||||
Can raise IOError.
|
||||
"""
|
||||
with open(path, 'rb') as fp:
|
||||
return from_fp(fp, steps, chunk_size, threshold, cp_isolation, cp_exclusion, preemptive_behaviour, explain)
|
||||
|
||||
|
||||
def normalize(path: PathLike, steps: int = 5, chunk_size: int = 512, threshold: float = 0.20, cp_isolation: List[str] = None, cp_exclusion: List[str] = None, preemptive_behaviour: bool = True) -> CharsetMatch:
|
||||
"""
|
||||
Take a (text-based) file path and try to create another file next to it, this time using UTF-8.
|
||||
"""
|
||||
results = from_path(
|
||||
path,
|
||||
steps,
|
||||
chunk_size,
|
||||
threshold,
|
||||
cp_isolation,
|
||||
cp_exclusion,
|
||||
preemptive_behaviour
|
||||
)
|
||||
|
||||
filename = basename(path)
|
||||
target_extensions = list(splitext(filename))
|
||||
|
||||
if len(results) == 0:
|
||||
raise IOError('Unable to normalize "{}", no encoding charset seems to fit.'.format(filename))
|
||||
|
||||
result = results.best()
|
||||
|
||||
target_extensions[0] += '-' + result.encoding # type: ignore
|
||||
|
||||
with open('{}'.format(path.replace(filename, ''.join(target_extensions))), 'wb') as fp:
|
||||
fp.write(
|
||||
result.output() # type: ignore
|
||||
)
|
||||
|
||||
return result # type: ignore
|
||||
@@ -0,0 +1,52 @@
|
||||
"""
|
||||
This submodule purpose is to load attached JSON asset.
|
||||
Will be loaded once per package import / python init.
|
||||
|
||||
The file 'frequencies.json' is mandatory for language/coherence detection. Not having it will weaker considerably
|
||||
the core detection.
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
|
||||
|
||||
FREQUENCIES = OrderedDict(
|
||||
[
|
||||
('English', ['e', 'a', 't', 'i', 'o', 'n', 's', 'r', 'h', 'l', 'd', 'c', 'u', 'm', 'f', 'p', 'g', 'w', 'y', 'b', 'v', 'k', 'x', 'j', 'z', 'q']),
|
||||
('German', ['e', 'n', 'i', 'r', 's', 't', 'a', 'd', 'h', 'u', 'l', 'g', 'o', 'c', 'm', 'b', 'f', 'k', 'w', 'z', 'p', 'v', 'ü', 'ä', 'ö', 'j']),
|
||||
('French', ['e', 'a', 's', 'n', 'i', 't', 'r', 'l', 'u', 'o', 'd', 'c', 'p', 'm', 'é', 'v', 'g', 'f', 'b', 'h', 'q', 'à', 'x', 'è', 'y', 'j']),
|
||||
('Dutch', ['e', 'n', 'a', 'i', 'r', 't', 'o', 'd', 's', 'l', 'g', 'h', 'v', 'm', 'u', 'k', 'c', 'p', 'b', 'w', 'j', 'z', 'f', 'y', 'x', 'ë']),
|
||||
('Italian', ['e', 'i', 'a', 'o', 'n', 'l', 't', 'r', 's', 'c', 'd', 'u', 'p', 'm', 'g', 'v', 'f', 'b', 'z', 'h', 'q', 'è', 'à', 'k', 'y', 'ò']),
|
||||
('Polish', ['a', 'i', 'o', 'e', 'n', 'r', 'z', 'w', 's', 'c', 't', 'k', 'y', 'd', 'p', 'm', 'u', 'l', 'j', 'ł', 'g', 'b', 'h', 'ą', 'ę', 'ó']),
|
||||
('Spanish', ['e', 'a', 'o', 'n', 's', 'r', 'i', 'l', 'd', 't', 'c', 'u', 'm', 'p', 'b', 'g', 'v', 'f', 'y', 'ó', 'h', 'q', 'í', 'j', 'z', 'á']),
|
||||
('Russian', ['о', 'а', 'е', 'и', 'н', 'с', 'т', 'р', 'в', 'л', 'к', 'м', 'д', 'п', 'у', 'г', 'я', 'ы', 'з', 'б', 'й', 'ь', 'ч', 'х', 'ж', 'ц']),
|
||||
('Japanese', ['の', 'に', 'る', 'た', 'は', 'ー', 'と', 'し', 'を', 'で', 'て', 'が', 'い', 'ン', 'れ', 'な', '年', 'ス', 'っ', 'ル', 'か', 'ら', 'あ', 'さ', 'も', 'り']),
|
||||
('Portuguese', ['a', 'e', 'o', 's', 'i', 'r', 'd', 'n', 't', 'm', 'u', 'c', 'l', 'p', 'g', 'v', 'b', 'f', 'h', 'ã', 'q', 'é', 'ç', 'á', 'z', 'í']),
|
||||
('Swedish', ['e', 'a', 'n', 'r', 't', 's', 'i', 'l', 'd', 'o', 'm', 'k', 'g', 'v', 'h', 'f', 'u', 'p', 'ä', 'c', 'b', 'ö', 'å', 'y', 'j', 'x']),
|
||||
('Chinese', ['的', '一', '是', '不', '了', '在', '人', '有', '我', '他', '这', '个', '们', '中', '来', '上', '大', '为', '和', '国', '地', '到', '以', '说', '时', '要', '就', '出', '会']),
|
||||
('Ukrainian', ['о', 'а', 'н', 'і', 'и', 'р', 'в', 'т', 'е', 'с', 'к', 'л', 'у', 'д', 'м', 'п', 'з', 'я', 'ь', 'б', 'г', 'й', 'ч', 'х', 'ц', 'ї']),
|
||||
('Norwegian', ['e', 'r', 'n', 't', 'a', 's', 'i', 'o', 'l', 'd', 'g', 'k', 'm', 'v', 'f', 'p', 'u', 'b', 'h', 'å', 'y', 'j', 'ø', 'c', 'æ', 'w']),
|
||||
('Finnish', ['a', 'i', 'n', 't', 'e', 's', 'l', 'o', 'u', 'k', 'ä', 'm', 'r', 'v', 'j', 'h', 'p', 'y', 'd', 'ö', 'g', 'c', 'b', 'f', 'w', 'z']),
|
||||
('Vietnamese', ['n', 'h', 't', 'i', 'c', 'g', 'a', 'o', 'u', 'm', 'l', 'r', 'à', 'đ', 's', 'e', 'v', 'p', 'b', 'y', 'ư', 'd', 'á', 'k', 'ộ', 'ế']),
|
||||
('Czech', ['o', 'e', 'a', 'n', 't', 's', 'i', 'l', 'v', 'r', 'k', 'd', 'u', 'm', 'p', 'í', 'c', 'h', 'z', 'á', 'y', 'j', 'b', 'ě', 'é', 'ř']),
|
||||
('Hungarian', ['e', 'a', 't', 'l', 's', 'n', 'k', 'r', 'i', 'o', 'z', 'á', 'é', 'g', 'm', 'b', 'y', 'v', 'd', 'h', 'u', 'p', 'j', 'ö', 'f', 'c']),
|
||||
('Korean', ['이', '다', '에', '의', '는', '로', '하', '을', '가', '고', '지', '서', '한', '은', '기', '으', '년', '대', '사', '시', '를', '리', '도', '인', '스', '일']),
|
||||
('Indonesian', ['a', 'n', 'e', 'i', 'r', 't', 'u', 's', 'd', 'k', 'm', 'l', 'g', 'p', 'b', 'o', 'h', 'y', 'j', 'c', 'w', 'f', 'v', 'z', 'x', 'q']),
|
||||
('Turkish', ['a', 'e', 'i', 'n', 'r', 'l', 'ı', 'k', 'd', 't', 's', 'm', 'y', 'u', 'o', 'b', 'ü', 'ş', 'v', 'g', 'z', 'h', 'c', 'p', 'ç', 'ğ']),
|
||||
('Romanian', ['e', 'i', 'a', 'r', 'n', 't', 'u', 'l', 'o', 'c', 's', 'd', 'p', 'm', 'ă', 'f', 'v', 'î', 'g', 'b', 'ș', 'ț', 'z', 'h', 'â', 'j']),
|
||||
('Farsi', ['ا', 'ی', 'ر', 'د', 'ن', 'ه', 'و', 'م', 'ت', 'ب', 'س', 'ل', 'ک', 'ش', 'ز', 'ف', 'گ', 'ع', 'خ', 'ق', 'ج', 'آ', 'پ', 'ح', 'ط', 'ص']),
|
||||
('Arabic', ['ا', 'ل', 'ي', 'م', 'و', 'ن', 'ر', 'ت', 'ب', 'ة', 'ع', 'د', 'س', 'ف', 'ه', 'ك', 'ق', 'أ', 'ح', 'ج', 'ش', 'ط', 'ص', 'ى', 'خ', 'إ']),
|
||||
('Danish', ['e', 'r', 'n', 't', 'a', 'i', 's', 'd', 'l', 'o', 'g', 'm', 'k', 'f', 'v', 'u', 'b', 'h', 'p', 'å', 'y', 'ø', 'æ', 'c', 'j', 'w']),
|
||||
('Serbian', ['а', 'и', 'о', 'е', 'н', 'р', 'с', 'у', 'т', 'к', 'ј', 'в', 'д', 'м', 'п', 'л', 'г', 'з', 'б', 'a', 'i', 'e', 'o', 'n', 'ц', 'ш']),
|
||||
('Lithuanian', ['i', 'a', 's', 'o', 'r', 'e', 't', 'n', 'u', 'k', 'm', 'l', 'p', 'v', 'd', 'j', 'g', 'ė', 'b', 'y', 'ų', 'š', 'ž', 'c', 'ą', 'į']),
|
||||
('Slovene', ['e', 'a', 'i', 'o', 'n', 'r', 's', 'l', 't', 'j', 'v', 'k', 'd', 'p', 'm', 'u', 'z', 'b', 'g', 'h', 'č', 'c', 'š', 'ž', 'f', 'y']),
|
||||
('Slovak', ['o', 'a', 'e', 'n', 'i', 'r', 'v', 't', 's', 'l', 'k', 'd', 'm', 'p', 'u', 'c', 'h', 'j', 'b', 'z', 'á', 'y', 'ý', 'í', 'č', 'é']),
|
||||
('Hebrew', ['י', 'ו', 'ה', 'ל', 'ר', 'ב', 'ת', 'מ', 'א', 'ש', 'נ', 'ע', 'ם', 'ד', 'ק', 'ח', 'פ', 'ס', 'כ', 'ג', 'ט', 'צ', 'ן', 'ז', 'ך']),
|
||||
('Bulgarian', ['а', 'и', 'о', 'е', 'н', 'т', 'р', 'с', 'в', 'л', 'к', 'д', 'п', 'м', 'з', 'г', 'я', 'ъ', 'у', 'б', 'ч', 'ц', 'й', 'ж', 'щ', 'х']),
|
||||
('Croatian', ['a', 'i', 'o', 'e', 'n', 'r', 'j', 's', 't', 'u', 'k', 'l', 'v', 'd', 'm', 'p', 'g', 'z', 'b', 'c', 'č', 'h', 'š', 'ž', 'ć', 'f']),
|
||||
('Hindi', ['क', 'र', 'स', 'न', 'त', 'म', 'ह', 'प', 'य', 'ल', 'व', 'ज', 'द', 'ग', 'ब', 'श', 'ट', 'अ', 'ए', 'थ', 'भ', 'ड', 'च', 'ध', 'ष', 'इ']),
|
||||
('Estonian', ['a', 'i', 'e', 's', 't', 'l', 'u', 'n', 'o', 'k', 'r', 'd', 'm', 'v', 'g', 'p', 'j', 'h', 'ä', 'b', 'õ', 'ü', 'f', 'c', 'ö', 'y']),
|
||||
('Simple English', ['e', 'a', 't', 'i', 'o', 'n', 's', 'r', 'h', 'l', 'd', 'c', 'm', 'u', 'f', 'p', 'g', 'w', 'b', 'y', 'v', 'k', 'j', 'x', 'z', 'q']),
|
||||
('Thai', ['า', 'น', 'ร', 'อ', 'ก', 'เ', 'ง', 'ม', 'ย', 'ล', 'ว', 'ด', 'ท', 'ส', 'ต', 'ะ', 'ป', 'บ', 'ค', 'ห', 'แ', 'จ', 'พ', 'ช', 'ข', 'ใ']),
|
||||
('Greek', ['α', 'τ', 'ο', 'ι', 'ε', 'ν', 'ρ', 'σ', 'κ', 'η', 'π', 'ς', 'υ', 'μ', 'λ', 'ί', 'ό', 'ά', 'γ', 'έ', 'δ', 'ή', 'ω', 'χ', 'θ', 'ύ']),
|
||||
('Tamil', ['க', 'த', 'ப', 'ட', 'ர', 'ம', 'ல', 'ன', 'வ', 'ற', 'ய', 'ள', 'ச', 'ந', 'இ', 'ண', 'அ', 'ஆ', 'ழ', 'ங', 'எ', 'உ', 'ஒ', 'ஸ']),
|
||||
('Classical Chinese', ['之', '年', '為', '也', '以', '一', '人', '其', '者', '國', '有', '二', '十', '於', '曰', '三', '不', '大', '而', '子', '中', '五', '四'])]
|
||||
)
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
from codecs import IncrementalDecoder
|
||||
from functools import lru_cache
|
||||
from typing import List, Set, Optional, Tuple, Dict
|
||||
import importlib
|
||||
|
||||
from charset_normalizer.models import CoherenceMatches
|
||||
from charset_normalizer.utils import unicode_range, is_unicode_range_secondary, is_multi_byte_encoding
|
||||
from charset_normalizer.md import is_suspiciously_successive_range
|
||||
from charset_normalizer.assets import FREQUENCIES
|
||||
from collections import Counter
|
||||
|
||||
|
||||
def encoding_unicode_range(iana_name: str) -> List[str]:
|
||||
"""
|
||||
Return associated unicode ranges in a single byte code page.
|
||||
"""
|
||||
if is_multi_byte_encoding(iana_name):
|
||||
raise IOError("Function not supported on multi-byte code page")
|
||||
|
||||
decoder = importlib.import_module('encodings.{}'.format(iana_name)).IncrementalDecoder # type: ignore
|
||||
|
||||
p = decoder(errors="ignore") # type: IncrementalDecoder
|
||||
seen_ranges = set() # type: Set[str]
|
||||
|
||||
for i in range(48, 255):
|
||||
chunk = p.decode(
|
||||
bytes([i])
|
||||
) # type: str
|
||||
|
||||
if chunk:
|
||||
character_range = unicode_range(chunk) # type: Optional[str]
|
||||
|
||||
if character_range is None:
|
||||
continue
|
||||
|
||||
if is_unicode_range_secondary(character_range) is False:
|
||||
seen_ranges.add(character_range)
|
||||
|
||||
return sorted(list(seen_ranges))
|
||||
|
||||
|
||||
def unicode_range_languages(primary_range: str) -> List[str]:
|
||||
"""
|
||||
Return inferred languages used with a unicode range.
|
||||
"""
|
||||
languages = [] # type: List[str]
|
||||
|
||||
for language, characters in FREQUENCIES.items():
|
||||
for character in characters:
|
||||
if unicode_range(character) == primary_range:
|
||||
languages.append(language)
|
||||
break
|
||||
|
||||
return languages
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def encoding_languages(iana_name: str) -> List[str]:
|
||||
"""
|
||||
Single-byte encoding language association. Some code page are heavily linked to particular language(s).
|
||||
This function does the correspondence.
|
||||
"""
|
||||
unicode_ranges = encoding_unicode_range(iana_name) # type: List[str]
|
||||
primary_range = None # type: Optional[str]
|
||||
|
||||
for specified_range in unicode_ranges:
|
||||
if "Latin" not in specified_range:
|
||||
primary_range = specified_range
|
||||
break
|
||||
|
||||
if primary_range is None:
|
||||
return ["Latin Based"]
|
||||
|
||||
return unicode_range_languages(primary_range)
|
||||
|
||||
|
||||
def mb_encoding_languages(iana_name: str) -> List[str]:
|
||||
"""
|
||||
Multi-byte encoding language association. Some code page are heavily linked to particular language(s).
|
||||
This function does the correspondence.
|
||||
"""
|
||||
if iana_name.startswith("shift_") or iana_name.startswith("iso2022_jp") or iana_name.startswith("euc_j") or iana_name in {"cp932"}:
|
||||
return ["Japanese"]
|
||||
if iana_name.startswith("gb") or iana_name in {"big5", "cp950", "big5hkscs"}:
|
||||
return ["Chinese", "Classical Chinese"]
|
||||
if iana_name.startswith("iso2022_kr") or iana_name in {"johab", "cp949", "euc_kr"}:
|
||||
return ["Korean"]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def alphabet_languages(characters: List[str]) -> List[str]:
|
||||
"""
|
||||
Return associated languages associated to given characters.
|
||||
"""
|
||||
languages = [] # type: List[str]
|
||||
|
||||
for language, language_characters in FREQUENCIES.items():
|
||||
character_match_count = 0 # type: int
|
||||
character_count = len(language_characters) # type: int
|
||||
|
||||
for character in language_characters:
|
||||
if character in characters:
|
||||
character_match_count += 1
|
||||
|
||||
if character_match_count / character_count >= 0.2:
|
||||
languages.append(language)
|
||||
|
||||
return languages
|
||||
|
||||
|
||||
def characters_popularity_compare(language: str, ordered_characters: List[str]) -> float:
|
||||
"""
|
||||
Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language.
|
||||
The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit).
|
||||
Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.)
|
||||
"""
|
||||
if language not in FREQUENCIES:
|
||||
raise ValueError("{} not available".format(language))
|
||||
|
||||
character_approved_count = 0 # type: int
|
||||
|
||||
for character in ordered_characters:
|
||||
if character not in FREQUENCIES[language]:
|
||||
continue
|
||||
|
||||
characters_before_source = FREQUENCIES[language][0:FREQUENCIES[language].index(character)] # type: List[str]
|
||||
characters_after_source = FREQUENCIES[language][FREQUENCIES[language].index(character):] # type: List[str]
|
||||
|
||||
characters_before = ordered_characters[0:ordered_characters.index(character)] # type: List[str]
|
||||
characters_after = ordered_characters[ordered_characters.index(character):] # type: List[str]
|
||||
|
||||
before_match_count = [e in characters_before for e in characters_before_source].count(True) # type: int
|
||||
after_match_count = [e in characters_after for e in characters_after_source].count(True) # type: int
|
||||
|
||||
if len(characters_before_source) == 0 and before_match_count <= 4:
|
||||
character_approved_count += 1
|
||||
continue
|
||||
|
||||
if len(characters_after_source) == 0 and after_match_count <= 4:
|
||||
character_approved_count += 1
|
||||
continue
|
||||
|
||||
if before_match_count / len(characters_before_source) >= 0.4 or after_match_count / len(characters_after_source) >= 0.4:
|
||||
character_approved_count += 1
|
||||
continue
|
||||
|
||||
return character_approved_count / len(ordered_characters)
|
||||
|
||||
|
||||
def alpha_unicode_split(decoded_sequence: str) -> List[str]:
|
||||
"""
|
||||
Given a decoded text sequence, return a list of str. Unicode range / alphabet separation.
|
||||
Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list;
|
||||
One containing the latin letters and the other hebrew.
|
||||
"""
|
||||
layers = {} # type: Dict[str, str]
|
||||
|
||||
for character in decoded_sequence:
|
||||
if character.isalpha() is False:
|
||||
continue
|
||||
|
||||
character_range = unicode_range(character) # type: str
|
||||
|
||||
layer_target_range = None # type: Optional[str]
|
||||
|
||||
for discovered_range in layers:
|
||||
if is_suspiciously_successive_range(discovered_range, character_range) is False:
|
||||
layer_target_range = discovered_range
|
||||
break
|
||||
|
||||
if layer_target_range is None:
|
||||
layer_target_range = character_range
|
||||
|
||||
if layer_target_range not in layers:
|
||||
layers[layer_target_range] = character.lower()
|
||||
continue
|
||||
|
||||
layers[layer_target_range] += character.lower()
|
||||
|
||||
return list(layers.values())
|
||||
|
||||
|
||||
def merge_coherence_ratios(results: List[CoherenceMatches]) -> CoherenceMatches:
|
||||
"""
|
||||
This function merge results previously given by the function coherence_ratio.
|
||||
The return type is the same as coherence_ratio.
|
||||
"""
|
||||
per_language_ratios = {} # type: Dict[str, List[float]]
|
||||
merge = [] # type: CoherenceMatches
|
||||
|
||||
for result in results:
|
||||
for sub_result in result:
|
||||
language, ratio = sub_result
|
||||
if language not in per_language_ratios:
|
||||
per_language_ratios[language] = [ratio]
|
||||
continue
|
||||
per_language_ratios[language].append(
|
||||
ratio
|
||||
)
|
||||
|
||||
for language in per_language_ratios:
|
||||
merge.append(
|
||||
(
|
||||
language,
|
||||
round(
|
||||
sum(
|
||||
per_language_ratios[language]
|
||||
) / len(per_language_ratios[language]),
|
||||
4
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return sorted(merge, key=lambda x: x[1], reverse=True)
|
||||
|
||||
|
||||
@lru_cache(maxsize=2048)
|
||||
def coherence_ratio(decoded_sequence: str, threshold: float = 0.1, lg_inclusion: Optional[str] = None) -> CoherenceMatches:
|
||||
"""
|
||||
Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers.
|
||||
A layer = Character extraction by alphabets/ranges.
|
||||
"""
|
||||
|
||||
results = [] # type: List[Tuple[str, float]]
|
||||
|
||||
sufficient_match_count = 0 # type: int
|
||||
|
||||
if lg_inclusion is not None:
|
||||
lg_inclusion = lg_inclusion.split(",")
|
||||
|
||||
if lg_inclusion is not None and "Latin Based" in lg_inclusion:
|
||||
lg_inclusion.remove("Latin Based")
|
||||
|
||||
for layer in alpha_unicode_split(decoded_sequence):
|
||||
sequence_frequencies = Counter(layer) # type: Counter
|
||||
most_common = sequence_frequencies.most_common()
|
||||
|
||||
character_count = sum([o for c, o in most_common]) # type: int
|
||||
|
||||
if character_count <= 32:
|
||||
continue
|
||||
|
||||
popular_character_ordered = [c for c, o in most_common] # type: List[str]
|
||||
|
||||
for language in lg_inclusion or alphabet_languages(popular_character_ordered):
|
||||
ratio = characters_popularity_compare(language, popular_character_ordered) # type: float
|
||||
|
||||
if ratio < threshold:
|
||||
continue
|
||||
elif ratio >= 0.8:
|
||||
sufficient_match_count += 1
|
||||
|
||||
results.append(
|
||||
(language, round(ratio, 4))
|
||||
)
|
||||
|
||||
if sufficient_match_count >= 3:
|
||||
break
|
||||
|
||||
return sorted(results, key=lambda x: x[1], reverse=True)
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
import argparse
|
||||
import sys
|
||||
from os.path import abspath
|
||||
from json import dumps
|
||||
|
||||
from charset_normalizer import from_fp
|
||||
from charset_normalizer.models import CliDetectionResult
|
||||
from charset_normalizer.version import __version__
|
||||
|
||||
from platform import python_version
|
||||
|
||||
|
||||
def query_yes_no(question, default="yes"):
|
||||
"""Ask a yes/no question via input() and return their answer.
|
||||
|
||||
"question" is a string that is presented to the user.
|
||||
"default" is the presumed answer if the user just hits <Enter>.
|
||||
It must be "yes" (the default), "no" or None (meaning
|
||||
an answer is required of the user).
|
||||
|
||||
The "answer" return value is True for "yes" or False for "no".
|
||||
|
||||
Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input
|
||||
"""
|
||||
valid = {"yes": True, "y": True, "ye": True,
|
||||
"no": False, "n": False}
|
||||
if default is None:
|
||||
prompt = " [y/n] "
|
||||
elif default == "yes":
|
||||
prompt = " [Y/n] "
|
||||
elif default == "no":
|
||||
prompt = " [y/N] "
|
||||
else:
|
||||
raise ValueError("invalid default answer: '%s'" % default)
|
||||
|
||||
while True:
|
||||
sys.stdout.write(question + prompt)
|
||||
choice = input().lower()
|
||||
if default is not None and choice == '':
|
||||
return valid[default]
|
||||
elif choice in valid:
|
||||
return valid[choice]
|
||||
else:
|
||||
sys.stdout.write("Please respond with 'yes' or 'no' "
|
||||
"(or 'y' or 'n').\n")
|
||||
|
||||
|
||||
def cli_detect(argv=None):
|
||||
"""
|
||||
CLI assistant using ARGV and ArgumentParser
|
||||
:param argv:
|
||||
:return: 0 if everything is fine, anything else equal trouble
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="The Real First Universal Charset Detector. "
|
||||
"Discover originating encoding used on text file. "
|
||||
"Normalize text to unicode."
|
||||
)
|
||||
|
||||
parser.add_argument('files', type=argparse.FileType('rb'), nargs='+', help='File(s) to be analysed')
|
||||
parser.add_argument('-v', '--verbose', action="store_true", default=False, dest='verbose',
|
||||
help='Display complementary information about file if any. Stdout will contain logs about the detection process.')
|
||||
parser.add_argument('-a', '--with-alternative', action="store_true", default=False, dest='alternatives',
|
||||
help='Output complementary possibilities if any. Top-level JSON WILL be a list.')
|
||||
parser.add_argument('-n', '--normalize', action="store_true", default=False, dest='normalize',
|
||||
help='Permit to normalize input file. If not set, program does not write anything.')
|
||||
parser.add_argument('-m', '--minimal', action="store_true", default=False, dest='minimal',
|
||||
help='Only output the charset detected to STDOUT. Disabling JSON output.')
|
||||
parser.add_argument('-r', '--replace', action="store_true", default=False, dest='replace',
|
||||
help='Replace file when trying to normalize it instead of creating a new one.')
|
||||
parser.add_argument('-f', '--force', action="store_true", default=False, dest='force',
|
||||
help='Replace file without asking if you are sure, use this flag with caution.')
|
||||
parser.add_argument('-t', '--threshold', action="store", default=0.1, type=float, dest='threshold',
|
||||
help="Define a custom maximum amount of chaos allowed in decoded content. 0. <= chaos <= 1.")
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
version="Charset-Normalizer {} - Python {}".format(__version__, python_version()),
|
||||
help="Show version information and exit."
|
||||
)
|
||||
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.replace is True and args.normalize is False:
|
||||
print('Use --replace in addition of --normalize only.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.force is True and args.replace is False:
|
||||
print('Use --force in addition of --replace only.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if args.threshold < 0. or args.threshold > 1.:
|
||||
print('--threshold VALUE should be between 0. AND 1.', file=sys.stderr)
|
||||
return 1
|
||||
|
||||
for my_file in args.files:
|
||||
|
||||
matches = from_fp(
|
||||
my_file,
|
||||
threshold=args.threshold,
|
||||
explain=args.verbose
|
||||
)
|
||||
|
||||
if len(matches) == 0:
|
||||
print('Unable to identify originating encoding for "{}". {}'.format(my_file.name, 'Maybe try increasing maximum amount of chaos.' if args.threshold < 1. else ''), file=sys.stderr)
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
continue
|
||||
|
||||
x_ = []
|
||||
|
||||
r_ = matches.best()
|
||||
p_ = r_.first()
|
||||
|
||||
x_.append(
|
||||
CliDetectionResult(
|
||||
abspath(my_file.name),
|
||||
p_.encoding,
|
||||
p_.encoding_aliases,
|
||||
[cp for cp in p_.could_be_from_charset if cp != p_.encoding],
|
||||
p_.language,
|
||||
p_.alphabets,
|
||||
p_.bom,
|
||||
p_.percent_chaos,
|
||||
p_.percent_coherence,
|
||||
None,
|
||||
True
|
||||
)
|
||||
)
|
||||
|
||||
if len(matches) > 1 and args.alternatives:
|
||||
for el in matches:
|
||||
if el != p_:
|
||||
x_.append(
|
||||
CliDetectionResult(
|
||||
abspath(my_file.name),
|
||||
el.encoding,
|
||||
el.encoding_aliases,
|
||||
[cp for cp in el.could_be_from_charset if cp != el.encoding],
|
||||
el.language,
|
||||
el.alphabets,
|
||||
el.bom,
|
||||
el.percent_chaos,
|
||||
el.percent_coherence,
|
||||
None,
|
||||
False
|
||||
)
|
||||
)
|
||||
|
||||
if args.normalize is True:
|
||||
|
||||
if p_.encoding.startswith('utf') is True:
|
||||
print('"{}" file does not need to be normalized, as it already came from unicode.'.format(my_file.name), file=sys.stderr)
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
continue
|
||||
|
||||
o_ = my_file.name.split('.') # type: list[str]
|
||||
|
||||
if args.replace is False:
|
||||
o_.insert(-1, p_.encoding)
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
else:
|
||||
if args.force is False and query_yes_no(
|
||||
'Are you sure to normalize "{}" by replacing it ?'.format(my_file.name), 'no') is False:
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
continue
|
||||
|
||||
try:
|
||||
x_[0].unicode_path = './{}'.format('.'.join(o_))
|
||||
|
||||
with open(x_[0].unicode_path, 'w', encoding='utf-8') as fp:
|
||||
fp.write(
|
||||
str(p_)
|
||||
)
|
||||
except IOError as e:
|
||||
print(str(e), file=sys.stderr)
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
return 2
|
||||
|
||||
if my_file.closed is False:
|
||||
my_file.close()
|
||||
|
||||
if args.minimal is False:
|
||||
print(
|
||||
dumps(
|
||||
[
|
||||
el.__dict__ for el in x_
|
||||
] if args.alternatives else x_[0].__dict__,
|
||||
ensure_ascii=True,
|
||||
indent=4
|
||||
)
|
||||
)
|
||||
else:
|
||||
print(
|
||||
', '.join(
|
||||
[
|
||||
el.encoding for el in x_
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli_detect()
|
||||
+343
File diff suppressed because one or more lines are too long
+38
@@ -0,0 +1,38 @@
|
||||
from charset_normalizer.api import from_bytes
|
||||
from charset_normalizer.constant import CHARDET_CORRESPONDENCE
|
||||
from typing import Dict, Optional, Union
|
||||
|
||||
|
||||
def detect(byte_str: bytes) -> Dict[str, Optional[Union[str, float]]]:
|
||||
"""
|
||||
chardet legacy method
|
||||
Detect the encoding of the given byte string. It should be mostly backward-compatible.
|
||||
Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it)
|
||||
This function is deprecated and should be used to migrate your project easily, consult the documentation for
|
||||
further information. Not planned for removal.
|
||||
|
||||
:param byte_str: The byte sequence to examine.
|
||||
"""
|
||||
if not isinstance(byte_str, (bytearray, bytes)):
|
||||
raise TypeError('Expected object of type bytes or bytearray, got: '
|
||||
'{0}'.format(type(byte_str)))
|
||||
|
||||
if isinstance(byte_str, bytearray):
|
||||
byte_str = bytes(byte_str)
|
||||
|
||||
r = from_bytes(byte_str).best()
|
||||
|
||||
encoding = r.encoding if r is not None else None
|
||||
language = r.language if r is not None and r.language != 'Unknown' else ''
|
||||
confidence = 1. - r.chaos if r is not None else None
|
||||
|
||||
# Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process
|
||||
# but chardet does return 'utf-8-sig' and it is a valid codec name.
|
||||
if r is not None and encoding == 'utf_8' and r.bom:
|
||||
encoding += '_sig'
|
||||
|
||||
return {
|
||||
'encoding': encoding if encoding not in CHARDET_CORRESPONDENCE else CHARDET_CORRESPONDENCE[encoding],
|
||||
'language': language,
|
||||
'confidence': confidence
|
||||
}
|
||||
+451
@@ -0,0 +1,451 @@
|
||||
from functools import lru_cache
|
||||
from typing import Optional, List
|
||||
|
||||
from charset_normalizer.constant import UNICODE_SECONDARY_RANGE_KEYWORD
|
||||
from charset_normalizer.utils import is_punctuation, is_symbol, unicode_range, is_accentuated, is_latin, \
|
||||
remove_accent, is_separator, is_cjk
|
||||
|
||||
|
||||
class MessDetectorPlugin:
|
||||
"""
|
||||
Base abstract class used for mess detection plugins.
|
||||
All detectors MUST extend and implement given methods.
|
||||
"""
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
"""
|
||||
Determine if given character should be fed in.
|
||||
"""
|
||||
raise NotImplementedError # pragma: nocover
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
"""
|
||||
The main routine to be executed upon character.
|
||||
Insert the logic in witch the text would be considered chaotic.
|
||||
"""
|
||||
raise NotImplementedError # pragma: nocover
|
||||
|
||||
def reset(self) -> None:
|
||||
"""
|
||||
Permit to reset the plugin to the initial state.
|
||||
"""
|
||||
raise NotImplementedError # pragma: nocover
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
"""
|
||||
Compute the chaos ratio based on what your feed() has seen.
|
||||
Must NOT be lower than 0.; No restriction gt 0.
|
||||
"""
|
||||
raise NotImplementedError # pragma: nocover
|
||||
|
||||
|
||||
class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._punctuation_count = 0 # type: int
|
||||
self._symbol_count = 0 # type: int
|
||||
self._character_count = 0 # type: int
|
||||
|
||||
self._last_printable_char = None # type: Optional[str]
|
||||
self._frenzy_symbol_in_word = False # type: bool
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return character.isprintable()
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
self._character_count += 1
|
||||
|
||||
if character != self._last_printable_char and character not in ["<", ">", "=", ":", "/", "&", ";", "{", "}", "[", "]"]:
|
||||
if is_punctuation(character):
|
||||
self._punctuation_count += 1
|
||||
elif character.isdigit() is False and is_symbol(character):
|
||||
self._symbol_count += 2
|
||||
|
||||
self._last_printable_char = character
|
||||
|
||||
def reset(self) -> None:
|
||||
self._punctuation_count = 0
|
||||
self._character_count = 0
|
||||
self._symbol_count = 0
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
|
||||
ratio_of_punctuation = (self._punctuation_count + self._symbol_count) / self._character_count # type: float
|
||||
|
||||
return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.
|
||||
|
||||
|
||||
class TooManyAccentuatedPlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._character_count = 0 # type: int
|
||||
self._accentuated_count = 0 # type: int
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return character.isalpha()
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
self._character_count += 1
|
||||
|
||||
if is_accentuated(character):
|
||||
self._accentuated_count += 1
|
||||
|
||||
def reset(self) -> None:
|
||||
self._character_count = 0
|
||||
self._accentuated_count = 0
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
ratio_of_accentuation = self._accentuated_count / self._character_count # type: float
|
||||
return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.
|
||||
|
||||
|
||||
class UnprintablePlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._unprintable_count = 0 # type: int
|
||||
self._character_count = 0 # type: int
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return True
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
if character not in {'\n', '\t', '\r'} and character.isprintable() is False:
|
||||
self._unprintable_count += 1
|
||||
self._character_count += 1
|
||||
|
||||
def reset(self) -> None:
|
||||
self._unprintable_count = 0
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
|
||||
return (self._unprintable_count * 8) / self._character_count
|
||||
|
||||
|
||||
class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._successive_count = 0 # type: int
|
||||
self._character_count = 0 # type: int
|
||||
|
||||
self._last_latin_character = None # type: Optional[str]
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return is_latin(character)
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
if self._last_latin_character is not None:
|
||||
if is_accentuated(character) and is_accentuated(self._last_latin_character):
|
||||
if remove_accent(character) == remove_accent(self._last_latin_character):
|
||||
self._successive_count += 1
|
||||
self._last_latin_character = character
|
||||
|
||||
def reset(self) -> None:
|
||||
self._successive_count = 0
|
||||
self._character_count = 0
|
||||
self._last_latin_character = None
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
|
||||
return (self._successive_count * 2) / self._character_count
|
||||
|
||||
|
||||
class SuspiciousRange(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._suspicious_successive_range_count = 0 # type: int
|
||||
self._character_count = 0 # type: int
|
||||
self._last_printable_seen = None # type: Optional[str]
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return character.isprintable()
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
self._character_count += 1
|
||||
|
||||
if self._last_printable_seen is None:
|
||||
self._last_printable_seen = character
|
||||
return
|
||||
|
||||
if character.isspace() or is_punctuation(character):
|
||||
self._last_printable_seen = None
|
||||
return
|
||||
|
||||
unicode_range_a = unicode_range(self._last_printable_seen) # type: Optional[str]
|
||||
unicode_range_b = unicode_range(character) # type: Optional[str]
|
||||
|
||||
if is_suspiciously_successive_range(unicode_range_a, unicode_range_b):
|
||||
self._suspicious_successive_range_count += 1
|
||||
|
||||
self._last_printable_seen = character
|
||||
|
||||
def reset(self) -> None:
|
||||
self._character_count = 0
|
||||
self._suspicious_successive_range_count = 0
|
||||
self._last_printable_seen = None
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
|
||||
ratio_of_suspicious_range_usage = (self._suspicious_successive_range_count * 2) / self._character_count # type: float
|
||||
|
||||
if ratio_of_suspicious_range_usage < 0.1:
|
||||
return 0.
|
||||
|
||||
return ratio_of_suspicious_range_usage
|
||||
|
||||
|
||||
class SuperWeirdWordPlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._word_count = 0 # type: int
|
||||
self._bad_word_count = 0 # type: int
|
||||
self._is_current_word_bad = False # type: bool
|
||||
|
||||
self._character_count = 0 # type: int
|
||||
self._bad_character_count = 0 # type: int
|
||||
|
||||
self._buffer = "" # type: str
|
||||
self._buffer_accent_count = 0 # type: int
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return True
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
if character.isalpha():
|
||||
self._buffer = "".join([self._buffer, character])
|
||||
if is_accentuated(character):
|
||||
self._buffer_accent_count += 1
|
||||
return
|
||||
if not self._buffer:
|
||||
return
|
||||
if (character.isspace() or is_punctuation(character) or is_separator(character)) and self._buffer:
|
||||
self._word_count += 1
|
||||
buffer_length = len(self._buffer) # type: int
|
||||
|
||||
self._character_count += buffer_length
|
||||
|
||||
if buffer_length >= 4 and self._buffer_accent_count / buffer_length >= 0.3:
|
||||
self._is_current_word_bad = True
|
||||
|
||||
if self._is_current_word_bad:
|
||||
self._bad_word_count += 1
|
||||
self._bad_character_count += len(self._buffer)
|
||||
self._is_current_word_bad = False
|
||||
|
||||
self._buffer = ""
|
||||
self._buffer_accent_count = 0
|
||||
elif character not in {"<", ">", "-", "="} and character.isdigit() is False and is_symbol(character):
|
||||
self._is_current_word_bad = True
|
||||
self._buffer += character
|
||||
|
||||
def reset(self) -> None:
|
||||
self._buffer = ""
|
||||
self._is_current_word_bad = False
|
||||
self._bad_word_count = 0
|
||||
self._word_count = 0
|
||||
self._character_count = 0
|
||||
self._bad_character_count = 0
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._word_count <= 16:
|
||||
return 0.
|
||||
|
||||
return self._bad_character_count / self._character_count
|
||||
|
||||
|
||||
class CjkInvalidStopPlugin(MessDetectorPlugin):
|
||||
"""
|
||||
GB(Chinese) based encoding often render the stop incorrectly when the content does not fit and can be easily detected.
|
||||
Searching for the overuse of '丅' and '丄'.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._wrong_stop_count = 0 # type: int
|
||||
self._cjk_character_count = 0 # type: int
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return True
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
if character in ["丅", "丄"]:
|
||||
self._wrong_stop_count += 1
|
||||
return
|
||||
if is_cjk(character):
|
||||
self._cjk_character_count += 1
|
||||
|
||||
def reset(self) -> None:
|
||||
self._wrong_stop_count = 0
|
||||
self._cjk_character_count = 0
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._cjk_character_count < 16:
|
||||
return 0.
|
||||
return self._wrong_stop_count / self._cjk_character_count
|
||||
|
||||
|
||||
class ArchaicUpperLowerPlugin(MessDetectorPlugin):
|
||||
|
||||
def __init__(self):
|
||||
self._buf = False # type: bool
|
||||
|
||||
self._character_count_since_last_sep = 0 # type: int
|
||||
|
||||
self._successive_upper_lower_count = 0 # type: int
|
||||
self._successive_upper_lower_count_final = 0 # type: int
|
||||
|
||||
self._character_count = 0 # type: int
|
||||
|
||||
self._last_alpha_seen = None # type: Optional[str]
|
||||
|
||||
def eligible(self, character: str) -> bool:
|
||||
return character.isspace() or character.isalpha()
|
||||
|
||||
def feed(self, character: str) -> None:
|
||||
if is_separator(character):
|
||||
if self._character_count_since_last_sep < 24:
|
||||
self._successive_upper_lower_count_final += self._successive_upper_lower_count
|
||||
self._successive_upper_lower_count = 0
|
||||
self._character_count_since_last_sep = 0
|
||||
|
||||
if self._last_alpha_seen is not None:
|
||||
if (character.isupper() and self._last_alpha_seen.islower()) or (character.islower() and self._last_alpha_seen.isupper()):
|
||||
if self._buf is True:
|
||||
self._successive_upper_lower_count += 1
|
||||
else:
|
||||
self._buf = True
|
||||
else:
|
||||
self._buf = False
|
||||
|
||||
self._character_count += 1
|
||||
self._last_alpha_seen = character
|
||||
|
||||
def reset(self) -> None:
|
||||
self._character_count = 0
|
||||
self._character_count_since_last_sep = 0
|
||||
self._successive_upper_lower_count = 0
|
||||
self._successive_upper_lower_count_final = 0
|
||||
self._last_alpha_seen = None
|
||||
|
||||
@property
|
||||
def ratio(self) -> float:
|
||||
if self._character_count == 0:
|
||||
return 0.
|
||||
|
||||
return (self._successive_upper_lower_count_final * 2) / self._character_count
|
||||
|
||||
|
||||
def is_suspiciously_successive_range(unicode_range_a: Optional[str], unicode_range_b: Optional[str]) -> bool:
|
||||
"""
|
||||
Determine if two Unicode range seen next to each other can be considered as suspicious.
|
||||
"""
|
||||
if unicode_range_a is None or unicode_range_b is None:
|
||||
return True
|
||||
|
||||
if unicode_range_a == unicode_range_b:
|
||||
return False
|
||||
|
||||
if "Latin" in unicode_range_a and "Latin" in unicode_range_b:
|
||||
return False
|
||||
|
||||
if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b:
|
||||
return False
|
||||
|
||||
keywords_range_a, keywords_range_b = unicode_range_a.split(" "), unicode_range_b.split(" ")
|
||||
|
||||
for el in keywords_range_a:
|
||||
if el in UNICODE_SECONDARY_RANGE_KEYWORD:
|
||||
continue
|
||||
if el in keywords_range_b:
|
||||
return False
|
||||
|
||||
# Japanese Exception
|
||||
if unicode_range_a in ['Katakana', 'Hiragana'] and unicode_range_b in ['Katakana', 'Hiragana']:
|
||||
return False
|
||||
|
||||
if unicode_range_a in ['Katakana', 'Hiragana'] or unicode_range_b in ['Katakana', 'Hiragana']:
|
||||
if "CJK" in unicode_range_a or "CJK" in unicode_range_b:
|
||||
return False
|
||||
|
||||
if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b:
|
||||
if "CJK" in unicode_range_a or "CJK" in unicode_range_b:
|
||||
return False
|
||||
if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin":
|
||||
return False
|
||||
|
||||
# Chinese/Japanese use dedicated range for punctuation and/or separators.
|
||||
if ('CJK' in unicode_range_a or 'CJK' in unicode_range_b) or (unicode_range_a in ['Katakana', 'Hiragana'] and unicode_range_b in ['Katakana', 'Hiragana']):
|
||||
if 'Punctuation' in unicode_range_a or 'Punctuation' in unicode_range_b:
|
||||
return False
|
||||
if 'Forms' in unicode_range_a or 'Forms' in unicode_range_b:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@lru_cache(maxsize=2048)
|
||||
def mess_ratio(decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False) -> float:
|
||||
"""
|
||||
Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier.
|
||||
"""
|
||||
detectors = [] # type: List[MessDetectorPlugin]
|
||||
|
||||
for md_class in MessDetectorPlugin.__subclasses__():
|
||||
detectors.append(
|
||||
md_class()
|
||||
)
|
||||
|
||||
length = len(decoded_sequence) # type: int
|
||||
|
||||
mean_mess_ratio = 0. # type: float
|
||||
|
||||
if length < 512:
|
||||
intermediary_mean_mess_ratio_calc = 32 # type: int
|
||||
elif length <= 1024:
|
||||
intermediary_mean_mess_ratio_calc = 64
|
||||
else:
|
||||
intermediary_mean_mess_ratio_calc = 128
|
||||
|
||||
for character, index in zip(decoded_sequence, range(0, length)):
|
||||
for detector in detectors:
|
||||
if detector.eligible(character):
|
||||
detector.feed(character)
|
||||
|
||||
if (index > 0 and index % intermediary_mean_mess_ratio_calc == 0) or index == length-1:
|
||||
mean_mess_ratio = sum(
|
||||
[
|
||||
dt.ratio for dt in detectors
|
||||
]
|
||||
)
|
||||
|
||||
if mean_mess_ratio >= maximum_threshold:
|
||||
break
|
||||
|
||||
if debug:
|
||||
for dt in detectors: # pragma: nocover
|
||||
print(
|
||||
dt.__class__,
|
||||
dt.ratio
|
||||
)
|
||||
|
||||
return round(
|
||||
mean_mess_ratio,
|
||||
3
|
||||
)
|
||||
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
import warnings
|
||||
from encodings.aliases import aliases
|
||||
from hashlib import sha256
|
||||
from json import dumps
|
||||
from typing import Optional, List, Tuple, Set
|
||||
from collections import Counter
|
||||
from re import sub, compile as re_compile
|
||||
|
||||
from charset_normalizer.constant import TOO_BIG_SEQUENCE
|
||||
from charset_normalizer.md import mess_ratio
|
||||
from charset_normalizer.utils import iana_name, is_multi_byte_encoding, unicode_range
|
||||
|
||||
|
||||
class CharsetMatch:
|
||||
def __init__(
|
||||
self,
|
||||
payload: bytes,
|
||||
guessed_encoding: str,
|
||||
mean_mess_ratio: float,
|
||||
has_sig_or_bom: bool,
|
||||
languages: "CoherenceMatches",
|
||||
decoded_payload: Optional[str] = None
|
||||
):
|
||||
self._payload = payload # type: bytes
|
||||
|
||||
self._encoding = guessed_encoding # type: str
|
||||
self._mean_mess_ratio = mean_mess_ratio # type: float
|
||||
self._languages = languages # type: CoherenceMatches
|
||||
self._has_sig_or_bom = has_sig_or_bom # type: bool
|
||||
self._unicode_ranges = None # type: Optional[List[str]]
|
||||
|
||||
self._leaves = [] # type: List[CharsetMatch]
|
||||
self._mean_coherence_ratio = 0. # type: float
|
||||
|
||||
self._output_payload = None # type: Optional[bytes]
|
||||
self._output_encoding = None # type: Optional[str]
|
||||
|
||||
self._string = decoded_payload # type: Optional[str]
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if not isinstance(other, CharsetMatch):
|
||||
raise TypeError('__eq__ cannot be invoked on {} and {}.'.format(str(other.__class__), str(self.__class__)))
|
||||
return self.encoding == other.encoding and self.fingerprint == other.fingerprint
|
||||
|
||||
def __lt__(self, other) -> bool:
|
||||
"""
|
||||
Implemented to make sorted available upon CharsetMatches items.
|
||||
"""
|
||||
if not isinstance(other, CharsetMatch):
|
||||
raise ValueError
|
||||
|
||||
chaos_difference = abs(self.chaos - other.chaos) # type: float
|
||||
|
||||
# Bellow 1% difference --> Use Coherence
|
||||
if chaos_difference < 0.01:
|
||||
return self.coherence > other.coherence
|
||||
|
||||
return self.chaos < other.chaos
|
||||
|
||||
@property
|
||||
def chaos_secondary_pass(self) -> float:
|
||||
"""
|
||||
Check once again chaos in decoded text, except this time, with full content.
|
||||
Use with caution, this can be very slow.
|
||||
Notice: Will be removed in 3.0
|
||||
"""
|
||||
warnings.warn("chaos_secondary_pass is deprecated and will be removed in 3.0", DeprecationWarning)
|
||||
return mess_ratio(
|
||||
str(self),
|
||||
1.
|
||||
)
|
||||
|
||||
@property
|
||||
def coherence_non_latin(self) -> float:
|
||||
"""
|
||||
Coherence ratio on the first non-latin language detected if ANY.
|
||||
Notice: Will be removed in 3.0
|
||||
"""
|
||||
warnings.warn("coherence_non_latin is deprecated and will be removed in 3.0", DeprecationWarning)
|
||||
return 0.
|
||||
|
||||
@property
|
||||
def w_counter(self) -> Counter:
|
||||
"""
|
||||
Word counter instance on decoded text.
|
||||
Notice: Will be removed in 3.0
|
||||
"""
|
||||
warnings.warn("w_counter is deprecated and will be removed in 3.0", DeprecationWarning)
|
||||
not_printable_pattern = re_compile(r'[0-9\W\n\r\t]+')
|
||||
string_printable_only = sub(not_printable_pattern, ' ', str(self).lower())
|
||||
|
||||
return Counter(string_printable_only.split())
|
||||
|
||||
def __str__(self) -> str:
|
||||
# Lazy Str Loading
|
||||
if self._string is None:
|
||||
self._string = str(self._payload, self._encoding, "strict")
|
||||
return self._string
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "<CharsetMatch '{}' bytes({})>".format(self.encoding, self.fingerprint)
|
||||
|
||||
def add_submatch(self, other: "CharsetMatch") -> None:
|
||||
if not isinstance(other, CharsetMatch) or other == self:
|
||||
raise ValueError("Unable to add instance <{}> as a submatch of a CharsetMatch".format(other.__class__))
|
||||
|
||||
other._string = None # Unload RAM usage; dirty trick.
|
||||
self._leaves.append(other)
|
||||
|
||||
@property
|
||||
def encoding(self) -> str:
|
||||
return self._encoding
|
||||
|
||||
@property
|
||||
def encoding_aliases(self) -> List[str]:
|
||||
"""
|
||||
Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855.
|
||||
"""
|
||||
also_known_as = [] # type: List[str]
|
||||
for u, p in aliases.items():
|
||||
if self.encoding == u:
|
||||
also_known_as.append(p)
|
||||
elif self.encoding == p:
|
||||
also_known_as.append(u)
|
||||
return also_known_as
|
||||
|
||||
@property
|
||||
def bom(self) -> bool:
|
||||
return self._has_sig_or_bom
|
||||
|
||||
@property
|
||||
def byte_order_mark(self) -> bool:
|
||||
return self._has_sig_or_bom
|
||||
|
||||
@property
|
||||
def languages(self) -> List[str]:
|
||||
"""
|
||||
Return the complete list of possible languages found in decoded sequence.
|
||||
Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'.
|
||||
"""
|
||||
return [e[0] for e in self._languages]
|
||||
|
||||
@property
|
||||
def language(self) -> str:
|
||||
"""
|
||||
Most probable language found in decoded sequence. If none were detected or inferred, the property will return
|
||||
"Unknown".
|
||||
"""
|
||||
if not self._languages:
|
||||
# Trying to infer the language based on the given encoding
|
||||
# Its either English or we should not pronounce ourselves in certain cases.
|
||||
if "ascii" in self.could_be_from_charset:
|
||||
return "English"
|
||||
|
||||
# doing it there to avoid circular import
|
||||
from charset_normalizer.cd import mb_encoding_languages, encoding_languages
|
||||
|
||||
languages = mb_encoding_languages(self.encoding) if is_multi_byte_encoding(self.encoding) else encoding_languages(self.encoding)
|
||||
|
||||
if len(languages) == 0 or "Latin Based" in languages:
|
||||
return "Unknown"
|
||||
|
||||
return languages[0]
|
||||
|
||||
return self._languages[0][0]
|
||||
|
||||
@property
|
||||
def chaos(self) -> float:
|
||||
return self._mean_mess_ratio
|
||||
|
||||
@property
|
||||
def coherence(self) -> float:
|
||||
if not self._languages:
|
||||
return 0.
|
||||
return self._languages[0][1]
|
||||
|
||||
@property
|
||||
def percent_chaos(self) -> float:
|
||||
return round(self.chaos * 100, ndigits=3)
|
||||
|
||||
@property
|
||||
def percent_coherence(self) -> float:
|
||||
return round(self.coherence * 100, ndigits=3)
|
||||
|
||||
@property
|
||||
def raw(self) -> bytes:
|
||||
"""
|
||||
Original untouched bytes.
|
||||
"""
|
||||
return self._payload
|
||||
|
||||
@property
|
||||
def submatch(self) -> List["CharsetMatch"]:
|
||||
return self._leaves
|
||||
|
||||
@property
|
||||
def has_submatch(self) -> bool:
|
||||
return len(self._leaves) > 0
|
||||
|
||||
@property
|
||||
def alphabets(self) -> List[str]:
|
||||
if self._unicode_ranges is not None:
|
||||
return self._unicode_ranges
|
||||
detected_ranges = set() # type: Set[str]
|
||||
for character in str(self):
|
||||
detected_ranges.add(
|
||||
unicode_range(character)
|
||||
)
|
||||
self._unicode_ranges = sorted(list(detected_ranges))
|
||||
return self._unicode_ranges
|
||||
|
||||
@property
|
||||
def could_be_from_charset(self) -> List[str]:
|
||||
"""
|
||||
The complete list of encoding that output the exact SAME str result and therefore could be the originating
|
||||
encoding.
|
||||
This list does include the encoding available in property 'encoding'.
|
||||
"""
|
||||
return [self._encoding] + [m.encoding for m in self._leaves]
|
||||
|
||||
def first(self) -> "CharsetMatch":
|
||||
"""
|
||||
Kept for BC reasons. Will be removed in 3.0.
|
||||
"""
|
||||
return self
|
||||
|
||||
def best(self) -> "CharsetMatch":
|
||||
"""
|
||||
Kept for BC reasons. Will be removed in 3.0.
|
||||
"""
|
||||
return self
|
||||
|
||||
def output(self, encoding: str = "utf_8") -> bytes:
|
||||
"""
|
||||
Method to get re-encoded bytes payload using given target encoding. Default to UTF-8.
|
||||
Any errors will be simply ignored by the encoder NOT replaced.
|
||||
"""
|
||||
if self._output_encoding is None or self._output_encoding != encoding:
|
||||
self._output_encoding = encoding
|
||||
self._output_payload = str(self).encode(encoding, "replace")
|
||||
|
||||
return self._output_payload # type: ignore
|
||||
|
||||
@property
|
||||
def fingerprint(self) -> str:
|
||||
"""
|
||||
Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one.
|
||||
"""
|
||||
return sha256(self.output()).hexdigest()
|
||||
|
||||
|
||||
class CharsetMatches:
|
||||
"""
|
||||
Container with every CharsetMatch items ordered by default from most probable to the less one.
|
||||
Act like a list(iterable) but does not implements all related methods.
|
||||
"""
|
||||
def __init__(self, results: List[CharsetMatch] = None):
|
||||
self._results = sorted(results) if results else [] # type: List[CharsetMatch]
|
||||
|
||||
def __iter__(self):
|
||||
for result in self._results:
|
||||
yield result
|
||||
|
||||
def __getitem__(self, item) -> CharsetMatch:
|
||||
"""
|
||||
Retrieve a single item either by its position or encoding name (alias may be used here).
|
||||
Raise KeyError upon invalid index or encoding not present in results.
|
||||
"""
|
||||
if isinstance(item, int):
|
||||
return self._results[item]
|
||||
if isinstance(item, str):
|
||||
item = iana_name(item, False)
|
||||
for result in self._results:
|
||||
if item in result.could_be_from_charset:
|
||||
return result
|
||||
raise KeyError
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self._results)
|
||||
|
||||
def append(self, item: CharsetMatch) -> None:
|
||||
"""
|
||||
Insert a single match. Will be inserted accordingly to preserve sort.
|
||||
Can be inserted as a submatch.
|
||||
"""
|
||||
if not isinstance(item, CharsetMatch):
|
||||
raise ValueError("Cannot append instance '{}' to CharsetMatches".format(str(item.__class__)))
|
||||
# We should disable the submatch factoring when the input file is too heavy (conserve RAM usage)
|
||||
if len(item.raw) <= TOO_BIG_SEQUENCE:
|
||||
for match in self._results:
|
||||
if match.fingerprint == item.fingerprint:
|
||||
match.add_submatch(item)
|
||||
return
|
||||
self._results.append(item)
|
||||
self._results = sorted(self._results)
|
||||
|
||||
def best(self) -> Optional["CharsetMatch"]:
|
||||
"""
|
||||
Simply return the first match. Strict equivalent to matches[0].
|
||||
"""
|
||||
if not self._results:
|
||||
return None
|
||||
return self._results[0]
|
||||
|
||||
def first(self) -> Optional["CharsetMatch"]:
|
||||
"""
|
||||
Redundant method, call the method best(). Kept for BC reasons.
|
||||
"""
|
||||
return self.best()
|
||||
|
||||
|
||||
CoherenceMatch = Tuple[str, float]
|
||||
CoherenceMatches = List[CoherenceMatch]
|
||||
|
||||
|
||||
class CliDetectionResult:
|
||||
|
||||
def __init__(self, path: str, encoding: str, encoding_aliases: List[str], alternative_encodings: List[str], language: str, alphabets: List[str], has_sig_or_bom: bool, chaos: float, coherence: float, unicode_path: Optional[str], is_preferred: bool):
|
||||
self.path = path # type: str
|
||||
self.unicode_path = unicode_path # type: Optional[str]
|
||||
self.encoding = encoding # type: str
|
||||
self.encoding_aliases = encoding_aliases # type: List[str]
|
||||
self.alternative_encodings = alternative_encodings # type: List[str]
|
||||
self.language = language # type: str
|
||||
self.alphabets = alphabets # type: List[str]
|
||||
self.has_sig_or_bom = has_sig_or_bom # type: bool
|
||||
self.chaos = chaos # type: float
|
||||
self.coherence = coherence # type: float
|
||||
self.is_preferred = is_preferred # type: bool
|
||||
|
||||
@property
|
||||
def __dict__(self):
|
||||
return {
|
||||
'path': self.path,
|
||||
'encoding': self.encoding,
|
||||
'encoding_aliases': self.encoding_aliases,
|
||||
'alternative_encodings': self.alternative_encodings,
|
||||
'language': self.language,
|
||||
'alphabets': self.alphabets,
|
||||
'has_sig_or_bom': self.has_sig_or_bom,
|
||||
'chaos': self.chaos,
|
||||
'coherence': self.coherence,
|
||||
'unicode_path': self.unicode_path,
|
||||
'is_preferred': self.is_preferred
|
||||
}
|
||||
|
||||
def to_json(self) -> str:
|
||||
return dumps(
|
||||
self.__dict__,
|
||||
ensure_ascii=True,
|
||||
indent=4
|
||||
)
|
||||
|
||||
|
||||
CharsetNormalizerMatch = CharsetMatch
|
||||
Vendored
+248
@@ -0,0 +1,248 @@
|
||||
try:
|
||||
import unicodedata2 as unicodedata
|
||||
except ImportError:
|
||||
import unicodedata
|
||||
|
||||
from codecs import IncrementalDecoder
|
||||
from re import findall
|
||||
from typing import Optional, Tuple, Union, List, Set
|
||||
import importlib
|
||||
from _multibytecodec import MultibyteIncrementalDecoder # type: ignore
|
||||
|
||||
from encodings.aliases import aliases
|
||||
from functools import lru_cache
|
||||
|
||||
from charset_normalizer.constant import UNICODE_RANGES_COMBINED, UNICODE_SECONDARY_RANGE_KEYWORD, \
|
||||
RE_POSSIBLE_ENCODING_INDICATION, ENCODING_MARKS, UTF8_MAXIMAL_ALLOCATION, IANA_SUPPORTED_SIMILAR
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def is_accentuated(character: str) -> bool:
|
||||
try:
|
||||
description = unicodedata.name(character) # type: str
|
||||
except ValueError:
|
||||
return False
|
||||
return "WITH GRAVE" in description or "WITH ACUTE" in description or "WITH CEDILLA" in description
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def remove_accent(character: str) -> str:
|
||||
decomposed = unicodedata.decomposition(character) # type: str
|
||||
if not decomposed:
|
||||
return character
|
||||
|
||||
codes = decomposed.split(" ") # type: List[str]
|
||||
|
||||
return chr(
|
||||
int(
|
||||
codes[0],
|
||||
16
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def unicode_range(character: str) -> Optional[str]:
|
||||
"""
|
||||
Retrieve the Unicode range official name from a single character.
|
||||
"""
|
||||
character_ord = ord(character) # type: int
|
||||
|
||||
for range_name, ord_range in UNICODE_RANGES_COMBINED.items():
|
||||
if character_ord in ord_range:
|
||||
return range_name
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def is_latin(character: str) -> bool:
|
||||
try:
|
||||
description = unicodedata.name(character) # type: str
|
||||
except ValueError:
|
||||
return False
|
||||
return "LATIN" in description
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def is_punctuation(character: str) -> bool:
|
||||
character_category = unicodedata.category(character) # type: str
|
||||
|
||||
if "P" in character_category:
|
||||
return True
|
||||
|
||||
character_range = unicode_range(character) # type: Optional[str]
|
||||
|
||||
if character_range is None:
|
||||
return False
|
||||
|
||||
return "Punctuation" in character_range
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def is_symbol(character: str) -> bool:
|
||||
character_category = unicodedata.category(character) # type: str
|
||||
|
||||
if "S" in character_category or "N" in character_category:
|
||||
return True
|
||||
|
||||
character_range = unicode_range(character) # type: Optional[str]
|
||||
|
||||
if character_range is None:
|
||||
return False
|
||||
|
||||
return "Forms" in character_range
|
||||
|
||||
|
||||
@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
|
||||
def is_separator(character: str) -> bool:
|
||||
if character.isspace() or character in ["|", "+"]:
|
||||
return True
|
||||
|
||||
character_category = unicodedata.category(character) # type: str
|
||||
|
||||
return "Z" in character_category
|
||||
|
||||
|
||||
def is_private_use_only(character: str) -> bool:
|
||||
character_category = unicodedata.category(character) # type: str
|
||||
|
||||
return "Co" == character_category
|
||||
|
||||
|
||||
def is_cjk(character: str) -> bool:
|
||||
try:
|
||||
character_name = unicodedata.name(character)
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
return "CJK" in character_name
|
||||
|
||||
|
||||
@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED))
|
||||
def is_unicode_range_secondary(range_name: str) -> bool:
|
||||
for keyword in UNICODE_SECONDARY_RANGE_KEYWORD:
|
||||
if keyword in range_name:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def any_specified_encoding(sequence: bytes, search_zone: int = 4096) -> Optional[str]:
|
||||
"""
|
||||
Extract using ASCII-only decoder any specified encoding in the first n-bytes.
|
||||
"""
|
||||
if not isinstance(sequence, bytes):
|
||||
raise TypeError
|
||||
|
||||
seq_len = len(sequence) # type: int
|
||||
|
||||
results = findall(
|
||||
RE_POSSIBLE_ENCODING_INDICATION,
|
||||
sequence[:seq_len if seq_len <= search_zone else search_zone].decode('ascii', errors='ignore')
|
||||
) # type: List[str]
|
||||
|
||||
if len(results) == 0:
|
||||
return None
|
||||
|
||||
for specified_encoding in results:
|
||||
specified_encoding = specified_encoding.lower().replace('-', '_')
|
||||
|
||||
for encoding_alias, encoding_iana in aliases.items():
|
||||
if encoding_alias == specified_encoding:
|
||||
return encoding_iana
|
||||
if encoding_iana == specified_encoding:
|
||||
return encoding_iana
|
||||
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def is_multi_byte_encoding(name: str) -> bool:
|
||||
"""
|
||||
Verify is a specific encoding is a multi byte one based on it IANA name
|
||||
"""
|
||||
return name in {"utf_8", "utf_8_sig", "utf_16", "utf_16_be", "utf_16_le", "utf_32", "utf_32_le", "utf_32_be", "utf_7"} or issubclass(
|
||||
importlib.import_module('encodings.{}'.format(name)).IncrementalDecoder, # type: ignore
|
||||
MultibyteIncrementalDecoder
|
||||
)
|
||||
|
||||
|
||||
def identify_sig_or_bom(sequence: bytes) -> Tuple[Optional[str], bytes]:
|
||||
"""
|
||||
Identify and extract SIG/BOM in given sequence.
|
||||
"""
|
||||
|
||||
for iana_encoding in ENCODING_MARKS:
|
||||
marks = ENCODING_MARKS[iana_encoding] # type: Union[bytes, List[bytes]]
|
||||
|
||||
if isinstance(marks, bytes):
|
||||
marks = [marks]
|
||||
|
||||
for mark in marks:
|
||||
if sequence.startswith(mark):
|
||||
return iana_encoding, mark
|
||||
|
||||
return None, b""
|
||||
|
||||
|
||||
def should_strip_sig_or_bom(iana_encoding: str) -> bool:
|
||||
return iana_encoding not in {"utf_16", "utf_32"}
|
||||
|
||||
|
||||
def iana_name(cp_name: str, strict: bool = True) -> str:
|
||||
cp_name = cp_name.lower().replace('-', '_')
|
||||
|
||||
for encoding_alias, encoding_iana in aliases.items():
|
||||
if cp_name == encoding_alias or cp_name == encoding_iana:
|
||||
return encoding_iana
|
||||
|
||||
if strict:
|
||||
raise ValueError("Unable to retrieve IANA for '{}'".format(cp_name))
|
||||
|
||||
return cp_name
|
||||
|
||||
|
||||
def range_scan(decoded_sequence: str) -> List[str]:
|
||||
ranges = set() # type: Set[str]
|
||||
|
||||
for character in decoded_sequence:
|
||||
character_range = unicode_range(character) # type: Optional[str]
|
||||
|
||||
if character_range is None:
|
||||
continue
|
||||
|
||||
ranges.add(
|
||||
character_range
|
||||
)
|
||||
|
||||
return list(ranges)
|
||||
|
||||
|
||||
def cp_similarity(iana_name_a: str, iana_name_b: str) -> float:
|
||||
|
||||
if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b):
|
||||
return 0.
|
||||
|
||||
decoder_a = importlib.import_module('encodings.{}'.format(iana_name_a)).IncrementalDecoder # type: ignore
|
||||
decoder_b = importlib.import_module('encodings.{}'.format(iana_name_b)).IncrementalDecoder # type: ignore
|
||||
|
||||
id_a = decoder_a(errors="ignore") # type: IncrementalDecoder
|
||||
id_b = decoder_b(errors="ignore") # type: IncrementalDecoder
|
||||
|
||||
character_match_count = 0 # type: int
|
||||
|
||||
for i in range(0, 255):
|
||||
to_be_decoded = bytes([i]) # type: bytes
|
||||
if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded):
|
||||
character_match_count += 1
|
||||
|
||||
return character_match_count / 254
|
||||
|
||||
|
||||
def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool:
|
||||
"""
|
||||
Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using
|
||||
the function cp_similarity.
|
||||
"""
|
||||
return iana_name_a in IANA_SUPPORTED_SIMILAR and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a]
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
"""
|
||||
Expose version
|
||||
"""
|
||||
|
||||
__version__ = "2.0.3"
|
||||
VERSION = __version__.split('.')
|
||||
Vendored
+68
-72
@@ -4,76 +4,72 @@ writing command line scripts fun. Unlike other modules, it's based
|
||||
around a simple API that does not come with too much magic and is
|
||||
composable.
|
||||
"""
|
||||
from .core import Argument
|
||||
from .core import BaseCommand
|
||||
from .core import Command
|
||||
from .core import CommandCollection
|
||||
from .core import Context
|
||||
from .core import Group
|
||||
from .core import MultiCommand
|
||||
from .core import Option
|
||||
from .core import Parameter
|
||||
from .decorators import argument
|
||||
from .decorators import command
|
||||
from .decorators import confirmation_option
|
||||
from .decorators import group
|
||||
from .decorators import help_option
|
||||
from .decorators import make_pass_decorator
|
||||
from .decorators import option
|
||||
from .decorators import pass_context
|
||||
from .decorators import pass_obj
|
||||
from .decorators import password_option
|
||||
from .decorators import version_option
|
||||
from .exceptions import Abort
|
||||
from .exceptions import BadArgumentUsage
|
||||
from .exceptions import BadOptionUsage
|
||||
from .exceptions import BadParameter
|
||||
from .exceptions import ClickException
|
||||
from .exceptions import FileError
|
||||
from .exceptions import MissingParameter
|
||||
from .exceptions import NoSuchOption
|
||||
from .exceptions import UsageError
|
||||
from .formatting import HelpFormatter
|
||||
from .formatting import wrap_text
|
||||
from .globals import get_current_context
|
||||
from .parser import OptionParser
|
||||
from .termui import clear
|
||||
from .termui import confirm
|
||||
from .termui import echo_via_pager
|
||||
from .termui import edit
|
||||
from .termui import get_terminal_size
|
||||
from .termui import getchar
|
||||
from .termui import launch
|
||||
from .termui import pause
|
||||
from .termui import progressbar
|
||||
from .termui import prompt
|
||||
from .termui import secho
|
||||
from .termui import style
|
||||
from .termui import unstyle
|
||||
from .types import BOOL
|
||||
from .types import Choice
|
||||
from .types import DateTime
|
||||
from .types import File
|
||||
from .types import FLOAT
|
||||
from .types import FloatRange
|
||||
from .types import INT
|
||||
from .types import IntRange
|
||||
from .types import ParamType
|
||||
from .types import Path
|
||||
from .types import STRING
|
||||
from .types import Tuple
|
||||
from .types import UNPROCESSED
|
||||
from .types import UUID
|
||||
from .utils import echo
|
||||
from .utils import format_filename
|
||||
from .utils import get_app_dir
|
||||
from .utils import get_binary_stream
|
||||
from .utils import get_os_args
|
||||
from .utils import get_text_stream
|
||||
from .utils import open_file
|
||||
from .core import Argument as Argument
|
||||
from .core import BaseCommand as BaseCommand
|
||||
from .core import Command as Command
|
||||
from .core import CommandCollection as CommandCollection
|
||||
from .core import Context as Context
|
||||
from .core import Group as Group
|
||||
from .core import MultiCommand as MultiCommand
|
||||
from .core import Option as Option
|
||||
from .core import Parameter as Parameter
|
||||
from .decorators import argument as argument
|
||||
from .decorators import command as command
|
||||
from .decorators import confirmation_option as confirmation_option
|
||||
from .decorators import group as group
|
||||
from .decorators import help_option as help_option
|
||||
from .decorators import make_pass_decorator as make_pass_decorator
|
||||
from .decorators import option as option
|
||||
from .decorators import pass_context as pass_context
|
||||
from .decorators import pass_obj as pass_obj
|
||||
from .decorators import password_option as password_option
|
||||
from .decorators import version_option as version_option
|
||||
from .exceptions import Abort as Abort
|
||||
from .exceptions import BadArgumentUsage as BadArgumentUsage
|
||||
from .exceptions import BadOptionUsage as BadOptionUsage
|
||||
from .exceptions import BadParameter as BadParameter
|
||||
from .exceptions import ClickException as ClickException
|
||||
from .exceptions import FileError as FileError
|
||||
from .exceptions import MissingParameter as MissingParameter
|
||||
from .exceptions import NoSuchOption as NoSuchOption
|
||||
from .exceptions import UsageError as UsageError
|
||||
from .formatting import HelpFormatter as HelpFormatter
|
||||
from .formatting import wrap_text as wrap_text
|
||||
from .globals import get_current_context as get_current_context
|
||||
from .parser import OptionParser as OptionParser
|
||||
from .termui import clear as clear
|
||||
from .termui import confirm as confirm
|
||||
from .termui import echo_via_pager as echo_via_pager
|
||||
from .termui import edit as edit
|
||||
from .termui import get_terminal_size as get_terminal_size
|
||||
from .termui import getchar as getchar
|
||||
from .termui import launch as launch
|
||||
from .termui import pause as pause
|
||||
from .termui import progressbar as progressbar
|
||||
from .termui import prompt as prompt
|
||||
from .termui import secho as secho
|
||||
from .termui import style as style
|
||||
from .termui import unstyle as unstyle
|
||||
from .types import BOOL as BOOL
|
||||
from .types import Choice as Choice
|
||||
from .types import DateTime as DateTime
|
||||
from .types import File as File
|
||||
from .types import FLOAT as FLOAT
|
||||
from .types import FloatRange as FloatRange
|
||||
from .types import INT as INT
|
||||
from .types import IntRange as IntRange
|
||||
from .types import ParamType as ParamType
|
||||
from .types import Path as Path
|
||||
from .types import STRING as STRING
|
||||
from .types import Tuple as Tuple
|
||||
from .types import UNPROCESSED as UNPROCESSED
|
||||
from .types import UUID as UUID
|
||||
from .utils import echo as echo
|
||||
from .utils import format_filename as format_filename
|
||||
from .utils import get_app_dir as get_app_dir
|
||||
from .utils import get_binary_stream as get_binary_stream
|
||||
from .utils import get_os_args as get_os_args
|
||||
from .utils import get_text_stream as get_text_stream
|
||||
from .utils import open_file as open_file
|
||||
|
||||
# Controls if click should emit the warning about the use of unicode
|
||||
# literals.
|
||||
disable_unicode_literals_warning = False
|
||||
|
||||
__version__ = "7.1.2"
|
||||
__version__ = "8.0.1"
|
||||
|
||||
Vendored
-375
@@ -1,375 +0,0 @@
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
|
||||
from .core import Argument
|
||||
from .core import MultiCommand
|
||||
from .core import Option
|
||||
from .parser import split_arg_string
|
||||
from .types import Choice
|
||||
from .utils import echo
|
||||
|
||||
try:
|
||||
from collections import abc
|
||||
except ImportError:
|
||||
import collections as abc
|
||||
|
||||
WORDBREAK = "="
|
||||
|
||||
# Note, only BASH version 4.4 and later have the nosort option.
|
||||
COMPLETION_SCRIPT_BASH = """
|
||||
%(complete_func)s() {
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\
|
||||
COMP_CWORD=$COMP_CWORD \\
|
||||
%(autocomplete_var)s=complete $1 ) )
|
||||
return 0
|
||||
}
|
||||
|
||||
%(complete_func)setup() {
|
||||
local COMPLETION_OPTIONS=""
|
||||
local BASH_VERSION_ARR=(${BASH_VERSION//./ })
|
||||
# Only BASH version 4.4 and later have the nosort option.
|
||||
if [ ${BASH_VERSION_ARR[0]} -gt 4 ] || ([ ${BASH_VERSION_ARR[0]} -eq 4 ] \
|
||||
&& [ ${BASH_VERSION_ARR[1]} -ge 4 ]); then
|
||||
COMPLETION_OPTIONS="-o nosort"
|
||||
fi
|
||||
|
||||
complete $COMPLETION_OPTIONS -F %(complete_func)s %(script_names)s
|
||||
}
|
||||
|
||||
%(complete_func)setup
|
||||
"""
|
||||
|
||||
COMPLETION_SCRIPT_ZSH = """
|
||||
#compdef %(script_names)s
|
||||
|
||||
%(complete_func)s() {
|
||||
local -a completions
|
||||
local -a completions_with_descriptions
|
||||
local -a response
|
||||
(( ! $+commands[%(script_names)s] )) && return 1
|
||||
|
||||
response=("${(@f)$( env COMP_WORDS=\"${words[*]}\" \\
|
||||
COMP_CWORD=$((CURRENT-1)) \\
|
||||
%(autocomplete_var)s=\"complete_zsh\" \\
|
||||
%(script_names)s )}")
|
||||
|
||||
for key descr in ${(kv)response}; do
|
||||
if [[ "$descr" == "_" ]]; then
|
||||
completions+=("$key")
|
||||
else
|
||||
completions_with_descriptions+=("$key":"$descr")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$completions_with_descriptions" ]; then
|
||||
_describe -V unsorted completions_with_descriptions -U
|
||||
fi
|
||||
|
||||
if [ -n "$completions" ]; then
|
||||
compadd -U -V unsorted -a completions
|
||||
fi
|
||||
compstate[insert]="automenu"
|
||||
}
|
||||
|
||||
compdef %(complete_func)s %(script_names)s
|
||||
"""
|
||||
|
||||
COMPLETION_SCRIPT_FISH = (
|
||||
"complete --no-files --command %(script_names)s --arguments"
|
||||
' "(env %(autocomplete_var)s=complete_fish'
|
||||
" COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t)"
|
||||
' %(script_names)s)"'
|
||||
)
|
||||
|
||||
_completion_scripts = {
|
||||
"bash": COMPLETION_SCRIPT_BASH,
|
||||
"zsh": COMPLETION_SCRIPT_ZSH,
|
||||
"fish": COMPLETION_SCRIPT_FISH,
|
||||
}
|
||||
|
||||
_invalid_ident_char_re = re.compile(r"[^a-zA-Z0-9_]")
|
||||
|
||||
|
||||
def get_completion_script(prog_name, complete_var, shell):
|
||||
cf_name = _invalid_ident_char_re.sub("", prog_name.replace("-", "_"))
|
||||
script = _completion_scripts.get(shell, COMPLETION_SCRIPT_BASH)
|
||||
return (
|
||||
script
|
||||
% {
|
||||
"complete_func": "_{}_completion".format(cf_name),
|
||||
"script_names": prog_name,
|
||||
"autocomplete_var": complete_var,
|
||||
}
|
||||
).strip() + ";"
|
||||
|
||||
|
||||
def resolve_ctx(cli, prog_name, args):
|
||||
"""Parse into a hierarchy of contexts. Contexts are connected
|
||||
through the parent variable.
|
||||
|
||||
:param cli: command definition
|
||||
:param prog_name: the program that is running
|
||||
:param args: full list of args
|
||||
:return: the final context/command parsed
|
||||
"""
|
||||
ctx = cli.make_context(prog_name, args, resilient_parsing=True)
|
||||
args = ctx.protected_args + ctx.args
|
||||
while args:
|
||||
if isinstance(ctx.command, MultiCommand):
|
||||
if not ctx.command.chain:
|
||||
cmd_name, cmd, args = ctx.command.resolve_command(ctx, args)
|
||||
if cmd is None:
|
||||
return ctx
|
||||
ctx = cmd.make_context(
|
||||
cmd_name, args, parent=ctx, resilient_parsing=True
|
||||
)
|
||||
args = ctx.protected_args + ctx.args
|
||||
else:
|
||||
# Walk chained subcommand contexts saving the last one.
|
||||
while args:
|
||||
cmd_name, cmd, args = ctx.command.resolve_command(ctx, args)
|
||||
if cmd is None:
|
||||
return ctx
|
||||
sub_ctx = cmd.make_context(
|
||||
cmd_name,
|
||||
args,
|
||||
parent=ctx,
|
||||
allow_extra_args=True,
|
||||
allow_interspersed_args=False,
|
||||
resilient_parsing=True,
|
||||
)
|
||||
args = sub_ctx.args
|
||||
ctx = sub_ctx
|
||||
args = sub_ctx.protected_args + sub_ctx.args
|
||||
else:
|
||||
break
|
||||
return ctx
|
||||
|
||||
|
||||
def start_of_option(param_str):
|
||||
"""
|
||||
:param param_str: param_str to check
|
||||
:return: whether or not this is the start of an option declaration
|
||||
(i.e. starts "-" or "--")
|
||||
"""
|
||||
return param_str and param_str[:1] == "-"
|
||||
|
||||
|
||||
def is_incomplete_option(all_args, cmd_param):
|
||||
"""
|
||||
:param all_args: the full original list of args supplied
|
||||
:param cmd_param: the current command paramter
|
||||
:return: whether or not the last option declaration (i.e. starts
|
||||
"-" or "--") is incomplete and corresponds to this cmd_param. In
|
||||
other words whether this cmd_param option can still accept
|
||||
values
|
||||
"""
|
||||
if not isinstance(cmd_param, Option):
|
||||
return False
|
||||
if cmd_param.is_flag:
|
||||
return False
|
||||
last_option = None
|
||||
for index, arg_str in enumerate(
|
||||
reversed([arg for arg in all_args if arg != WORDBREAK])
|
||||
):
|
||||
if index + 1 > cmd_param.nargs:
|
||||
break
|
||||
if start_of_option(arg_str):
|
||||
last_option = arg_str
|
||||
|
||||
return True if last_option and last_option in cmd_param.opts else False
|
||||
|
||||
|
||||
def is_incomplete_argument(current_params, cmd_param):
|
||||
"""
|
||||
:param current_params: the current params and values for this
|
||||
argument as already entered
|
||||
:param cmd_param: the current command parameter
|
||||
:return: whether or not the last argument is incomplete and
|
||||
corresponds to this cmd_param. In other words whether or not the
|
||||
this cmd_param argument can still accept values
|
||||
"""
|
||||
if not isinstance(cmd_param, Argument):
|
||||
return False
|
||||
current_param_values = current_params[cmd_param.name]
|
||||
if current_param_values is None:
|
||||
return True
|
||||
if cmd_param.nargs == -1:
|
||||
return True
|
||||
if (
|
||||
isinstance(current_param_values, abc.Iterable)
|
||||
and cmd_param.nargs > 1
|
||||
and len(current_param_values) < cmd_param.nargs
|
||||
):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_user_autocompletions(ctx, args, incomplete, cmd_param):
|
||||
"""
|
||||
:param ctx: context associated with the parsed command
|
||||
:param args: full list of args
|
||||
:param incomplete: the incomplete text to autocomplete
|
||||
:param cmd_param: command definition
|
||||
:return: all the possible user-specified completions for the param
|
||||
"""
|
||||
results = []
|
||||
if isinstance(cmd_param.type, Choice):
|
||||
# Choices don't support descriptions.
|
||||
results = [
|
||||
(c, None) for c in cmd_param.type.choices if str(c).startswith(incomplete)
|
||||
]
|
||||
elif cmd_param.autocompletion is not None:
|
||||
dynamic_completions = cmd_param.autocompletion(
|
||||
ctx=ctx, args=args, incomplete=incomplete
|
||||
)
|
||||
results = [
|
||||
c if isinstance(c, tuple) else (c, None) for c in dynamic_completions
|
||||
]
|
||||
return results
|
||||
|
||||
|
||||
def get_visible_commands_starting_with(ctx, starts_with):
|
||||
"""
|
||||
:param ctx: context associated with the parsed command
|
||||
:starts_with: string that visible commands must start with.
|
||||
:return: all visible (not hidden) commands that start with starts_with.
|
||||
"""
|
||||
for c in ctx.command.list_commands(ctx):
|
||||
if c.startswith(starts_with):
|
||||
command = ctx.command.get_command(ctx, c)
|
||||
if not command.hidden:
|
||||
yield command
|
||||
|
||||
|
||||
def add_subcommand_completions(ctx, incomplete, completions_out):
|
||||
# Add subcommand completions.
|
||||
if isinstance(ctx.command, MultiCommand):
|
||||
completions_out.extend(
|
||||
[
|
||||
(c.name, c.get_short_help_str())
|
||||
for c in get_visible_commands_starting_with(ctx, incomplete)
|
||||
]
|
||||
)
|
||||
|
||||
# Walk up the context list and add any other completion
|
||||
# possibilities from chained commands
|
||||
while ctx.parent is not None:
|
||||
ctx = ctx.parent
|
||||
if isinstance(ctx.command, MultiCommand) and ctx.command.chain:
|
||||
remaining_commands = [
|
||||
c
|
||||
for c in get_visible_commands_starting_with(ctx, incomplete)
|
||||
if c.name not in ctx.protected_args
|
||||
]
|
||||
completions_out.extend(
|
||||
[(c.name, c.get_short_help_str()) for c in remaining_commands]
|
||||
)
|
||||
|
||||
|
||||
def get_choices(cli, prog_name, args, incomplete):
|
||||
"""
|
||||
:param cli: command definition
|
||||
:param prog_name: the program that is running
|
||||
:param args: full list of args
|
||||
:param incomplete: the incomplete text to autocomplete
|
||||
:return: all the possible completions for the incomplete
|
||||
"""
|
||||
all_args = copy.deepcopy(args)
|
||||
|
||||
ctx = resolve_ctx(cli, prog_name, args)
|
||||
if ctx is None:
|
||||
return []
|
||||
|
||||
has_double_dash = "--" in all_args
|
||||
|
||||
# In newer versions of bash long opts with '='s are partitioned, but
|
||||
# it's easier to parse without the '='
|
||||
if start_of_option(incomplete) and WORDBREAK in incomplete:
|
||||
partition_incomplete = incomplete.partition(WORDBREAK)
|
||||
all_args.append(partition_incomplete[0])
|
||||
incomplete = partition_incomplete[2]
|
||||
elif incomplete == WORDBREAK:
|
||||
incomplete = ""
|
||||
|
||||
completions = []
|
||||
if not has_double_dash and start_of_option(incomplete):
|
||||
# completions for partial options
|
||||
for param in ctx.command.params:
|
||||
if isinstance(param, Option) and not param.hidden:
|
||||
param_opts = [
|
||||
param_opt
|
||||
for param_opt in param.opts + param.secondary_opts
|
||||
if param_opt not in all_args or param.multiple
|
||||
]
|
||||
completions.extend(
|
||||
[(o, param.help) for o in param_opts if o.startswith(incomplete)]
|
||||
)
|
||||
return completions
|
||||
# completion for option values from user supplied values
|
||||
for param in ctx.command.params:
|
||||
if is_incomplete_option(all_args, param):
|
||||
return get_user_autocompletions(ctx, all_args, incomplete, param)
|
||||
# completion for argument values from user supplied values
|
||||
for param in ctx.command.params:
|
||||
if is_incomplete_argument(ctx.params, param):
|
||||
return get_user_autocompletions(ctx, all_args, incomplete, param)
|
||||
|
||||
add_subcommand_completions(ctx, incomplete, completions)
|
||||
# Sort before returning so that proper ordering can be enforced in custom types.
|
||||
return sorted(completions)
|
||||
|
||||
|
||||
def do_complete(cli, prog_name, include_descriptions):
|
||||
cwords = split_arg_string(os.environ["COMP_WORDS"])
|
||||
cword = int(os.environ["COMP_CWORD"])
|
||||
args = cwords[1:cword]
|
||||
try:
|
||||
incomplete = cwords[cword]
|
||||
except IndexError:
|
||||
incomplete = ""
|
||||
|
||||
for item in get_choices(cli, prog_name, args, incomplete):
|
||||
echo(item[0])
|
||||
if include_descriptions:
|
||||
# ZSH has trouble dealing with empty array parameters when
|
||||
# returned from commands, use '_' to indicate no description
|
||||
# is present.
|
||||
echo(item[1] if item[1] else "_")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def do_complete_fish(cli, prog_name):
|
||||
cwords = split_arg_string(os.environ["COMP_WORDS"])
|
||||
incomplete = os.environ["COMP_CWORD"]
|
||||
args = cwords[1:]
|
||||
|
||||
for item in get_choices(cli, prog_name, args, incomplete):
|
||||
if item[1]:
|
||||
echo("{arg}\t{desc}".format(arg=item[0], desc=item[1]))
|
||||
else:
|
||||
echo(item[0])
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def bashcomplete(cli, prog_name, complete_var, complete_instr):
|
||||
if "_" in complete_instr:
|
||||
command, shell = complete_instr.split("_", 1)
|
||||
else:
|
||||
command = complete_instr
|
||||
shell = "bash"
|
||||
|
||||
if command == "source":
|
||||
echo(get_completion_script(prog_name, complete_var, shell))
|
||||
return True
|
||||
elif command == "complete":
|
||||
if shell == "fish":
|
||||
return do_complete_fish(cli, prog_name)
|
||||
elif shell in {"bash", "zsh"}:
|
||||
return do_complete(cli, prog_name, shell == "zsh")
|
||||
|
||||
return False
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user