From e75b20ea24f5039a208a0a697450b248537bd633 Mon Sep 17 00:00:00 2001 From: COPELLI Lorenzo Date: Wed, 8 Apr 2026 10:28:22 +0200 Subject: [PATCH 1/2] Refactored and improved code. --- .coveragerc | 3 + .github/workflows/python-ci.yml | 45 - .gitignore | 7 + LICENSE | 961 ++++++------------- MANIFEST.in | 4 - README.md | 309 +----- dist/eppoPynder-1.0.0-py3-none-any.whl | Bin 22743 -> 0 bytes dist/eppopynder-1.0.0.tar.gz | Bin 27856 -> 0 bytes docs/guide.md | 342 +++++++ media/logo.png | Bin 0 -> 278029 bytes pyproject.toml | 46 +- requirements.txt | Bin 670 -> 1504 bytes setup.py | 49 - src/eppoPynder/__init__.py | 23 + src/eppoPynder/_core/__init__.py | 1 + src/eppoPynder/_core/_country.py | 69 ++ src/eppoPynder/_core/_general.py | 53 + src/eppoPynder/_core/_references.py | 63 ++ src/eppoPynder/_core/_reporting_service.py | 65 ++ src/eppoPynder/_core/_rppo.py | 68 ++ src/eppoPynder/_core/_taxon.py | 82 ++ src/eppoPynder/_core/_taxons.py | 60 ++ src/eppoPynder/_core/_tools.py | 59 ++ src/eppoPynder/_utils/__init__.py | 1 + src/eppoPynder/_utils/_checks.py | 147 +++ src/eppoPynder/_utils/_data.py | 275 ++++++ src/eppoPynder/_utils/_requests.py | 309 ++++++ src/eppoPynder/api_query.py | 78 -- src/eppoPynder/client.py | 448 +++++++++ src/eppoPynder/data_dump.py | 74 -- src/eppoPynder/data_wrangling.py | 75 ++ src/eppoPynder/getting_countries.py | 106 -- src/eppoPynder/query_the_eppo_for_service.py | 82 -- src/eppoPynder/query_the_whole_eppo.py | 64 -- src/eppoPynder/taxonomy_ranked.py | 34 - src/eppoPynder/unnest_lists.py | 25 - tests/test__checks.py | 132 +++ tests/test__country.py | 103 ++ tests/test__data.py | 209 ++++ tests/test__general.py | 73 ++ tests/test__references.py | 73 ++ tests/test__reporting_service.py | 110 +++ tests/test__requests.py | 403 ++++++++ tests/test__rppo.py | 101 ++ tests/test__taxon.py | 101 ++ tests/test__taxons.py | 76 ++ tests/test__tools.py | 98 ++ tests/test_api_query.py | 37 - tests/test_client.py | 251 +++++ tests/test_data_dump.py | 50 - tests/test_data_wrangling.py | 36 + tests/test_getting_countries.py | 96 -- tests/test_query_the_eppo_for_service.py | 34 - tests/test_query_the_whole_eppo.py | 37 - tests/test_taxonomy_ranked.py | 27 - tests/test_unnest_lists.py | 70 -- 56 files changed, 4281 insertions(+), 1863 deletions(-) create mode 100644 .coveragerc delete mode 100644 .github/workflows/python-ci.yml create mode 100644 .gitignore delete mode 100644 MANIFEST.in delete mode 100644 dist/eppoPynder-1.0.0-py3-none-any.whl delete mode 100644 dist/eppopynder-1.0.0.tar.gz create mode 100644 docs/guide.md create mode 100644 media/logo.png delete mode 100644 setup.py create mode 100644 src/eppoPynder/_core/__init__.py create mode 100644 src/eppoPynder/_core/_country.py create mode 100644 src/eppoPynder/_core/_general.py create mode 100644 src/eppoPynder/_core/_references.py create mode 100644 src/eppoPynder/_core/_reporting_service.py create mode 100644 src/eppoPynder/_core/_rppo.py create mode 100644 src/eppoPynder/_core/_taxon.py create mode 100644 src/eppoPynder/_core/_taxons.py create mode 100644 src/eppoPynder/_core/_tools.py create mode 100644 src/eppoPynder/_utils/__init__.py create mode 100644 src/eppoPynder/_utils/_checks.py create mode 100644 src/eppoPynder/_utils/_data.py create mode 100644 src/eppoPynder/_utils/_requests.py delete mode 100644 src/eppoPynder/api_query.py create mode 100644 src/eppoPynder/client.py delete mode 100644 src/eppoPynder/data_dump.py create mode 100644 src/eppoPynder/data_wrangling.py delete mode 100644 src/eppoPynder/getting_countries.py delete mode 100644 src/eppoPynder/query_the_eppo_for_service.py delete mode 100644 src/eppoPynder/query_the_whole_eppo.py delete mode 100644 src/eppoPynder/taxonomy_ranked.py delete mode 100644 src/eppoPynder/unnest_lists.py create mode 100644 tests/test__checks.py create mode 100644 tests/test__country.py create mode 100644 tests/test__data.py create mode 100644 tests/test__general.py create mode 100644 tests/test__references.py create mode 100644 tests/test__reporting_service.py create mode 100644 tests/test__requests.py create mode 100644 tests/test__rppo.py create mode 100644 tests/test__taxon.py create mode 100644 tests/test__taxons.py create mode 100644 tests/test__tools.py delete mode 100644 tests/test_api_query.py create mode 100644 tests/test_client.py delete mode 100644 tests/test_data_dump.py create mode 100644 tests/test_data_wrangling.py delete mode 100644 tests/test_getting_countries.py delete mode 100644 tests/test_query_the_eppo_for_service.py delete mode 100644 tests/test_query_the_whole_eppo.py delete mode 100644 tests/test_taxonomy_ranked.py delete mode 100644 tests/test_unnest_lists.py diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..a7cba45 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[run] +omit = + tests/* diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml deleted file mode 100644 index 5fcb149..0000000 --- a/.github/workflows/python-ci.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Run tests and upload coverage - -on: - push: - branches: - - dev # Trigger the workflow on push to the dev branch - pull_request: - branches: - - dev # Trigger the workflow on pull requests to the dev branch - -jobs: - test: - name: Run tests and collect coverage - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set up Python - uses: actions/setup-python@v4 - - - name: Install dependencies - run: | - pip install pytest-cov codecov - pip install -r requirements.txt - - - name: Set PYTHONPATH to src - run: echo "PYTHONPATH=$(pwd)/src" >> $GITHUB_ENV # Set PYTHONPATH to the 'src' directory - - - name: Set EPPO Token as environment variable - run: echo "EPPO_token=${{ secrets.EPPO_TOKEN }}" >> $GITHUB_ENV # Use EPPO token set under Secrets section - - - name: Run tests - run: | - coverage run -m pytest --ignore=/usr/lib/python3/dist-packages - coverage report -m - coverage xml - - - name: Upload results to Codecov - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - file: coverage.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..31910b2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea/ +*.egg-info/ +.env +__pycache__/ +.coverage +dist/ +coverage.xml diff --git a/LICENSE b/LICENSE index f288702..c29ce2f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,287 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + EUROPEAN UNION PUBLIC LICENCE v. 1.2 + EUPL © the European Union 2007, 2016 + +This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined +below) which is provided under the terms of this Licence. Any use of the Work, +other than as authorised under this Licence is prohibited (to the extent such +use is covered by a right of the copyright holder of the Work). + +The Work is provided under the terms of this Licence when the Licensor (as +defined below) has placed the following notice immediately following the +copyright notice for the Work: + + Licensed under the EUPL + +or has expressed by any other means his willingness to license under the EUPL. + +1. Definitions + +In this Licence, the following terms have the following meaning: + +- ‘The Licence’: this Licence. + +- ‘The Original Work’: the work or software distributed or communicated by the + Licensor under this Licence, available as Source Code and also as Executable + Code as the case may be. + +- ‘Derivative Works’: the works or software that could be created by the + Licensee, based upon the Original Work or modifications thereof. This Licence + does not define the extent of modification or dependence on the Original Work + required in order to classify a work as a Derivative Work; this extent is + determined by copyright law applicable in the country mentioned in Article 15. + +- ‘The Work’: the Original Work or its Derivative Works. + +- ‘The Source Code’: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- ‘The Executable Code’: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- ‘The Licensor’: the natural or legal person that distributes or communicates + the Work under the Licence. + +- ‘Contributor(s)’: any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of + the Work under the terms of the Licence. + +- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, online or offline, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + +2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +sublicensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, +- reproduce the Work, +- modify the Work, and make Derivative Works based upon the Work, +- communicate to the public, including the right to make available or display + the Work or copies thereof to the public and perform publicly, as the case may + be, the Work, +- distribute the Work or copies thereof, +- lend and rent the Work or copies thereof, +- sublicense rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + +3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute or communicate the Work. + +4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Work, of the exhaustion of those rights or of other applicable limitations +thereto. + +5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: The Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes or communicates copies of the +Original Works or Derivative Works, this Distribution or Communication will be +done under the terms of this Licence or of a later version of this Licence +unless the Original Work is expressly distributed only under this version of the +Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee +(becoming Licensor) cannot offer or impose any additional terms or conditions on +the Work or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes or Communicates Derivative +Works or copies thereof based upon both the Work and another work licensed under +a Compatible Licence, this Distribution or Communication can be done under the +terms of this Compatible Licence. For the sake of this clause, ‘Compatible +Licence’ refers to the licences listed in the appendix attached to this Licence. +Should the Licensee's obligations under the Compatible Licence conflict with +his/her obligations under this Licence, the obligations of the Compatible +Licence shall prevail. + +Provision of Source Code: When distributing or communicating copies of the Work, +the Licensee will provide a machine-readable copy of the Source Code or indicate +a repository where this Source will be easily and freely available for as long +as the Licensee continues to distribute or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or 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 copyright notice. + +6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + +7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +Contributors. It is not a finished work and may therefore contain defects or +‘bugs’ inherent to this type of development. + +For the above reason, the Work is provided under the Licence on an ‘as is’ basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + +8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such damage. +However, the Licensor will be liable under statutory product liability laws as +far such laws apply to the Work. + +9. Additional agreements + +While distributing the Work, You may choose to conclude an additional agreement, +defining obligations or services consistent with this Licence. However, if +accepting obligations, You may act only on your own behalf and on your sole +responsibility, not on behalf of the original Licensor or 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 +the fact You have accepted any warranty or additional liability. + +10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution or Communication by You of the Work or copies thereof. + +11. Information to the public + +In case of any Distribution or Communication of the Work by means of electronic +communication by You (for example, by offering to download the Work from a +remote location) the distribution channel or media (for example, a website) must +at least provide to the public the information requested by the applicable law +regarding the Licensor, the Licence and the way it may be accessible, concluded, +stored and reproduced by the Licensee. + +12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + +13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed or reformed so as necessary to make it +valid and enforceable. + +The European Commission may publish other linguistic versions or new versions of +this Licence or updated versions of the Appendix, so far this is required and +reasonable, without reducing the scope of the rights granted by the Licence. New +versions of the Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + +14. Jurisdiction + +Without prejudice to specific agreement between parties, + +- any litigation resulting from the interpretation of this License, arising + between the European Union institutions, bodies, offices or agencies, as a + Licensor, and any Licensee, will be subject to the jurisdiction of the Court + of Justice of the European Union, as laid down in article 272 of the Treaty on + the Functioning of the European Union, + +- any litigation arising between other parties and resulting from the + interpretation of this License, will be subject to the exclusive jurisdiction + of the competent court where the Licensor resides or conducts its primary + business. + +15. Applicable Law + +Without prejudice to specific agreement between parties, + +- this Licence shall be governed by the law of the European Union Member State + where the Licensor has his seat, resides or has his registered office, + +- this licence shall be governed by Belgian law if the Licensor has no seat, + residence or registered office inside a European Union Member State. + +Appendix + +‘Compatible Licences’ according to Article 5 EUPL are: + +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 +- Open Software License (OSL) v. 2.1, v. 3.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for + works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong + Reciprocity (LiLiQ-R+). + +The European Commission may update this Appendix to later versions of the above +licences without producing a new version of the EUPL, as long as they provide +the rights granted in Article 2 of this Licence and protect the covered Source +Code from exclusive appropriation. + +All other changes or additions to this Appendix require the production of a new +EUPL version. \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 0081be3..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -# Exclude the following Python files -exclude eppoPynder/api_query.py -exclude eppoPynder/unnest_lists.py -exclude requirements.txt diff --git a/README.md b/README.md index d2aad7b..c780ad6 100644 --- a/README.md +++ b/README.md @@ -1,301 +1,60 @@ -# eppoPynder +# eppoPynder -## Overview - -Welcome to the *eppoPynder* package! This package is a wrapper around the public APIs of the European and Mediterranean Plant Protection Organization (EPPO) database. It provides a straightforward way to access a wide range of pest-specific information that has been produced or collected by EPPO. +[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) -*eppoPynder* is designed for use by researchers and practitioners working in plant protection who need easy access to the EPPO database using Python. +## Overview -## Prerequisites +**eppoPynder** provides a Python interface to the public APIs of the **European +and Mediterranean Plant Protection Organization (EPPO)** database. +The package facilitates access to a wide range of pest-related information +collected and maintained by EPPO, allowing users to query, retrieve, and +process this data directly from Python. -To use the *eppoPynder* package, you need a stable internet connection, as it interacts with the EPPO database online services to fetch and manipulate data. A reliable internet connection is essential for the functionality of the package. +The package is intended for researchers, analysts, and practitioners in plant +protection who require convenient programmatic access to EPPO data. ## Installation -You can install the *eppoPynder* package from PyPi using the following command: - -``` -pip install eppoPynder -``` - -Alternatively, if you want to install the package from GitHub (for the latest development version), use: - -``` -pip install git+https://github.com/openefsa/eppoPynder.git -``` - -## Working with API Tokens - -The *eppoPynder* package requires your unique token to be included in each API request for proper functionality. There are three ways to provide this token: - -1. **Using the `.env` file** -2. **Manually adding it to each API request** - -### 1. Setting Environment Variables via `.env` - -The `.env` file is used to specify environment variables that Python loads at the start of every session. It is particularly useful for setting variables, such as API keys, that can be accessed by Python scripts and functions. - -After installing the *eppoPynder* package, you should create a `.env` file in your project's root directory (i.e., the same directory as `setup.py`). This is important because the `python-dotenv` package expects the `.env` file to be in this location by default. - -#### Example Project Structure: - -``` -/eppoPynder - ├── .env # Place your .env file here - ├── setup.py - ├── src/ - │ └── eppoPynder/ - │ └── __init__.py - │ └── module.py - └── README.md -``` - -You can create or modify the `.env` file manually using any text editor. In the `.env` file, you set environment variables in the following format: - -`EPPO_token=your-eppo-token` - -After adding your EPPO token to the `.env` file, save and close the file. Python will automatically read the token when it starts up, and you can access it in any Python session using `os.getenv('EPPO_token')`. - -### 2. Manually adding your token to each API request - -For functions that require an API token, you can manually specify the token in the `token` argument of the function. This method is useful if you want to use different tokens for different function calls or if you don't want to store the token globally. For example: - -`query_the_eppo_for_service(queried_eppocode = "BEMITA", service = "general", token = "your-eppo-token")` - -#### Explanation: - -`query_the_eppo_for_service(queried_eppocode = "BEMITA", service = "general", token = "your-eppo-token")`: This calls the function with the necessary parameters: - -- `queried_eppocode = "BEMITA"`: The EPPO code for which you want to query a service. -- `service = "general"`: Specifies the service you want to query (you can replace this with any valid service type). -- `token = "your-eppo-token"`: Passes the token for authentication. Replace "your-eppo-token" with your actual EPPO token enclosed in quotes. - -## Basic Usage - -The primary functionality of *eppoPynder* is to query the EPPO database for specific EPPO codes and retrieve data across various services. Users can either choose to: 1) query a single service for a given EPPO code or 2) query all available services in the database for more comprehensive information. - -For plant and pest species, the basic available information includes scientific names, synonyms, common names in different languages, and taxonomic position. For each pest of regulatory interest, more detailed information can also be retrieved regarding its host plants and categorization (quarantine status). - -The examples below will guide you on how to use the functions in this package to access these data, but to begin, we need to load the *eppoPynder* package with this command: - -``` -import eppoPynder -``` - -If you want to learn more about the arguments and usage of a particular function, you can use Python's built-in `help()` function. Simply run: - -``` -help(function_name) -``` - -This will display the detailed documentation for the function, including its arguments, return values, and examples. - -For example, if you're working with a function called `query_the_eppo_for_service()`, you would use: - -``` -help(query_the_eppo_for_service) -``` - -## Querying a Specific Service - -To query a specific service (e.g., categorization) for an EPPO code (e.g., "BEMITA"), you can use the `query_the_eppo_for_service()` function as follows: +### From PyPi -``` -categorization_BEMITA = query_the_eppo_for_service("BEMITA", service = "categorization") ``` - -### Expected Output: - -``` ->>> categorization_BEMITA - nomcontinent isocode ... queried_on queried_url -0 America CL ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -1 Asia BH ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -2 Asia KZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -3 Europe AZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -4 Europe BY ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -5 Europe GE ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -6 Europe MD ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -7 Europe NO ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -8 Europe RU ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -9 Europe RS ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -10 Europe CH ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -11 Europe TR ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -12 Europe UA ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -13 Europe GB ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -14 Oceania NZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -15 RPPO/EU 9M ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -16 RPPO/EU 9A ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -17 RPPO/EU 9L ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -18 RPPO/EU 9L ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -19 RPPO/EU 9H ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... - -[20 rows x 11 columns] -``` - -`categorization_BEMITA` is a dataframe containing information about the categorization of the EPPO code "BEMITA", and includes the following columns: - -- **nomcontinent**: The continent where the country is located. -- **isocode**: The ISO country code. -- **country**: The name of the country or region. -- **qlist**: A code representing the pest status or classification. -- **qlistlabel**: A label explaining the pest classification (e.g., "A1 list" or "Quarantine pest"). -- **yr_add**: The year the country was added to the list. -- **yr_del**: The year the country was removed (if applicable). -- **yr_trans**: The year the country transitioned (if applicable). -- **queried_eppocode**: The input EPPO code. -- **queried_on**: The date when the query was performed. -- **queried_url**: The queried URL. - -## Querying All Available Services - -If you wish to query all available services for the EPPO code "BEMITA", you can use the `query_the_whole_eppo()` function. This will return a dictionary of dataframes, each corresponding to a different service. - -``` -result_dict = query_the_whole_eppo("BEMITA") -``` - -### Expected Output: - -``` -# Print the names of the services in the result - ->>> result_dict.keys() -dict_keys(['general', 'names', 'taxonomy', 'categorization', 'hosts', 'pests', 'kingdom']) -``` - -`result_dict.keys()` returns the names of the services: general, names, taxonomy, categorization, hosts, pests, and kingdom. - -``` -# Print the data from a specific service, e.g., categorization - ->>> result_dict["categorization"] - nomcontinent isocode ... queried_on queried_url -0 America CL ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -1 Asia BH ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -2 Asia KZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -3 Europe AZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -4 Europe BY ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -5 Europe GE ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -6 Europe MD ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -7 Europe NO ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -8 Europe RU ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -9 Europe RS ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -10 Europe CH ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -11 Europe TR ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -12 Europe UA ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -13 Europe GB ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -14 Oceania NZ ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -15 RPPO/EU 9M ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -16 RPPO/EU 9A ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -17 RPPO/EU 9L ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -18 RPPO/EU 9L ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -19 RPPO/EU 9H ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... - -[20 rows x 11 columns] -``` - -Accessing a specific service (e.g., `result_dict["categorization"]`) will show the data related to that particular service for the EPPO code "BEMITA". - -## Wrangling Data - -The *eppoPynder* package also provides a data wrangling function, `taxonomy_ranked()`, which can combine the data fetched from the "taxonomy" and "kingdom" EPPO services to create a unified, integrated dataframe. - -For example, assume you have two dataframes: `taxonomy` and `kingdom`, which were obtained by querying the "taxonomy" and "kingdom" services for the EPPO code "BEMITA" using the `query_the_eppo_for_service()` function. - -You can combine these two dataframes as follows: - -``` -# Query the taxonomy service for the EPPO code "BEMITA" -taxonomy = query_the_eppo_for_service("BEMITA", service = "taxonomy") - -# Query the kingdom service for the EPPO code "BEMITA" -kingdom = query_the_eppo_for_service("BEMITA", service = "kingdom") - -# Combine taxonomy and kingdom data -wrangled_data = taxonomy_ranked(taxonomy, kingdom) +pip install eppopynder ``` -### Expected Output: +### Development version -``` ->>> wrangled_data - rank codeid ... queried_on queried_url -0 kingdom 57021 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -1 57200 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -2 77963 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -3 59061 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -4 58830 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -5 73260 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -6 56905 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -7 57321 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... -8 5935 ... 2024-12-19 https://data.eppo.int/api/rest/1.0/taxon/BEMIT... +To install the latest development version: -[9 rows x 8 columns] ``` - -`wrangled_data` is a dataframe that combines the taxonomy and kingdom information for the EPPO code "BEMITA". This integration provides a more comprehensive view of the organism's taxonomic rank. - -Specifically, the output dataframe contains the following columns: - -- **rank**: The taxonomic rank. -- **codeid**: A unique identifier for each entry. -- **eppocode**: The EPPO code representing the taxonomic group. -- **prefname**: The preferred name of the taxonomic group (e.g., "Animalia", "Insecta"). -- **level**: The taxonomic level in the hierarchy (1 for the broadest category, progressing to more specific levels). -- **queried_eppocode**: The input EPPO code. -- **queried_on**: The date when the query was performed. -- **queried_url**: The queried URL. - -## Retrieving Countries in Regional Plant Protection Organizations - -The `getting_countries()` function allows you to retrieve all the member countries of a specific Regional Plant Protection Organization (RPPO). - -For example, to get the member countries of the EAEU (Eurasian Economic Union), you can use the following command: - -``` -EAEU_countries = getting_countries('EAEU') -``` - -### Expected Output: - -``` ->>> EAEU_countries -'Armenia, Belarus, Kazakhstan, Kyrgyzstan, Russia' +pip install git+https://github.com/openefsa/eppoPynder.git ``` -`EAEU_countries` is a string of country names that are members of the EAEU. +## Requirements -## Data Dump for Multiple EPPO Codes +An active internet connection is required, as the package communicates with +EPPO's online services to fetch and process data. -The `data_dump()` function allows you to retrieve a comprehensive data dump for multiple EPPO codes. This function queries all available EPPO services for a list of input codes. +## Usage -The following is an example of how the function can be used to query all available EPPO services for the EPPO codes "APHIPO" and "LEUCSC": +Once installed, load the package as usual: -``` -data_dump_result = data_dump(["APHIPO", "LEUCSC"]) +```python +from eppopynder import * ``` -### Expected Output: +Basic usage examples and full documentation are available in the package +[guide](docs/guide.md). -``` -# Print the names of the services in the result +## Authors and maintainers ->>> data_dump_result.keys() -dict_keys(['general', 'names', 'taxonomy', 'categorization', 'hosts', 'pests', 'kingdom']) -``` +- **Lorenzo Copelli** (author, [ORCID](https://orcid.org/0009-0002-4305-065X)). +- **Dayana Stephanie Buzle** (author, [ORCID](https://orcid.org/0009-0003-2990-7431)). +- **Rafael Vieira** (author, [ORCID](https://orcid.org/0009-0009-0289-5438)). +- **Agata Kaczmarek** (author, [ORCID](https://orcid.org/0000-0002-7463-5821)). +- **Luca Belmonte** (author, maintainer, [ORCID](https://orcid.org/0000-0002-7977-9170)). -The output is a dictionary of dataframes, each corresponding to a different service: general, names, taxonomy, categorization, hosts, pests, and kingdom. - -``` -# Print the data from a specific service, e.g., general - ->>> data_dump_result["general"] - pestCode ... queried_url -0 APHIPO ... https://data.eppo.int/api/rest/1.0/taxon/APHIP... -0 LEUCSC ... https://data.eppo.int/api/rest/1.0/taxon/LEUCS... - -[2 rows x 20 columns] -``` +## Links -Accessing a specific service (e.g., `data_dump["general"]`) will show the data related to that particular service for the EPPO codes "APHIPO" and "LEUCSC". The column `queried_eppocode` in the dataframe distinguishes which data have been retrieved for each EPPO code. \ No newline at end of file +- **Homepage**: [GitHub](https://github.com/openefsa/eppoPynder). +- **Bug Tracker**: [Issues on GitHub](https://github.com/openefsa/eppoPynder/issues). +- **EPPO Database**: [https://gd.eppo.int](https://gd.eppo.int). diff --git a/dist/eppoPynder-1.0.0-py3-none-any.whl b/dist/eppoPynder-1.0.0-py3-none-any.whl deleted file mode 100644 index fd886baaac60d74a0168f6d70ec5b18ef2e7c920..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22743 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 gimCa>8vomQ)RoX~C#0F?z{G5`Po diff --git a/dist/eppopynder-1.0.0.tar.gz b/dist/eppopynder-1.0.0.tar.gz deleted file mode 100644 index a4c3faaf53478acc754b382ddce69240eff891c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27856 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%0A)TRZ^(4^g4?|A3-M-!j5!v-~<1Ig~z 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 YN!T=tRG$Vz#zP<<*TFp$T{M*c17F$BH~;_u diff --git a/docs/guide.md b/docs/guide.md new file mode 100644 index 0000000..d01fa18 --- /dev/null +++ b/docs/guide.md @@ -0,0 +1,342 @@ +# Introduction to eppoPynder + +## Overview + +**eppoPynder** provides a Python interface to the public APIs of the **European +and Mediterranean Plant Protection Organization (EPPO)** database. +The package facilitates access to a wide range of pest-related information +collected and maintained by EPPO, allowing users to query, retrieve, and +process this data directly from Python. + +The package is intended for researchers, analysts, and practitioners in plant +protection who require convenient programmatic access to EPPO data. + +## Installation + +### From PyPi + +```bash +$ pip install eppoPynder +``` + +### Development version + +To install the latest development version: + +```bash +$ pip install git+https://github.com/openefsa/eppoPynder.git +``` + +## Requirements + +An active internet connection is required, as the package communicates with +EPPO's online services to fetch and process data. + +## Working with API keys + +The *eppoPynder* package requires your unique API token to function properly. +You can provide this token in one of two ways: + +1. By setting it in a `.env` file. +2. By including it manually during the client initialization. + +### Setting the API key via `.env` + +A `.env` file is used to define environment variables that Python can load at +runtime. This approach is particularly convenient for sensitive information +like API keys, as it allows you to use them in any Python script or function +without hardcoding them. + +Place the `.env` file in the root directory of you project (for example, +`C:/Users/username/Documents/myProject/.env` on Windows or +`~/Documents/myProject/.env` on Unix-like systems). You can create or edit this +file with any plain text editor. + +Add your EPPO API key in the following format: + +`EPPO_API_KEY=` + +Once the file is saved, the variable will be correctly set for the library to +use during execution. + +### Setting the API key manually during client initialization + +Alternatively, you can provide the API key directly in the `api_key` argument +of client instantiation. This is useful if you prefer not to store the token +globally. For example: + +```python +from eppopynder import Client + +client = Client(api_key="") +``` + +Note that if an API key is explicitly provided, the API key set through the +`.env` file will be ignored, if any. + +## Basic usage + +The main purpose of *eppoPynder* is to query the EPPO database for specific +EPPO codes and retrieve relevant information across various endpoints. For each +endpoint, you can either: + +1. Query all available services to obtain more comprehensive data. +2. Query one or more services to obtain specific data. + +For plant and pest species, the basic information returned includes scientific +names, synonyms, common names in different languages, and taxonomic +classification. For pests of regulatory interest, you can also retrieve more +detailed information, such as host plants and quarantine categorization. + +Below are examples demonstrating how to use the functions in this package. +First, load the *eppoPynder* package: + +```python +from eppopynder import * +``` + +Then, initialize the client by specifying the API key you want to use: + +```python +client = Client() # Use the API key defined in .env file. +client = Client(api_key="") # Manually define the API key. +``` + +To explore the arguments and usage of a specific function, you can run: + +```python +help(function_name) +``` + +This will show the full documentation for the function, including its +arguments, return values, and usage examples. + +For example, if you are working with the `uniform_taxonoy()` function, +you can check its documentation with: + +```python +help(uniform_taxonomy) +``` + +Again, if you want to check the documentation of a function that represents a +category, you can run: + +```python +help(Client.taxon) +``` + +Note that the functions representing the categories are all defined inside the +`Client` class. + +## Querying a specific category + +The *eppoPynder* package allows you to query all categories available in +version 2.0 of the EPPO APIs: General, Taxons, Taxon, Country, Tools, Reporting +Services, and References. + +Each category has a corresponding function in the package with the same name +in *snake_case* format: general(), taxons(), taxon(), country(), tools(), +reporting_service(), and reportings(). By default, these functions return all +data available under the selected category, but you can customize the query by +specifying the desired services. + +For example, to query all services of the Taxon category for the EPPO code +"BEMITA", you can use the following code: + +```python +data = client.taxon(eppo_codes=["BEMITA"]) +``` + +Some services require certain mandatory parameters, which must be provided when +making the request. For example: + +```python +data = client.tools( + services=[ToolsService.NAME2CODES], + params={ + ToolsService.NAME2CODES: { + "name": "Bemisia tabaci" + } + } +) +``` + +Each category comes with a set of service names that can be queried. These are +stored in an enumeration whose name follows the convention Category + +"Service". For example, for the Taxon category, the collection of queryable +services is named `TaxonService`, and its values are `OVERVIEW`, `INFOS`, +`NAMES` and so on, exactly matching the names of the available services. +Keep in mind that services can be provided to the corresponding functions only +through their dedicated enum. + +You can import the enumeration associated with a specific category as shown +below: + +```python +from eppopynder import TaxonService, ToolsService # And so on... +``` + +Alternatively, you can import all of them at once by importing everything from +the library: + +```python +from eppopynder import * +``` + +## Querying a specific service + +To query a specific service within an endpoint, *eppoPynder* allows you to +specify it directly in the function call. For example, to access only the +`/taxons/taxon/categorization` service for the EPPO code "BEMITA", you can use +the `Client.taxon()` function as follows: + +```python +data = client.taxon( + eppo_codes=["BEMITA"], + services=[TaxonService.CATEGORIZATION] +) +``` + +### Expected output + +```python +print(data) +``` +```python +{: queried_eppo_code continent_id continent_name country_iso country_name ... year_add year_delete year_transient queried_url queried_on +0 BEMITA 4 America CL Chile ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +1 BEMITA 2 Asia BH Bahrain ... 2003 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +2 BEMITA 2 Asia KZ Kazakhstan ... 2017 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +3 BEMITA 1 Europe AZ Azerbaijan ... 2024 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +4 BEMITA 1 Europe BY Belarus ... 1994 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +5 BEMITA 1 Europe GE Georgia ... 2018 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +6 BEMITA 1 Europe MD Moldova, Republic of ... 2017 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +7 BEMITA 1 Europe NO Norway ... 2012 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +8 BEMITA 1 Europe RU Russian Federation (the) ... 2014 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +9 BEMITA 1 Europe RS Serbia ... 2015 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +10 BEMITA 1 Europe CH Switzerland ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +11 BEMITA 1 Europe TR Türkiye ... 2016 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +12 BEMITA 1 Europe UA Ukraine ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +13 BEMITA 1 Europe GB United Kingdom ... 2020 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +14 BEMITA 5 Oceania NZ New Zealand ... 2000 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +15 BEMITA 6 RPPO/EU 9M EAEU ... 2016 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +16 BEMITA 6 RPPO/EU 9A EPPO ... 1989 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +17 BEMITA 6 RPPO/EU 9L EU ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +18 BEMITA 6 RPPO/EU 9L EU ... 2019 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 +19 BEMITA 6 RPPO/EU 9H OIRSA ... 1992 None None https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 14:58:20.605414 + +[20 rows x 12 columns]} +``` + +All function calls return a dictionary of data frames, each containing the +information from the requested services. + +## Querying all available services + +To fetch data from all available services within a specific endpoint, simply +use the corresponding function without modifying the `services` parameter. Each +function will return a dictionary of data frames, with each data frame +containing information from one service. + +```python +data = client.taxon(eppo_codes=["BEMITA"]) +``` + +### Expected output + +```python +# Print the names of the services in the result. +print(data.keys()) +``` +```python +dict_keys([, , , , , , , , , , , , , , , , ]) +``` + +```python +# Print the data from a specific service. +print(data[TaxonService.OVERVIEW]) +``` +```python + queried_eppo_code eppocode datecreate lastupdate infos replacedby prefname is_active datatype queried_url queried_on +0 BEMITA BEMITA 2002-10-28 00:00:00 2002-10-28 00:00:00 None None Bemisia tabaci True GAI https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:08:26.388685 +``` + +Using `data.keys()` will display the names of the queried services. You can +then access a specific service to view the data associated with it. + +## Data wrangling + +The *eppoPynder* package provides a convenient function, `uniform_taxonomy()`, +to create a complete and standardized taxonomy data frame. This function takes +the taxonomy data returned by the taxonomy service and ensures a uniform +structure, including all expected taxonomic ranks, even if some ranks are +missing in the original result. + +For example, assume you have retrieved taxonomy data for the EPPO code "BEMITA" +using the `Client.taxon()` function: + +```python +data = client.taxon(eppo_codes=["BEMITA"], services=[TaxonService.TAXONOMY]) +``` + +You can then generate a uniform taxonomy table with all ranks using: + +```python +taxonomy = uniform_taxonomy(data[TaxonService.TAXONOMY]) +``` + +### Expected output + +```python +print(taxonomy) +``` +```python + type queried_eppo_code eppocode prefname queried_url queried_on +0 Kingdom BEMITA 1ANIMK Animalia https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +1 Phylum BEMITA 1ARTHP Arthropoda https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +2 Subphylum BEMITA 1HEXAQ Hexapoda https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +3 Class BEMITA 1INSEC Insecta https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +4 Subclass NaN NaN NaN NaN NaT +5 Order BEMITA 1HEMIO Hemiptera https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +6 Suborder BEMITA 1STERR Sternorrhyncha https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +7 Family BEMITA 1ALEYF Aleyrodidae https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +8 Subfamily NaN NaN NaN NaN NaT +9 Genus BEMITA 1BEMIG Bemisia https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +10 Species BEMITA BEMITA Bemisia tabaci https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:26:07.594529 +``` + +## Data retrieval for multiple EPPO or ISO codes + +The `Client.taxon()` and `Client.country()` functions allow you to retrieve +also a complete data dump for multiple EPPO or ISO codes by querying all +available EPPO services for each of them. + +Here is an example showing how to use the function to fetch all available +information for the EPPO codes "BEMITA" and "GOSHI": + +```python +data = client.taxon(eppo_codes=["BEMITA", "GOSHI"]) +``` + +### Expected output + +```python +# Print the names of the services in the result. +print(data.keys()) +``` +```python +dict_keys([, , , , , , , , , , , , , , , , ]) +``` + +```python +# Print the data from a specific service. +print(data[TaxonService.OVERVIEW]) +``` +```python + queried_eppo_code eppocode datecreate lastupdate ... is_active datatype queried_url queried_on +0 BEMITA BEMITA 2002-10-28 00:00:00 2002-10-28 00:00:00 ... True GAI https://api.eppo.int/gd/v2/taxons/taxon/BEMITA... 2025-12-10 15:31:54.300453 +1 GOSHI GOSHI 2004-04-21 00:00:00 2004-04-21 00:00:00 ... True PFL https://api.eppo.int/gd/v2/taxons/taxon/GOSHI/... 2025-12-10 15:31:54.864112 +``` + +Using `data.keys()` will display the names of the queried services. You can +then access a specific service to view the data associated with it. diff --git a/media/logo.png b/media/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d48006914546fb3119551ccc274f4e90342ae0b GIT binary patch literal 278029 zcmZsD2Ut^Evvw?qB1MiM(yP)zq)9K*dq+S(r6UmOHJ~D(AXR$rp(8aA1XP-I=_M4E zn$V;KBq8D7K|SAh?|=32F*|$hS?|0vv&yX5d84PJN=8CQ0s?`^)YX&>K%fhRf8&=g z0pCD}FMkI9JLhSjs(5aumoEgkxagputpEbm#9lplOaxrB*r*w3gFpedL7?ZaKp+h8 z)$?@_$omcmgn9%5Nv488G|w{O`qIFSOHVXal|ZM2zqzf@cfdDSo~fC6fwUvpHq*ute$dAkoa)3@i>PiYmezTkNzKIW49v|&4W;NEe9!*sF6d8ld z&!4}j=A}h8PZjF!`@?EUTxXM`+vnMvtb6VqHQK_DNT>5@9+O_ahH8Bp)p*n)vhA$kSw)^)K z1zDW~UFHUXwAdqa&x5W3JZZ7zz6QQvB?5iqIRE#{^Uew9l=Xf$rBv4X{UM)5?;f-PsB=kN3IrO@Za#_m-L1Sl<$o&-AO)CWdBetIb)HB6Wn}94-~Ce>{g(5* zlcGc^vcxZz8z3C8Axl0$G{InJC@GBq$_Txk=jpxn8~SA~Hl8<6{ zz&X5?C;>zMW)N_Yf8}1J0zBvseU!@bFMcDw%ypjRKdo8*z+q`V9|?HKe;~xM5O_PY zAX~1y-fuB1xj(!SZ@2(82_`wGEYEtTCgI|&gWqZb^y>YUdri+h^0ngKE&%Hv0?rfE zCddW!1mqeLL=p77_J{4uCBKxEUZet=0;I|VsX`IpMT4T1&#;Cu0hF@nWGzv%*OaQ-#HlB`4o2%vvk0|Ehi12#?ICCF_1 zBa>k5=L9hT90GU$fdl%Z2@5U2-T4Gz0($^XHlTwu0|Fg9KkMKO8v*El%aK1bAV5mo z0l?ikf=Pf20(XDqUei;ek|!7t@C1Uw&wtAS@PPhpeeR6tS5(iJNx0ZZSpEw_93V#P z9Ds+Q@Rih7MgkK0ZD0Zqpx-CHT%cmSU5ht;XvFz5ZK-5l z47LDvKW4IM81OfdKx~Jpr%sAI5&G3Jm&yu76vfBUlG$9d;JhAP|QQAoCT~ zS)2eoby5-J0C95WJc_`q@(03;xZiS~D*=X%j5~h@fnaF1KO7SbEw4sN@Es6gw76#Q z+g1d<+0F?2+ZupCh&|RYj;p}P0$c$8dzt$zsL%8U<{UtVd@V3{D+2-v7X(cx0f9h# zfC!YmqWb6Vnat;%Bs@xb9i&Tb_Udz{fKL zJXikecqWkG(*y*6)B-)>F?-4LI79*nfiw1%)ov-AMH5J^GgqTCRiniE^?y)YVbUWo z4NBlI{^wT74?N8`3&6_1i6z7-2&8`9XqV2=9X4{NHKC)w&%7?}yjs>Yt=1MsfSJHq z@`JV5rS--C*Y0xJ@?{T;Rio6=P9#oxD#c5fI71$z9x z^}5uLtgJ+i`|m9#BYnu-vsv8H?ETDa+R^0n$J*;uJBk+<+FT zd`hD##}l?Q)vo1u{_s2T;h|Gli9G1OPT)~Ks3(!*CC?~eD1wR?ljdJKm)Z1*CehRE z2$F!*#6~c8w0y%8cdqb^F&eaq=hkYqlL!a#4A2?+Z^vnPTuRIlWr4DPVI~4Jc-@sK z;=QQTTl4;xE_7i-a%L7uK5YLmRkxT~l9N0A&mp zy*u`jn=*1C=zh;^OEx07M#^F~iyvxSL~l>N{*s74-C~5TpF~I=^k~W7`)>C3TKeX@ zfAm1l)vmlM3_Nl`E#T55p@jypDwpvOeFdbXfYl6{3`dvSvOHd4l>psY(ybiPs7ckQ z=p0=^okuj4S> z5lD)t9yt~uR^Ajjjptb~Wfz$GOx?K&`WPhrL&2M^N{N&UB>#itRiUn&Md?oeXjwBc z?KRNrcgOzumU1ii7UWofp!YdSbAURH-LV8*75oeHv_0NQ{>^mJ^2AOvx^rtOnmSa}LfF2IzF1|GX)jl5pUt4297Zw1 z4hEsC>n&65tT4|^Il|Pff2B-(r)k`yYyaZ~&_ArB-J-tcb*nm0Cq<#ls1(8B@s5bW z6bb7^W*Ajna1^k7{^2gY|XxZzcx);am}7mcOe zg_=MhshWzoA&U>Xv{vo1yIx5n?SN|pJPu64uZ~-ivVc1MwYvIYhB1CO^?;!!VYqK5 z0-a=th-N-r(hj5BZ=t;hQhS~o8FAd+u^sw)>FUL-z2kY3FuqF{36ZUKS=Bh`*+)uu{8`dkYs4xmbDF#@BFYUsA(sNh~=!F8$49 zs>D#cLx=1l9=xXaoviGhXzt5#_d&j!69+F@lU9H)9OP%5?yHOY*aXL#2i8uEzRSZ5 zc`+h&jE74M=h<}{-rf@xaVurx&&{uY?$Nr$Gjvd1{7jAd_ySKa($r-3nL*p?O_=W* zvu|mgoF;!Ot>kQ06}x3Aiq^fP3qx&`9AASAmSOzFEKAu&2pAqT2byVVe zFdbavG<_>Vkw^0?mmGRJM3jiVY=GIwX**ZLGjPS{)|y7rK>X(u(yLA579W(j1~LJZ*f1u8Zg~sBbBK zP|d{kH54l>N+-QLy~Xs*>FBwpK_7y7{uJAuW%6z8);_%6HXtL?Gr$H9e>C@`AmpBQ zOGacp{!tr~Y^u=rY0`^)4OoVR1%Kz6(`a2|XL-{h^bzj?zj4^SeC9fM(TSNSa3YA(Pe4PQuOGxD`%Mng|6YzqrO+Mb$rMH|A=L;i#E0G zyU{HT=x5DVv!=PK6j0q?vI#N#PN&XL)oPyr4m%B=L=OHhbW?Vof%O$|OJik5cWl7+ zdjDi2hE1lqMLxtOV;$^RS~tv!Zf&rZ$P_4*PcZsMjzZ1g%=PDsW>#GH0)nozGCzu; zS_l-p=H=*XQ)(q=RI<1=7_hO=-8Qp};ZDiAblYqTEHGk|!F%xW(_8M-nGN$+^C|P& zrCJVDG00Ww!Lo9vgfU9B*EJhVU&hBQpd0Ot%d`;rj0Zpm_vkx6NC9-Kqs1j^~bkVA62P zr{HmrHyuPyP{5XHwbN&@wXyX3Os4YI4^1DRe30wES+@eSU~i*>;Ct!NF}f!Ut*$!l zCW5c=fzO_C7!QN1Ck0_tH;LZAVZ;e+`L*f=wCd3$Mx$nnR2xd*+yZS#vP+D!0fmYb zE_`GA{0rR2X<5M$!L{tFax?J-=Y1PwYby-P*TlIvA#oB0{|v{USAdE!W)`R6C*=IR#Ecq6Ku9 z?@xk}st6Bsfon6o)JNWQT(k^cXzAzc*^l7}jY}vT!XGS!1LHMJAWN*GA=*CvWMJrt zMfmt+hn))LE%miwa1168xiUY2+2*x#W{jGn{OOS18c^&XJ|xILMLaBBNSDzTvOr#P z>R+k2A;k^@BM+nwqNgIg);5$e>p$EqYfj`J=C}u2wFT$gI`zTghO*Nkg2J^Q!LIRnO^QGb3jv-xV-Ri>nSdDuJbgSdkGH zdk5dPS1@~K+LEq^loCHSzcG6j_J*x_BAn3;DSd1KapP4&x4O0w+^T%R-)*By9(~QD z@f{fV_MPf-A>K_quT%*Dl52ETvL3ZRjYcl>hVhL(ia_ip>;khsgbe03eN{Q{$7MZFI1$0 z`}IDKrc5SnAfBc;*$ymN=Loy?OpT{i$Ii7V%H5GR<};s#^xT$P^bbl4?@3r1CpF|| zYTva{#qHonR()bNl5ef5rZP{PJSq>pUA-kJ8t@P>)NH5b#OB3nMHi%;^IL3ZDxHrNN^3_=4tk| zjD=@P8z~z0ko!nXk7_as7O@p*w0?Y}TJ{tn*>Gfsa6_OFSJCmrH&hQ!_IiKK$9v(% zY`h!E^t!ix`G_TM;3x#XW-DNs9tW-Kh2!zx?NCf#mJN6LtL_Nknb1psBX9%nT0(1Qkub>2_1~!Nn^h?&43&cUq#Wh)P+qqM6l}zQ?@wo3{FCs%f_Ny z59Qz=fG~@dX;O=3Bx;-~p3Hs-*^6&3V|JhQ7$9)e6|pgHS9e7a2rI#@%sd2BrD&U; zT(Z^H!TJ(~fPQH7LTnAy4GirnZ$>4;H8$g9+lgo7`{TN!gLMCR zYuo%van&5ioGc}}5km>Z<7b3_U5@Zq&ekn|iV-bnvR0ny=+mK3o?1#lNL0yx zWnFC2vyN7(FW|vCm(9>IR!KW02m6C&97rQgtu(45sX&;hb$v_#a{X z0pA`~jtsXr=r+1pC6x_~$EU`8+7DNN!TtDt9GTHEc%l}w)1Lpq-qaTAjwSN%%IDzTizQzf&*h~f-^UFH#)<6 zJ`hyW#hCYNIjE&fkvjYA#_{YCC*=rLP#rZHNC$^0j;1bF>gQNw;hf5L`o0b&lj7QB z=kM7d{8G~q=Vb%Epb-ASbq>2`~#V$Bpa zOsb%AV0t8au8K{@&(Y(kbo%SoNQi8Ud`{qSajL-nATUK{7aKqhXL_?H6P8Gj9p0Aa z`eVg?p9Ko2-}79R^46&I8q`2u4NaRJ(JLetqtSJCLaz!%wC!P!F$)bAiCM`Xcrj?Q zG{F~{D_Oq+$|R`y(=*I)lVru5+0WgiA5=|TCGXrmV%C|$VF%kjwFam^?S!pmL#~50 zi-ikg$Gx4+N+~R*mYpyKvj$6A-CoUJ`hHp$c4alvCB9p&(D`DU61e z|GF&I`-52BNff8}p|EP?lEi2Sc>H!Jna>sO59QYF^(>nOPFAXFIhG@NS8p&IzAn{ZDfQ$KZZj8ioz2o8 zGr;WJA&cW0W*l`eZFHWP!@LWSTeT-$AMn2*X|v6`<;FKwZJlxB5GjYi%)xE86mk2D zE|TAsc;g!mQrjCzYH#CLzaTH8if=JuBIMHe7k++e%ufv;?+&$7ss4W6S5LDnw)|A0HL8}cF^|}QCsEjpy$(F>VsNuozXL<`v`kVkc2-(Or1ye4 zY!Eq>)Q>XGUKB;H4XZJZ0NcF=kHg3Fb4F!YtLn^W#yyZw0o*Y28qWk{OK31KRqUX< zyXhq6YXsC|3)$Bv+a;j3Mme(J zohz|bS}KuhKxZBuq)RFS$>%Pxrx97dbGT_CMCk3UaZB;65yX(va zkLK{R*E8(HAd>UqL(Y?Hg8sr!*4m{Q6|(A{wQsjOm7_dP9^()@;JzumeIQ@ZHSHI< zhOyg18Q*|iE~j+#W>)Q3#6jE4D)b)CN!Lj$_>_GstQ#7WCCcfusFGB85ncDxN83rM zb?jwX0j5_}%9yqr@{t26*SM^E+?p7)mt9>uJC?#vWY3~gN9SajWV z-R9?uIl$|S2Yw0hmZyXtGA$_D%VH$8u-w#P5GaP1( zR~#8x_Sm8|C5>GfSQrNTJ#Llt!P~FclajnLdg#2-JK`&z9x`|uwvvU(F!WW1NUfPN zO~eYwIG+4EUC1tP%+5@W-APZ-hu|UyDW#@xeh-J9%X)3!fH(&G@fJg#LTX&M&n3Pk z>^m{v_rF_08h2`e4DVSj01bNnDvI5Q12=D5Oun%rIG-;}GAQ_9VQypcUB(tQDt?)w z$!n^7_1!mP;f|Jt!p3@S-n{{xu#H0tVBg4B)_z(tToCA!KL6-&Pnll`D>d&Q99m4H zx>nzV>|(^MHfuk|Wdw@T@Z3yKM=*Jj*`h2qI$B`U1QIT+xsdVh>6!p@Xq#8>ZA;O4 zrl|2ds*w+saGQ}hVE6I(_K#OaL4iII$7PSEhHs8f@cMSSSfm(^m6#Lt(w;O z#kU8~@pu`j#Pok~)E*2bYOt)<`!tDZ%*qU8<^k@eo8aKoilxTmul4V@HTPBwCF}31 zFe^H7+hBS$eH~Tc#}_vi#i?|TOEr8N4hPM;p$-0gP720;ypv`oYE%3|i!`!rGH~&= zc@yhmx6{sZdRaHVo|H|$8YdIJRDj1z*bL>pZ*!dyULPH)I^p);rtvZArRi2kzuK?j zwJ{^b)<%lmZL(a#EE6Fb_@oHr^ z@via~KWq%D9ugGISjKxBp+eWvbjEyFa#gG=)wxa4v>z;XO}$ z-+i)WggyE)Dma-D66&rnQ&J^u=c~0C<)3x|gHc}P{Y*y0C)45@@Oj77dQsfc_mz9V zY6OipZwEcTHQQuBy37kY!*SGGQ0lzZ8$Ekdy18TXsNGH-IybbNy6NC%)*y!(erm=# z?_ut@+gP`|eBaq`pgadGbSgo;klXfbH>M;j-A5W2G9kFptUj;q?V;X*c($cR37jNk zi1qgOS4Jm+{=P-wq^936d#Lb|Yc?Sftf>zs zuI&SSN>z_Sew9bKpY41*vyyWg3g4=$rxJ4Ef6c5RRAuBuU9wslYw&#KX7 zDg0r@WsAgD+OOfVfh5^p8d>AaA+UsmH+FB*M{)YBDMPR~Y@;_ui?FW3R=f_3BSm8a zzCS5kxFdUgZtpkAv~~m~V4GL6IK3%SN`2;?0;5ei2oV+3B>nvmnuRmN;IH=|ba{X0 zC;vH9WZ7MgW*koUUyah4YvH$EI_J>Y^8<~uuU-L`Qi;rY#*@W z99zr{n9yk$Oq!CH62p&oM^&&l`hzRYp6NMIE1!yhSJmQoYv2Mag>~;QvL=Dd;hqhF zA6=-^GfYJg+qWH4_{Fd+L9P7-hi#iBZit>?$4I1%K0d)N%xg?zpXiDhx@lsP9v7we z&U@~XiUB&~f_;>+A0P50Ow|Q#rKL$bL7WodZiU}If9s|E*F4TG}fbdVo&B_%4@0{7amg-(-Q_Vy827>l)PVi8*u;Tzgj4N7WzGf?g* zYW27h0WRI=xKZbX9GaN4+E2o`S(!1vqn~Z3PZ7?g$YjE)0o!<5hv5}Cmm-hCrpsOI zdtUV`&b?mP)}Ic^4dtCb>5?s@!}JkV&1p+O(yo5dFR2kZXRuF14XKWn`dKQar z)W2M3vbBj3L7ULTmU6&U-+wws68>!&hkQOmlxRA*{jO&VHh2&*s~uC5dc*yN4atG9oA(8!Y2)^+cluWMMviHNvrgA|5PMyHu{zNK=GX6uPmBoikH&Q6pW2{iq(Y)++EaduaUcZlt_0|eGG@aZFTdLjXHE(tjpy@)8mrMu4KuV zt4s8y>fz%h!!{p&ModwT&P9qL+Q2uo!SQ2}L!Lsak#Eh4g6M(s&euc1`}>vUk(=1h zg2TcHb&~1yZx{Tl8Wz2H?>}}UDb4aB4y;bKXtT);s(7JI%{7QnCnQJ?P zm=winma~TBTiu<&Rw0RPPIQWFL!rfvjLlkNj=9ey!+zIwra6;4cH;gJXf$#E+igQH z#D|5{O1D+-S5F#0c3Jlgi!g^$E-v4=a>c>g3;kB1s0q>t*(oe~i`pw&57Gf<)3;AD z7&<|$-lMaaf!jiLce`C%;Tl%q$2tuKf_wV!;f;vH5UkCnL$oFkIs)!gTp4Vpmco-h)YDSZ$Tz5&-R%{wl0NLyXKl;%x0^hfVFL#Uq@66)Mw-k=1{S9R$>?ORY&k= z*MY2i(#+v;_pOQR$8mRY6)A;#(%29SJ+o_B!z8O}hG3l-YnH-)RPMuOj^9&D*fip0 z3_ee*lg26sM2%P){y4Q1WrDz>cAG;3t5$UBc=4GDM#sHGY#IZLY6{;9X2^ct`Bwg!QI`Q z{>-Hqf&F&(#|)bhSL+JuC~RY>UJQq8Dfa0+XxQQKCd(lEek8WC5tw1Z*|{VABWkn1 znB$ggTjS8r7)O-=d1A6;u5G3_Cl>rOJ(Wd^HU~||W=oCmp2-&OA+b}7Lvkn=WtRTE zVqO{_$CZlk68xZamHRxr&~VYu^@ri6N@%he6W^HGK1KGye$4Sa+@YtFH*}>*(cFBD zYOGy5vS0Q{)kBhv*}E8)Itx+lw>t@eAsud72;&0fght43QD=V5rBr=P)8y;zrsRyJvcyqv>9Pk9E{c-;8@ zPK)l;Bq=KI{&nk+Ll4zRI!O{EvuS^W;p1_gx-j0MYy_W@Y07tem)D{_@yM@%N5Bxx z@G$Yd+O34ck!7jbA6`m_YPQmlYj!u?p7y9MTXXixx`J!0TzlR$S+1%!;$D0S zsSWmeTrK3z`F7YM%!{Pcrv54 z=ZCW#Ll}hBlY>JNe#n8wR00{9c}l$b%tmBRb)`0}0X$bb*vNruA|oDT+VCb`T87xm z_FlR84lGASwqM-fs1rUT9_kAoo=9C3My>_S|6FY|6>wUixPAc_j?MRz+~N@>!78q* zu@pX2?Beb{3U^oiHTR1$8YK)mkjf*v0X?8c~|ef~5J zkSD4mh1oVCo^K9Gbxw}jT-Bk{0?D#5VdpzG-dy_O=pOcoi|=J8!=!p;CZShCWc8fHi zS6|^6HhePp@49zq7Mv(N;h6eKUy85!m1d&6BpfR753rWkOBM&@EBSHOv>>jF+tjr5 z*knwp*T!1B`QE^%9lBd%^y^#6acf?!0U*C{pQiq%++hRcd)9*Zy@ayBLtEWnO;5`r zj1uR2nAuHo(BX?QJDZ1GRFSb8FMZHTctS7#FqR)?75>o5DLlBs?2E_@o^K0qP&^rm z2WAfcfxNcwUUtwK>}oBL>30^D#ym);KE9PjQ1C7!;kFgp#i3oZKsI&@+=rOWcziOQ zS+CFP;oNWDAOcg#2)G^dGZ412kzl9OOiFWg#;Zh2HdK>mp{^uMPKh+hE|wND3B$&0 zMR<-9U$>VVVCc2-Y5tdlmwQT-kFI2&R7 z@Ihv_>?!0miwvtI&bvhK13fPy%|wZA3YE+ulD^_WbNSXI|wPmn-zCH z1l^fBMEugYiEzY7KAyWR=eFXH>yDitvE6Z}W7>CiZ8cNNGQ8VY%Ap?@FPV>6&9E%+ z0?zZ$xLq>9bJd$ImbhSN;fy4}nT(;rP@=;(hA$ljF z?>VhGBGrClmyQmN+EuADtmgTkuwqMk*Nu`1_PHXM`li4O{PGJv3+robM~?9$-ogp> z^-rENsw8F#51%mU(35BSja*r5vN+mG^}8F`zZs0kxt&avgQg8FyZf*Y`=;2)Vkd%F z#UT2qV;~-+$Wwd4G0e-Zawh&~c#QNVK2k(X;;av%aVmx9(Y=w@Ad?&hlh=eLmjr`? zrGbsu_c`%(15X$vmag6B&f>3{ecpg+GbMFz_ZAcCbjzOIualpzcVl8O1_e>LVe5}% zep?@F72z()$7OGP7ARCb5vlAi;y%AhHqEfCZ>x;YQo6StTxawm7iX0ZRO(=X)WlRHA{lIJWY@e%RDdS2N(#-Z9jD*LCyFcI!bZJ8OK+$uX50u%lYkVjcxkMAB9bB%+Y-FFpB$ys8BPs=!i1vN(HKaS@3m?HDxt&RS2J_mLioEC$+64IVNQc~Zz zG|_L7lVS51eDNFI_74uejc(E%Skvm2DGDv=PddKg^-pd`X-%WRId_Yn0;%t|3u*S) z@1{_s6g7YM5mi+E?sG%AkfOV&;eLiIZ{C6ni@y{_4G!6~Z!~yVFuMDDgNt^_pO{t2 zp`>1;vzTOHuHmlT8!Pjo0eKTA7H>6g^sHjSZJA(EH|pu+4i~NX^-bGll6lC(`EY*o zF430;$^EOp>^qs5m0yE642uRr$cgw|B@fmX$%#YBWtu74Nnd9?dLL9D5sc(U~Cx`HFI3u5~)_i%zI4A&~ zKoZF=^@QxN7yy$^XHbhppa*);RO89v$=UeRdBG{ntDmH8@$&3Ng zgJs7Y2lxxLK#`b>ToXk-)durqn)Q@P%F+~f1A5cXW<9dYe(_SUo|44lXh1NzEUXFCWprKSbShXj|gMgb#uuA z{i~!guZR^#X{Lq@0>M55jp&Bf3Cyv;{@UrU1UI{4@*bB!ae(z5UBScVU zw>&Es;r7ShGT*xM=gi#PpR%ouL2%d68Ku~?UG6Zo;+x7Yo_=_90jORWK3O{vCVCSf-5X6^Uh;`-_5nQ-efM06DQ z3fe01?kT~)20oVv-uXlr4L%dj;`i4W!~$G^W7m))gtFu;HEu-~#*|&GD`#kT^2^IX zjb@55=J=PaNlvj;PRZD7!2niT7V#wVoa>VFpm_Kt7e2!fqX_JLxpQ-1;<8C5Rio|3lDzy zNHNvg--tQY!Dp^}@_9s8$C zpVmJx6IekoWrBlHuQ`m1FL@!%0;fl2JIiM5p?mdMhFL4?V!2JO%%3$d0hCE3qUT%p zCkLE%!-dB^>n-3(F6&b&bZa zb#>82erw>9ZMSF-a<9Q}mm>GVYC`X|euVDdV1AAIHQ0A=*Ys4dKES)bRTJHfM^Ylf zEu-x)KOz0m$s@s>z&igZr&;dy*_o0h%%i$&Y(Vz~JrFDFOQM*Ss3>+H?GB)-E*Ss$ zAIMJ%VUcUAqE}C!xwY1g-h*@sM0xVeZvpBt{y4jtd!P_C{TvpoK}kU z-UE5<5Dz%sb<1M{Mx!(12|HXy^$brSCspm879ahZqK05Us8FvRbT51NG%>D;ZZb}Y zFVrpmx}6Tjjx;`mtS_vXx5EPZss!n2HAjFt9CTZY={l#>XX~zwtNl{0N7|f)M|>hJ z&x4OXc2*bk^F|maAUblp-<%AbgJAQ2>LQ()JlEM{r`Dxnb+>~3tUcf0S8Av+%VWmZ z1%B>N)MXgGW6p?s67x#wGnqfTEpSc;3Diz+qw3apNXD)Mak6agv*MrNk7}v+urKf1 zZ{hTIzz*U0TxAR@7F~JA>F3``abhjjL`$UQ#Ez7jd{*3A&D#~}Z%-daklU^2-QV|i z9n2Ll|5_#i6!E?Cj~)cd#c+dN0q(l))6jy}F(?Y|jmf+(1eq6d3#n|ZFkWnBG0yRW z11D@S@Yf<;S<9j{Bv6=EE5@I_z~r+@bU&F+illz`S^V}a;K_0c?Oxb9Sxe7Z9iIv@ z5wLlbeX;4r$FIGD9M5L*Z(I@?;;VG}YN|8%m9d&83rtV=x!ooT&hu*a8*B<8qtE zp1R@WzJ(hz_tV~C!nd=kO6Vqur(9x@2AF%FB1(jFEl`pNx`H`#ink`5&J9+x75*5Z z<~>~3b4U;NeC9Egi$8n@4-RZnK@K@vTFDej+zL%kmMb}V`?$#OWDnj$O`={94C_8| z^FD-@=JDQ_vbcM&9)Iw@YRxQ8v}*X_`>`9?>x7`YlXsL|bN|J+^SHIi-b!gtpvve1 z!jnUJCp_5t!9r<&@=nb0bkZt%eX)A3fa1ibYPW%-b!oB&tm>l*o*9qoS3T%Da;Y2i z7=Me{wQLKD?Y=+`*@*7V(Wq-1D?n!vC6MIT4iXNi7PH$e-DsdO(=$$W>4on|OD&SU zJR81PMQ%ye${U%J_O9U;Y-i0%Sijt51iyc5qrqRdKHU zl=kHp56PDSi)IM4F0`iyqJT#ph*|n#$Pq5Oz``1j?Su4rBK93mCMNDAXE+VTuwZ~P74QBEJW%BW9bUE1-W^yv+!&*A zo!s)ox->)VxD{|e`(zqhF2xddvNyHA30SsS$Tj6ESVhQiHl_{51$*sMS~_{WqV1LX2)> zg!j}6u~8BocC58JUAAz?vQEOjy!S3JBZYATBVa+bb%Vm9bc-2sXqw4?S5gs!a&m?5 z&yw*B@6_U^?Vw~x=Bnx3olFGPVXIVeUzi;`e5aUS$T}<5UCO_i_5$YQ7CkzLhEb>u zs$NLd6pC5!kH*X{x;#4G@Wb8lzKCA9^__XwI&o`ibI;_`olkt}3x(Em_4?uiuLnP+ zGnlF^N>%Gyw`~qK!H*a`IXdZYWV}8HWiQ#ku`?E#riz|BL}GS}&!b~3^ykAVhIb~6 zdC9ru%H^uMhaQJ{9iCiBm#egFH`&;vjIerZa!7tom^ms<% zpxCEDKe;C0Z%8AWxWOrC>I8vu@(g1M)hnxsq3%b=LuX5?ge=*@a?|bcuqZ=xkEJmj z{PdH$U{Vkp;C-!N_mrXRsgjrX79|M9csl}fh2t^w5W7KQtvu6mIOL5}c&amsng z>fvAE{Y)DVf>>(?tEJ0A+Vhm9==u)6tlq73)r$JEALJNZEnsb)b7#?6n6L(6r!8fN z+s-gqemIyOl!7sEk1qv!G&CPA?<}-(A*w}1FPMw98aCLuHk#!J_W1<)&ts;6%xSP) zv5yE9G7NGYaKa&1NGJ{&oqxy-9TwmN z#;Y%SDkTW;Fps30%>$NV7pOA*xST1`GI+1hEn|w_6l(c+57kDlRWtENByg!aW>lwf@!usAf9TyO)iv=_T`)xag{Nm7Ys-I5tZBZtB1Ny3ZrR zC>>EPO<#Gj;YUPyG}F;YSS#jZIzOkV+o0u)GivDTrx>rTor5y(>Cysr9kSM?HVx!Z zoV`PIxnvJC{e;q(nzXd+y(v&F)))!u=061X%Ro7&f#-0|(T|ZfDs(h_9NoU7tXZ^> z8)01|7P-CpFPwBQBz(k^iWF~S~svz~P#S?I<)T3GW~;r{855PFJx)R!e! zye{6`>ujP0icHGjwnh`Twj|j<1;a$Inz24ByZDlP9#-^ay#`A2%cX@uG@n!0`@ueM zglKz0&7+uCeoAVr%~n5k&PTdmV6)LREcH3efK*snOeMcx{B~Zx_R%r$D-OjU4H25r zOesqwPEKS|fO%MnK=KJ2K<)rcZhuqe5ElhcO1|5jd-le>yhorNxOvxRIJ-Ze@$6mn zxaE^`DZ#BpAJ=PWl460P!YG9cz>BD$=gW<)ZCb#)1_eD{!fk$Mz5Z+m#dScwT-u)id$;)6bX1Q2XmC2p};R2&~B> zYq2*)&fe%(bIYJeDIWtL3I*&c-bg$96$8+^uf@QPwA6P(RsLh? zsA((Ph#RAP^!4nuewOA+gk9s8S7Qk#Lr>zb{BG+JT2P9a7-A^sX#@MTdyEp({_Tza zFy$%NBU+im4@7g%Y0iFKBH`g3TjUG=E|plzKPjL~gjdo*y{^sLa)I&^*>B+p41}8GW_Bsep6Oo; z0k2KL9W-B0e;};4r|z>HRSMKd6AJDx9-s+lY-|HG_$|8%5|})i%C+h{mQtjI0_< z!p>cI&hg{P+|d<*zPAO?7268Px` z;FZPyzTqd%7edbR(VVKqb1dT%5}y9R6)6$EV8RF=t& zvPSSVb2J;wdDuy;JhSj9G)s7i+Q&|K`aK{KiHsD6A_r!ynk|E* z09}C>@2|K7Nta-AoJR#u*T}YlTFtUWB0Oq^mwSD=3)qxt?UQAD&75}pb2oONFtx_Os_o#4&E<5bbYEH5TiO& zksFy}&($)^t6OZLQA2fbu`u^Ot7gJ2GZOW4u@z2k(PVF*=8EQKU&^ssd~eYl=Ejft zS<15)LwJ|(qsfB?ijRpiL4I1=(XAfPCMpjiqgoLQWzD)3?nAC+GVa_sk?pwi3cZ46 z_*@YtBQ7evudclrYx)iH3<;Eb+%2=@ zTM-?s{j5Zx3eCcdJZ6cN?4er$yRm`elQg!^0p?hVSazwBS9nDS3%)&2!?(qC!_U{+ zs+-8O64|wSKTf=*ZlY%Jv+|TL%xm+sUXj%-x#(k4V)~lFNG7Qax{p=n#2_Oeg4X7@ zhIbr{Vw~MAi-Kg^yL$>JW$u$4s_Q`SCoA^g>l8`M4b;fh$<0_bP1Hzu3gea@81*J7 zl52i?q?Xpj6c*Wy{y2s>h}e=P!_K(=HtKoxql@03y6ToSV73w`bW)OK+uETT%$lYu z8t}PfO_MJP_gN(XP$WDDliI%b!9*r{=ZNknC@O?i#3{OIHjfE=*SF{%Env&&Bq87| zrpv!!f&`#N<+}Z&)UeF5?KYv_9V2WqE2DqS{kCoQURUnr%Y7u~BxXHT@wE$Z10D{| zPjOVW6*lMW!VXSn0>@Z1tFa$;e24r~S{4z3!v~wf)5IS^or*76lz9rNE9-3y6OG-S z-thGsml_yQhiI1N7aHiaDRFbw^7kj(@!z;*&Zev%$L$7E2X(5voEExCYM+yhY{k0m zcnrxg4+XYFlxf@& zV0PkI@rZwX?fT*3#FA!g*7uy#F6FA&&vYN;S*`&h7iB&tsj*!96_eoD z9~i^icZ!i^h*6c>XG52CANJeqjn*7&lcS4nQtl2yYAxhmd?^e#pUCz9sQSjhNVj0y zK``M=?8(GN$F{AGZQGpKPRC9t)V)@80u%^{@VVe|zn!TD7WnwGgfZ z*0;dPsN!u3|C9@f&G$vVKe&SmLX`5`7taB4qD^S)@CTc>H2e*J zUV98>Y7q)&ZJMU@K$;*7hTOq<*`iQe0pBm!AHgO1VI{;`xO1RnDC+dGT1r8l*H8?% z)0-39n$Q0}l>qGv#2S0Ai0i%TZ{F7dpYZ7CYjGtl6so@S^xdg#uNvmyuoBm-kmx(J zMKqQ8^>%3zawMT_9usevWmKZ>~Z=J}>#aeS6#3Kg;3P z5ab*^*ZjR}(x{sq62V_;&LQ!k*jWOGZ894*_ape1ukHaY_*!P}VW&`g zi~9Qu{{`urf-m0&p1;7tJjKIoR%?dNL!XBl+mZnLaDTW#gAOi=hIBrWXOnEsjP_!{ z?bn~-d=c68f=MK_v?-mz+#XjPdvkc}R%?^z4M_^j-rwetq^ZJtbfA7q3f zWqm?>T<6&i#iwZpTj=J7w)W zhF8Z6bO*w|z#kp}UY$L%1R!$@dGQ{YDVHh33kLeTWex^{&ts^`!_B%+#yl-X&QHSs zY+{DLK$FWGROfT}nf`hXR+#kWV>o955r5rh5>u_&Oe%g0K2%z03J97ZPT(wf`qoAYuGa^`~7X3HUj4>~JK>ua3z+DrvH>izv^Byl$zykLp>a%bNq5 z|J}_1^^%9*cQlto_|0jSF|}Uq0XQ3yWF@MZ3QA94Qhf>e#HdYm{>jEKh$i;9B+d0R z1w@IbW)90ffB`rR+H;@hc-gBoANNE?l^Wab{~Y;_JAg#f0bd6GV>PFkIt-`Ez;z|6 z>14L&Qzl*d2RlDSKbh<~`fR-?2^pVe2n*X-K|OgAA)3(Av+$1Pk^c# zm0%-71SoPA!{ubEot=N;F`MCq%G-q&2*E}&ruKXHt4{R(E;B1ciN~J6{8Jz|ZtfFP!LlRb{2~YMUSQJr z)egq^`M%59{u*?Y?UNR?+kFg}dsZ(8L!MRG)!@JOu!hU+=7-XlxjEHL6O;ruq=9=; zCy>5Q1_|tz4aWfHeuJD-%WW_|jiR-ni*9}#iFt9UH={F$Po09T#)O3xgIkgey0y%B zb`8%M#!8~AxE#XQB7F1@Q7lBXKl)8_%DuL^;EN6?>9E4VifAMApR>3e9}j0>&AYNu zT20@g9aqUdrR}GPNam+7t4(q7!j=oM%ZEb1rnJo9;SxD(!%@N2-t($RQ-DZfnnA>u zpGS#J{tfP+EqBd=-li<(%qUhH|z3CIITs^r_qldwSGDFq}s zKWfMBIIKdW)H)iYH|hSAigVT7mkbn`0%LwS5wnCTRjQ_Lz4%Wc^23vmxeh1?GMt?> zk{3x53|gK2dODpg2Ls{SM0(Eo-GvTxNoW&x=Vb!K@0t5!{#BKW(BKJmgNW{ct+0O< zdyUw>oI&=@1U+OcGK^qKK60^ZD8NJjez=!kz@8c}Kz85lfGDaH?x! zS=(JurBO#NNv&q^P0O1T%tGM_ClAK$hm}E;!deoOTZQZe77GjS@1Sl22gYvFPli9Q zscY}mPm`2Poy)K@C3gQ1liQ$lCgC}h7D1u2$y;?JobjA z?0FVZll5_v#=k*~X_}r+fpkkrRpjoqPSzb(v3=n0Pl!^CtrMGTeSRXfBBjfDjMK(% z5qccoA?@Bd!v77zKhCqr^Affee!obaSXA442VbcB*7!{iX~-9u^OP)6fIYLa1WIlc zfLMW_ClmJ+My6U@HD9)%YASSY=&v68vxG{0-W=(CC~EZI{oG+U|SEsv*dI*ZTga zQvS^k6np5LxXF?W^URJW98z>rjJ0fivCScU>iFD9Du){0aR2MJz8vR(&NoJ|Syx*I zFLBZma7cuW0SNx&atiE<70B{op%IszRQyCCifrTSO<}M;JQ5uV&0Tch zXXLT~w;yHtm5l+_1&eaMcD;KI1_s0WaDs-KH}{`J^av5q)5#-(h^K^@2~JG6+@xQ` z0`QmzAG=K%dv0lr)&Xl26pvB%)Yk)$%So*4Z*v^_kmWzbiPST&%Vi{5HB1`PCM+W?yuts{gMVyq-6X$ytD!ae{6V%;q{Hm@ zliZnft{2F13dBmJGz@OT0Sg2BK?3aGyDwGF*M(5T4EauJ^M_XQRDSZ|@q_k2;>86!$Whi|PqtEk$vLQftb+G>YQ-zD zu6{wAur-*P_F}2b4Z!zf$(Q`8Ly)&r)oFx(LOfy``q{TN|16-*=d;WZk6F+f9SLM#*w>@G4L3>>+ASCr(j+@LeH+PVTF-mbIwWa9$Tj)7hi zx4whZFEDE$!+gTnR+TAJxw3!(hn{;w*R^AO$|7R8q@vWQ^B<|%18G+FNr#a_BB}S8 zjsVioknQCBME$rBXC;Mcy$9R>^#^C-`k%=#Hs&~uo4oD(U+evfQ7B3Zx3P;IU|U7J1&$jpD}zCby6*ioTCQK zSg01Q>j0Pjxg35Bh7wt+Yyo>Oy>sVJ-I0`&L`$(=p`2xuL<5w-I!vIGD!2=VQ1{|O zu$+IM$xMr2^^4FXYRuHQ>EehUqissht{)C;U)7JaUI=KpC~9kB)Rd}P4r33uk!Jl2 zDQc1i%6(f?Cdq-;k&%Xj8}(~oY+xKQ=eH2 z$F#6TQz}osf4P&uJE>{I0}KIl#@SpwgLWBlc5onfF&*0})4z2A4|s~h$UZ2|9_||@ zV$k>rgm&xMDd;PVj+`K@4Awka_V2&CBG5!Bo>>8A?M-KQ-Yqq1)DE17PO(?WwDjvS zwNEXOx%M>OB5PVYop>m*%uHp;>I%(g(qJN;BSjd&i{;bitfnlA1_qF;^q{q zDTsyY4;t_IDOg?L=lz$$CDeqbc z4LnH}aN`Gp6v!_Cyv%lm>D^4an;oPQa4K0?7lWOxQIkk6JS*9Xwd9IK-(m9F43*TC zs7Iu*>V6HS{s8M5*v`ce)3@{Pl}{U}k8`fwb)aWpC-k6hrJGU`hT+Y#;%);%OzUp9 z`hZk{Hs|vt>Tt|hPXbl$#sqMLusskbD3CiSf2^(QEqEJ+#rMPg`AGUMA znCLr1>*Rkfhfc5swG+xL@8oe{spSq!^w)g-22FE&zk!kD^-Z0S)iXHCl{1=)6BZ8= zic=7;o=j47QuXyZMn@H~GED!tc$q~iz~aFI{^5at+2@z%(U=(vTn?Td%p6?xu#C8% zsg6fY6&+#_3NTVi9+>-nj|x5zKQ*=P38>?bVoF(XY8?-Xs^4eexoJ(ZwU61pE6ise zD6^)IaCj6R%O;-y(=&o8B>Vb}f#$wM!vX4o04Ju+>u{{;n{>`I3prT^kWx-vSlf=e2q$_R~6Ya+(i7^?0;z!N4#H8?YF){N1tY9<=DUlCK)!S`ML zrFI5kP9qdcAcIivE|3SJ=Uu<#tV0~NKmYUT=~miq-_NKzHg7wGJW5<&_!5z-3o|Lz zPFX+vlgaAo$r9$2xI!>b*JIiDf<=`FHLie=TYJBn&MFrdx08&dVt40r7QbbkuD0m=b_Ef2g;r1w zX;+Z<`kDfP9kt7HMYl}EgxcT439=zje4}3GIiC@!b5cwR-jh%D>k-8YbTHdivqFR*t>)v6K_nkwg6t55mj0hK+LW zAE9w-b~f^#Z0G@HOOqgK?$(iaPX8`kDG^&IrYwAW97%ZNJTs-}6<7*Y<(d`g_iE6l zaXlVy2yyKG?SdmE9U_bb29Wx_vI$z~*=cX58?@4qm)r5h@;fL`aw_j%WvK=4!9$;# z>xV~VWFV_FG93c0gv!Kz|3Kk;Qp)AahhP$t@cnocQ1cvRXSS19Te}g75=2r}kU7!cpsO z(LKQ??DeWsr#H!qyu+K?GPyKj7Y%PC-Z#4+b)Jp020E`PWxWrmU%a!3NC^&p75Lwb zTtt%5UMAuDybELQU-4f;mmdZ_mK?G5M(zLS%&zlqF&PN~@( zBod9IsYbGOQFLJnTjGl6Qb=NQkW2DY-i_iHR7kO8X($0L<;lWkgir+sOj`}>QYJHG z%*KR^X0{~A%X-w#Sj@oRz%PqetPc*m(hO(E&Egb6f}t)WLVRZY6p`VS7wVrsV}j)< zFLJ5ozf`--Nkk?@>0AD0rP-Fm@~=<7NF-TqDAQcmdw53Ixu2n8I)VwdNin|Iz!jCH zwjK5!oyt+O=BXZBm9&v9Je)mZ{{D7Z`n*YGa=(OG0h(krQ5TYyF3AwIBhZAT}M+r9Ku|dB<)`xceuAqTWnU?LPIoOb!(>oh?5=A)p(!0fK6yF8a-F zUY1~1KtDJebl)J99!A0Ew#4gMHt+S#;FN*gSJS5hFxkveA?z?rJcDA~LnIAfY; z*rXt53A;@*+y`fo&e=XT9o@lSTb`n3>To}S>#{Pleg8X;%XOS`-}f?(_QU;CVt-xm6MIQ0%4UegB8a#SwWA8z6sNHK$*{8KoTgRTeEhv-0Y= zKCZH(y3gi0e1O8Kx6=Fi!woT;;$JHKPt5a#HoaLo)=2FS+Yph1hfSaHG?b+{gOE;r zAeD)aqx5Ehxmo=dn#M*cA-4sGTX#Fj23Pl$W#LVG6f`ie#;$bGW-{7w z5p^<0f)e)8WSE|0D{QLSGVza?-I35c?B23MsNiAVxysVq6vWTaE3lydV&OGVRmX(f z#lj3mNs!vhWRmc>E6c=IcM|5FE3@Jd0b?k}+fnR3XHCXi!y>TNk!zOyp<$U&zSv`J zkoOwU`pUY{NY}lHe8dFiGYdoxcS_AYKTWC?IPko-N$2curXPYlg4Zt!P%!$Se5LG1 z*Se6giEJH0c#7u51{cyp$v;bAjurO;;6^fpx1Ofg93PxxfJ#feXfSG1v)wF57^|mM z8-Fj{{WBLJLwmP0+AQ_N#&&}*TEm9-m)0HrcFq%`y`l#iUf-X=?0ONQs=zGnRHbdQ z&>VEHeTey?sLges^6|5m@bRl5$31xony_{Dz$)(1)e4 zYw1E&OA4Q7q@_;>seK%+BiCO~2H0(P&ff2U9QIOhm7so1ovoza?&rD!ZIp^~&W7MM6N9^Z&)A@) zNWfutuDSJ3)#gOB)+fCTb%`zD4ZuQu^rJ&Gu5j7tDK z;{ZKMe+rQctO|EhRx>gwyM#P2JiAuvAqWk& znht|D?J5Tv6UQ9GwmnQMP+Nz6Mh6r*?nv{t6l>S(zv@-}v^%Hz(#sgEXi#yN84I()0gQ_Of+a~O_b%Cj{ z;PzTbT`x1dj64LnREwI?p`*k?-dbtPf<+&~f*BI|VzWXdWi>}@we+xeb~!tYZs#ql zL@ThJt#3WCw^(^P@uz>~s)ME7cu!|t%wH9oJ1`X0B2B<7Fn3}B`BEVkQ#kdD10F#r zYEp#;OAu_jPoD%ZPZtg zolr)M$Ka^;C7w;jW&@zgU`FDldFdI5Vycy7Xm9PekzP6}P&83xk&=0wJuA{ELG40T z1KElxSBT_7bJv)d_VnF@51Tkq{cqyBKoPGXz&0q()3n)MFTA!eOE6~=6E#N9E@76@ z0yWBCw7~T(Smsiv!z3!6Y`^))R-qa6X4hu#{EPRkSJ-=hohu5D^L3KO;rW+zxKM)U zV|}UT-l(*86VIn3*YkGK`)ZV6@nz{tT#;>p%8o};S)VH|Ssm7Nbu4?wg3#{sp>P$q zO&k;Uo1XAZ9Nu@N{#71rvc^VGr)#aC($WlZAp44b)kS6nPsJ04N=SuXA$SeVhp3#u zYa56D0LuHP3QeH?K$IU+DWLkLMr>afMU1*lN;Qty^ejEhSTFrura+AiR}q~=f}eR0AJ%%~!qK?aceYUv8S*cH~@ zO{kbKfk3tZVhJ�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�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
&a&eTG~ejLuQgo)nMXNW^Wlh4$XM->)wW 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㨞gLRLSk(Mwq9^r z92qT<^PW{g$?V{Zx*=f|Arv9Pp-wnBBW5umGg$pk9&2e0)(B#myfvk} zb}AS?vFd6mWg%C`KHog7&1+j-s%76+Q^(dJ3{YdDet$dv^x>!n(D|TCOm&Kh5~k_V z2BN6I6)@|Sjm*tOIwXpOI#3$dOu7kPdy!JI6*OostmH!;GUz45s0nEXx<(2h+S*np zAbf0Wm1D?zgYWsZsh!yd_zxr&^o0j3xeg=}<+UAGXKaGkJ=(csyFch`jAtxUU!MPC zU-JUqe-!-A{)I2S9U*k*cHesVWxg`-3oUtYHYL`OX8E4EFkH`bFDuypT|oBV%>$qH z4&0h%<-lbQ7^AU96Z$cez|53q*ID9D4uJdZ2&go7*=bn_P(a05yluP=|0mY3PIm?+ ztJ=fqksMDBK%2RpITCQg^F?*Vu$ZVWUC(zW{zKaaej;F>|gcV}+5{9ba(nRh5 zBf?9xJL}GA^+#5OLCsb5DDQekYBZ&|WHnk+vtU*!$18))q{&8`8=AF%6@JS22Zaxn z0Yer#6HSxm`m$=-~;EjImqQ;lQQzF)M-JjAz3ucvDxrnM` z$6BpkPuu%FxELu?*@ztA+AQ=q*JB;NsQtuiDjky5H@vg96XAvSLsOUy;N7phY2RY8 z{hRPvfbT5sP|pi!>vZQ_n4#Z8Mr)t58;($5Cn@oR2JB@lD2=R_GqBP0I85p9#Ky-SBE_ zHcZ^%nJ!(+z1wg~8jXDC_lL2chrR5PecHM}cuqNN(cSEA;IyWKUB6334Dkfv6suM- zlQsFsz@MS|c^NJj%H08HX%4w%EUqd$4Bd?~EOqRCH^E*BjcJ-V&k&E$HuRG=u^>p+ z_C!S)#&hf_^oBSC8@nIT{gz^x*4(Y}hfq;^6T$-Fd?tZM_8r4KU@_($MC*Q50~={H z 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%0DU zw=_IXg-qJ9cUjziNVQ9H+Knjt4a_MY7A3`YSXxMor$X7O*{ie%t!STN&HN>bA=FLp z2NU6E{@|7Eo!+;u*^H`Esk5B<8cLp1SQ=|`ov4@2HigrVUbn8UfCz6m;(Gi*@2lFA zPe&b4^Y|I+iNBW~yEVS+e@tW8t#-$2xN|a;?|!pYXJvSv&9UUF=(?SUQ2sSW8xsrf zs0kEYDR#w`!wTE|+DP+%`^-w@A1$152Blis^DQz&UuzaHA<6Ao>09-DJs(~1e)W>} z+){G%QG)76t_X0g<3?Yh-M6wX3$8mPZ9N&79$6GK{*JDl6U%>&R3DDmpBtOM)G0|e zB_Ii}6KJTa)m`~;+NaP)>hZHa9}UR3gIoO%>ptfg-d6{Wk{>2 zSmJx^GF)0a)2`-o<97%6ckcg|=zFvul%M@+WDp0-*y{p88wRF9l}W}|P0{2oR$eey z#&VXN)Xn*K-s$WW(-zmyK`*-j7rxuzw?dY)Y3Kf*b&wl?zV~8oNl!Jm>zLE$6=p5J zD?Vnt#VBheqPvJyLR9HO5adGpB3=&-=s|*NC5JyJbiJ}k99~6+dBDxr|6%GKxGUj; zb=@zvZQC|GwrzIIj&0kvZQJhHS+R{3b#ij=ID3!t8)l7~Rc}?jkFLw_YHL_eb@`iu zu^!@h6ccB+ku!sgdh+(+tKqkE!Dmx7V2TnRGu`CmUy6>Rr30e@74soIwi&+H|ULbNcCke2A@ZGmYb#E83+_{e%#Re zG!h%M#z-jKDNk)sIGo->j%%dc9`w9z&6Nkq|4B(Wp(uIO&Z`&TR~Z1qj6%~1=M%)fEvuLPvWzg>Q*kp zo8XizkRxI>>QkcUZuE~lGu6;6-3c1TR4V;C#jOWXK}27G;hc4?|0g}l!HhcyiSENP z#^Kc|gg{O&;LO!%^A3b++5;}Z7W@yHhM)Za!9-pmOoC3iOnxugg3mE`um1v7kznhd zI*Q{E=#B9{-9~Pq%Rrke;R&zUcoEo?1%b5?-yfRg=%xEP7&j{8QfzI!=qae&rtph+ zMu$N{9cnK3(Q9v!;gUXQae|VF-cK5_T%r+H3A@;(jwocJnxF!Jg#ni5A$yF*%tywdi4W0~r;hBz%jpMS|vrl;wKc7Pd488#qPv;6r%=mBpLrBqW1soxx zh%8JYk;S2j0)D6B{hxt;EbpB)!Gg%7;@45|=fPfIelk@`oc`y4L9EFB5S`|FOIY`N zT;ep3Sk@*9S(@k5GVG3mh_(7 z=O%y0;C(Wb=X2&|Mui$5VL8eTrzJ*QnC>xtyN^gzUZf4}s)jwh@ zj>bY5==5T(-ox6`2sUz}kyc(%oQce@&cCAsupzQ8pQ%zDwalvFJ69+IMqo~90ca%F zMc**+ocQ8cpZFHZ6C%%EfKT zBEc#UmFK%kipvZEUE|!%h?!PPZR%znEsLIBKIr$WEJ!cRpX1Kc{lm}g@YUVrd$6Bm zC?oY#HCDg3o1x?LbV)k^Iy`n<{JaB!zj#+2%PhGKF!_Nq5R}o~+!;Xfz2ChbaarGY zd;SS1}VH$u7H2W#ji8(76FTH649`Hu%{%irpymak8C55T-bXp0l@Oq0Qrm z5l6{=j}q4$8i;6SidG5;A{JC`8~WT56UN3GEi5bk^!d@OZLd8c;b@ejxSKSBInhTEM^ zevaUKkB{-zRy~hfVI<+kHw5A3rxqe{BX$9`3%^IARowW{OMQod_ie4&+rAdT_5Ko_ zN|Fk-7&)7cJ$~nuOg^U=yDk=w3{G{3KkoTYlVCoRB}U5@?UWhsOvGCCxWq{63jUU}IS(a=L7H+puYo}C}@fTO|L z8!Aw}N*k?cI8@JHtL#`zKO@rEo|tnWNYbKP^k8nqTr=fEW-84Un^%qK$e5}4VuUVt&i2OaFiFO>lvFYyLo~s8=Il*s z9D4m4OYDmho~2~jVpVIHfWdhIq35M|){FWyub+6#SI=Cb(ORkcvQ1g;+~Tz*AQX-1 z>AS2{b0V0ZR36;1A?v#v#d=*VB@y&<&z!O^Am}h?`=Y8b&C(PbTPLG83JL%#FGq z&L<$qjO#ez_VzCw_v=w{7vTRomBM5%X%A1ja|jVWhoIfxD`_cPC|An|hm^{N3>xYM zn`|N95QH8@2fxU&UZ?W%15qRmRC4p&N%wiF+F#O4jl_%@aeVn5-dDMx+uZWn62*a8 zY<0jZR*Gs~G=yI&(x5-=d&@T&F8GD~{p|lD`1LZslPp+H;(!e_*v@jh^DCpICuDg+E$e(6tbad4X1|&;0)(i_<2igc*V_wK!fO(Fux83x zC6r7B&|Ru&O2|^aklikEb!|CO&_dz4)2V^DHcbWKkbnAk^LD(9>+tf!x*!z&76wH- zn{_r^Duilvs2YXw`JsV<8Y?tJq&GU^tm_#1P6AGB5_O~r+LJ{ia+`x!o5PA4TyVuK zL(rQ5Gu2lc?skMx?V$D`FEb=;xoh{(38bxE8RlQQbUaM9V2o^gNpRg?E`D+S829Q& ze~Ef?<9ok}%{z52ezK##M(bwT{~waB=8F8_>X2aE+brA78^^$U zhsVz)EEu4Ja>lK^91huMYkc0xX!`DG|Lb%8<8*#K&-(cT84&Tzjq(*al7#f>td8q9 zvc23sQXk6+n<8B>w2<@E!(UTe!d378*#&?YcTeSxrY~BAVIfN<&?qF4*LR3K4pbNn z9BNeO%gb8+Tx0YH>UKW)9p8*cfEX9@HOup55zr}Hn1)(Ofhq+TIz&_U zpCO}rargclL5L20_t6V*Uue_iYsv=#)Lqwr9$zI2LZXr zB*z$)K34cHult5)aPLDm-tl3C7nnmEup`8^c4)(7V9KfOSfIL4E@$WadK@E75|-D@ zU3=acMwUAXbp4y(_kpde3zpZ@0VpTJAmrmXKr+C7T!v%I6TI~p-+=6c0zU8kA>en4 zi2dbT#&sHkd$MMH4X;%`jYIG&2&E#6;#2q~R7%#qU)6YneeGdWEGgO?K`UKnhTY6a zIKgc@vcl=DJInBvIHL7@sT=$rnQoK|Wd{bp5xSlx-H<7|AnK^$jBVeA@B_(dlRaTevRGs`%2{MEUdIai zb(R))FV^YUY0<=tO*fs%5sYllsaDSwf$PI@I!xqEg=dqSL)Z4Riu8YbYNbkSg&b~Z zaC><=N?1w0I0UZKrv`wT^4$;JHpI^dEb4X^hXoXv%l?_0-y2-s_sl!r=auaL`lipw z$lC+d%SY1<3#?p(6L?zB!x8+J0l0r3;ig;fZ!5hPy7&@y&#LHGZ1keDbkiWWM~G6H z6{#7>vExz)Y>h0q3=JBGTUuZ+F_QK_;D64!bm#Cj%o z$lW63bW(#ogVa5k( z*}_i;C?;bK6QF6i9Nt#T)46Z* zFR8LqXWLk9Vr;Dz2Y;q9<9P2Gn0FDCeb4(nRIZz(r6LacyEMd;c#i+sO@4X##4^^1 z4^kIfZrq4BO{c4vC|RMJZ1D#zkxtf*CBT3iqgO#;aOId+L1sVWls4-^JB##sMJ!CyQ&S z4BcC2%pEYBII1;0n;jU91(qDTgJyK(HWk{`p@K3F@_hFyd3y+kRM)&}h#>jD0wcsU z_HZU&JlNFi&V)U~LOVQU+|p$n*d@fC=LM;v-8TdwU)L<~-N`c65ttkPy6%5x@AvHg zg|BFk=W_i0;PaIk_Tj+P@fcxTZMxB^{CLnBrr3+@@lsaG92B1i0c(?3r*)xId4ggC zOYU`%SzZlOY*3zniXN=wFIy5HCYNL9KwTeu zZ`DHX5f2WXp#_ij@7t1P)E!qTuNu)P4`Kc|ehMWE_%~d>b30#;<*-sqcBMV%iI0?z z)?<&9F)MD(Eo1kUX9@(&)}4a+pQC&MmY5#14Y!VGRzY^%PXio$-Z1;`@%$%>%XeqH ziL~bJoE&z&?f^02yKW&uUssP>7#GzT&-VE@iOWG2wFRMzD1+X2D0eW4wVigd=1iAT z&3J(q`Of7DQX^)L26>6J;F3YcRb`!I2r!=sT~n+)%ws765D~H1^g7^Yf%@*~I-+2W zkt5>dt5Nw-S&iX4^g}YtrLvid1lg>sa&j(;n-Wk`Hth_fm{~@wW@cSdHn_()^gnaP zeoBf#;u56M!lZZWV70WjWmN{!OA{%c?J36;y}VI!R2$(dm4KUmp%)&WNQsR5!xqPg zw5SfEzQ%O0vX7Iol!yxH{(J{Tj$XzjywrajJ1!+JkQ?wp!(2+Uq|KfMRfAB;Cv7Dd znWAwaI;iL@SqU$kzVb~07w(}Vn%D>-&xK&>jC%KaJ*Zmr@SH?8AFNHvzuiFht%L3G zcUOD<`8piFsN$`w|9AU8T8?hx$WId72JO<@c;3ztUuR9Ri8EH@S>WRL{4?XiWN_R_ zM&Uz*7aqQrV)$Cg$J5g{R{!sj=`Po@?k>|3fRvxldIl+D343}a)41c6QU^4 zJ-sn2h(vh3z-N?UfP~J{V1W?qXQn|DJ;hu*<4i~_W7cbWraO&;vfIgdwEJJbmvMG^ zdElJJWQXCyTB3PgN(*sfjHDv<4Ox?huP%4k+~j0@N7crRz(a}TERHBKGvsLKD-L_4ftrDG8C>fW6d zmwSFyKKA&v4(?evfk}>Y;9u~ZXkzueUfE1|-+uPp-oE}GH2imF$}XSo{|WR@zRnG6 zEgA<&seY7#UPzzlv_EoPyZ6F)dnp1uVhOklXgc+1Htlk_wt;Jly^l2-==2Dy;*7Z% zuTsm$NU7Oc;Y5)hbm+j<%Uf($&>`k)ot6uJK?Ci_dLPD{t^_A%M0{vpL^^FA@}UoJY=7X;GJR{ub$sCWYBOIM-j_{ z^l~-!qG)o1B=N8$B#4(n#BP&I@5#9)6~7xVg44HWW%inT=N}shLwbFJtbj z*t6EOTUjZPntI^tWWNv5p4Wl7;C&|+xAVf?t8e%#-rxgWzHjXJ5!T0#pZLnJoUVV& zcspDUQn$rGqNCSIguIVc^AVl4c`kgP3Q1-55Nx!h9CEW5+EA1n6rW;`e4T%;8{?_< zijyW*l_bE;86CzTE6Y0e`D3Y%-k5E9Qo7W6J{+O?Bx0h*-X`E*2zkMe zs;->m#nR~1{&qF9^KTX*^Tu3?=#QaD^$6t(f#udFt$_Me|ZG^4Na3eI?WNN z(m2MEGv!7p23YUkrn^rY7q{D+X2!ro8}7ec@S;cOR7}oR zK0@OXd;W2M18+Eqz5&L9kCVeb`^`)bfWJxkK3fr^wOKpUaASX+d}f_bEheMYiF^2u zAJLAH@*Fz6YY)P2&zu2jk$bUc_M5tGkWBxhH<+eZ;crz`j zS-v?~p~pt3SEzLNx3#@ZW1HIH@Ogp~c!cjKr2J#7uicdVuS=m3L(h3gD#Tu%$w(k! zj`REvk?cj2aS;!PQWI;&;c0{0ywX>UMNHXN5}AqJ0Hqk6U=Rb4Ep;gGhU84Qx@*nf zUNov>wfmDuGULKBOobOtf%DS!nmQj;&RJ+Oo9s-_5pGdIL4IS;fP?;zfb8;368sY8xfE zS$>syb_g3AQj#=+=xgn&oq?k)=QI1@sPK$j!bw*7ml9lAmUgH@EnbVP(95Q8=5~oH z`tj3S|X%p`(Y4dE}{+DU`Tdd)Kha`5Asjo{CTLwA=7z5hq> zeut}3b$+l5w~F9*H=did5m+rM6z(W)$!UngGUyydV`Acd0Ra8|#XH6(V<&o%a`#n# z=&h=t?z@6VBV!qF11_fa(1On1nmjBmS21v9si)_ecmDjkODPZz{j~rW=wiZtq{`+J?(|Kd<#W1orwfGY9pLC?EfqEzIz3v-)%R+bUOMJ(HHuhAe1G1oj~IAnz#0WZ|6%%b3y={VJS% zsRxmYgp!-|W@oXRD3uew8IAQJp#xv|tPG-Cs(JPfYU^y@250i94m%AMJtax0GK?TY z3y1YCvNWg#5&|LGb)A~+d4q`Z?E>Y&DeRvD1Mra`bV}oOIMg424)L;?m{)dpO5*ty z%0x0Tbus{!t<*qxA?KKUNM~=qOKBePfQF%44iBY}76SOo*|D0y1!8iOGZO$W4}eHk zk8Kkfs%1tcX)&I%o48>u;XbLqHU8T46bl@JkmwDXeGZ!aW4zAhngg&M^tkZ+_Zg(g#6fSJt&4g{Xe2gq9hC(?r9WzD zoABA?yZ2+}FvmxLtU)yJzghAc_XTd((?0llKLU=6&Vb+0=|KysI!u*dU#uSxX@kbt z=Zr$wbNyY9L450XtN*!K?;BZf`1^G`G%J6d_IymA^PQqQw&^af4~>w|wzG_&&cODy zxEcYgzh}6!7y{^!#_!m0q^5Z86}^hNH{fR1!T;F9UiY?G8|852aS?YoF62if^!P{w z0CS(!zWvwVZu3X(mnC=%y;WCNE%fp?5fnNOVo1AyW72FZh^7OF&-EnUwp(5FHMJAN zdEKTk1u}yX>5~2AQt|-YA2Y?T;@4dM-F%;OZvV5w@gY*JlgYvzpQ7U1v*ABn z#Xg_tc)wS_ug&;6ma~mpT(QE;6rg`IuuLRL|1@*=G1uj$w{zK`_m*#g_$3w`CZV81 zhE!YyG`xg-YSqJppTwIT4N-Aqg!^-zWuK^RI4`4-48KW$&3IO9y-AEAMG}=p<)F`) zq>%~16|7g&U41QSx)+!;FErPwEv{Wc4IA*^%Rg*#t(~)}ndD4;;4JW8o@SPBvgX@1 zE1Zyb^h5t%cRE&|J7Ki>^%b_zgyT|>CPfLY1YMAHuh5~fksf3P#3}k#`|IX`4aG7p zP;YTJLAtRWT9xV#3I(xvbGF&ym)eD=H8B*63>3JPhjVftndzZjMlB$92)U<#q@eX+ zrGNuXxwH?3Ca5BQE*xz{`+=WySe^h_En4~d{DbZ2pXO%PKI$9?8lv*aFK|YtOV=l} zp@FdNMohR(7GYohpvctJXhdVlD+_}XUp>^hx(hFm-FL@+%{!t43oeLRBr?2ON`7u=>$RmtS#9fT410jU#InVd`N~TXAG*_`1l&|odZ+c%o@XS+fF`X zjz%1J5t;@%Xa-$65631Wapy7r1cp;)E31?CCz|!t^=Jg9Q&kkr@%#S>-ToV}`<#Mu zcX2#@w~;W-b_2WF;5yj-h`(=T5*$t^>>t~Tw>SO4%QTURQdiOqf`=mn)|h%KgbMXB z15!~>++1HTSz-Q;2VA3qcynfe{${2k{F2)Vnm@lGW^S0814?&*H;L%v58gkN*DK2N6Z&fke7 zoYUuKp95=45>_5>Dx;QtUa=eJghbxDb8|ey)wA^(7uq+Sx8RCC&+u%IJb3B+!?GCB zkNQ(10`XS8)S%%Pnmo9HhDVT!QnVdMMYD)ZlAg;ew^%fpmI@B8{6eS1U0h7SUe4;+QVoCs z6%?Vfrik&~u5SWK#vxafazmRZg_WR`A5H?RT&uzb4_eb=jv4<0pPOg?54MA*@4aT3d>#mI_Syp%Nawe# z$}v=~TOQF^a}~nDKCpP6ci4J-YAv)NVKFS=ru($RySa}VRl)N3^PMj9G^yfPc3eKo z^E(o!>82e1)f=7yy-h7F*$__y`x;XQnF*J*%4ah0C9$e(X0C6X?*NPjg3TlC`T7TZ z%rvXu+#a@x!{Kc%mwn=h`RjAt_FHp1?YAbo28XQ@QA}4_MpNSPHn~=@^z1G(pNX!4;cmTC%a#tpfEG@7cXy~E#~~g9k@B?mzu#l)@89Nq(?9k+le~#KB0m(l-DY_8Zjeo(NtDt#iU%X+`LEut_dZz- zznZDI-E6rozmK6_$B7Jxo9k~N%-XXb0bA~m_1{!*2Njw&8U}S*{ELIfx(4^S%-GA+ zo+Mf}PMpltg>~Rn{~a`Dn&eW@!Q-Y>!KWNT>)(@L^q43iG?vpw(ty;!VRKCWU7QWt zF5`==Md?b=t7}nR=GM-JX;b@x?EtT-Kw~B;kgW83`hyGAPyB1NsTgvASwBxt05*~CX_IWp$Ot=k~?!HXl2UeSvL04oO@9HrSR`B zEmq&ZE2M$ zKU*2X@rOn)<+f{ymEIWnII|pY?Lp#6XL<6keupzf?RSA+OyPRqEP+#ShmFqWod;KM zNyp|Dz2Y$<5hw%DBMXz^_$+NW#VN-474yptAkQ5qbMA!4rbOH_iQd2AJpLy-lUY^S zRPp(nf}eGGyg3}r)i-dqeyy+knc>?XJ!N#fpMh9s1JdqPHM!`98@}_kyF5?P8h#H` zZD<2KEj4~N$uPSSRbkeul4Ln*G{ZJR8NZKy?$whe-J6`w;rI9)Xy_{F6jz<(fG%+i z8n)S(WtNtidmPg@CKw$rT{(wwp3@BDWgDIK1efD#&`hiu}W zSn#2%^mg3_<{b)oo>7P87Lw#oNz4CtF za1k8~+zQOaQUO`pO{4hTQx2n!OaB;nypZ~TbyEFZTxu7%>HQ`b^1Vf@fvNAxxa}CI z^#;`5@=O8y{0NmhUSwv^tPA?b0olFyJEUG>ldQpPVLi|>VM88Q*s);6jpItm?gZlF z3)eWjp~n0gRj@t4`=HLrGb^wZXl~0hH;7C6)-~whI{+R?%73uNsO4~Iu=@1%sSFT< z#*2p05@!*U;ElN5Rie&LMZKX&Ae9lv1B5@}C_*VpMIKKsOaou2CW>?Sr^NdJB3ZYA za%?+>)H4P=3L|W|qdS#@T$;+2Hw>BIZFNCN$LIt!cqwdOHqX-EAvnE#_){JS?gP$i zi**KGO4Et5tCDckTk$tFsvsuS_`1PBIwcHEJP`7hBQ;Rki*YGa-awUd6n&QRyl6v1 zb#z_IZie*?y-}*28h$5kfgyxG8C@tA)SewZO_P>UzpAt6fF>M~3X)DnYQDhezz?fL zYEJ`!Dx@^ZkMm6j#<{pwk`#xA>7GM#pnarwy|Lko?@bGFrnohB(7 zP>>wxB9lj_ZI6wZdM~W4TeX3FHf!cuj-YK!tXhKF5~UOcI23nL0{KBR|FEdM7ij3~ zu;9#kMb$ln(y43sDmK4Q7m>aNHY^BN(A0H{Eq&!@#rze}Q@lW%Hl z`_f!|k;v|oXcdO)wcc&>g8u2q3raX5gX7z0#*(JQwytYJV^hIU)$R?%5bLcFdPcI|;Hlz8$&PyFJ z5PI8eOTWH(&)ZJsr<&ykGS!^u56<2==A0(@bojRee5g30|0L=seR&#`9;S)8R{ zl#c?7OtCS-lrh(nD8EPlXBR-LzVqSXKdQK|9Pcs>9%Nh%O6oI+*4rSNa3hyHCgt9~Q^ z&J>}8x}-_wz8E@xL4^b=d#i)$SlEUlB}jv$Xcta8i2V8(q?%4f{k&{|Z9!gCMi!cJ zDq3eTzjE+6YA1b3*X0$&R;*ya>R**hgciF-8273uId2e6vh<|&ZULh9k5A3IxfY1xbXuqA_N?MicW?+f( z+yzrvi&TN3cCF_?cA>p3IDXT+<@q^-GgqGu51FP=dxb;S?#}z^R}RPwHv~-0U!B~= zWirrB*9T=xrMT}gAN3Vez0H-jKP*-&2G&11=HoM(!&B$U5s>MvI=?Yhe{a&MV2r`yLV z+TUZKqGS33H?_wk-rkS1=KFhwe1-hEZh1J5T8D=5_}#Dc56k>LLeQvA-iC$zvc~(~ zNb^0Nf^T#1Tx=;%8Q8$=^Us|M@*5pUB;CwXQdK+~vQTPBRUwd=Qd2n0-fTXyIKW>B zHYXX}uTST{&!l6x>vF4@-RD?29JG^B4n$%VLt7ZfcEQCEBrrGttfl$el|5AG{}79} z8~yq$j@6_aL@im$g)E&2NVo!tjg!Z)4iM9jC?!5PL5D>KxJ$QKT)QAm2PvNV6|v4V z_z`9EB-3fZ2iGV?#HFzAY1+ylIY{0ZK~RF>0JSEU(2md~UtJi%I-@#w+UV9gw1tQj zWNxb3gRUV)@~(|z93rH0gXn3S>M?8legePT16CWCJGe|IYRvUS^r6VX4#CgiD5n$i zEL}@S@F?=KX5Z=1lw$1(tCjL=nTOX+-S)u3JKoyBw3fbV?8l;B3?B@Mmv{~Z7MI#9e+!x1n-c)xNn~0s8Pl0)BdKft% zo!PzZ#B!}@IT00Y%}+kgW#8QQZn}7s9RYlx zFs9k)Ouq#3G%>xdE_fzD%hx17Z<v3BGx=^^Gw!sQtY_xTs^IV3T@njA9Xg(jF|uhg!@sqfJM4J7$m{p7 zw%BG7#xY+PPf0oKu0>}{mx?_=ZbMX(gTbBZEt2oY z4%zax2IwVk0yaLlC@_L9mq7kzW%$t|M))8}WP}i8)EY7gLN=Aec8na5^uSg~xa%!BPd5sj9Fp%(38sF^S0w+?pEdU=b;`nTQF8h3900>LYMS6ggV*)ssEh(P`zG z@n&TQ>h!T!S!KQX+l#wFsCcKPT@CTprMXLng0IyOHM)w;PQudxx9LHBeR4DnYc2J4 z8xcDrOTrF+%fb9yqK8x_fx&X39)zykmj%CxBhN6FF#DVJmHA8>8_v1<#{;98se&=u zCohPPvd=$Apf^()XjDKpE+G8nT9}Vb=?R_ev|81ZeAv7*rvwJkS14cS$1D0+jE6wZ z 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 literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml index fa7093a..0f7bcf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,45 @@ [build-system] -requires = ["setuptools>=42"] -build-backend = "setuptools.build_meta" \ No newline at end of file +requires = ["setuptools>=61", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "eppopynder" +version = "2.0.0" +description = "Python interface to the EPPO Database and Public APIs" +readme = "README.md" +authors = [ + { name = "Lorenzo Copelli" }, + { name = "Dayana Stephanie Buzle" }, + { name = "Rafael Vieira" }, + { name = "Agata Kaczmarek" }, + { name = "Luca Belmonte" } +] +maintainers = [ + { name = "Luca Belmonte", email = "luca.belmonte@efsa.europa.eu" } +] +license = "EUPL-1.2" +license-files = ["LICENSE"] +requires-python = ">=3.11" +dependencies = [ + "numpy>=2.0", + "pandas>=2.2", + "requests>=2.32", + "python-dotenv>=1.0" +] + +[project.optional-dependencies] +dev = [ + "coverage>=7.6", + "pytest>=8.0", +] + +[project.urls] +"Homepage" = "https://github.com/openefsa/eppoPynder" +"Repository" = "https://github.com/openefsa/eppoPynder" +"Bug Tracker" = "https://github.com/openefsa/eppoPynder/issues" + +[tool.setuptools] +package-dir = {"" = "src"} + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/requirements.txt b/requirements.txt index 2955c1ed79038af327b83e1022a55c15f1ffeb63..a8a67499b130232ad4ade80c8a31418a03dea884 100644 GIT binary patch literal 1504 zcmZ8h(Nf|-5S-_$x=(>JfF3^h5B>oaAOaGS7=oxDuh%`jlSGP2sLjswbob2e&-dCc zcCga6_Jm(%Q(NG=_xIO{}sSs}sJJ z$oz5~=Fb!UB4yR6TcA#D?+KsCeCB;b=~%g=5#uglJoFLoj-T5O|BU#T5U7Rhwm{fG zCzX`o7$`HapQcKOkpt8x2l%yuir`MwL_FZ@!FgBi&CVl)7P+tPNbXTnyi2Ul?vNOS z7pim{U86z=Js)_p`h#<#GpzqR`UTo5ROq0y?iI3+tReg(us+cfG7q-YNv{;aZnbuF zx2}kqAeOyskVgiZiy?Z8sx7L8o9vsW;p81F5`t!E%q;UBF8j)r?ZGr~$XPfQDxCWI zbe9~o*MRK?Y}xf&P13`N3To&&vE@ZL*ns&3xx1u}?By~2ea6=vY8OE0Qad$WsR$+grjfgSXL?z2W zZV<<6;Rh=WxwYq3>Es1h&6l`-InUwD4@|G_`5e{AwS%(8l|>JA66j=$?>U&#%ayO# z6V3!5#xK%jMf4l=$R+hnSbX36>@#y5GeLb#*BUz|Rz#&9x-0E1PU!{{@MuePIeZ%L z^EB^Mrlu@%b*EjRFzSfc(!Cxq&hX@;ubqufR%h}{w-cv~YQ(I=?WjKLmbrCXXN8qwRNfP9p z{lY3_%YKkdp4cUS_i`t-9Hj!;gHN)NP9lGw+_mtorlRZ;j&dhfq^`)yu!`7@h~20g z6NX1=D+XGDj4#jCwD8J$`9E$R)+)m8bC?au0%cu&t)x!%i#tJR}r- zn!KJ(EhB$4owf3HL`}0QEb$qYFLc~@NnNgT`veD66S_Jd$L%e>cG!J-vV5D1zAU$i ncqK7!?Mh;M*4q>V^KMx|Ug`Dpnsw)HUmsCAFoDbL<`et}_}5|Y diff --git a/setup.py b/setup.py deleted file mode 100644 index 1478d2a..0000000 --- a/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='eppoPynder', - version='1.0.0', - description='A Wrapper for EPPO Codes', - long_description='A wrapper around the European and Mediterranean Plant Protection Organization (EPPO) database public APIs at https://data.eppo.int/. It enables users to retrieve EPPO-related data through searches across the entire EPPO database or by utilizing specific services, including categorization, taxonomy, and more. The package also includes a data wrangling function to integrate taxonomy and rank information, and a function that returns the list of member countries for each Regional Plant Protection Organization acronym which is used in the EPPO database.', - long_description_content_type='text/markdown', - author='Luca Belmonte, Dayana Stephanie Buzle, Rafael Vieira, Agata Kaczmarek', - author_email='luca.belmonte@efsa.europa.eu', - maintainer='Luca Belmonte', - maintainer_email='luca.belmonte@efsa.europa.eu', - url='https://github.com/openefsa/eppoPynder', - project_urls={ - 'Luca Belmonte ORCID': 'https://orcid.org/0000-0002-7977-9170', - 'Dayana Stephanie Buzle ORCID': 'https://orcid.org/0009-0003-2990-7431', - 'Rafael Vieira ORCID': 'https://orcid.org/0009-0009-0289-5438', - 'Agata Kaczmarek ORCID': 'https://orcid.org/0000-0002-7463-5821', - }, - license='GPL-3.0', - packages=find_packages(where='src'), - package_dir={'': 'src'}, - install_requires=[ - 'numpy>=2.1.3', - 'pandas>=2.2.3', - 'python-dateutil>=2.9.0.post0', - 'requests>=2.32.3', - 'certifi>=2024.8.30', - 'charset-normalizer>=3.4.0', - 'idna>=3.10', - 'urllib3>=2.2.3', - 'pytz>=2024.2', - 'tzdata>=2024.2', - 'python-dotenv>=1.0.0' - ], - extras_require={ - 'dev': [ - 'setuptools>=75.3.0', - 'coverage>=7.6.4', - 'colorama>=0.4.6', - 'pytest>=8.3.3', - 'iniconfig>=2.0.0', - 'pluggy>=1.5.0', - 'packaging>=24.1', - 'six>=1.16.0' - ], - }, - python_requires='>=3.11' - ) diff --git a/src/eppoPynder/__init__.py b/src/eppoPynder/__init__.py index e69de29..9191fd5 100644 --- a/src/eppoPynder/__init__.py +++ b/src/eppoPynder/__init__.py @@ -0,0 +1,23 @@ +from .client import Client +from .data_wrangling import uniform_taxonomy +from ._core._general import GeneralService +from ._core._taxons import TaxonsService +from ._core._taxon import TaxonService +from ._core._country import CountryService +from ._core._rppo import RPPOService +from ._core._tools import ToolsService +from ._core._reporting_service import ReportingServiceService +from ._core._references import ReferencesService + +__all__ = [ + "Client", + "GeneralService", + "TaxonsService", + "TaxonService", + "CountryService", + "RPPOService", + "ToolsService", + "ReportingServiceService", + "ReferencesService", + "uniform_taxonomy" +] diff --git a/src/eppoPynder/_core/__init__.py b/src/eppoPynder/_core/__init__.py new file mode 100644 index 0000000..a9a2c5b --- /dev/null +++ b/src/eppoPynder/_core/__init__.py @@ -0,0 +1 @@ +__all__ = [] diff --git a/src/eppoPynder/_core/_country.py b/src/eppoPynder/_core/_country.py new file mode 100644 index 0000000..5f96b38 --- /dev/null +++ b/src/eppoPynder/_core/_country.py @@ -0,0 +1,69 @@ +"""This module contains core functions for working with the Country endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests, _data + + +class CountryService(StrEnum): + """The list of services supported by the Country endpoint.""" + OVERVIEW = "overview" + CATEGORIZATION = "categorization" + PRESENCE = "presence" + + +def _country(api_key, iso_codes, services=None): + """Query the EPPO API Country endpoint. + + This internal function queries the Country endpoints of the EPPO Global + Database via REST API for one or more ISO code(s) and one or more + service(s). For each ISO code in `iso_codes`, the function sequentially + queries all specified `services` and returns the extracted data through a + list of dataframes. + + Args: + api_key (str): The API key used for authentication. + iso_codes (list[str]): One or more ISO codes to query. + services (list[CountryService], optional): One or more Country services + to query. A validation step ensures that all provided services are + of type `CountryService` and match the supported service names. If + not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content for all the specified ISO codes. + """ + + _checks._require_type(value=api_key, expected_type=str) + _checks._require_type(value=iso_codes, expected_type=list) + _checks._require_list_of(items=iso_codes, expected_type=str) + if services is None: + services = list(CountryService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services( + services=services, + choices=list(CountryService) + ) + + country_data_ = { + service_: { + iso_code_: _requests._fetch_service( + base_path='/country', + api_key=api_key, + code=iso_code_, + service=service_ + ) + for iso_code_ in iso_codes + } + for service_ in services + } + + country_data_ = _data._merge_batch( + datasets=country_data_, + parent_column_name="queried_iso_code" + ) + + return country_data_ diff --git a/src/eppoPynder/_core/_general.py b/src/eppoPynder/_core/_general.py new file mode 100644 index 0000000..75f522b --- /dev/null +++ b/src/eppoPynder/_core/_general.py @@ -0,0 +1,53 @@ +"""This module contains core functions for working with the General endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests + + +class GeneralService(StrEnum): + """The list of services supported by the General endpoint.""" + STATUS = "status" + + +def _general(api_key, services=None): + """Query the EPPO API General endpoint. + + This internal function queries the General endpoints of the EPPO Global + Database via REST API. The function sequentially queries all specified + `services` and returns the extracted data. + + Args: + api_key (str): The API key used for authentication. + services (list[GeneralService], optional): One or more General services + to query. A validation step ensures that all provided services are + of type `GeneralService` and match the supported service names. If + not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content. + """ + + _checks._require_type(value=api_key, expected_type=str) + if services is None: + services = list(GeneralService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services( + services=services, + choices=list(GeneralService) + ) + + general_data_ = { + service_: _requests._fetch_service( + base_path='/', + api_key=api_key, + service=service_ + ) + for service_ in services + } + + return general_data_ diff --git a/src/eppoPynder/_core/_references.py b/src/eppoPynder/_core/_references.py new file mode 100644 index 0000000..d364807 --- /dev/null +++ b/src/eppoPynder/_core/_references.py @@ -0,0 +1,63 @@ +"""This module contains core functions for working with the References endpoint +of the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests, _data + + +class ReferencesService(StrEnum): + """The list of services supported by the References endpoint.""" + RPPOS = "rppos" + Q_LIST = "qList" + DISTRIBUTION_STATUS = "distributionStatus" + PEST_HOST_CLASSIFICATION = "pestHostClassification" + VECTOR_CLASSIFICATION = "vectorClassification" + COUNTRIES = "countries" + COUNTRIES_STATES = "countriesStates" + + +def _references(api_key, services=None): + """Query the EPPO API References endpoint. + + This internal function queries the References endpoints of the EPPO Global + Database via REST API. The function sequentially queries all specified + `services` and returns the extracted data through a dictionary of data + frames. + + Args: + api_key (str): The API key used for authentication. + services (list[ReferencesService], optional): One or more References + services to query. A validation step ensures that all provided + services are of type `ReferencesService` and match the supported + service names. If not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content. + """ + + _checks._require_type(value=api_key, expected_type=str) + if services is None: + services = list(ReferencesService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services( + services=services, + choices=list(ReferencesService) + ) + + references_data_ = { + service_: _requests._fetch_service( + base_path='/references', + api_key=api_key, + service=service_ + ) + for service_ in services + } + + references_data_ = _data._transform_references( + references_data=references_data_) + + return references_data_ diff --git a/src/eppoPynder/_core/_reporting_service.py b/src/eppoPynder/_core/_reporting_service.py new file mode 100644 index 0000000..216a742 --- /dev/null +++ b/src/eppoPynder/_core/_reporting_service.py @@ -0,0 +1,65 @@ +"""This module contains core functions for working with the Reporting Service +endpoint of the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests + + +class ReportingServiceService(StrEnum): + """The list of services supported by the Reporting Service endpoint.""" + LIST = "list" + REPORTING = "reporting" + ARTICLE = "article" + + +def _reporting_service(api_key, services=None, params=None): + """Query the EPPO API Reporting Service endpoint. + + This internal function queries the Reporting Service endpoints of the EPPO + Global Database via REST API. The function sequentially queries all + specified `services` and returns the extracted data through a dictionary of + data frames. + + Args: + api_key (str): The API key used for authentication. + services (list[ReportingServiceService], optional): One or more + Reporting Service services to query. A validation step ensures that + all provided services are of type `ReportingServiceService` and + match the supported service names. If not provided, all services + are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content. + """ + + _checks._require_type(value=api_key, expected_type=str) + if services is None: + services = list(ReportingServiceService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services(services=services, + choices=list(ReportingServiceService)) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + reporting_service_data_ = { + service_: _requests._fetch_service( + base_path="/reportings", + api_key=api_key, + service=_requests._build_reporting_service_path( + service=service_, + params=params.get(service_, None) + if params is not None else None + ) + ) + for service_ in services + } + + return reporting_service_data_ diff --git a/src/eppoPynder/_core/_rppo.py b/src/eppoPynder/_core/_rppo.py new file mode 100644 index 0000000..493abef --- /dev/null +++ b/src/eppoPynder/_core/_rppo.py @@ -0,0 +1,68 @@ +"""This module contains core functions for working with the RPPO endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests, _data + + +class RPPOService(StrEnum): + """The list of services supported by the RPPO endpoint.""" + OVERVIEW = "overview" + CATEGORIZATION = "categorization" + + +def _rppo(api_key, rppo_codes, services=None): + """Query the EPPO API RPPO endpoint. + + This internal function queries the RPPO endpoints of the EPPO Global + Database via REST API for one or more RPPO code(s) and one or more + service(s). For each RPPO code in `rppo_codes`, the function sequentially + queries all specified `services` and returns the extracted data through a + list of dataframes. + + Args: + api_key (str): The API key used for authentication. + rppo_codes (list[str]): One or more RPPO codes to query. + services (list[CountryService], optional): One or more RPPO services + to query. A validation step ensures that all provided services are + of type `RPPOService` and match the supported service names. If + not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content for all the specified RPPO codes. + """ + + _checks._require_type(value=api_key, expected_type=str) + _checks._require_type(value=rppo_codes, expected_type=list) + _checks._require_list_of(items=rppo_codes, expected_type=str) + if services is None: + services = list(RPPOService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services( + services=services, + choices=list(RPPOService) + ) + + rppo_data_ = { + service_: { + rppo_code_: _requests._fetch_service( + base_path='/rppo', + api_key=api_key, + code=rppo_code_, + service=service_ + ) + for rppo_code_ in rppo_codes + } + for service_ in services + } + + rppo_data_ = _data._merge_batch( + datasets=rppo_data_, + parent_column_name="queried_rppo_code" + ) + + return rppo_data_ diff --git a/src/eppoPynder/_core/_taxon.py b/src/eppoPynder/_core/_taxon.py new file mode 100644 index 0000000..61b82e4 --- /dev/null +++ b/src/eppoPynder/_core/_taxon.py @@ -0,0 +1,82 @@ +"""This module contains core functions for working with the Taxon endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests, _data + + +class TaxonService(StrEnum): + """The list of services supported by the Taxon endpoint.""" + OVERVIEW = "overview" + INFOS = "infos" + NAMES = "names" + TAXONOMY = "taxonomy" + CATEGORIZATION = "categorization" + KINGDOM = "kingdom" + HOSTS = "hosts" + PESTS = "pests" + VECTORS = "vectors" + VECTOR_OF = "vectorof" + BCA = "bca" + BCA_OF = "bcaof" + PHOTOS = "photos" + REPORTING_ARTICLES = "reporting_articles" + DOCUMENTS = "documents" + STANDARDS = "standards" + DISTRIBUTION = "distribution" + + +def _taxon(api_key, eppo_codes, services=None): + """Query the EPPO API Taxon endpoint. + + This internal function queries the Taxon endpoints of the EPPO Global + Database via REST API for one or more EPPO code(s) and one or more + service(s). For each EPPO code in `eppo_codes`, the function sequentially + queries all specified `services` and returns the extracted data. + + Args: + api_key (str): The API key used for authentication. + eppo_codes (list[str]): One or more EPPO codes to query. + services (list[TaxonService], optional): One or more Taxon services + to query. A validation step ensures that all provided services are + of type `TaxonService` and match the supported service names. If + not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content for all the specified EPPO codes. + """ + + _checks._require_type(value=api_key, expected_type=str) + _checks._require_type(value=eppo_codes, expected_type=list) + _checks._require_list_of(items=eppo_codes, expected_type=str) + if services is None: + services = list(TaxonService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services( + services=services, + choices=list(TaxonService) + ) + + taxon_data_ = { + service_: { + eppo_code_: _requests._fetch_service( + base_path='/taxons/taxon', + api_key=api_key, + code=eppo_code_, + service=service_ + ) + for eppo_code_ in eppo_codes + } + for service_ in services + } + + taxon_data_ = _data._merge_batch( + datasets=taxon_data_, + parent_column_name="queried_eppo_code" + ) + + return taxon_data_ diff --git a/src/eppoPynder/_core/_taxons.py b/src/eppoPynder/_core/_taxons.py new file mode 100644 index 0000000..6c8727b --- /dev/null +++ b/src/eppoPynder/_core/_taxons.py @@ -0,0 +1,60 @@ +"""This module contains core functions for working with the Taxons endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests, _data + + +class TaxonsService(StrEnum): + """The list of services supported by the Taxons endpoint.""" + LIST = "list" + + +def _taxons(api_key, services=None, params=None): + """Query the EPPO API Taxons endpoint. + + This internal function queries the Taxons endpoints of the EPPO Global + Database via REST API. The function sequentially queries all specified + `services` and returns the extracted data. + + Args: + api_key (str): The API key used for authentication. + services (list[TaxonsService], optional): One or more Taxons services + to query. A validation step ensures that all provided services are + of type `TaxonsService` and match the supported service names. If + not provided, all services are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content. + """ + + _checks._require_type(value=api_key, expected_type=str) + if services is None: + services = list(TaxonsService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services(services=services, choices=list(TaxonsService)) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + taxons_data_ = { + service_: _requests._fetch_service( + base_path="/taxons", + api_key=api_key, + service=service_, + params=params.get(service_, None) + if params is not None else None + ) + for service_ in services + } + + taxons_data_ = _data._transform_taxons(taxons_data=taxons_data_) + + return taxons_data_ diff --git a/src/eppoPynder/_core/_tools.py b/src/eppoPynder/_core/_tools.py new file mode 100644 index 0000000..73eabe7 --- /dev/null +++ b/src/eppoPynder/_core/_tools.py @@ -0,0 +1,59 @@ +"""This module contains core functions for working with the Tools endpoint of +the EPPO API. +""" + +from enum import StrEnum + +from eppopynder._utils import _checks, _requests + + +class ToolsService(StrEnum): + """The list of services supported by the Tools endpoint.""" + NAME2CODES = "name2codes" + + +def _tools(api_key, services=None, params=None): + """Query the EPPO API Tools endpoint. + + This internal function queries the Tools endpoints of the EPPO Global + Database via REST API. The function sequentially queries all specified + `services` and returns the extracted data through a dictionary of data + frames. + + Args: + api_key (str): The API key used for authentication. + services (list[ToolsService], optional): One or more Tools services to + query. A validation step ensures that all provided services are of + type `ToolsService` and match the supported service names. If not + provided, all services are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content. + """ + + _checks._require_type(value=api_key, expected_type=str) + if services is None: + services = list(ToolsService) + _checks._require_type(value=services, expected_type=list) + _checks._check_services(services=services, choices=list(ToolsService)) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + tools_data_ = { + service_: _requests._fetch_service( + base_path="/tools", + api_key=api_key, + service=service_, + params=params.get(service_, None) + if params is not None else None + ) + for service_ in services + } + + return tools_data_ diff --git a/src/eppoPynder/_utils/__init__.py b/src/eppoPynder/_utils/__init__.py new file mode 100644 index 0000000..a9a2c5b --- /dev/null +++ b/src/eppoPynder/_utils/__init__.py @@ -0,0 +1 @@ +__all__ = [] diff --git a/src/eppoPynder/_utils/_checks.py b/src/eppoPynder/_utils/_checks.py new file mode 100644 index 0000000..4c007c4 --- /dev/null +++ b/src/eppoPynder/_utils/_checks.py @@ -0,0 +1,147 @@ +"""This module contains internal functions for performing type and data checks. +""" + +import pandas as pd + + +def _require_type(value, expected_type): + """Check that a value is of the expected type. + + Args: + value: The value to check. + expected_type: The expected type. + + Raises: + TypeError: If the value is not of the expected type. + + Returns: + None: The function returns nothing if the check passes. + """ + + if not isinstance(value, expected_type): + raise TypeError(f"Expected type {expected_type}, got {type(value)}") + + +def _require_trailing_slash(string): + """Check that a string starts with a trailing slash. + + Args: + string (str): The string value to check. + + Raises: + ValueError: If the string is not starting with a trailing slash. + + Returns: + None: The function returns nothing if the check passes. + """ + + _require_type(value=string, expected_type=str) + + if not string.startswith('/'): + raise ValueError(f"Expected trailing slash, got {string}") + + +def _require_list_of(items, expected_type): + """Check that a list contains only elements of the expected type. + + Args: + items (list): The list to check. + expected_type (type): The expected type of the elements. + + Raises: + TypeError: If at least one element of the list is not of the expected + type. + + Returns: + None: The function returns nothing if the check passes. + """ + + _require_type(value=items, expected_type=list) + _require_type(value=expected_type, expected_type=type) + + for item_ in items: + if not isinstance(item_, expected_type): + raise TypeError(f"Expected list of {expected_type}") + + +def _check_services(services, choices): + """Validate service names against a set of allowed choices. + + This function checks whether all elements in `services` are included in the + allowed `choices`. If any unsupported services are found, the function + raises an informative exception. + + Args: + services (list): A list of service names to validate. + choices (list): A list containing the allowed service names. + + Raises: + ValueError: If any unsupported services are found. + + Returns: + None: The function returns nothing if the check passes. + """ + + _require_type(value=services, expected_type=list) + _require_list_of(items=services, expected_type=type(choices[0])) + _require_type(value=choices, expected_type=list) + + invalid_services_ = set(services) - set(choices) + + if len(invalid_services_) > 0: + raise ValueError("Unsupported services requested: " + + f"{", ".join(invalid_services_)}") + + +def _require_column_names(dataframe, column_names): + """Check if a dataframe contains the specified column names. + + This function checks whether a dataframe contains the specified column + names. If the condition is not verified, the function raises an informative + exception. + + Args: + dataframe (pd.DataFrame): The dataframe to validate. + column_names (list): The list of required column names. + + Raises: + ValueError: If the required column names are not present in the + dataframe. + + Returns: + None: The function returns nothing if the check passes. + """ + + _require_type(value=dataframe, expected_type=pd.DataFrame) + _require_type(value=column_names, expected_type=list) + + if not all(column_ in dataframe.columns for column_ in column_names): + raise ValueError("Missing required columns in dataframe: " + + f"{", ".join(column_names)}") + + +def _require_not_all_nan(dataframe, column_name): + """Check if a dataframe contains the specified column names. + + This function checks whether a dataframe contains the specified column + names. If the condition is not verified, the function raises an informative + exception. + + Args: + dataframe (pd.DataFrame): The dataframe to check. + column_name (str): The name of the column to check. + + Raises: + ValueError: If the specified column contains only NaN values. + + Returns: + None: The function returns nothing if the check passes. + """ + + _require_type(value=dataframe, expected_type=pd.DataFrame) + _require_type(value=column_name, expected_type=str) + + if (not column_name in dataframe.columns + or not dataframe[column_name].notna().any()): + raise ValueError(f"Column {column_name} must contain at least a " + + "non-NaN value.") diff --git a/src/eppoPynder/_utils/_data.py b/src/eppoPynder/_utils/_data.py new file mode 100644 index 0000000..a9ab186 --- /dev/null +++ b/src/eppoPynder/_utils/_data.py @@ -0,0 +1,275 @@ +"""This module contains internal functions for processing API response data.""" + +import pandas as pd + +from eppopynder._utils import _checks +from eppopynder._core import _taxons, _references + + +def _flatten(nested_data, separator='_'): + """Flattens nested JSON structures into a pandas DataFrame. + + This helper function automatically expands lists into multiple rows and + flattens nested dictionaries. + + Args: + nested_data: The dictionary or list of dictionaries to flatten. + separator (str): The separator to use for nested columns names. + Defaults to '_'. + + Raises: + TypeError: If data is not a dictionary or a list of dictionaries. Data + can be empty. + + Returns: + pandas.DataFrame: A flattened DataFrame, where: + - Lists are expanded into multiple rows. + - Nested dictionaries become columns with separator-notation. + - Parent-level fields are repeated for each child row. + """ + + def _flatten_dictionary(dictionary, sep, parent_key=''): + """Flatten a nested dictionary without expanding lists. + + This helper function recursively traverses a dictionary and creates + flat key-value pairs for nested keys, using the specified separator. + Lists are kept as-is and not expanded by this function. + + Args: + dictionary (dict): The dictionary to flatten. + sep (str): The separator to use between parent and child keys. + parent_key (str, optional): The parent key for the flattened + dictionary. It is the prefix to prepend to keys (used in + recursion). Defaults to ''. + + Returns: + dict: A flattened dictionary with sep-notated keys for nested + structures. + """ + + dictionary_items_ = [] + + for key_, value_ in dictionary.items(): + new_key_ = f"{parent_key}{sep}{key_}" if parent_key else key_ + if isinstance(value_, dict): + dictionary_items_.extend( + _flatten_dictionary(dictionary=value_, sep=sep, + parent_key=new_key_).items()) + else: + dictionary_items_.append((new_key_, value_)) + + return dict(dictionary_items_) + + def _is_dictionary_of_lists(dictionary): + """Check if a dictionary contains only lists as values. + + This helper function identifies the special case where the top-level + dictionary keys represent categories amd all values are lists. + + Args: + dictionary (dict): The dictionary to check. + + Returns: + bool: True if all values in the dictionary are lists, False + otherwise. + """ + + return all(isinstance(value_, list) for value_ in dictionary.values()) + + def _expand_dictionary_of_lists(dictionary, sep): + """Expand a dictionary where all values are lists. + + This helper function handles the special case where each top-level key + maps to a list of items. It creates a "key" column to preserve the + original dictionary key and expands each list item into a separate row. + + Args: + dictionary (dict): The dictionary where all values are lists. + sep (str): The separator for flattening nested dictionaries within + list items. + + Returns: + pandas.DataFrame: DataFrame with a "key" column containing the + original dictionary key and additional columns from the list + items. + """ + + expanded_rows_ = [] + + for key_, value_ in dictionary.items(): + for item_ in value_: + if isinstance(item_, dict): + row_ = {"parent_key": key_} + flat_item_ = _flatten_dictionary(dictionary=item_, sep=sep) + row_.update(flat_item_) + expanded_rows_.append(row_) + else: + expanded_rows_.append({"parent_key": key_, + "atomic_value": item_}) + + return pd.DataFrame(expanded_rows_) + + def _find_list_columns(dictionary): + """Finds dictionary keys that contain lists of dictionaries. + + This helper function identifies columns that need to be expanded into + multiple rows. It only considers lists that contain at least one + dictionary. + + Args: + dictionary (dict): The dictionary to check. + + Returns: + list: The list of keys whose values are lists of dictionaries. + """ + + list_keys_ = [] + + for key_, value_ in dictionary.items(): + if (isinstance(value_, list) and value_ + and any(isinstance(item_, dict) for item_ in value_)): + list_keys_.append(key_) + + return list_keys_ + + def _expand_lists(dictionary, sep): + """Recursively expand lists in a dictionary into DataFrame rows. + + This helper is the main recursive function that handles the expansion + logic. It detects different types of structures and applies the + appropriate expansion strategy. It processes one list level at a time + and recurses for additional nested lists. + + Args: + dictionary (dict): The dictionary to process. + sep (str): The separator for nested column names. + + Returns: + pandas.DataFrame: A DataFrame with all lists expanded into rows and + nested dictionaries flattened. + """ + + if _is_dictionary_of_lists(dictionary=dictionary): + return _expand_dictionary_of_lists(dictionary=dictionary, sep=sep) + + list_keys_ = _find_list_columns(dictionary=dictionary) + + if not list_keys_: + flat_ = _flatten_dictionary(dictionary=dictionary, sep=sep) + return pd.DataFrame([flat_]) + + list_key_ = list_keys_[0] + list_data_ = dictionary[list_key_] + + base_data_ = {key_: value_ for key_, value_ in dictionary.items() + if key_ != list_key_} + + expanded_rows_ = [] + + for item_ in list_data_: + row_data_ = base_data_.copy() + + if isinstance(item_, dict): + for key_, value_ in item_.items(): + row_data_[f"{list_key_}{sep}{key_}"] = value_ + else: + row_data_[list_key_] = item_ + + expanded_rows_.append(_expand_lists(dictionary=row_data_, sep=sep)) + + return pd.concat(expanded_rows_, ignore_index=True) + + if not nested_data: + return pd.DataFrame() + + elif (isinstance(nested_data, list) + and all(isinstance(item_, dict) for item_ in nested_data)): + dataframes_ = [_expand_lists(dictionary=item_, sep=separator) + for item_ in nested_data] + return pd.concat(dataframes_, ignore_index=True) + + elif isinstance(nested_data, dict): + return _expand_lists(dictionary=nested_data, sep=separator) + + raise TypeError("Data must empty, a dictionary or a list of dictionaries") + + +def _transform_taxons(taxons_data): + """Transform EPPO Taxons response data. + + This helper function restructures the raw output returned by the EPPO + Taxons endpoint for each queried service. Depending on the service name, + the function applies the appropriate post-processing steps. + + Args: + taxons_data (dict): The response from the EPPO Taxons endpoint. + + Returns: + dict: The transformed dictionary. + """ + + _checks._require_type(value=taxons_data, expected_type=dict) + + for service_, dataframe_ in taxons_data.items(): + if service_ == _taxons.TaxonsService.LIST: + dataframe_.drop(columns=[ + column_ for column_ in dataframe_.columns + if column_.startswith("pagination") + or column_.startswith("meta") + ], inplace=True, errors="ignore") + + return taxons_data + + +def _transform_references(references_data): + """Transform EPPO References response data. + + This helper function restructures the raw output returned by the EPPO + References endpoint for each queried service. Depending on the service + name, the function applies the appropriate post-processing steps. + + Args: + references_data (dict): The response from the EPPO References endpoint. + + Returns: + dict: The transformed dictionary. + """ + + _checks._require_type(value=references_data, expected_type=dict) + + for service_, dataframe_ in references_data.items(): + if service_ == _references.ReferencesService.COUNTRIES_STATES: + dataframe_.rename(columns={"parent_key": "country_iso"}, + inplace=True) + + return references_data + + +def _merge_batch(datasets, parent_column_name): + """Merge results containing more EPPO or ISO codes. + + This helper function merges results + + Args: + datasets (dict): The response from the EPPO Taxon or Country endpoints. + parent_column_name (str): The name of the new column that will contain + the EPPO or ISO code. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a data + frame with the queried content for all the specified EPPO or ISO + codes, along with a new column named `parent_column_name`. + """ + + _checks._require_type(value=datasets, expected_type=dict) + _checks._require_type(value=parent_column_name, expected_type=str) + + for service_, value_dictionary_ in datasets.items(): + dataframes_ = [] + for code_, dataframe_ in value_dictionary_.items(): + dataframe_.insert(0, parent_column_name, code_) + dataframes_.append(dataframe_) + datasets[service_] = pd.concat(dataframes_, ignore_index=True) + + return datasets diff --git a/src/eppoPynder/_utils/_requests.py b/src/eppoPynder/_utils/_requests.py new file mode 100644 index 0000000..c691495 --- /dev/null +++ b/src/eppoPynder/_utils/_requests.py @@ -0,0 +1,309 @@ +"""This module contains internal functions for working with EPPO API requests. +""" + +import pandas as pd +import requests +from datetime import datetime +from json import JSONDecodeError + +from eppopynder._utils import _checks +from eppopynder._utils import _data + + +def _build_endpoint(base_path, code=None, service=None): + """Build an EPPO API endpoint path. + + This helper function constructs an endpoint path for retrieving data from + the EPPO API. The result must be appended to the EPPO API base URL. It + allows for the optional inclusion of a specific code and/or service name, + depending on the desired API resource. The function is based on the fact + that EPPO API endpoints follow the pattern: + {base path}/{resource identifier}/{service}. + + Args: + base_path (str): The base path, starting with '/' (e.g. + "/taxons/taxon"). + code (str, optional): The resource identifier (e.g. an EPPO code or + an ISO code). If provided, it will be appended to the base path. + service (str, optional): The desired API service. If provided, it will + be appended to the path after the resource identifier (if any, + otherwise after the base path). + + Returns: + str: A string representing the complete endpoint path to be used in an + API request. + """ + + _checks._require_type(value=base_path, expected_type=str) + _checks._require_trailing_slash(string=base_path) + if code is not None: + _checks._require_type(value=code, expected_type=str) + if service is not None: + _checks._require_type(value=service, expected_type=str) + + endpoint_parts_ = [base_path] + [part_ for part_ in (code, service) + if part_ is not None] + endpoint_path_ = '/'.join(endpoint_parts_) + endpoint_path_ = endpoint_path_.replace("//", '/') + + return endpoint_path_ + + +def _build_reporting_service_path(service, params = None): + """Build the EPPO reporting-related service path. + + This helper function constructs the endpoint path for EPPO API reporting + services based on the service type and parameters provided in the `params` + dictionary. It also handles missing or invalid parameters by raising + informative errors. + + Args: + service (str): The type of service. Supported values are `reporting` + and `article`. + params (dict, optional): A dictionary containing identifiers needed for + the endpoint path. Must include `reporting_id` if service is + "reporting" or `article_id` if service is "article". + + Raises: + ValueError: If a required parameter is missing or invalid for the + specified service. + + Returns: + str: The constructed service path to use with API calls. + """ + + _checks._require_type(value=service, expected_type=str) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + required_ids_ = { + "reporting": "reporting_id", + "article": "article_id", + } + + required_id_name_ = required_ids_.get(service) + + if required_id_name_ is not None: + if params is None or not params.get(required_id_name_): + raise ValueError("Missing required parameter " + + f"\"{required_id_name_}\"") + + service = f"{service}/{params[required_id_name_]}" + + return service + + +def _perform_request(url, api_key, params=None): + """Build and execute an HTTP GET request to the EPPO API. + + This helper function prepares and sends a GET request to the EPPO API, + setting the necessary headers, authentication key and query parameters. It + then performs the request and returns the corresponding response data. + + Args: + url (str): The full API endpoint URL to query. + api_key (str): The API key used for authentication. + params (dict, optional): Optional query parameters to include in the + request. + + Returns: + class (requests.Response): The HTTP response object returned by + the request. + """ + + _checks._require_type(value=url, expected_type=str) + _checks._require_type(value=api_key, expected_type=str) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + request_headers_ = { + "X-Api-Key": api_key, + "Accept": "application/json" + } + + response_ = requests.get(url, headers=request_headers_, params=params) + + return response_ + + +def _handle_http_errors(response): + """Handle non-successful HTTP responses from the EPPO API. + + This helper function checks whether an HTTP response from the EPPO API + indicates success (status code 200). If the response contains any other + status code, it attempts to parse the JSON body for an error message and + raises a formatted error. + + Args: + response (requests.Response): The HTTP response object. + + Raises: + requests.exceptions.HTTPError: If the request was not successful. + + Returns: + None: The function returns nothing if the request was successful. + """ + + _checks._require_type(value=response, expected_type=requests.Response) + + handled_error_status_codes_ = [400, 401, 403, 404, 429, 500] + + if response.status_code == 200: + return + + if response.status_code in handled_error_status_codes_: + try: + error_message_ = response.json().get("error", "Unknown error") + except JSONDecodeError as e_: + error_message_ = e_.msg + raise requests.HTTPError(f"API request failed: {error_message_}") + + raise requests.HTTPError("API request failed with status code " + + f"{response.status_code}") + + +def _parse_response(response): + """Parse a JSON API response. + + This helper function parses the JSON body of an API response. + + Args: + response (requests.Response): The HTTP response object. + + Raises: + JSONDecodeError: If the response body can not be parsed as valid JSON. + + Returns: + DataFrame: A Pandas DataFrame representing the parsed JSON response. + """ + + _checks._require_type(value=response, expected_type=requests.Response) + + try: + response_json_ = response.json() + response_data_ = _data._flatten(response_json_) + except (JSONDecodeError, KeyError) as e_: + raise JSONDecodeError(f"Failed to parse API response: {e_.msg}", + e_.doc, e_.pos) + + return response_data_ + + +def _enrich_response(response_data, url): + """Enrich API response data. + + This helper function takes a structure containing API response data and + enriches it with metadata, including the timestamp and the queried URL. + + Args: + response_data (DataFrame): A structure containing the API response + data. + url (str): The URL that was queried. + + Returns: + DataFrame: A Pandas DataFrame containing the original API response + data, along with two additional fields: `queried_on`, the timestamp + when the data was queried, and `queried_url`, the URL used for + the API request. + """ + + _checks._require_type(value=response_data, expected_type=pd.DataFrame) + _checks._require_type(value=url, expected_type=str) + + response_data["queried_on"] = datetime.now() + response_data["queried_url"] = url + + return response_data + + +def _query(endpoint, api_key, params=None): + """Query the EPPO REST API and return the result. + + This function performs a GET request to the EPPO REST API, automatically + builds the full request URL, adds the authentication header, handles HTTP + errors, parses the response and adds metadata about the query. + + Specific HTTP status codes (400, 401, 403, 404, 429 and 500) are handled + explicitly to extract the error message returned by the API; other status + codes trigger a connection error. + + Args: + endpoint (str): The relative path of the endpoint to query, starting + with a forward slash (`/`). + api_key (str): The API key used for authentication. + params (dict, optional): Optional query parameters to include in the + request. + + Returns: + DataFrame: A Pandas DataFrame containing the parsed JSON response from + the API, along with metadata fields. + """ + + _checks._require_type(value=endpoint, expected_type=str) + _checks._require_trailing_slash(string=endpoint) + _checks._require_type(value=api_key, expected_type=str) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + base_url_ = "https://api.eppo.int/gd/v2" + full_url_ = base_url_ + endpoint + + response_ = _perform_request( + url=full_url_, + api_key=api_key, + params=params + ) + + _handle_http_errors(response=response_) + + response_data_ = _parse_response(response=response_) + + enriched_data_ = _enrich_response(response_data=response_data_, + url=full_url_) + + return enriched_data_ + + +def _fetch_service(base_path, api_key, code=None, service=None, + params=None): + """Fetch data from a specific EPPO API service. + + This function retrieves data from a specific service of the EPPO API. It + builds the appropriate endpoint according to the EPPO API structure, then + queries the API. + + Args: + base_path (str): The base path, starting with '/' (e.g. + "/taxons/taxon"). + api_key (str): The API key used for authentication. + code (str, optional): The resource identifier (e.g. an EPPO code or an + ISO code). + service (str, optional): The desired API service. + params (dict, optional): Optional query parameters to include in the + request. + + Returns: + DataFrame: A Pandas DataFrame containing the data returned by the + specified EPPO API service, along with metadata fields. + """ + + _checks._require_type(value=base_path, expected_type=str) + _checks._require_trailing_slash(string=base_path) + _checks._require_type(value=api_key, expected_type=str) + if code is not None: + _checks._require_type(value=code, expected_type=str) + if service is not None: + _checks._require_type(value=service, expected_type=str) + if params is not None: + _checks._require_type(value=params, expected_type=dict) + + service_endpoint_ = _build_endpoint( + base_path=base_path, + code=code, + service=service + ) + + service_data_ = _query(endpoint=service_endpoint_, api_key=api_key, + params=params) + + return service_data_ diff --git a/src/eppoPynder/api_query.py b/src/eppoPynder/api_query.py deleted file mode 100644 index 8252228..0000000 --- a/src/eppoPynder/api_query.py +++ /dev/null @@ -1,78 +0,0 @@ -import numpy as np -import pandas as pd -import requests -from datetime import date - -from eppoPynder.unnest_lists import unnest_lists - -def api_query(queried_eppocode, queried_url): - """ - Query the EPPO database via REST API to retrieve basic information, - all names, taxonomy, categorization, hosts, pests, or kingdom data about an EPPO code. - - Parameters - ---------- - queried_eppocode : str - A single EPPO code. EPPO codes are unique computer codes developed for plants and pests - (including pathogens) important in agriculture and plant protection. These codes - facilitate the management of plant and pest names in databases and enable data exchange - between IT systems. Each EPPO code consists of 5 to 6 letters, often mnemonic - abbreviations of the scientific name of the organism, and can be freely downloaded - from the EPPO Data Services platform at https://data.eppo.int/. - - queried_url : str - The URL to query. The URL should be in the format: - https://data.eppo.int/api/rest/1.0/taxon/queriedEppocode?authtoken=xxxxxxxxxxxxxxxxxxx - Replace "queriedEppocode" with the EPPO code of interest and add your unique token using the "authtoken" parameter. - - Returns - ------- - df : pd.DataFrame - A dataframe containing the contents of the request converted from JSON. - Based on the query, the output dataframe will contain basic information, all names, - taxonomy, categorization, hosts, pests, or kingdom data about the input EPPO code. - The dataframe will also include the following columns: - - queried_eppocode: The EPPO code requested. - - queried_on: The date when the query was performed. - - queried_url: The URL that was queried. - - Examples - -------- - # Get basic information about Bemisia tabaci: - queried_eppocode = "BEMITA" - queried_url = "https://data.eppo.int/api/rest/1.0/taxon/BEMITA?authtoken=xxxxxxxxxxxxxxxxxxx" - api_query(queried_eppocode, queried_url) - - # Get taxonomy data about Bemisia tabaci: - queried_eppocode = "BEMITA" - queried_url = "https://data.eppo.int/api/rest/1.0/taxon/BEMITA/taxonomy?authtoken=xxxxxxxxxxxxxxxxxxx" - api_query(queried_eppocode, queried_url) - - # Get all names about Aphis pomi: - queried_eppocode = "APHIPO" - queried_url = "https://data.eppo.int/api/rest/1.0/taxon/APHIPO/names?authtoken=xxxxxxxxxxxxxxxxxxx" - api_query(queried_eppocode, queried_url) - """ - assert isinstance(queried_eppocode, str), "queried_eppocode must be a string!" - assert isinstance(queried_url, str), "queried_url must be a string!" - - df = pd.DataFrame() - - try: - requested_service = requests.get(queried_url) - requested_service.raise_for_status() - json_response = requested_service.json() - data = unnest_lists(json_response) - df = pd.json_normalize(data) - - except (requests.exceptions.MissingSchema, requests.exceptions.InvalidURL) as e: - print(f"{e}") - except requests.exceptions.HTTPError as e: - print(f"HTTP error: {e}") - - finally: - df['queried_eppocode'] = pd.Series([queried_eppocode for i in range(len(df)+1)]) - df['queried_on'] = pd.Series([str(date.today()) for i in range(len(df)+1)]) - df['queried_url'] = pd.Series([queried_url for i in range(len(df)+1)]) - - return df diff --git a/src/eppoPynder/client.py b/src/eppoPynder/client.py new file mode 100644 index 0000000..7a5e733 --- /dev/null +++ b/src/eppoPynder/client.py @@ -0,0 +1,448 @@ +import os +from dotenv import load_dotenv + +from eppopynder._utils import _checks +from eppopynder._core import (_general, _taxons, _taxon, _country, _rppo, + _tools, _reporting_service, _references) + + +class Client: + """Client class for working with the EPPO API. + + Attributes: + _api_key (str): The API key used for authentication. + + Methods: + general(services): Query the EPPO API General endpoint. + taxons(services, params): Query the EPPO API Taxons endpoint. + taxon(eppo_codes, services): Query the EPPO API Taxon endpoint. + country(iso_codes, services): Query the EPPO API Country endpoint. + rppo(rppo_codes, services): Query the EPPO API RPPO endpoint. + tools(services, params): Query the EPPO API Tools endpoint. + reporting_service(services, params): Query the EPPO API Reporting + Service endpoint. + references(services): Query the EPPO API References endpoint. + """ + + def __init__(self, api_key=None): + """Initialize the client. + + Args: + api_key (str, optional): The API key used for authentication. + + Examples: + >>> from eppopynder import Client + + >>> # Create a client using the API key defined in the .env file. + >>> client_with_default = Client() + + >>> # Create a client using a manually specified API key. + >>> client_with_api_key = Client(api_key="") + """ + + if api_key is not None: + self._api_key = api_key + else: + load_dotenv() + self._api_key = os.getenv("EPPO_API_KEY") + + if self._api_key is None: + raise ValueError( + "The EPPO_API_KEY environment variable is not set") + + _checks._require_type(value=self._api_key, expected_type=str) + + if not self._api_key.strip(): + raise ValueError("The API key can not be empty") + + def general(self, services=None): + """Query the EPPO API General endpoint. + + This function queries the General endpoints of the EPPO Global Database + via REST API. The function sequentially queries all specified + `services` and returns the extracted data. + + Args: + services (list[GeneralService], optional): One or more General + services to query. A validation step ensures that all provided + services are of type `GeneralService` and match the supported + service names. If not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content. + + Examples: + >>> from eppopynder import Client, GeneralService + + >>> client = Client() + + >>> # Get information about system health status. + >>> data = client.general(services=[GeneralService.STATUS]) + """ + + return _general._general(api_key=self._api_key, services=services) + + def taxons(self, services=None, params=None): + """Query the EPPO API Taxons endpoint. + + This function queries the Taxons endpoints of the EPPO Global Database + via REST API. The function sequentially queries all specified + `services` and returns the extracted data. + + Args: + services (list[TaxonsService], optional): One or more Taxons + services to query. A validation step ensures that all provided + services are of type `TaxonsService` and match the supported + service names. If not provided, all services are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content. + + Examples: + >>> from eppopynder import Client, TaxonsService + + >>> client = Client() + + >>> # Get the list of taxons with default parameters. + >>> data = client.taxons(services=[TaxonsService.LIST]) + + >>> # Get the list of taxons with custom parameters. + ... data = client.taxons( + ... services=[TaxonsService.LIST], + ... params={ + ... "list": { + ... "createdFromDate": "2000-01-01", + ... "limit": 5, + ... "offset": 100, + ... "orderAsc": False, + ... "orderBy": "eppocode" + ... } + ... } + ... ) + """ + + return _taxons._taxons(api_key=self._api_key, services=services, + params=params) + + def taxon(self, eppo_codes, services=None): + """Query the EPPO API Taxon endpoint. + + This function queries the Taxon endpoints of the EPPO Global Database + via REST API for one or more EPPO code(s) and one or more service(s). + For each EPPO code in `eppo_codes`, the function sequentially queries + all specified `services` and returns the extracted data. + + Args: + eppo_codes (list[str]): One or more EPPO codes to query. + services (list[TaxonService], optional): One or more Taxon services + to query. A validation step ensures that all provided services + are of type `TaxonService` and match the supported service + names. If not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content for all the specified EPPO + codes. + + Examples: + >>> from eppopynder import Client, TaxonService + + >>> client = Client() + + >>> # Get all information about Bemisia tabaci. + >>> data = client.taxon(eppo_codes=["BEMITA"]) + + >>> # Get names data about Bemisia tabaci. + >>> data = client.taxon( + ... eppo_codes=["BEMITA"], + ... services=[TaxonService.NAMES] + ... ) + + >>> # Get taxonomy and categorization data about Bemisia tabaci and + >>> # Gossypium hirsutum. + >>> data = client.taxon( + ... eppo_codes=["BEMITA", "GOSHI"], + ... services=[ + ... TaxonService.TAXONOMY, + ... TaxonService.CATEGORIZATION + ... ] + ... ) + """ + + return _taxon._taxon(api_key=self._api_key, eppo_codes=eppo_codes, + services=services) + + def country(self, iso_codes, services=None): + """Query the EPPO API Country endpoint. + + This function queries the Country endpoints of the EPPO Global Database + via REST API for one or more ISO code(s) and one or more service(s). + For each ISO code in `iso_codes`, the function sequentially queries all + specified `services` and returns the extracted data through a list of + dataframes. + + Args: + iso_codes (list[str]): One or more ISO codes to query. + services (list[CountryService], optional): One or more Country + services to query. A validation step ensures that all provided + services are of type `CountryService` and match the supported + service names. If not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content for all the specified ISO + codes. + + Examples: + >>> from eppopynder import Client, CountryService + + >>> client = Client() + + >>> # Get all information about France. + >>> data = client.country(iso_codes=["FR"]) + + >>> # Get overview data about France. + >>> data = client.country( + ... iso_codes=["FR"], + ... services=[CountryService.OVERVIEW] + ... ) + + >>> # Get overview and categorization data about France and Italy. + >>> data = client.country( + ... iso_codes=["FR", "IT"], + ... services=[ + ... CountryService.OVERVIEW, + ... CountryService.CATEGORIZATION + ... ] + ... ) + """ + + return _country._country(api_key=self._api_key, iso_codes=iso_codes, + services=services) + + def rppo(self, rppo_codes, services=None): + """Query the EPPO API RPPO endpoint. + + This function queries the RPPO endpoints of the EPPO Global Database + via REST API for one or more RPPO code(s) and one or more service(s). + For each RPPO code in `rppo_codes`, the function sequentially queries + all specified `services` and returns the extracted data through a list + of dataframes. + + Args: + rppo_codes (list[str]): One or more RPPO codes to query. + services (list[CountryService], optional): One or more RPPO + services to query. A validation step ensures that all provided + services are of type `RPPOService` and match the supported + service names. If not provided, all services are considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content for all the specified RPPO + codes. + + Examples: + >>> from eppopynder import Client, RPPOService + + >>> client = Client() + + >>> # Get all information about the European and Mediterranean + >>> # Plant Protection Organisation. + >>> data = client.rppo(rppo_codes=["9A"]) + + >>> # Get overview data about the European and Mediterranean + >>> # Plant Protection Organisation. + >>> data = client.rppo( + ... rppo_codes=["9A"], + ... services=[RPPOService.OVERVIEW] + ... ) + + >>> # Get overview and categorization data about the European and + >>> # Mediterranean Plant Protection Organisation and the European + >>> # Union. + >>> data = client.rppo( + ... rppo_codes=["9A", "9L"], + ... services=[ + ... RPPOService.OVERVIEW, + ... RPPOService.CATEGORIZATION + ... ] + ... ) + """ + + return _rppo._rppo(api_key=self._api_key, rppo_codes=rppo_codes, + services=services) + + def tools(self, services=None, params=None): + """Query the EPPO API Tools endpoint. + + This function queries the Tools endpoints of the EPPO Global Database + via REST API. The function sequentially queries all specified + `services` and returns the extracted data through a dictionary of data + frames. + + Args: + services (list[ToolsService], optional): One or more Tools services + to query. A validation step ensures that all provided services + are of type `ToolsService` and match the supported service + names. If not provided, all services are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content. + + Examples: + >>> from eppopynder import Client, ToolsService + + >>> client = Client() + + >>> # Get the EPPO codes associated to the name Bemisia tabaci. + >>> data = client.tools( + ... services=[ToolsService.NAME2CODES], + ... params={ + ... ToolsService.NAME2CODES: { + ... "name": "Bemisia tabaci", + ... "onlyPreferred": False + ... } + ... } + ... ) + """ + + return _tools._tools(api_key=self._api_key, services=services, + params=params) + + def reporting_service(self, services=None, params=None): + """Query the EPPO API Reporting Service endpoint. + + This function queries the Reporting Service endpoints of the EPPO + Global Database via REST API. The function sequentially queries all + specified `services` and returns the extracted data through a + dictionary of data frames. + + Args: + services (list[ReportingServiceService], optional): One or more + Reporting Service services to query. A validation step ensures + that all provided services are of type + `ReportingServiceService` and match the supported service + names. If not provided, all services are considered. + params (dict, optional): A named dictionary of query parameters to + include in the request. The list of available parameters can be + accessed via the EPPO API Documentation platform + (https://data2025.eppo.int/ui/#/docs/GDAPI). + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content. + + Examples: + >>> from eppopynder import Client, ReportingServiceService + + >>> client = Client() + + >>> # Get the list of reporting service issues. + >>> data = client.reporting_service( + ... services=[ReportingServiceService.LIST] + ... ) + + >>> # Get a specific reporting service issue. + >>> data = client.reporting_service( + ... services=[ReportingServiceService.REPORTING], + ... params={ + ... ReportingServiceService.REPORTING: { + ... "reporting_id": 10 + ... } + ... } + ... ) + + >>> # Get a specific article. + >>> data = client.reporting_service( + ... services=[ReportingServiceService.ARTICLE], + ... params={ + ... ReportingServiceService.ARTICLE: { + ... "article_id": 234 + ... } + ... } + ... ) + + >>> # Get the list of reporting service issues, a specific + >>> # reporting service issue and a specific article. + >>> data = client.reporting_service( + ... params={ + ... ReportingServiceService.REPORTING: { + ... "reporting_id": 10 + ... }, + ... ReportingServiceService.ARTICLE: { + ... "article_id": 234 + ... } + ... } + ... ) + """ + + return _reporting_service._reporting_service( + api_key=self._api_key, + services=services, + params=params + ) + + def references(self, services=None): + """Query the EPPO API References endpoint. + + This function queries the References endpoints of the EPPO Global + Database via REST API. The function sequentially queries all specified + `services` and returns the extracted data through a dictionary of data + frames. + + Args: + services (list[ReferencesService], optional): One or more + References services to query. A validation step ensures that + all provided services are of type `ReferencesService` and match + the supported service names. If not provided, all services are + considered. + + Returns: + dict: A dictionary, in which each entry corresponds to the data + retrieved for each specified service. Each element contains a + data frame with the queried content. + + Examples: + >>> from eppopynder import Client, ReferencesService + + >>> client = Client() + + >>> # Get all references information. + >>> data = client.references() + + >>> # Get information about distribution status codes. + >>> data = client.references( + ... services=[ReferencesService.DISTRIBUTION_STATUS] + ... ) + + # Get information about EPPO list codes and labels and countries. + >>> data = client.references( + ... services=[ + ... ReferencesService.Q_LIST, + ... ReferencesService.COUNTRIES + ... ] + ... ) + """ + + return _references._references( + api_key=self._api_key, + services=services + ) diff --git a/src/eppoPynder/data_dump.py b/src/eppoPynder/data_dump.py deleted file mode 100644 index b0eeab4..0000000 --- a/src/eppoPynder/data_dump.py +++ /dev/null @@ -1,74 +0,0 @@ -from eppoPynder.query_the_eppo_for_service import query_the_eppo_for_service -import pandas as pd -import os -from dotenv import load_dotenv - -# Load environment variables from a .env file (if present) -load_dotenv() - -def data_dump(codes_to_scan, token = os.getenv('EPPO_token')): - """ - Create a dump of the whole EPPO database via REST API for one or more EPPO code(s). - - Parameters - ---------- - codes_to_scan : list of str - One or more EPPO code(s) as a list of strings. - - token : str, optional - Manually add your unique token or set it inside a .env file. - Default is retrieved from the environment variable EPPO_token using os.getenv('EPPO_token'). - - Returns - ------- - dump : dict of {str : pd.DataFrame} - A dictionary of pandas dataframes, each containing basic information, all names, taxonomy, categorization, hosts, pests and kingdom data about the input EPPO code, respectively. - The dataframes will also include the following columns: - - queried_eppocode: The EPPO code requested. - - queried_on: The date when the query was performed. - - queried_url: The URL that was queried. - - Examples - -------- - # Create a dump of all data about Bemisia tabaci: basic information, all names, taxonomy, categorization, hosts, pests and kingdom data. - data_dump(["BEMITA"]) - - # Create a dump of all data about Aphis pomi and Leucoptera malifoliella: basic information, all names, taxonomy, categorization, hosts, pests and kingdom data. - data_dump(["APHIPO", "LEUCSC"]) - """ - if not token: - token = "default_token" - else: - assert isinstance(token, str), "token must be a string!" - - if not isinstance(codes_to_scan, list): - raise AssertionError("Input must be a list!") - if not codes_to_scan: - raise AssertionError("Input list cannot be empty!") - if not all(isinstance(code, str) for code in codes_to_scan): - raise AssertionError("All codes must be strings!") - - general = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="", token=token) for i in codes_to_scan]) - general.insert(0, "pestCode", general[["queried_eppocode"]], True) - - names = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="names", token=token) for i in codes_to_scan]) - names.insert(0, "pestCode", names[["queried_eppocode"]], True) - - taxonomy = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="taxonomy", token=token) for i in codes_to_scan]) - taxonomy.insert(0, "pestCode", taxonomy[["queried_eppocode"]], True) - - categorization = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="categorization", token=token) for i in codes_to_scan]) - categorization.insert(0, "pestCode", categorization[["queried_eppocode"]], True) - - hosts = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="hosts", token=token) for i in codes_to_scan]) - hosts.insert(0, "pestCode", hosts[["queried_eppocode"]], True) - - pests = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="pests", token=token) for i in codes_to_scan]) - pests.insert(0, "pestCode", pests[["queried_eppocode"]], True) - - kingdom = pd.concat([query_the_eppo_for_service(queried_eppocode=i, service="kingdom", token=token) for i in codes_to_scan]) - kingdom.insert(0, "pestCode", kingdom[["queried_eppocode"]], True) - - dump = {"general":general, "names":names, "taxonomy":taxonomy, "categorization":categorization, "hosts":hosts, "pests":pests, "kingdom":kingdom} - - return dump diff --git a/src/eppoPynder/data_wrangling.py b/src/eppoPynder/data_wrangling.py new file mode 100644 index 0000000..f767bf8 --- /dev/null +++ b/src/eppoPynder/data_wrangling.py @@ -0,0 +1,75 @@ +"""This module contains functions for data wrangling.""" + +import pandas as pd + +from eppopynder._utils import _checks + +def uniform_taxonomy(taxonomy_data): + """Create a complete and uniform taxonomy dataframe. + + This function normalizes the taxonomy returned by the EPPO service, + producing a uniform structure that includes all possible taxonomic + categories, even when some of them are not present in the original result. + + Args: + taxonomy_data (pandas.DataFrame): A dataframe containing taxonomy data + provided by the EPPO service for a given EPPO code. + + Returns: + pandas.DataFrame: A dataframe where each row represents one of the + expected taxonomic ranks. Fields corresponding to ranks not present in + the original taxonomy are filled with `NaN`/`NaT`. The `level` column + is excluded from the output. + + Examples: + >>> from eppopynder import Client, TaxonService uniform_taxonomy + + >>> client = Client() + + >>> # Retrieve taxonomy data from the EPPO service. + >>> taxon_data = client.taxon( + ... eppo_codes=["BEMITA"], + ... services=[TaxonService.TAXONOMY] + ... ) + + >>> # Create a uniform taxonomy with all ranks. + >>> taxonomy = uniform_taxonomy( + ... taxonomy_data=taxon_data[TaxonService.TAXONOMY]) + """ + + _checks._require_type(value=taxonomy_data, expected_type=pd.DataFrame) + _checks._require_column_names(dataframe=taxonomy_data, + column_names=["queried_eppo_code", "type"]) + _checks._require_not_all_nan(dataframe=taxonomy_data, + column_name="queried_eppo_code") + + taxonomy_types_ = pd.DataFrame({ + "type": [ + "Kingdom", + "Phylum", + "Subphylum", + "Class", + "Subclass", + "Order", + "Suborder", + "Family", + "Subfamily", + "Genus", + "Species" + ] + }) + + uniformed_taxonomy_data_ = ( + taxonomy_types_ + .merge(taxonomy_data, on="type", how="left") + .drop(columns="level", errors="ignore") + ) + + queried_eppo_code_ = \ + uniformed_taxonomy_data_["queried_eppo_code"].dropna().iloc[0] + + uniformed_taxonomy_data_["queried_eppo_code"] = \ + uniformed_taxonomy_data_["queried_eppo_code"] \ + .fillna(queried_eppo_code_) + + return uniformed_taxonomy_data_ diff --git a/src/eppoPynder/getting_countries.py b/src/eppoPynder/getting_countries.py deleted file mode 100644 index 077318b..0000000 --- a/src/eppoPynder/getting_countries.py +++ /dev/null @@ -1,106 +0,0 @@ -import numpy as np - -def getting_countries(acronym): - """ - Function to translate the acronyms of the Regional Plant Protection Organizations used in the EPPO database to the corresponding member countries. - - Parameters - ---------- - acronym : str - The acronym of the Regional Plant Protection Organization. - - Returns - ------- - countries : str - All the member countries. - - Examples - -------- - getting_countries('OIRSA') - """ - assert isinstance(acronym, str), "acronym must be a string!" - - if acronym == 'EPPO': - countries = ", ".join([ - 'Albania', 'Algeria', 'Austria', 'Azerbaijan', 'Belarus', 'Belgium', - 'Bosnia and Herzegovina', 'Bulgaria', 'Croatia', 'Cyprus', 'Czech Republic', - 'Denmark', 'Estonia', 'Finland', 'France', 'Georgia', 'Germany', 'Greece', - 'Guernsey', 'Hungary', 'Ireland', 'Israel', 'Italy', 'Jersey', 'Jordan', - 'Kazakhstan', 'Kyrgyzstan', 'Latvia', 'Lithuania', 'Luxembourg', 'Malta', - 'Moldova', 'Montenegro', 'Morocco', 'Netherlands', 'North Macedonia', 'Norway', - 'Poland', 'Portugal', 'Romania', 'Russia', 'Serbia', 'Slovakia', 'Slovenia', - 'Spain', 'Sweden', 'Switzerland', 'Tunisia', 'Türkiye', 'Ukraine', 'United Kingdom', - 'Uzbekistan' - ]) - elif acronym == 'OIRSA': - countries = ", ".join([ - 'Belize', 'Costa Rica', 'Dominican Republic', 'El Salvador', 'Guatemala', - 'Honduras', 'Mexico', 'Nicaragua', 'Panama' - ]) - elif acronym == 'EAEU': - countries = ", ".join([ - 'Armenia', 'Belarus', 'Kazakhstan', 'Kyrgyzstan', 'Russia' - ]) - elif acronym == 'COSAVE': - countries = ", ".join([ - 'Argentina', 'Bolivia', 'Brazil', 'Chile', 'Paraguay', 'Peru', 'Uruguay' - ]) - elif acronym == 'EU': - countries = ", ".join([ - 'Austria', 'Belgium', 'Bulgaria', 'Croatia', 'Cyprus', 'Czech Republic', - 'Denmark', 'Estonia', 'Finland', 'France', 'Germany', 'Greece', 'Hungary', - 'Ireland', 'Italy', 'Latvia', 'Lithuania', 'Luxembourg', 'Malta', 'Netherlands', - 'Poland', 'Portugal', 'Romania', 'Slovakia', 'Slovenia', 'Spain', 'Sweden' - ]) - elif acronym == 'APPPC': - countries = ", ".join([ - 'Australia', 'Bangladesh', 'Cambodia', 'China', 'East Timor', 'Fiji', - 'French Polynesia', 'India', 'Indonesia', "Korea Dem. People's Republic", - 'Korea, Republic', 'Laos', 'Malaysia', 'Myanmar', 'Nepal', 'New Zealand', - 'Pakistan', 'Papua New Guinea', 'Philippines', 'Samoa', 'Solomon Islands', - 'Sri Lanka', 'Thailand', 'Tonga', 'Vietnam' - ]) - elif acronym == 'CAHFSA': - countries = ", ".join([ - 'Antigua and Barbuda', 'Bahamas', 'Barbados', 'Belize', 'Dominica', 'Grenada', - 'Guyana', 'Haiti', 'Jamaica', 'Montserrat', 'Saint Lucia', 'St Kitts-Nevis', - 'St Vincent and the Grenadines', 'Suriname', 'Trinidad and Tobago' - ]) - elif acronym == 'CAN': - countries = ", ".join([ - 'Bolivia', 'Colombia', 'Ecuador', 'Peru', 'Venezuela' - ]) - elif acronym == 'IAPSC': - countries = ", ".join([ - 'Algeria', 'Angola', 'Benin', 'Botswana', 'Burkina Faso', 'Burundi', 'Cameroon', - 'Cape Verde', 'Central African Republic', 'Chad', 'Comoros', 'Congo', - 'Congo, Democratic Republic of the', "Cote d'Ivoire", 'Djibouti', 'Egypt', - 'Equatorial Guinea', 'Eritrea', 'Eswatini', 'Ethiopia', 'Gabon', 'Gambia', - 'Ghana', 'Guinea', 'Guinea-Bissau', 'Kenya', 'Lesotho', 'Liberia', 'Libya', - 'Madagascar', 'Malawi', 'Mali', 'Mauritania', 'Mauritius', 'Morocco', 'Mozambique', - 'Namibia', 'Niger', 'Nigeria', 'Rwanda', 'Sao Tome & Principe', 'Senegal', - 'Seychelles', 'Sierra Leone', 'Somalia', 'South Africa', 'South Sudan', 'Sudan', - 'Tanzania', 'Togo', 'Tunisia', 'Uganda', 'Zaire', 'Zambia', 'Zimbabwe' - ]) - elif acronym == 'NAPPO': - countries = ", ".join([ - 'Canada', 'Mexico', 'United States of America' - ]) - elif acronym == 'NEPPO': - countries = ", ".join([ - 'Algeria', 'Egypt', 'Jordan', 'Libya', 'Malta', 'Morocco', 'Pakistan', - 'South Sudan', 'Sudan', 'Syria', 'Tunisia' - ]) - elif acronym == 'PPPO': - countries = ", ".join([ - 'American Samoa', 'Australia', 'Cook Islands', 'Fiji', 'French Polynesia', - 'Guam', 'Kiribati', 'Marshall Islands', 'Micronesia', 'Nauru', 'New Caledonia', - 'New Zealand', 'Niue', 'Northern Mariana Islands', 'Palau', 'Papua New Guinea', - 'Pitcairn', 'Samoa', 'Solomon Islands', 'Tokelau', 'Tonga', 'Tuvalu', 'Vanuatu', - 'Wallis and Futuna Islands' - ]) - else: - countries = np.nan - print("Unknown acronym") - - return countries diff --git a/src/eppoPynder/query_the_eppo_for_service.py b/src/eppoPynder/query_the_eppo_for_service.py deleted file mode 100644 index 5f4c867..0000000 --- a/src/eppoPynder/query_the_eppo_for_service.py +++ /dev/null @@ -1,82 +0,0 @@ -from eppoPynder.api_query import api_query -import numpy as np -import os -from dotenv import load_dotenv - -# Load environment variables from a .env file (if present) -load_dotenv() - -def query_the_eppo_for_service(queried_eppocode, base_url = "https://data.eppo.int/api/rest/1.0/taxon/", service = "categorization", token = os.getenv('EPPO_token')): - """ - Query the EPPO database via REST API by specifying the name of the required service to retrieve - basic information, all names, taxonomy, categorization, hosts, pests, or kingdom data - about an EPPO code. - - Parameters - ---------- - queried_eppocode : str - A single EPPO code. EPPO codes are unique computer codes developed for plants and pests - (including pathogens) important in agriculture and plant protection. These codes - facilitate the management of plant and pest names in databases and enable data exchange - between IT systems. Each EPPO code consists of 5 to 6 letters, often mnemonic - abbreviations of the scientific name of the organism, and can be freely downloaded - from the EPPO Data Services platform at https://data.eppo.int/. - - base_url : str, optional - URL root for all REST API requests. Default is "https://data.eppo.int/api/rest/1.0". - - service : str, optional - The specific service to query. Choose from the following options: - - "" : basic information - - "names" : all names - - "taxonomy" : taxonomy data - - "categorization" : categorization data - - "hosts" : hosts data - - "pests" : pests data - - "kingdom" : kingdom taxonomic rank - Default is "categorization". - - token : str, optional - Manually add your unique token or set it inside a .env file. - Default is retrieved from the environment variable EPPO_token using os.getenv('EPPO_token'). - - Returns - ------- - queried_service : pd.DataFrame - A dataframe containing the contents of the request converted from JSON. - Based on the query, the output dataframe will contain basic information, all names, - taxonomy, categorization, hosts, pests, or kingdom data about the input EPPO code. - The dataframe will also include the following columns: - - queried_eppocode: The EPPO code requested. - - queried_on: The date when the query was performed. - - queried_url: The URL that was queried. - - Examples - -------- - # Get basic information about Bemisia tabaci: - query_the_eppo_for_service("BEMITA", service="") - - # Get all names for Bemisia tabaci: - query_the_eppo_for_service("BEMITA", service="names") - - # Get categorization data for Bemisia tabaci: - query_the_eppo_for_service("BEMITA", service="categorization") - """ - assert isinstance(queried_eppocode, str), "queried_eppocode must be a string!" - assert isinstance(base_url, str), "base_url must be a string!" - assert isinstance(service, str), "service must be a string!" - - if not token: - token = "default_token" - else: - assert isinstance(token, str), "token must be a string!" - - queried_url = base_url+queried_eppocode+"/"+service+"?authtoken="+token - - if service == "": - queried_url = base_url+queried_eppocode+"?authtoken="+token - - queried_service = api_query(queried_eppocode=queried_eppocode, queried_url=queried_url) - - return queried_service - diff --git a/src/eppoPynder/query_the_whole_eppo.py b/src/eppoPynder/query_the_whole_eppo.py deleted file mode 100644 index 2e6a338..0000000 --- a/src/eppoPynder/query_the_whole_eppo.py +++ /dev/null @@ -1,64 +0,0 @@ -from eppoPynder.query_the_eppo_for_service import query_the_eppo_for_service -import numpy as np -import os -from dotenv import load_dotenv - -# Load environment variables from a .env file (if present) -load_dotenv() - -def query_the_whole_eppo(queried_eppocode, base_url = "https://data.eppo.int/api/rest/1.0/taxon/", token = os.getenv('EPPO_token')): - """ - Query the EPPO database via REST API to retrieve basic information, - all names, taxonomy, categorization, hosts, pests, and kingdom data about an EPPO code. - - Parameters - ---------- - queried_eppocode : str - A single EPPO code. EPPO codes are unique computer codes developed for plants and pests - (including pathogens) important in agriculture and plant protection. These codes - facilitate the management of plant and pest names in databases and enable data exchange - between IT systems. Each EPPO code consists of 5 to 6 letters, often mnemonic - abbreviations of the scientific name of the organism, and can be freely downloaded - from the EPPO Data Services platform at https://data.eppo.int/. - - base_url : str, optional - URL root for all REST API requests. Default is "https://data.eppo.int/api/rest/1.0". - - token : str, optional - Manually add your unique token or set it inside a .env file. - Default is retrieved from the environment variable EPPO_token using os.getenv('EPPO_token'). - - Returns - ------- - EPPO_dict : dict of {str : pd.DataFrame} - A dictionary of pandas dataframes, each containing basic information, all names, taxonomy, categorization, hosts, pests and kingdom data about the input EPPO code, respectively. - The dataframes will also include the following columns: - - queried_eppocode: The EPPO code requested. - - queried_on: The date when the query was performed. - - queried_url: The URL that was queried. - - Examples - -------- - # Get all information about Bemisia tabaci: basic information, all names, taxonomy, - # categorization, hosts, pests, and kingdom data. - query_the_whole_eppo("BEMITA") - """ - if not token: - token = "default_token" - else: - assert isinstance(token, str), "token must be a string!" - - assert isinstance(queried_eppocode, str), "queried_eppocode must be a string!" - assert isinstance(base_url, str), "base_url must be a string!" - - services = ["", "names", "taxonomy", "categorization", "hosts", "pests", "kingdom"] - - EPPO_list = [] - - for service in services: - EPPO_list.append(query_the_eppo_for_service(queried_eppocode=queried_eppocode, base_url=base_url, service=service, token=token)) - - services[0]="general" - EPPO_dict = {name: df for name, df in zip(services, EPPO_list)} - - return EPPO_dict diff --git a/src/eppoPynder/taxonomy_ranked.py b/src/eppoPynder/taxonomy_ranked.py deleted file mode 100644 index 1a22c66..0000000 --- a/src/eppoPynder/taxonomy_ranked.py +++ /dev/null @@ -1,34 +0,0 @@ -import numpy as np -import pandas as pd - -def taxonomy_ranked(taxonomy, kingdom): - """ - Merge taxonomy and kingdom information into a single dataframe. - - Parameters - ---------- - taxonomy : pd.DataFrame - A pandas dataframe containing taxonomy data about the queried EPPO code. - - kingdom : pd.DataFrame - A pandas dataframe containing kingdom data about the queried EPPO code. - - Returns - ------- - taxonomy_ranked_ : pd.DataFrame - A pandas dataframe containing taxonomy and kingdom information about the queried EPPO code. - - Examples - -------- - # Get taxonomy and kingdom data about Bemisia tabaci: - taxonomy = query_the_eppo_for_service(queried_eppocode="BEMITA", service="taxonomy") - kingdom = query_the_eppo_for_service(queried_eppocode="BEMITA", service="kingdom") - - # Merge taxonomy and kingdom information about Bemisia tabaci into a single dataframe: - taxonomy_ranked(taxonomy, kingdom) - """ - taxonomy_ranked_ = pd.merge(taxonomy, kingdom[["eppocode", "queried_eppocode", "status"]], how='left', on=["eppocode", "queried_eppocode"]) - taxonomy_ranked_ = taxonomy_ranked_.rename(columns={'status':'rank'}) - taxonomy_ranked_.insert(0, "rank", taxonomy_ranked_.pop("rank")) - taxonomy_ranked_["rank"] = np.where(taxonomy_ranked_["rank"].notnull(), "kingdom", pd.NA) - return taxonomy_ranked_ diff --git a/src/eppoPynder/unnest_lists.py b/src/eppoPynder/unnest_lists.py deleted file mode 100644 index aeda42c..0000000 --- a/src/eppoPynder/unnest_lists.py +++ /dev/null @@ -1,25 +0,0 @@ -def unnest_lists(json_response): - """ - Unnest nested lists and dictionaries in a JSON dictionary of host data retrieved from EPPO. - - Parameters - ---------- - json_response : dict - A JSON dictionary of nested lists and dictionaries containing the contents of a request. - - Returns - ------- - json_response : list - A list of JSON dictionaries containing the contents of a request. - """ - if type(json_response) is dict and len(json_response)>0 and ("Major host" in json_response or "Host" in json_response or "Wild/Weed" in json_response or "Alternate" in json_response or "Experimental" in json_response or "Doubtful host" in json_response or "Non-host" in json_response): - unnest_hosts = (json_response.get("Major host") if json_response.get("Major host") is not None else []) + \ - (json_response.get("Host") if json_response.get("Host") is not None else []) + \ - (json_response.get("Wild/Weed") if json_response.get("Wild/Weed") is not None else []) + \ - (json_response.get("Alternate") if json_response.get("Alternate") is not None else []) + \ - (json_response.get("Experimental") if json_response.get("Experimental") is not None else []) + \ - (json_response.get("Doubtful host") if json_response.get("Doubtful host") is not None else []) + \ - (json_response.get("Non-host") if json_response.get("Non-host") is not None else []) - json_response = unnest_hosts - - return json_response diff --git a/tests/test__checks.py b/tests/test__checks.py new file mode 100644 index 0000000..96af93b --- /dev/null +++ b/tests/test__checks.py @@ -0,0 +1,132 @@ +import unittest +import pandas as pd + +from eppopynder._utils._checks import (_require_type, _require_trailing_slash, + _require_list_of, _check_services, + _require_column_names, + _require_not_all_nan) + + +class TestChecks(unittest.TestCase): + + ################### + # _require_type() # + ################### + + def test__require_type_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _require_type, value=123, + expected_type=str) + + def test__require_type_output(self): + """Test the behaviour for valid data.""" + self.assertIsNone(_require_type(value=123, expected_type=int)) + + ############################# + # _require_trailing_slash() # + ############################# + + def test__require_trailing_slash_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _require_trailing_slash, string=123) + + def test__require_trailing_slash_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(ValueError, _require_trailing_slash, string="country") + + def test__require_trailing_slash_output(self): + """Test the behaviour for valid data.""" + self.assertIsNone(_require_trailing_slash(string="/country")) + + ###################### + # _require_list_of() # + ###################### + + def test__require_list_of_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _require_list_of, items=123, + expected_type=int) + self.assertRaises(TypeError, _require_list_of, items=list(), + expected_type=123) + + def test__require_list_of_invalid(self): + """Test the behaviour for invalid elements.""" + self.assertRaises(TypeError, _require_list_of, items=[1, 2, 'x'], + expected_type=int) + + def test__require_list_of_output(self): + """Test the output for valid elements.""" + self.assertIsNone(_require_list_of(items=[1, 2, 3], expected_type=int)) + + ##################### + # _check_services() # + ##################### + + def test__check_services_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _check_services, services=123, + choices=list()) + self.assertRaises(TypeError, _check_services, services=list(), + choices=123) + self.assertRaises(TypeError, _check_services, services=[1, 2], + choices=['x', 'y']) + + def test__check_services_invalid(self): + """Test the behaviour for invalid element types.""" + self.assertRaises(ValueError, _check_services, services=['x', 'a'], + choices=['x', 'y']) + + def test__check_services_output(self): + """Test the output for valid elements.""" + self.assertIsNone(_check_services( + services=['a', 'b'], + choices=['a', 'b', 'c'] + )) + + ########################### + # _require_column_names() # + ########################### + + def test__require_column_names_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _require_column_names, dataframe=123, + column_names=list()) + self.assertRaises(TypeError, _require_column_names, + dataframe=pd.DataFrame(), column_names=123) + + def test__require_column_names_invalid(self): + """Test the behaviour for invalid element types.""" + self.assertRaises(ValueError, _require_column_names, + dataframe=pd.DataFrame(), column_names=["column_a"]) + + def test__require_column_names_output(self): + """Test the output for valid elements.""" + self.assertIsNone(_require_column_names( + dataframe=pd.DataFrame({"column_a": [1, 2, 3]}), + column_names=["column_a"] + )) + + ########################## + # _require_not_all_nan() # + ########################## + + def test__require_not_all_nan_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _require_not_all_nan, dataframe=123, + column_name="") + self.assertRaises(TypeError, _require_not_all_nan, + dataframe=pd.DataFrame(), column_names=123) + + def test__require_not_all_nan_invalid(self): + """Test the behaviour for invalid element types.""" + self.assertRaises(ValueError, _require_not_all_nan, + dataframe=pd.DataFrame({ + "column_a": [None, None, None]}), + column_name="column_a") + + def test__require_not_all_nan_output(self): + """Test the output for valid elements.""" + self.assertIsNone(_require_not_all_nan( + dataframe=pd.DataFrame({"column_a": [1, None, 1]}), + column_name="column_a" + )) diff --git a/tests/test__country.py b/tests/test__country.py new file mode 100644 index 0000000..256cf01 --- /dev/null +++ b/tests/test__country.py @@ -0,0 +1,103 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._country import _country, CountryService + +load_dotenv() + + +class TestCountry(unittest.TestCase): + + ############## + # _country() # + ############## + + def test__country_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _country, api_key=123, iso_codes=[''], + services=list()) + self.assertRaises(TypeError, _country, api_key='', iso_codes=123, + services=123) + self.assertRaises(TypeError, _country, api_key='', iso_codes=[1, 2], + services=list()) + self.assertRaises(TypeError, _country, api_key='', iso_codes=[''], + services=123) + self.assertRaises(TypeError, _country, api_key='', iso_codes=[''], + services=[1, 2]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__country_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [CountryService.OVERVIEW] + data_ = _country( + api_key="EPPO_API_KEY", + iso_codes=["FR"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[CountryService.OVERVIEW], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__country_output_online(self): + """Test the output dict structure.""" + services_ = [CountryService.OVERVIEW] + data_ = _country( + api_key=os.getenv("EPPO_API_KEY"), + iso_codes=["FR"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[CountryService.OVERVIEW], pd.DataFrame) + + @patch("eppopynder._utils._requests._fetch_service") + def test__country_invalid_iso(self, mock_fetch_service): + """Test the behaviour for invalid ISO codes.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _country, + api_key="EPPO_API_KEY", + iso_codes=["BAD_ISO_CODE"]) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__country_invalid_iso_online(self): + """Test the behaviour for invalid ISO codes.""" + self.assertRaises(HTTPError, _country, + api_key=os.getenv("EPPO_API_KEY"), + iso_codes=["BAD_ISO_CODE"]) + + def test__country_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _country, + api_key="EPPO_API_KEY", + iso_codes=["FR"], services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__country_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _country, api_key="BAD_API_KEY", + iso_codes=["FR"]) + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _country, api_key=None, iso_codes=["FR"]) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__country_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _country, api_key="BAD_API_KEY", + iso_codes=["FR"]) + self.assertRaises(TypeError, _country, + api_key=os.getenv("BAD_API_KEY"), iso_codes=["FR"]) diff --git a/tests/test__data.py b/tests/test__data.py new file mode 100644 index 0000000..d397f55 --- /dev/null +++ b/tests/test__data.py @@ -0,0 +1,209 @@ +import unittest +import pandas as pd + +from eppopynder._utils._data import (_flatten, _transform_taxons, + _transform_references, _merge_batch) +from eppopynder._core._taxons import TaxonsService +from eppopynder._core._references import ReferencesService + + +class TestData(unittest.TestCase): + + ############## + # _flatten() # + ############## + + def test__flatten_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _flatten, nested_data=123) + + def test__flatten_empty(self): + """Test the behaviour for empty data.""" + self.assertTrue(_flatten(nested_data=list()).empty) + self.assertTrue(_flatten(nested_data=dict()).empty) + + def test__flatten_sep(self): + flattened_ = _flatten(nested_data={'a': {'b': 1}}) + self.assertEqual(flattened_.keys()[0], "a_b") + flattened_ = _flatten(nested_data={'a': {'b': 1}}, separator='.') + self.assertEqual(flattened_.keys()[0], "a.b") + + def test__flatten_dict1(self): + """Test the behaviour for flattening a dictionary.""" + flattened_ = _flatten(nested_data={ + 'a': 1, + 'b': 2, + 'c': 3, + 'd': { + '1': 4, + '2': 5 + } + }) + self.assertEqual( + list(flattened_.keys()), + ['a', 'b', 'c', "d_1", "d_2"] + ) + + def test__flatten_dict2(self): + """Test the behaviour for flattening a dictionary.""" + flattened_ = _flatten(nested_data={ + 'a': 1, + 'b': 2, + 'c': 3, + 'd': { + '1': 4, + '2': { + '3': 5 + } + } + }) + self.assertEqual( + list(flattened_.keys()), + ['a', 'b', 'c', "d_1", "d_2_3"] + ) + + def test__flatten_dict3(self): + """Test the behaviour for flattening a dictionary.""" + flattened_ = _flatten(nested_data={ + 'a': 1, + 'b': [ + {'x': 1, 'y': 2, 'z': 3}, + {'x': 4, 'y': 5, 'z': 6} + ] + }) + self.assertEqual( + list(flattened_.keys()), + ['a', "b_x", "b_y", "b_z"] + ) + + def test__flatten_dict4(self): + """Test the behaviour for flattening a dictionary.""" + flattened_ = _flatten(nested_data={ + 'a': 1, + 'b': [ + {'x': 1, 'y': 2, 'z': 3}, + {'x': 4, 'y': 5, 'z': 6}, + "some text" + ] + }) + self.assertEqual( + list(flattened_.keys()), + ['a', "b_x", "b_y", "b_z", 'b'] + ) + + def test__flatten_list_of_dicts(self): + """Test the behaviour for flattening a list of dictionaries.""" + flattened_ = _flatten(nested_data=[ + {'a': 1, 'b': 2, 'c': 3}, + {'a': 4, 'b': 5, 'c': 6} + ]) + self.assertEqual(list(flattened_.keys()), ['a', 'b', 'c']) + + def test__flatten_dict_of_lists1(self): + """Test the behaviour for flattening a dictionary of lists.""" + flattened_ = _flatten(nested_data={ + 'a': [ + {'x': 1, 'y': 2, 'z': 3}, + {'x': 4, 'y': 5, 'z': 6} + ], + 'b': [ + {'x': 7, 'y': 8, 'z': 9}, + {'x': 10, 'y': 11, 'z': 12} + ] + }) + self.assertEqual( + list(flattened_.keys()), + ["parent_key", 'x', 'y', 'z'] + ) + + def test__flatten_dict_of_lists2(self): + """Test the behaviour for flattening a dictionary of lists.""" + flattened_ = _flatten(nested_data={ + 'a': [ + {'x': 1, 'y': 2, 'z': 3}, + {'x': 4, 'y': 5, 'z': 6} + ], + 'b': [ + {'x': 7, 'y': 8, 'z': 9}, + "some text" + ] + }) + self.assertEqual( + list(flattened_.keys()), + ["parent_key", 'x', 'y', 'z', "atomic_value"] + ) + + ####################### + # _transform_taxons() # + ####################### + + def test__transform_taxons_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _transform_taxons, taxons_data=123) + + def test__transform_taxons_valid(self): + """Test the behaviour for valid data.""" + data_ = _transform_taxons(taxons_data={ + TaxonsService.LIST: pd.DataFrame({ + "pagination_a": [1, 2, 3], + "meta_b": [4, 5, 6], + "other": [7, 8, 9] + }) + }) + self.assertEqual( + list(data_[TaxonsService.LIST].keys()), + ["other"] + ) + + ########################### + # _transform_references() # + ########################### + + def test__transform_references_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _transform_references, + references_data=123) + + def test__transform_references_valid(self): + """Test the behaviour for valid data.""" + data_ = _transform_references(references_data={ + ReferencesService.COUNTRIES_STATES: pd.DataFrame({ + "parent_key": [1, 2, 3], + "other_1": [4, 5, 6], + "other_2": [7, 8, 9] + }) + }) + self.assertEqual( + list(data_[ReferencesService.COUNTRIES_STATES].keys()), + ["country_iso", "other_1", "other_2"] + ) + + ################## + # _merge_batch() # + ################## + + def test__merge_batch_invalid(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _merge_batch, datasets=123, + parent_column_name="") + self.assertRaises(TypeError, _merge_batch, datasets=dict(), + parent_column_name=123) + + def test__merge_batch_valid(self): + """Test the behaviour for valid data.""" + data_ = _merge_batch( + datasets={ + "service1": { + 'A': pd.DataFrame({}), + 'B': pd.DataFrame({}) + } + }, + parent_column_name="parent_name" + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), ["service1"]) + self.assertIsInstance(data_["service1"], pd.DataFrame) + self.assertEqual( + list(data_["service1"].keys()), + ["parent_name"] + ) diff --git a/tests/test__general.py b/tests/test__general.py new file mode 100644 index 0000000..800e936 --- /dev/null +++ b/tests/test__general.py @@ -0,0 +1,73 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._general import _general, GeneralService + +load_dotenv() + + +class TestGeneral(unittest.TestCase): + + ############## + # _general() # + ############## + + def test__general_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _general, api_key=123, services=list()) + self.assertRaises(TypeError, _general, api_key='', services=123) + + @patch("eppopynder._utils._requests._fetch_service") + def test__general_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [GeneralService.STATUS] + data_ = _general( + api_key="EPPO_API_KEY", + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[GeneralService.STATUS], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__general_output_online(self): + """Test the output dict structure.""" + services_ = [GeneralService.STATUS] + data_ = _general( + api_key=os.getenv("EPPO_API_KEY"), + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[GeneralService.STATUS], pd.DataFrame) + + def test__general_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _general, + api_key="EPPO_API_KEY", + services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__general_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _general, api_key="BAD_API_KEY") + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _general, api_key=None) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__general_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _general, api_key="BAD_API_KEY") + self.assertRaises(TypeError, _general, + api_key=os.getenv("BAD_API_KEY")) diff --git a/tests/test__references.py b/tests/test__references.py new file mode 100644 index 0000000..3ff5c38 --- /dev/null +++ b/tests/test__references.py @@ -0,0 +1,73 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._references import _references, ReferencesService + +load_dotenv() + + +class TestGeneral(unittest.TestCase): + + ################# + # _references() # + ################# + + def test__references_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _references, api_key=123, services=list()) + self.assertRaises(TypeError, _references, api_key='', services=123) + + @patch("eppopynder._utils._requests._fetch_service") + def test__references_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [ReferencesService.Q_LIST] + data_ = _references( + api_key="EPPO_API_KEY", + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[ReferencesService.Q_LIST], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__references_output_online(self): + """Test the output dict structure.""" + services_ = [ReferencesService.Q_LIST] + data_ = _references( + api_key=os.getenv("EPPO_API_KEY"), + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[ReferencesService.Q_LIST], pd.DataFrame) + + def test__references_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _references, + api_key="EPPO_API_KEY", + services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__references_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _references, api_key="BAD_API_KEY") + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _references, api_key=None) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__references_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _references, api_key="BAD_API_KEY") + self.assertRaises(TypeError, _references, + api_key=os.getenv("BAD_API_KEY")) diff --git a/tests/test__reporting_service.py b/tests/test__reporting_service.py new file mode 100644 index 0000000..eb88dc5 --- /dev/null +++ b/tests/test__reporting_service.py @@ -0,0 +1,110 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._reporting_service import (_reporting_service, + ReportingServiceService) + +load_dotenv() + + +class TestReportingService(unittest.TestCase): + + ######################## + # _reporting_service() # + ######################## + + def test__reporting_service_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _reporting_service, api_key=123, + services=list(), params=dict()) + self.assertRaises(TypeError, _reporting_service, api_key='', + services=123, params=dict()) + self.assertRaises(TypeError, _reporting_service, api_key='', + services=list(), params=123) + + @patch("eppopynder._utils._requests._fetch_service") + def test__reporting_service_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [ReportingServiceService.LIST] + data_ = _reporting_service( + api_key="EPPO_API_KEY", + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance( + data_[ReportingServiceService.LIST], + pd.DataFrame + ) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__reporting_service_output_online(self): + """Test the output dict structure.""" + services_ = [ReportingServiceService.LIST] + data_ = _reporting_service( + api_key=os.getenv("EPPO_API_KEY"), + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance( + data_[ReportingServiceService.LIST], + pd.DataFrame + ) + + @patch("eppopynder._utils._requests._fetch_service") + def test__reporting_service_invalid_param(self, mock_fetch_service): + """Test the behaviour for invalid request parameters.""" + mock_fetch_service.side_effect = ValueError + self.assertRaises(ValueError, _reporting_service, + api_key="EPPO_API_KEY", + params={ReportingServiceService.REPORTING: { + "bad_param": 234 + }}) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__reporting_service_invalid_param_online(self): + """Test the behaviour for invalid request parameters.""" + self.assertRaises(ValueError, _reporting_service, + api_key=os.getenv("EPPO_API_KEY"), + params={ReportingServiceService.REPORTING: { + "bad_param": 234 + }}) + + def test__reporting_service_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _reporting_service, + api_key="EPPO_API_KEY", + services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__reporting_service_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _reporting_service, api_key="BAD_API_KEY", + services=[ReportingServiceService.LIST]) + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _reporting_service, api_key=None, + services=[ReportingServiceService.LIST]) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__reporting_service_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _reporting_service, api_key="BAD_API_KEY", + services=[ReportingServiceService.LIST]) + self.assertRaises(TypeError, _reporting_service, + api_key=os.getenv("BAD_API_KEY"), + services=[ReportingServiceService.LIST]) diff --git a/tests/test__requests.py b/tests/test__requests.py new file mode 100644 index 0000000..6b2fcc6 --- /dev/null +++ b/tests/test__requests.py @@ -0,0 +1,403 @@ +import os +import json +import unittest +from unittest.mock import patch +import pandas as pd +import requests.exceptions +from dotenv import load_dotenv +from json import JSONDecodeError +from requests import Response, HTTPError + +from eppopynder._utils._requests import (_build_endpoint, _perform_request, + _handle_http_errors, _parse_response, + _enrich_response, _query, + _fetch_service, + _build_reporting_service_path) + +load_dotenv() + + +class TestRequests(unittest.TestCase): + + ##################### + # _build_endpoint() # + ##################### + + def test__build_endpoint_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _build_endpoint, base_path=123, code='', + service='') + self.assertRaises(ValueError, _build_endpoint, base_path="general", + code='', service='') + self.assertRaises(TypeError, _build_endpoint, base_path="/general", + code=123, service='') + self.assertRaises(TypeError, _build_endpoint, base_path="/general", + code='', service=123) + + def test__build_endpoint_output1(self): + """Test the behaviour if only the base path is given.""" + self.assertEqual( + _build_endpoint(base_path="/taxons/taxon"), + "/taxons/taxon" + ) + + def test__build_endpoint_output2(self): + """Test the behaviour if a resource identifier is given.""" + self.assertEqual( + _build_endpoint(base_path="/taxon/taxon", code="BEMITA"), + "/taxon/taxon/BEMITA" + ) + + def test__build_endpoint_output3(self): + """Test the behaviour if a service is given.""" + self.assertEqual( + _build_endpoint( + base_path="/country", + code="FR", + service="overview" + ), + "/country/FR/overview" + ) + + def test__build_endpoint_output4(self): + """Test the behaviour if no resource identifier is given.""" + self.assertEqual( + _build_endpoint(base_path="/reportings", service="list"), + "/reportings/list" + ) + + ################################### + # _build_reporting_service_path() # + ################################### + + def test__build_reporting_service_path_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _build_reporting_service_path, + service=123, params=dict()) + self.assertRaises(TypeError, _build_reporting_service_path, service='', + params=123) + + def test__build_reporting_service_path_output1(self): + """Test the behaviour for valid parameters.""" + self.assertEqual( + _build_reporting_service_path( + service="reporting", + params={"reporting_id": 234}), + "reporting/234" + ) + self.assertEqual( + _build_reporting_service_path( + service="article", + params={"article_id": 234}), + "article/234" + ) + + def test__build_reporting_service_path_output3(self): + """Test the behaviour for services without parameters.""" + self.assertEqual( + _build_reporting_service_path( + service="list", + params=dict()), + "list" + ) + + def test__build_reporting_service_path_invalid(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(ValueError, _build_reporting_service_path, + service="reporting", params={'a': 10}) + self.assertRaises(ValueError, _build_reporting_service_path, + service="article", params={'a': 234}) + + ###################### + # _perform_request() # + ###################### + + def test__perform_request_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _perform_request, url=123, api_key='', + params=None) + self.assertRaises(TypeError, _perform_request, + url="https://example.org", api_key=123, + params=None) + self.assertRaises(TypeError, _perform_request, + url="https://example.org", api_key='', params=123) + + @patch("eppopynder._utils._requests.requests.get") + def test__perform_request_malformed(self, mock_get): + """Test the behaviour for malformed requests.""" + mock_get.side_effect = requests.exceptions.ConnectionError + self.assertRaises(Exception, _perform_request, + url="https://invalid-domain", api_key="EPPO_API_KEY") + + # This test performs real requests. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__perform_request_malformed_online(self): + """Test the behaviour for malformed requests.""" + self.assertRaises(Exception, _perform_request, + url="https://invalid-domain", api_key="EPPO_API_KEY") + + @patch("eppopynder._utils._requests.requests.get") + def test__perform_request_output(self, mock_get): + """Test the output type of the request.""" + mock_get.return_value = Response() + response_ = _perform_request( + url="https://api.eppo.int/gd/v2/taxons/taxon/BEMITA/overview", + api_key="EPPO_API_KEY" + ) + self.assertIsInstance(response_, Response) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__perform_request_output_online(self): + """Test the output type of the request.""" + response_ = _perform_request( + url="https://api.eppo.int/gd/v2/taxons/taxon/BEMITA/overview", + api_key=os.getenv("EPPO_API_KEY") + ) + self.assertIsInstance(response_, Response) + + ######################### + # _handle_http_errors() # + ######################### + + def test__handle_http_errors_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _handle_http_errors, response=123) + + def test__handle_http_errors_valid(self): + """Test the behaviour for status code 200.""" + response_ = Response() + response_.status_code = 200 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "application/json" + response_._content = (json.dumps({"data": "Custom data"}) + .encode("utf-8")) + self.assertIsNone(_handle_http_errors(response=response_)) + + def test__handle_http_errors_handled(self): + """Test the behaviour for handled status codes.""" + response_ = Response() + response_.status_code = 403 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "application/json" + response_._content = (json.dumps({"error": "Custom message"}) + .encode("utf-8")) + self.assertRaises(HTTPError, _handle_http_errors, response=response_) + + def test__handle_http_errors_handled_invalid(self): + """Test the behaviour for handled status codes.""" + response_ = Response() + response_.status_code = 403 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "text/html" + response_._content = "content".encode("utf-8") + self.assertRaises( + HTTPError, + _handle_http_errors, + response=response_ + ) + + def test__handle_http_errors_invalid(self): + """Test the behaviour for bad status codes.""" + response_ = Response() + response_.status_code = 502 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + self.assertRaises(HTTPError, _handle_http_errors, response=response_) + + ##################### + # _parse_response() # + ##################### + + def test__parse_response_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _parse_response, response=123) + + def test__parse_response_valid(self): + """Test the behaviour for valid parameters and data.""" + response_ = Response() + response_.status_code = 200 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "application/json" + response_._content = (json.dumps({"data": "Custom data"}) + .encode("utf-8")) + self.assertIsInstance( + _parse_response(response=response_), + pd.DataFrame + ) + + def test__parse_response_invalid(self): + """Test the behaviour for invalid body data.""" + response_ = Response() + response_.status_code = 200 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "text/html" + response_._content = "content".encode("utf-8") + self.assertRaises( + JSONDecodeError, + _parse_response, + response=response_ + ) + + ###################### + # _enrich_response() # + ###################### + + def test__enrich_response_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _enrich_response, response_data=123, + url='') + self.assertRaises(TypeError, _enrich_response, + response_data=pd.DataFrame(), url=123) + + def test__enrich_response_valid(self): + """Test the behaviour for valid parameters.""" + data_ = _enrich_response( + response_data=pd.DataFrame({"data": ["Custom data"]}), + url="https://example.org" + ) + self.assertTrue("queried_on" in data_) + self.assertTrue("queried_url" in data_) + self.assertEqual(data_["queried_url"].iloc[0], + "https://example.org") + + ############ + # _query() # + ############ + + def test__query_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _query, endpoint=123, api_key='', + params=dict()) + self.assertRaises(ValueError, _query, endpoint="general", api_key='', + params=dict()) + self.assertRaises(TypeError, _query, endpoint="/general", api_key=123, + params=dict()) + self.assertRaises(TypeError, _query, endpoint="/general", api_key='', + params=123) + + @patch("eppopynder._utils._requests._perform_request") + def test__query_wrong_endpoint(self, mock_perform_request): + """Test the behaviour if a bad endpoint is given.""" + mock_perform_request.side_effect = HTTPError + self.assertRaises(HTTPError, _query, + endpoint="/taxons/taxon/BEMITA/badService", + api_key="EPPO_API_KEY") + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__query_wrong_endpoint_online(self): + """Test the behaviour if a bad endpoint is given.""" + self.assertRaises(HTTPError, _query, + endpoint="/taxons/taxon/BEMITA/badService", + api_key=os.getenv("EPPO_API_KEY")) + + @patch("eppopynder._utils._requests._perform_request") + def test__query_wrong_api_key(self, mock_perform_request): + """Test the behaviour if a bad API key is given.""" + mock_perform_request.side_effect = HTTPError + self.assertRaises(HTTPError, _query, + endpoint="/taxons/taxon/BEMITA/overview", + api_key="BAD_API_KEY") + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__query_wrong_api_key_online(self): + """Test the behaviour if a bad API key is given.""" + self.assertRaises(HTTPError, _query, + endpoint="/taxons/taxon/BEMITA/overview", + api_key="BAD_API_KEY") + + @patch("eppopynder._utils._requests._perform_request") + def test__query_valid(self, mock_perform_request): + """Test the behaviour for valid parameters.""" + response_ = Response() + response_.status_code = 200 + response_.url = "https://api.eppo.int/gd/v2/status" + response_.method = "GET" + response_.headers["Content-Type"] = "application/json" + response_._content = (json.dumps({"data": "Custom data"}) + .encode("utf-8")) + mock_perform_request.return_value = response_ + self.assertIsInstance( + _query( + endpoint="/status", + api_key="EPPO_API_KEY" + ), + pd.DataFrame + ) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__query_valid_online(self): + """Test the behaviour for valid parameters.""" + self.assertIsInstance( + _query( + endpoint="/taxons/taxon/BEMITA/overview", + api_key=os.getenv("EPPO_API_KEY") + ), + pd.DataFrame + ) + + #################### + # _fetch_service() # + #################### + + def test__fetch_service_types(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(TypeError, _fetch_service, base_path=123, api_key='', + code='', service='', params=dict()) + self.assertRaises(ValueError, _fetch_service, base_path="taxons/taxon", + api_key='', code='', service='', params=dict()) + self.assertRaises(TypeError, _fetch_service, base_path="/taxons/taxon", + api_key=123, code='', service='', params=dict()) + self.assertRaises(TypeError, _fetch_service, base_path="/taxons/taxon", + api_key='', code=123, service='', params=dict()) + self.assertRaises(TypeError, _fetch_service, base_path="/taxons/taxon", + api_key='', code='', service=123, params=dict()) + self.assertRaises(TypeError, _fetch_service, base_path="/taxons/taxon", + api_key='', code='', service='', params=123 + ) + + @patch("eppopynder._utils._requests._query") + def test__fetch_service_output(self, mock_query): + """Test the output type for valid parameters.""" + mock_query.return_value = pd.DataFrame({'a': [1]}) + self.assertIsInstance( + _fetch_service( + base_path="/taxons/taxon", + api_key="EPPO_API_KEY", + code="BEMITA", + service="overview" + ), + pd.DataFrame + ) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__fetch_service_output_online(self): + """Test the output type for valid parameters.""" + self.assertIsInstance( + _fetch_service( + base_path="/taxons/taxon", + api_key=os.getenv("EPPO_API_KEY"), + code="BEMITA", + service="overview" + ), + pd.DataFrame + ) diff --git a/tests/test__rppo.py b/tests/test__rppo.py new file mode 100644 index 0000000..654e13e --- /dev/null +++ b/tests/test__rppo.py @@ -0,0 +1,101 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._rppo import _rppo, RPPOService + +load_dotenv() + + +class TestRPPO(unittest.TestCase): + + ########### + # _rppo() # + ########### + + def test__rppo_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _rppo, api_key=123, rppo_codes=[''], + services=list()) + self.assertRaises(TypeError, _rppo, api_key='', rppo_codes=123, + services=123) + self.assertRaises(TypeError, _rppo, api_key='', rppo_codes=[1, 2], + services=list()) + self.assertRaises(TypeError, _rppo, api_key='', rppo_codes=[''], + services=123) + self.assertRaises(TypeError, _rppo, api_key='', rppo_codes=[''], + services=[1, 2]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__rppo_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [RPPOService.OVERVIEW] + data_ = _rppo( + api_key="EPPO_API_KEY", + rppo_codes=["9A"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[RPPOService.OVERVIEW], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__rppo_output_online(self): + """Test the output dict structure.""" + services_ = [RPPOService.OVERVIEW] + data_ = _rppo( + api_key=os.getenv("EPPO_API_KEY"), + rppo_codes=["9A"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[RPPOService.OVERVIEW], pd.DataFrame) + + @patch("eppopynder._utils._requests._fetch_service") + def test__rppo_invalid_rppo(self, mock_fetch_service): + """Test the behaviour for invalid RPPO codes.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _rppo, api_key="EPPO_API_KEY", + rppo_codes=["BAD_RPPO_CODE"]) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__rppo_invalid_rppo_online(self): + """Test the behaviour for invalid RPPO codes.""" + self.assertRaises(HTTPError, _rppo, + api_key=os.getenv("EPPO_API_KEY"), + rppo_codes=["BAD_RPPO_CODE"]) + + def test__rppo_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _rppo, api_key="EPPO_API_KEY", + rppo_codes=["9A"], services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__rppo_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _rppo, api_key="BAD_API_KEY", + rppo_codes=["9A"]) + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _rppo, api_key=None, rppo_codes=["9A"]) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__rppo_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _rppo, api_key="BAD_API_KEY", + rppo_codes=["9A"]) + self.assertRaises(TypeError, _rppo, + api_key=os.getenv("BAD_API_KEY"), rppo_codes=["9A"]) diff --git a/tests/test__taxon.py b/tests/test__taxon.py new file mode 100644 index 0000000..6478f53 --- /dev/null +++ b/tests/test__taxon.py @@ -0,0 +1,101 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._taxon import _taxon, TaxonService + +load_dotenv() + + +class TestTaxon(unittest.TestCase): + + ############# + # _taxon() # + ############# + + def test__taxon_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _taxon, api_key=123, eppo_codes=[''], + services=list()) + self.assertRaises(TypeError, _taxon, api_key='', eppo_codes=123, + services=123) + self.assertRaises(TypeError, _taxon, api_key='', eppo_codes=[1, 2], + services=list()) + self.assertRaises(TypeError, _taxon, api_key='', eppo_codes=[''], + services=123) + self.assertRaises(TypeError, _taxon, api_key='', eppo_codes=[''], + services=[1, 2]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__taxon_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [TaxonService.OVERVIEW] + data_ = _taxon( + api_key="EPPO_API_KEY", + eppo_codes=["BEMITA"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[TaxonService.OVERVIEW], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__taxon_output_online(self): + """Test the output dict structure.""" + services_ = [TaxonService.OVERVIEW] + data_ = _taxon( + api_key=os.getenv("EPPO_API_KEY"), + eppo_codes=["BEMITA"], + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[TaxonService.OVERVIEW], pd.DataFrame) + + @patch("eppopynder._utils._requests._fetch_service") + def test__taxon_invalid_eppo(self, mock_fetch_service): + """Test the behaviour for invalid EPPO codes.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _taxon, api_key="EPPO_API_KEY", + eppo_codes=["BAD_EPPO_CODE"]) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__taxon_invalid_eppo_online(self): + """Test the behaviour for invalid EPPO codes.""" + self.assertRaises(HTTPError, _taxon, api_key=os.getenv("EPPO_API_KEY"), + eppo_codes=["BAD_EPPO_CODE"]) + + def test__taxon_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _taxon, api_key="EPPO_API_KEY", + eppo_codes=["BEMITA"], services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__taxons_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _taxon, api_key="BAD_API_KEY", + eppo_codes=["BEMITA"]) + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _taxon, api_key=None, + eppo_codes=["BEMITA"]) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__taxons_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _taxon, api_key="BAD_API_KEY", + eppo_codes=["BEMITA"]) + self.assertRaises(TypeError, _taxon, api_key=os.getenv("BAD_API_KEY"), + eppo_codes=["BEMITA"]) diff --git a/tests/test__taxons.py b/tests/test__taxons.py new file mode 100644 index 0000000..9505cf0 --- /dev/null +++ b/tests/test__taxons.py @@ -0,0 +1,76 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._taxons import _taxons, TaxonsService + +load_dotenv() + + +class TestTaxons(unittest.TestCase): + + ############# + # _taxons() # + ############# + + def test__taxons_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _taxons, api_key=123, services=list(), + params=dict()) + self.assertRaises(TypeError, _taxons, api_key='', services=123, + params=dict()) + self.assertRaises(TypeError, _taxons, api_key='', services=list(), + params=123) + + @patch("eppopynder._utils._requests._fetch_service") + def test__taxons_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [TaxonsService.LIST] + data_ = _taxons( + api_key="EPPO_API_KEY", + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[TaxonsService.LIST], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__taxons_output_online(self): + """Test the output dict structure.""" + services_ = [TaxonsService.LIST] + data_ = _taxons( + api_key=os.getenv("EPPO_API_KEY"), + services=services_ + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[TaxonsService.LIST], pd.DataFrame) + + def test__taxons_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _taxons, + api_key="EPPO_API_KEY", + services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__taxons_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _taxons, api_key="BAD_API_KEY") + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _taxons, api_key=None) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__taxons_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + self.assertRaises(HTTPError, _taxons, api_key="BAD_API_KEY") + self.assertRaises(TypeError, _taxons, api_key=os.getenv("BAD_API_KEY")) diff --git a/tests/test__tools.py b/tests/test__tools.py new file mode 100644 index 0000000..40a775a --- /dev/null +++ b/tests/test__tools.py @@ -0,0 +1,98 @@ +import os +import unittest +from unittest.mock import patch +import pandas as pd +from dotenv import load_dotenv +from requests import HTTPError + +from eppopynder._core._tools import _tools, ToolsService + +load_dotenv() + + +class TestTools(unittest.TestCase): + + ############ + # _tools() # + ############ + + def test__tools_types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, _tools, api_key=123, services=list(), + params=dict()) + self.assertRaises(TypeError, _tools, api_key='', services=123, + params=dict()) + self.assertRaises(TypeError, _tools, api_key='', services=list(), + params=123) + + @patch("eppopynder._utils._requests._fetch_service") + def test__tools_output(self, mock_fetch_service): + """Test the output dict structure.""" + mock_fetch_service.return_value = pd.DataFrame() + services_ = [ToolsService.NAME2CODES] + data_ = _tools( + api_key="EPPO_API_KEY", + services=services_, + params={ToolsService.NAME2CODES: {"name": "Bemisia tabaci"}} + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[ToolsService.NAME2CODES], pd.DataFrame) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__tools_output_online(self): + """Test the output dict structure.""" + services_ = [ToolsService.NAME2CODES] + data_ = _tools( + api_key=os.getenv("EPPO_API_KEY"), + services=services_, + params={ToolsService.NAME2CODES: {"name": "Bemisia tabaci"}} + ) + self.assertIsInstance(data_, dict) + self.assertEqual(list(data_.keys()), services_) + self.assertIsInstance(data_[ToolsService.NAME2CODES], pd.DataFrame) + + @patch("eppopynder._utils._requests._fetch_service") + def test__tools_invalid_param(self, mock_fetch_service): + """Test the behaviour for invalid parameters.""" + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _tools, api_key="EPPO_API_KEY", + params={"name2codes": {"onlyPreferred": False}}) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__tools_invalid_param_online(self): + """Test the behaviour for invalid parameters.""" + self.assertRaises(HTTPError, _tools, api_key=os.getenv("EPPO_API_KEY"), + params={"name2codes": {"onlyPreferred": False}}) + + def test__tools_invalid_service(self): + """Test the behaviour for invalid services.""" + self.assertRaises(TypeError, _tools, api_key="EPPO_API_KEY", + services=["badService"]) + + @patch("eppopynder._utils._requests._fetch_service") + def test__tools_invalid_key(self, mock_fetch_service): + """Test the behaviour for invalid API keys.""" + params_ = {"name2codes": {"name": "Bemisia tabaci"}} + mock_fetch_service.side_effect = HTTPError + self.assertRaises(HTTPError, _tools, api_key="BAD_API_KEY", + params=params_) + mock_fetch_service.side_effect = TypeError + self.assertRaises(TypeError, _tools, api_key=None, params=params_) + + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test__tools_invalid_key_online(self): + """Test the behaviour for invalid API keys.""" + params_ = {"name2codes": {"name": "Bemisia tabaci"}} + self.assertRaises(HTTPError, _tools, api_key="BAD_API_KEY", + params=params_) + self.assertRaises(TypeError, _tools, api_key=os.getenv("BAD_API_KEY"), + params=params_) diff --git a/tests/test_api_query.py b/tests/test_api_query.py deleted file mode 100644 index 77b7404..0000000 --- a/tests/test_api_query.py +++ /dev/null @@ -1,37 +0,0 @@ -import unittest -from unittest.mock import patch, MagicMock -import pandas as pd -import requests -from datetime import date -from eppoPynder.api_query import api_query - -class TestApiQuery(unittest.TestCase): - - def test_if_wrong_service_is_requested_standard_df_returned(self): - """Test successful API response""" - result = api_query("BEMITA", "https://data.eppo.int/api/rest/1.0/taxon/BEMITA?authtoken=token") - self.assertIn('queried_url', result.columns) - self.assertEqual(result.iloc[0,0], 'BEMITA') - - @patch('builtins.print') - @patch('requests.get') - def test_missing_schema_print(self, mock_get, mock_print): - mock_get.side_effect = requests.exceptions.InvalidURL() - api_query("BEMITA", "https://data.eppo.int/api/rest/1.0/taxon/BEMITA?authtoken=token ") - mock_print.assert_called_once_with('') - - @patch('requests.get') - def test_successful_json_processing(self, mock_get): - # Setup mock response - mock_response = MagicMock() - mock_response.json.return_value = {"name": "Test Name", "nested": [{"value": 1}, {"value": 2}]} - mock_get.return_value = mock_response - - # Call function - result = api_query("BEMITA", "https://data.eppo.int/api/rest/1.0/taxon/BEMITA?authtoken=token") - - # Verify json() was called and DataFrame was created - mock_response.json.assert_called_once() - assert len(result) > 0 - assert 'name' in result.columns - assert result.iloc[0]['name'] == "Test Name" diff --git a/tests/test_client.py b/tests/test_client.py new file mode 100644 index 0000000..6696c68 --- /dev/null +++ b/tests/test_client.py @@ -0,0 +1,251 @@ +import os +import unittest +from unittest.mock import patch +from dotenv import load_dotenv + +from eppopynder.client import Client +from eppopynder._core._general import GeneralService +from eppopynder._core._taxons import TaxonsService +from eppopynder._core._taxon import TaxonService +from eppopynder._core._country import CountryService +from eppopynder._core._rppo import RPPOService +from eppopynder._core._tools import ToolsService +from eppopynder._core._reporting_service import ReportingServiceService +from eppopynder._core._references import ReferencesService + +load_dotenv() + + +class TestClient(unittest.TestCase): + + ############## + # __init__() # + ############## + + def test___init___types(self): + """Test the behaviour for invalid data.""" + self.assertRaises(TypeError, Client, api_key=123) + self.assertRaises(ValueError, Client, api_key='') + + def test___init___invalid_key(self): + """Test that ValueError is raised when EPPO_API_KEY is not set.""" + with patch.dict(os.environ, {}, clear=True): + with patch("eppopynder.client.load_dotenv"): + self.assertRaises(ValueError, Client) + + def test___init__1(self): + """Test the correct creation of the object.""" + with patch.dict(os.environ, { + "EPPO_API_KEY": "EPPO_API_KEY", + }, clear=True): + with patch("eppopynder.client.load_dotenv"): + self.assertIsInstance(Client(api_key="EPPO_API_KEY"), Client) + + # This test requires the EPPO_API_KEY environment variable to be set. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test___init__1_online(self): + """Test the correct creation of the object.""" + self.assertIsInstance(Client(), Client) + + def test___init__2(self): + """Test the correct creation of the object.""" + self.assertIsInstance(Client(api_key="EPPO_API_KEY"), Client) + + ############# + # general() # + ############# + + @patch("eppopynder._core._general._general") + def test_general(self, mock_general): + """Test the General endpoint.""" + mock_general.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [GeneralService.STATUS] + data_ = client_.general(services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_general_online(self): + """Test the General endpoint.""" + client_ = Client() + services_ = [GeneralService.STATUS] + data_ = client_.general(services=services_) + self.assertIsInstance(data_, dict) + + ############ + # taxons() # + ############ + + @patch("eppopynder._core._taxons._taxons") + def test_taxons(self, mock_taxons): + """Test the Taxons endpoint.""" + mock_taxons.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [TaxonsService.LIST] + data_ = client_.taxons(services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_taxons_online(self): + """Test the Taxons endpoint.""" + client_ = Client() + services_ = [TaxonsService.LIST] + data_ = client_.taxons(services=services_) + self.assertIsInstance(data_, dict) + + ########### + # taxon() # + ########### + + @patch("eppopynder._core._taxon._taxon") + def test_taxon(self, mock_taxon): + """Test the Taxon endpoint.""" + mock_taxon.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [TaxonService.OVERVIEW] + data_ = client_.taxon(eppo_codes=["BEMITA"], services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_taxon_online(self): + """Test the Taxon endpoint.""" + client_ = Client() + services_ = [TaxonService.OVERVIEW] + data_ = client_.taxon(eppo_codes=["BEMITA"], services=services_) + self.assertIsInstance(data_, dict) + + ############# + # country() # + ############# + + @patch("eppopynder._core._country._country") + def test_country(self, mock_country): + """Test the Country endpoint.""" + mock_country.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [CountryService.OVERVIEW] + data_ = client_.country(iso_codes=["FR"], services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_country_online(self): + """Test the Country endpoint.""" + client_ = Client() + services_ = [CountryService.OVERVIEW] + data_ = client_.country(iso_codes=["FR"], services=services_) + self.assertIsInstance(data_, dict) + + ########## + # rppo() # + ########## + + @patch("eppopynder._core._rppo._rppo") + def test_rppo(self, mock_rppo): + """Test the RPPO endpoint.""" + mock_rppo.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [RPPOService.OVERVIEW] + data_ = client_.rppo(rppo_codes=["9A"], services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_rppo_online(self): + """Test the RPPO endpoint.""" + client_ = Client() + services_ = [RPPOService.OVERVIEW] + data_ = client_.rppo(rppo_codes=["9A"], services=services_) + self.assertIsInstance(data_, dict) + + ########### + # tools() # + ########### + + @patch("eppopynder._core._tools._tools") + def test_tools(self, mock_tools): + """Test the Tools endpoint.""" + mock_tools.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [ToolsService.NAME2CODES] + data_ = client_.tools( + services=services_, + params={ToolsService.NAME2CODES: {"name": "Bemisia tabaci"}} + ) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_tools_online(self): + """Test the Tools endpoint.""" + client_ = Client() + services_ = [ToolsService.NAME2CODES] + data_ = client_.tools( + services=services_, + params={ToolsService.NAME2CODES: {"name": "Bemisia tabaci"}} + ) + self.assertIsInstance(data_, dict) + + ####################### + # reporting_service() # + ####################### + + @patch("eppopynder._core._reporting_service._reporting_service") + def test_reporting_service(self, mock_reporting_service): + """Test the Reporting Service endpoint.""" + mock_reporting_service.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [ReportingServiceService.LIST] + data_ = client_.reporting_service(services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_reporting_service_online(self): + """Test the Reporting Service endpoint.""" + client_ = Client() + services_ = [ReportingServiceService.LIST] + data_ = client_.reporting_service(services=services_) + self.assertIsInstance(data_, dict) + + ################ + # references() # + ################ + + @patch("eppopynder._core._references._references") + def test_references(self, mock_references): + """Test the References endpoint.""" + mock_references.return_value = {} + client_ = Client(api_key="EPPO_API_KEY") + services_ = [ReferencesService.Q_LIST] + data_ = client_.references(services=services_) + self.assertIsInstance(data_, dict) + + # This test requires the EPPO_API_KEY environment variable to be set. + # This test performs real requests to the EPPO API. + @unittest.skipIf(os.getenv("SKIP_ONLINE_TESTS") == "true", + "Skip online tests") + def test_references_online(self): + """Test the References endpoint.""" + client_ = Client() + services_ = [ReferencesService.Q_LIST] + data_ = client_.references(services=services_) + self.assertIsInstance(data_, dict) diff --git a/tests/test_data_dump.py b/tests/test_data_dump.py deleted file mode 100644 index 174b5ba..0000000 --- a/tests/test_data_dump.py +++ /dev/null @@ -1,50 +0,0 @@ -import unittest -from unittest.mock import patch -import pandas as pd -from eppoPynder.data_dump import data_dump - - -class DataDumpEppo(unittest.TestCase): - - def test_data_dump(self): - # Call the function being tested - result = data_dump(["BEMITA", "LEUCSC"]) - - # Ensure the dictionary contains the expected keys - services = ["general", "names", "taxonomy", "categorization", - "hosts", "pests", "kingdom"] - - self.assertTrue( - set(services).issubset(result.keys()), - "The keys in the dictionary do not match the expected services.") - - def test_input_type_validation(self): - with self.assertRaises(AssertionError) as context: - data_dump("not_a_list") - self.assertEqual(str(context.exception), "Input must be a list!") - - with self.assertRaises(AssertionError) as context: - data_dump([]) - self.assertEqual(str(context.exception), "Input list cannot be empty!") - - with self.assertRaises(AssertionError) as context: - data_dump(["BEMITA", 123]) - self.assertEqual(str(context.exception), "All codes must be strings!") - - def test_non_string_token_raises_assertion_error(self): - with self.assertRaisesRegex(AssertionError, "token must be a string!"): - data_dump(["BEMITA"], token=123) - - def test_default_token_assignment(self): - with patch('eppoPynder.data_dump.query_the_eppo_for_service') as mock_query: - # Configure mock to return a DataFrame with required columns - mock_query.return_value = pd.DataFrame({'queried_eppocode': ['BEMITA']}) - - # Call function without a token - result = data_dump(["BEMITA"], token=None) - - # Get the first call to verify token value - first_call = mock_query.call_args_list[0] - - # Verify that default_token was used - self.assertEqual(first_call.kwargs['token'], 'default_token') diff --git a/tests/test_data_wrangling.py b/tests/test_data_wrangling.py new file mode 100644 index 0000000..8d4e483 --- /dev/null +++ b/tests/test_data_wrangling.py @@ -0,0 +1,36 @@ +import unittest +import pandas as pd + +from eppopynder.data_wrangling import uniform_taxonomy + + +class TestDataWrangling(unittest.TestCase): + + ###################### + # uniform_taxonomy() # + ###################### + + def test_uniform_taxonomy_types(self): + """Test if the parameters are of the correct types.""" + self.assertRaises(TypeError, uniform_taxonomy, taxonomy_data=123) + self.assertRaises(ValueError, uniform_taxonomy, + taxonomy_data=pd.DataFrame()) + self.assertRaises(ValueError, uniform_taxonomy, + taxonomy_data=pd.DataFrame({ + "queried_eppo_code": [None], + "type": ["type_a"] + })) + + def test_output(self): + """Test the output for correct parameters.""" + taxonomy_ = pd.DataFrame({ + "queried_eppo_code": ['A', 'A', 'A'], + "eppocode": ['D', 'E', 'F'], + "prefname": ['G', 'H', 'I'], + "level": ['1', '2', '3'], + "type": ['Kingdom', 'Class', 'Order'], + "queried_url": ['M', 'N', 'O'], + "queried_on": ['P', 'Q', 'R'], + }) + self.assertIsInstance(uniform_taxonomy(taxonomy_data=taxonomy_), + pd.DataFrame) diff --git a/tests/test_getting_countries.py b/tests/test_getting_countries.py deleted file mode 100644 index 100b973..0000000 --- a/tests/test_getting_countries.py +++ /dev/null @@ -1,96 +0,0 @@ -import unittest -import numpy as np -from io import StringIO -import sys - -from eppoPynder.getting_countries import getting_countries - -class TestGettingCountries(unittest.TestCase): - - def test_EPPO(self): - """Test if a concatenation of countries corresponding to the acronym 'EPPO' is returned.""" - result = getting_countries("EPPO") - expected = "Albania, Algeria, Austria, Azerbaijan, Belarus, Belgium, Bosnia and Herzegovina, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Georgia, Germany, Greece, Guernsey, Hungary, Ireland, Israel, Italy, Jersey, Jordan, Kazakhstan, Kyrgyzstan, Latvia, Lithuania, Luxembourg, Malta, Moldova, Montenegro, Morocco, Netherlands, North Macedonia, Norway, Poland, Portugal, Romania, Russia, Serbia, Slovakia, Slovenia, Spain, Sweden, Switzerland, Tunisia, Türkiye, Ukraine, United Kingdom, Uzbekistan" - self.assertEqual(result, expected) - - def test_OIRSA(self): - """Test if a concatenation of countries corresponding to the acronym 'OIRSA' is returned.""" - result = getting_countries("OIRSA") - expected = "Belize, Costa Rica, Dominican Republic, El Salvador, Guatemala, Honduras, Mexico, Nicaragua, Panama" - self.assertEqual(result, expected) - - def test_EAEU(self): - """Test if a concatenation of countries corresponding to the acronym 'EAEU' is returned.""" - result = getting_countries("EAEU") - expected = "Armenia, Belarus, Kazakhstan, Kyrgyzstan, Russia" - self.assertEqual(result, expected) - - def test_COSAVE(self): - """Test if a concatenation of countries corresponding to the acronym 'COSAVE' is returned.""" - result = getting_countries("COSAVE") - expected = "Argentina, Bolivia, Brazil, Chile, Paraguay, Peru, Uruguay" - self.assertEqual(result, expected) - - def test_EU(self): - """Test if a concatenation of countries corresponding to the acronym 'EU' is returned.""" - result = getting_countries("EU") - expected = "Austria, Belgium, Bulgaria, Croatia, Cyprus, Czech Republic, Denmark, Estonia, Finland, France, Germany, Greece, Hungary, Ireland, Italy, Latvia, Lithuania, Luxembourg, Malta, Netherlands, Poland, Portugal, Romania, Slovakia, Slovenia, Spain, Sweden" - self.assertEqual(result, expected) - - def test_APPPC(self): - """Test if a concatenation of countries corresponding to the acronym 'APPPC' is returned.""" - result = getting_countries("APPPC") - expected = "Australia, Bangladesh, Cambodia, China, East Timor, Fiji, French Polynesia, India, Indonesia, Korea Dem. People's Republic, Korea, Republic, Laos, Malaysia, Myanmar, Nepal, New Zealand, Pakistan, Papua New Guinea, Philippines, Samoa, Solomon Islands, Sri Lanka, Thailand, Tonga, Vietnam" - self.assertEqual(result, expected) - - def test_CAHFSA(self): - """Test if a concatenation of countries corresponding to the acronym 'CAHFSA' is returned.""" - result = getting_countries("CAHFSA") - expected = "Antigua and Barbuda, Bahamas, Barbados, Belize, Dominica, Grenada, Guyana, Haiti, Jamaica, Montserrat, Saint Lucia, St Kitts-Nevis, St Vincent and the Grenadines, Suriname, Trinidad and Tobago" - self.assertEqual(result, expected) - - def test_CAN(self): - """Test if a concatenation of countries corresponding to the acronym 'CAN' is returned.""" - result = getting_countries("CAN") - expected = "Bolivia, Colombia, Ecuador, Peru, Venezuela" - self.assertEqual(result, expected) - - def test_IAPSC(self): - """Test if a concatenation of countries corresponding to the acronym 'IAPSC' is returned.""" - result = getting_countries("IAPSC") - expected = "Algeria, Angola, Benin, Botswana, Burkina Faso, Burundi, Cameroon, Cape Verde, Central African Republic, Chad, Comoros, Congo, Congo, Democratic Republic of the, Cote d'Ivoire, Djibouti, Egypt, Equatorial Guinea, Eritrea, Eswatini, Ethiopia, Gabon, Gambia, Ghana, Guinea, Guinea-Bissau, Kenya, Lesotho, Liberia, Libya, Madagascar, Malawi, Mali, Mauritania, Mauritius, Morocco, Mozambique, Namibia, Niger, Nigeria, Rwanda, Sao Tome & Principe, Senegal, Seychelles, Sierra Leone, Somalia, South Africa, South Sudan, Sudan, Tanzania, Togo, Tunisia, Uganda, Zaire, Zambia, Zimbabwe" - self.assertEqual(result, expected) - - def test_NAPPO(self): - """Test if a concatenation of countries corresponding to the acronym 'NAPPO' is returned.""" - result = getting_countries("NAPPO") - expected = "Canada, Mexico, United States of America" - self.assertEqual(result, expected) - - def test_NEPPO(self): - """Test if a concatenation of countries corresponding to the acronym 'NEPPO' is returned.""" - result = getting_countries("NEPPO") - expected = "Algeria, Egypt, Jordan, Libya, Malta, Morocco, Pakistan, South Sudan, Sudan, Syria, Tunisia" - self.assertEqual(result, expected) - - def test_PPPO(self): - """Test if a concatenation of countries corresponding to the acronym 'PPPO' is returned.""" - result = getting_countries("PPPO") - expected = "American Samoa, Australia, Cook Islands, Fiji, French Polynesia, Guam, Kiribati, Marshall Islands, Micronesia, Nauru, New Caledonia, New Zealand, Niue, Northern Mariana Islands, Palau, Papua New Guinea, Pitcairn, Samoa, Solomon Islands, Tokelau, Tonga, Tuvalu, Vanuatu, Wallis and Futuna Islands" - self.assertEqual(result, expected) - - def test_unknown_acronym(self): - """Test if np.nan and print message are returned for unknown acronyms.""" - # Capture print output - captured_output = StringIO() - sys.stdout = captured_output - - # Test unknown acronym - result = getting_countries("XYZ") - - # Reset stdout - sys.stdout = sys.__stdout__ - - # Verify results - self.assertTrue(np.isnan(result)) - self.assertEqual(captured_output.getvalue().strip(), "Unknown acronym") diff --git a/tests/test_query_the_eppo_for_service.py b/tests/test_query_the_eppo_for_service.py deleted file mode 100644 index 46a7d02..0000000 --- a/tests/test_query_the_eppo_for_service.py +++ /dev/null @@ -1,34 +0,0 @@ -import unittest -from unittest.mock import patch -import pandas as pd - -from eppoPynder.query_the_eppo_for_service import query_the_eppo_for_service - -class TestQueryTheEPPOForService(unittest.TestCase): - - def test_if_code_is_passed_dataframe_is_returned(self): - result = query_the_eppo_for_service("BEMITA") - self.assertTrue(isinstance(result, pd.DataFrame)) - - @patch('eppoPynder.query_the_eppo_for_service') - def test_if_wrong_service_is_requested_standard_df_returned(self, mock_query): - mock_query.return_value = pd.DataFrame(columns=['col1', 'col2', 'col3']) - result = query_the_eppo_for_service("BEMITA", service="wrongservice") - self.assertEqual(result.shape[1], 3) - - def test_default_token_assignment(self): - with patch('eppoPynder.query_the_eppo_for_service.api_query') as mock_api: - # Configure mock to return an empty DataFrame - mock_api.return_value = pd.DataFrame() - - # Call function without a token - result = query_the_eppo_for_service("BEMITA", token=None) - - # Get the call arguments - call_args = mock_api.call_args - - # Extract the queried_url from the kwargs - queried_url = call_args.kwargs['queried_url'] - - # Verify that default_token was used in the URL - self.assertIn('authtoken=default_token', queried_url) diff --git a/tests/test_query_the_whole_eppo.py b/tests/test_query_the_whole_eppo.py deleted file mode 100644 index 8bd762d..0000000 --- a/tests/test_query_the_whole_eppo.py +++ /dev/null @@ -1,37 +0,0 @@ -import unittest -from unittest.mock import patch -import pandas as pd -from eppoPynder.query_the_whole_eppo import query_the_whole_eppo - -class TestQueryTheWholeEPPO(unittest.TestCase): - - def test_getting_7_dataframes_are_returned(self): - result = query_the_whole_eppo('BEMITA') - self.assertEqual(len(result), 7) - - def test_getting_the_right_names(self): - services = ["general", "names", "taxonomy", "categorization", "hosts", "pests", "kingdom"] - result = query_the_whole_eppo('BEMITA') - - self.assertEqual(list(result.keys()), services) - - def test_non_string_token_raises_assertion_error(self): - with self.assertRaisesRegex(AssertionError, "token must be a string!"): - query_the_whole_eppo("BEMITA", token=123) - - def test_default_token_assignment(self): - # Using the full import path for the mock - with patch('eppoPynder.query_the_whole_eppo.query_the_eppo_for_service') as mock_query: - # Configure mock to return an empty DataFrame - mock_query.return_value = pd.DataFrame() - - # Call function without a token - result = query_the_whole_eppo("BEMITA", token=None) - - # Get the first call to verify token value - first_call = mock_query.call_args_list[0] - - # Verify that default_token was used - self.assertEqual(first_call.kwargs['token'], 'default_token') - - \ No newline at end of file diff --git a/tests/test_taxonomy_ranked.py b/tests/test_taxonomy_ranked.py deleted file mode 100644 index 9908852..0000000 --- a/tests/test_taxonomy_ranked.py +++ /dev/null @@ -1,27 +0,0 @@ -import unittest -import pandas as pd -from eppoPynder.taxonomy_ranked import taxonomy_ranked - -class TaxonomyRanked(unittest.TestCase): - def test_taxonomy_ranked_merge_and_transform(self): - # Create test input data - taxonomy = pd.DataFrame({ - 'eppocode': ['CODE1'], - 'queried_eppocode': ['BEMITA'], - 'name': ['Test Species'] - }) - - kingdom = pd.DataFrame({ - 'eppocode': ['CODE1'], - 'queried_eppocode': ['BEMITA'], - 'status': ['Animalia'] - }) - - # Call the function - result = taxonomy_ranked(taxonomy, kingdom) - - # Verify the results - assert 'rank' in result.columns - assert result.columns[0] == 'rank' # Check if rank is first column - assert result.iloc[0]['rank'] == 'kingdom' - assert len(result) == 1 \ No newline at end of file diff --git a/tests/test_unnest_lists.py b/tests/test_unnest_lists.py deleted file mode 100644 index fdd55df..0000000 --- a/tests/test_unnest_lists.py +++ /dev/null @@ -1,70 +0,0 @@ -import unittest - -from eppoPynder.unnest_lists import unnest_lists - -class TestUnnestLists(unittest.TestCase): - - def test_unnest_lists_all_keys_present(self): - # Test when all keys are present and the lists are non-empty - input_data = { - "Major host": ["Host1", "Host2"], - "Host": ["Host3", "Host4"], - "Wild/Weed": ["Host5"], - "Alternate": ["Host6", "Host7"], - "Experimental": ["Host8"], - "Doubtful host": [], - "Non-host": ["Host9"] - } - expected_output = [ - "Host1", "Host2", "Host3", "Host4", "Host5", - "Host6", "Host7", "Host8", "Host9" - ] - result = unnest_lists(input_data) - self.assertEqual(result, expected_output) - - def test_unnest_lists_some_keys_missing(self): - # Test when some keys are missing - input_data = { - "Major host": ["Host1", "Host2"], - "Host": ["Host3"] - } - expected_output = ["Host1", "Host2", "Host3"] - result = unnest_lists(input_data) - self.assertEqual(result, expected_output) - - def test_unnest_lists_non_dict_input(self): - # Test when the input is not a dictionary (edge case) - input_data = ["Some", "List"] - expected_output = ["Some", "List"] - result = unnest_lists(input_data) - self.assertEqual(result, expected_output) - - def test_unnest_lists_with_empty_lists(self): - # Test when input has empty lists for some of the keys - input_data = { - "Major host": ["Host1"], - "Host": [], - "Wild/Weed": [], - "Alternate": [], - "Experimental": [], - "Doubtful host": [], - "Non-host": ["Host2"] - } - expected_output = ["Host1", "Host2"] - result = unnest_lists(input_data) - self.assertEqual(result, expected_output) - - def test_unnest_lists_with_none_values(self): - # Test when the input has None for some values of the lists - input_data = { - "Major host": None, - "Host": ["Host1"], - "Wild/Weed": None, - "Alternate": None, - "Experimental": ["Host2"], - "Doubtful host": None, - "Non-host": ["Host3"] - } - expected_output = ["Host1", "Host2", "Host3"] - result = unnest_lists(input_data) - self.assertEqual(result, expected_output) \ No newline at end of file From ee00ea0f5ba995fb92f01d4f976c4b83875333d2 Mon Sep 17 00:00:00 2001 From: COPELLI Lorenzo Date: Wed, 8 Apr 2026 10:55:21 +0200 Subject: [PATCH 2/2] Added GitHub workflows. --- .github/workflows/codecov.yml | 37 +++++++++++++++++++++++++++++++++ .github/workflows/mkdocs.yml | 39 +++++++++++++++++++++++++++++++++++ README.md | 2 +- mkdocs.yml | 13 ++++++++++++ 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/codecov.yml create mode 100644 .github/workflows/mkdocs.yml create mode 100644 mkdocs.yml diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..204f6df --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,37 @@ +name: Run tests and upload coverage report to Codecov + +on: + push: + branches: [dev, main] + +jobs: + coverage: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install Python dependencies + run: | + pip install -r requirements.txt + pip install codecov + pip install -e . + + - name: Run tests with coverage + env: + SKIP_ONLINE_TESTS: "true" + run: | + coverage run -m pytest + coverage xml + + - name: Upload score to Codecov + uses: codecov/codecov-action@v4 + with: + files: coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/mkdocs.yml b/.github/workflows/mkdocs.yml new file mode 100644 index 0000000..b40ad50 --- /dev/null +++ b/.github/workflows/mkdocs.yml @@ -0,0 +1,39 @@ +name: Build and deploy mkdocs site to GitHub Pages + +on: + push: + branches: [main] + +jobs: + mkdocs: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install docs dependencies + run: | + pip install mkdocs + + - name: Generate index.md from README.md + run: | + cp README.md docs/index.md + sed -i 's|docs/guide.md|guide/|g' docs/index.md + mkdir docs/media + cp media/logo.png docs/media/logo.png + + - name: Build mkdocs site + run: mkdocs build + + - name: Deploy site to gh-pages branch + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site diff --git a/README.md b/README.md index c780ad6..87ab033 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eppoPynder -[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) +[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) [![codecov](https://codecov.io/gh/openefsa/eppoPynder/branch/main/graph/badge.svg?token=6U3TL9T27T)](https://codecov.io/gh/openefsa/eppoPynder) ## Overview diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..25eaa24 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,13 @@ +site_name: eppoPynder +site_description: Python interface to the EPPO Database and Public APIs +site_url: https://openefsa.github.io/eppoPynder +repo_url: https://github.com/openefsa/eppoPynder +docs_dir: docs +site_dir: site + +theme: + name: mkdocs + +nav: + - Home: 'index.md' + - 'Get started': 'guide.md'