6 |
7 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DEVELOPMENT.md:
--------------------------------------------------------------------------------
1 | # Development documentation
2 |
3 | Source of information: https://packaging.python.org/
4 |
5 | ## Prepare the local environment
6 |
7 | * https://packaging.python.org/en/latest/tutorials/installing-packages/
8 |
9 | ## Install package from the local copy
10 |
11 | * https://packaging.python.org/en/latest/tutorials/installing-packages/#installing-from-a-local-src-tree
12 | * https://setuptools.pypa.io/en/latest/userguide/development_mode.html
13 |
14 | ```
15 | python -m venv .venv
16 | source .venv/bin/activate
17 | pip install --editable .
18 | ```
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Developer Terms
2 | Welcome to our API and SDK! These Terms along with any other terms and policies referenced and incorporated by reference herein, as may be amended from time to time (the “Terms”) constitute a legally binding agreement as of the Effective Date (as defined below), governing your access to, and the use of, our application program interfaces, software, or accompanying documentation or materials (collectively, the “API”) and our software development kit or accompanying documentation or materials (collectively, the “SDK”) so please read these Terms carefully before accessing or using the API or downloading, installing or using the SDK. The Terms is between monday.com Ltd. (“monday.com”, “us”, “we” or “our”) and you, either individually, or on behalf of your employer or any other entity which you represent (“you” or “your”). In case you represent your employer or another entity, you hereby represent that (a) you have full legal authority to bind your employer or such entity (as applicable) to the Terms; and (b) after reading and understanding the Terms, you agree to the Terms on behalf of your employer or the respective entity (as applicable), and the Terms will bind your employer or such entity (as the case may be). YOU ACKNOWLEDGE THAT THE TERMS ARE BINDING, AND YOU AFFIRM AND SIGNIFY YOUR CONSENT TO THE TERMS, BY EITHER: (I) CLICKING ON A BUTTON OR CHECKING A CHECKBOX FOR THE ACCEPTANCE OF THE TERMS; OR (II) ACCESSING OR USING THE API AND DOWNLOADING, INSTALLING OR USING THE SDK, WHICHEVER IS EARLIER (THE “EFFECTIVE DATE”). IF YOU DO NOT AGREE TO COMPLY WITH, AND BE BOUND BY, THE TERMS OR DO NOT HAVE AUTHORITY TO BIND YOUR EMPLOYER OR ANY OTHER ENTITY (AS APPLICABLE), PLEASE DO NOT ACCEPT THE TERMS OR USE THE API AND SDK.
3 |
4 | 1. Permissions – What you are allowed to do with our API and SDK
5 | API License. Subject to your compliance with the Terms, monday.com grants you a limited, non-transferable, nonexclusive, revocable royalty-free license, without a right to sublicense, to use the API to develop, implement, integrate, and interface your application (“App“) with the monday.com Services as defined in our Terms of Service and distribute Your App to end users that are also customers of monday.com Service.
6 |
7 | SDK License. Subject to your compliance with the Terms, monday.com grants you a limited, non-transferrable, non-exclusive, revocable royalty-free license (a) without a right to sublicense, to download, install, and use the SDK to develop your App and if required by the functionality of your App to embed the monday.com software contained in the SDK into your App that communicates with the Services; and (b) to distribute and sub-license the monday.com software, only as embedded through use of the SDK, only as included in your App.
8 |
9 | License Restrictions. Except as expressly authorized under these Terms, you may not: (a) use, copy, modify, display, distribute, transfer, or sublicense any portion of the API or SDK; (b) make the functionality of the API or SDK available to any third party through any means, including, without limitation, any hosting, application services provider, service bureau, or other type of service; or (c) use the monday.com name, trademarks logos, anything confusingly similar or anything that may create a connotation of false-endorsement by monday.com, in connection with any App created by you, or in a manner that creates a sense of endorsement, sponsorship, or false association with monday.com. You acknowledge and agree that portions of the API, SDK and Services, including, without limitation, the source code and the specific design and structure of individual modules or programs, constitute or contain trade secrets of monday.com and its licensors. Accordingly, you agree not to disassemble, decompile, or otherwise reverse engineer the API, SDK or Services, in whole or in part, or to permit or authorize a third party to do so, except to the extent that such activities are expressly permitted by law notwithstanding this prohibition. You agree to fully comply with all U.S. export laws and regulations or any other applicable export laws and regulations to ensure that neither the API, SDK and Services, any technical data related thereto, nor any direct product thereof are exported or re-exported directly or indirectly in violation of, or used for any purposes prohibited by, such laws and regulations.
10 |
11 | 2. API Access Requirements.
12 | Each App must maintain absolute compatibility with the API in order to be granted access to the API and Services, including by (a) applying all SDK and API updates provided by monday.com, (b) providing all functionalities identified as critical by monday.com, and (c) supporting any standards (including encryption standards) required by monday.com. You agree to abide by any limitations on access, calls, or use of the API or Services (any “Service Limits”) that may be set by monday.com and will not attempt to circumvent such Service Limits without the separate prior written consent of monday.com. You may not use or access the API or Services for the purposes of monitoring the availability, performance, or functionality of the API or Services or for any other benchmarking or competitive purpose.
13 |
14 | 3. Updates and Support.
15 | monday.com may, but is under no obligation to maintain, support, update, or provide error corrections for the API or SDK. If monday.com provides you with an update or maintenance release for the API or SDK, unless you receive a separate license from monday.com for that update or release that expressly supersedes these Terms, such update or release will be subject to the terms and conditions of these Terms.
16 |
17 | 4. Your App.
18 | If you offer your App for use by others outside your organization, you agree to do so only subject to the terms of a user agreement (“EULA”) and privacy policy (“Privacy Policy”) for your App, which will be presented to users before they download or access your App. You agree that the EULA and Privacy Policy will comply with all applicable law, and that you will obtain and maintain all consents and permissions required in connection with the collection, use, storage and sharing of data in clear, understandable and accurate terms. You agree that each EULA and Privacy Policy will be at least as protective of monday.com’s proprietary rights in the API and SDK as those contained in the Terms and which will include, without limitation, terms for monday.com’s benefit regarding (a) restrictions on reverse engineering (to the maximum extent permitted by applicable law); (b) disclaimer of warranties; and (c) limitation of liability. You must obtain the explicit consent of the end user before collecting, using, posting, or sharing any Customer Data obtained through the API on an end user’s behalf. Mere authorization of your application by the end user does not constitute consent. In no event shall you or the App engage in any transmission, storage, accessor other use of Customer Data outside the scope of what the end user consented. In respect of any third party “open source” software or other third party intellectual property in any App (“Third Party Code”): (1) You will fully comply with any terms and conditions governing such Third Party Code, including without limitations, displaying any attributions, copyright information and other notices, terms and conditions that may be required to be provided to end users based on your use of such Third Party Code; (2) you shall use only Third Party Code that does not impose any obligation on, or affect monday.com, the end users, or any aspect of our Services (including our Marketplace) and related intellectual property, on an ordinary use and exploitation of your App (including as indicated in any terms applicable between you and monday.com).
19 |
20 | 5. Services Data.
21 | Results, usage statistics, data, or information (in the aggregate or otherwise) derived from your or your App’s use of the API, SDK or Services (“Services Data”) may be used only for your internal business purposes.
22 |
23 | 6. Acceptable Use.
24 | You may not use or access the API, SDK or Services for any unlawful purpose, for any purpose not expressly authorized hereunder, or in any manner that is inconsistent with the Terms. In addition, you agree that your Apps will not:
25 |
26 | contain any content that: (i) infringes, misappropriates or violates a third party’s patent, copyright, trademark, trade secret, moral rights or other intellectual property rights, or rights of publicity or privacy; (ii) violates, or encourages any conduct that would violate, any applicable law or regulation or would give rise to civil liability; (iii) is fraudulent, false, misleading or deceptive; (iv) is defamatory, obscene, pornographic, vulgar or offensive; (v) promotes discrimination, bigotry, racism, hatred, harassment or harm against any individual or group; (vi) is violent or threatening or promotes violence or actions that are threatening to any person or entity; or (vii) promotes illegal or harmful activities or substances;
27 |
28 | use, display, mirror or frame the Services or any individual element within the Services, without monday.com’s express written consent;
29 |
30 | access, tamper with, or use non-public areas of the Services, monday.com’s computer systems, or the technical delivery systems of monday.com’s providers;
31 |
32 | attempt to probe, scan or test the vulnerability of any monday.com system or network or breach any security or authentication measures;
33 |
34 | avoid, bypass, remove, deactivate, impair, descramble or otherwise circumvent any technological measure implemented by monday.com or any of monday.com’s providers or any other third party (including another user) to protect the Services;
35 |
36 | collect or store any personally identifiable information from the Services from other users of the Services without their express permission; or
37 |
38 | violate any applicable law or regulation.
39 |
40 | use Third Party Code that impose any obligation on, or affect monday.com, the end users, or any aspect of our Services, and related intellectual property, on an ordinary use or any exploitation of your App.
41 |
42 | 7. End User Data Protection
43 | (a) Data Collection. In connection with your use of the API, we may provide you with access to data or information (including personal data) associated with your Apps, and you may also collect other information, content, Customer Data or any other data from the end users who have installed your App, either as part of the App’s performance and activities, or data you collect from the end users in connection with their usage of the App or any other lawful reason, which may include personal data. Any data, content, Customer Data or information provided or collected pursuant to this clause (a) is collectively “End User Data“.
44 |
45 | (b) Use of End User Data. You agree that you will: (i) use, process, share, transfer and limit data collected from API calls to End User Data as has been specifically authorized by the end user or that is necessary and lawfully authorized for usage for the purposes of providing and improving the functionality of your App, all as specifically detailed in your Privacy Policy or any other Data Protection Agreement with the end user, governing your collection and use of the End User Data; and (ii) treat, store, transmit, use, or otherwise process the End User Data only in accordance with this Agreement, your Privacy Policy and your agreements with each respective end users and all applicable laws, rules, regulations, orders, and other requirements of governmental agencies the “Laws“); and (iii) comply with any and all data subject rights of the end users, including without limitation, the right to delete, rescind and review the End User Data. monday.com shall not be liable for, or have any responsibility in connection with, End User Data processed, used, shared or transferred by you or your App.
46 |
47 | (c) Security. You shall maintain and handle all End User Data in accordance with: (i) privacy and security measures adequate to preserve its confidentiality and security and (ii) all applicable Laws. You agree to implement appropriate technical and organizational measures (1) to ensure a level of security appropriate for the processing operations you undertake, and (2) that are, in any case, no less than measures consistent with industry standard practices. In addition, you shall adhere to the security requirements set forth in the app developer documentation and any other requirements provided to you by monday.com.
48 |
49 | (d) Incident Notification. In the event of any actual, alleged or suspected (i) unauthorized access, acquisition, use, disclosure, modification, loss or destruction of End User Data, whether intentional or accidental, (ii) security vulnerability or compromise of an App, or (iii) an issue that materially degrades monday.com’s systems or networks (collectively, an “Incident”), you shall promptly notify monday.com, and in no event later than 24 hours of first being aware of such Incident, and such notification must be prior to any notification to the end users. At our request, you will provide monday.com with further information and prompt assistance related to the Incident, including information regarding how it may affect monday.com and the end users. You shall investigate and remediate the Incidence, at your sole expense, in accordance with all applicable Laws and contractual obligations, including notification obligations, and you shall fully indemnify monday.com for any cost, expense or damage that monday.com may incur in connection with such Incident.
50 |
51 | (e) Deletion of End User Data upon App Deactivation. When we or an end user de-authorizes, deactivates, uninstalls or otherwise terminates an App, you shall either: (1) permanently delete all End User Data and any meta-data that was collected, transmitted, created or received by the App, within 30 days; or (2) Obtain express, written consent from the end user to retain End User Data longer than 30 days, provided such consent is clear and explicit. In the event that you retain End User Data, you must continue to maintain the such End User Data according to the your Privacy Policy and the EULA with the end user and continue to maintain any security measures that were in effect at the time of collection. End User Data must be deleted at any time an end user withdraws their consent to the collection and use of the End User Data. You must notify monday.com at marketplace@monday.com of your compliance with End User Data deletion or when further consent is obtained from the end user.
52 |
53 | 8. Ownership.
54 | The API and SDK are licensed, not sold, and monday.com retains ownership thereof, including all intellectual property rights therein and reserves all rights not expressly granted to you in these Terms.
55 |
56 | 9. Feedback.
57 | As a developer, you may provide suggestions, comments, feature requests or other feedback to any of monday.com Materials, the monday.com Service or the API (“Feedback”). Such Feedback is deemed an integral part of monday.com Materials, and as such, it is the sole property of monday.com without restrictions or limitations on use of any kind. monday.com may either implement or reject such Feedback, without any restriction or obligation of any kind.
58 |
59 | 10. Term and Termination.
60 | The Terms remains effective as of the Effective Date until terminated. You may terminate the Terms at any time by providing notice of such termination to monday.com. If you breach any term or condition of this Terms, monday.com may, at its sole discretion, without notice: (a) suspend your and your App’s access to the API, SKI or Services; (b) terminate all licenses or permissions granted hereunder; or (c) terminate these Terms. monday.com may, at its sole discretion, terminate this Terms or any licenses or permissions granted hereunder, by providing you with thirty (30) days’ notice of such termination. Upon termination, (x) all licenses or permissions granted to you hereunder will terminate; (y) you will terminate your App’s access to and use of the API and SDK; and (z) you will, within fifteen (15) days of termination, destroy all copies of the API, SDK and Services Data and any confidential information of monday.com. Sections 1 (with respect to License Restrictions only), 6, 7, 8, 10, 11, 12, 13, 14, 16 and 17 will survive termination of these Terms.
61 |
62 | 11. No Warranty.
63 | THE API AND SDK ARE PROVIDED ON AN “AS IS” AND “AS AVAILABLE” BASIS, WITHOUT WARRANTY OF ANY KIND. monday.com EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, AND ANY WARRANTIES AND CONDITIONS ARISING OUT OF COURSE OF DEALING OR USAGE OF TRADE RELATIVE TO THE API OR SDK. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED FROM ELSEWHERE WILL CREATE ANY WARRANTY OR CONDITION NOT EXPRESSLY STATED IN THESE TEMS.
64 |
65 | 12. Limitation of Liability.
66 | monday.com’S TOTAL LIABILITY TO YOU FROM ALL CAUSES OF ACTION AND UNDER ALL THEORIES OF LIABILITY UNDER THESE TERMS WILL BE LIMITED TO AND WILL NOT EXCEED ONE HUNDERD DOLLARS. EXCEPT FOR BREACH OF SECTION 11 AND YOUR INDEMNITY OBIGATIONS UNDER SECTION 12, IN NO EVENT WILL EITHER PARTY BE LIABLE TO THE OTHER FOR ANY SPECIAL, INCIDENTAL, EXEMPLARY, PUNITIVE OR CONSEQUENTIAL DAMAGES (INCLUDING LOSS OF USE, DATA, BUSINESS OR PROFITS) OR FOR THE COST OF PROCURING SUBSTITUTE PRODUCTS ARISING OUT OF OR IN CONNECTION WITH THESE TERMS OR THE USE OR PERFORMANCE OF THE API OR SDK, WHETHER SUCH LIABILITY ARISES FROM A CLAIM BASED UPON CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, OR OTHERWISE, AND WHETHER OR NOT SUCH PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS OR DAMAGE. THE FOREGOING LIMITATIONS WILL SURVIVE AND APPLY EVEN IF ANY LIMITED REMEDY SPECIFIED IN THESE TERMS IS FOUND TO HAVE FAILED OF ITS ESSENTIAL PURPOSE.
67 |
68 | 13. Indemnity.
69 | You agree to defend, indemnify, and hold monday.com harmless from and against any liabilities, losses, damages, judgments, fines, penalties, costs and expenses (including reasonable attorneys’ fees and court costs), as incurred, arising out of or resulting from any third-party claim, action, or proceeding brought against monday.com (any “Claim”) arising from your App or use of the API of SDK (including without limitations, any alleged infringement, violation, misappropriation of any third party right (e.g. intellectual property rights and privacy rights) or your breach of these Terms. Upon receiving a Claim, monday.com being shall provide written notice to you and allow you to assume control over the defense and/or settlement of the claim, provided that monday.com reserves the right to retain counsel, at its own expense, to participate in the defense and settlement of the Claim.
70 |
71 | 14. Confidentiality.
72 | The API and SDK are the confidential information of monday.com and you agree not to use the API and SDK except as expressly authorized hereunder and as necessary to exercise your rights under these Terms. Except as expressly authorized hereunder, you will not disclose monday.com’s confidential information to any third party. Notwithstanding the forgoing, you may disclose monday.com’s confidential information to those of your employees and subcontractors that need to know such confidential information for the purpose of performing under these Terms, provided that each such employee or subcontractor is subject to a written agreement that includes binding use and disclosure restrictions that are at least as protective as those set forth herein. You agree to use all reasonable efforts to maintain the confidentiality of monday.com’s confidential information, but in no event less than the efforts that you ordinarily use with respect to your own proprietary information of similar importance.
73 |
74 | 15. Modification.
75 | monday.com may modify the terms of these Terms, at any time and in its sole discretion, by providing you with written notice of such modification, including by posting the new terms on the monday.com’s website. If any noticed modification to these Terms is unacceptable to you, your sole recourse will be to terminate these Terms in accordance with Section 8 above. Your access and/or use of the API or SDK after receiving such notice will constitute your acceptance of the noticed modifications.
76 |
77 | 16. Governing Law and Jurisdiction.
78 | These Terms and any action related thereto will be governed and interpreted by and under the laws of the State of Israel without giving effect to any conflicts of laws principles that require the application of the law of a different jurisdiction. Courts of competent jurisdiction located in Tel Aviv-Jaffa, Israel, will have the sole and exclusive jurisdiction and venue over all controversies and claims arising out of, or relating to, these Terms. You and us mutually agree that the United Nations Convention on Contracts for the International Sale of Goods does not apply to this Terms.
79 |
80 | 17. General.
81 | These Terms is written in English, and translated into other languages for your convenience. If a translated (non-English) version of these Terms conflicts in any way with the English version, the provisions of the English version will prevail. Neither us nor you will be liable by reason of any failure or delay in the performance of its obligations on account of events beyond the reasonable control of a party, which may include denial-of-service attacks, interruption or failure of the Internet or any utility service, failures in third-party hosting services, strikes, shortages, riots, fires, acts of God, war, pandemics, terrorism, and governmental action. The parties are independent contractors. These Terms does not create a partnership, franchise, joint venture, agency, fiduciary or employment relationship between the parties. There are no third party beneficiaries to these Terms. We will use your contact details that we have in our records, in connection with providing you notices, as provided herein. Our contact details for any notices are detailed below. You acknowledge that notices that we provide you, in connection with these Terms, will be provided via e-mail or otherwise in connection with your use of the API and SDK. Any notice to you will be deemed given upon the earlier of: (i) receipt; or (ii) 24 hours of delivery. Notices to us will be provided to monday.com Ltd., attn: General Counsel, at legal@monday.com, or sent to 52 Menachem Begin Road, Tel Aviv 6713701, Israel. These Terms, and any and all rights and obligations hereunder, may not be transferred or assigned by you without our written approval. We may assign our rights and/or obligations hereunder without your consent or prior notice to you. Subject to the foregoing conditions, this Terms will bind and inure to the benefit of the parties, their respective successors, and permitted assigns. Any assignment not authorized herein will be null and void. These Terms will be enforced to the fullest extent permitted under applicable law. If any provision of these Terms is held by a court of competent jurisdiction to be contrary to law, the provision will be modified by the court and interpreted so as best to accomplish the objectives of the original provision to the fullest extent permitted by law, and the remaining provisions of these Terms will remain in effect. No failure or delay by either party in exercising any right under these Terms will constitute a waiver of that right. No waiver under these Terms will be effective unless made in writing and signed by an authorized representative of the party being deemed to have granted the waiver.
82 |
83 | Last Updated: October 16, 2020
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # monday-api-python-sdk
2 |
3 | A Python SDK for interacting with Monday"s GraphQL API.
4 |
5 | ## Table of Contents
6 |
7 | - [Installation](#installation)
8 | - [Usage](#usage)
9 | - [Examples](#examples)
10 | - [Authentication](#authentication)
11 | - [Response Types](#response-types)
12 |
13 | ## Installation
14 |
15 | To install the SDK, use pip:
16 |
17 | ```bash
18 | pip install monday-api-python-sdk
19 | ```
20 | ## Authentication
21 | To use the SDK, you need to authenticate with your Monday API token:
22 |
23 | ```python
24 | from monday_sdk import MondayClient, MondayApiResponse, Board
25 |
26 | client = MondayClient(token="your_token")
27 | ```
28 |
29 | ## Examples
30 |
31 | Here are some examples of how to use the SDK:
32 |
33 | ### Example 1: Create a new item
34 | ```python
35 | from monday_sdk import MondayClient
36 |
37 | client = MondayClient(token="your_token")
38 |
39 | column_values = {
40 | "status_column_id": "In Progress", # Replace with your actual status column ID and value
41 | "date_column_id": "2025-01-06", # Replace with your actual date column ID and date (YYYY-MM-DD format)
42 | "text_column_id": "Important task" # Replace with your actual text column ID and value
43 | }
44 |
45 | item = client.items.create_item(
46 | board_id="your_board_id",
47 | group_id="your_group_id",
48 | item_name="New Item",
49 | column_values=column_values
50 | )
51 |
52 | print(item)
53 | ```
54 | ### Example 2: Create an Update and Update Column Values
55 | ```python
56 | from monday_sdk import MondayClient, StatusColumnValue, DateColumnValue
57 |
58 | client = MondayClient(token="your_token")
59 |
60 | # Create an update for an item
61 | update_response = client.updates.create_update(
62 | item_id="your_item_id",
63 | update_value="This is a new update message for the item."
64 | )
65 |
66 | # Change a status column value
67 | status_response = client.items.change_status_column_value(
68 | board_id="your_board_id",
69 | item_id="your_item_id",
70 | column_id="status_column_id", # Replace with the actual column ID
71 | value="Done" # Replace with the desired status value
72 | )
73 | print(f"Status column updated: {status_response}")
74 |
75 | # Change a date column value
76 | date_response = client.items.change_date_column_value(
77 | board_id="your_board_id",
78 | item_id="your_item_id",
79 | column_id="date_column_id",
80 | timestamp="2025-01-06"
81 | )
82 | ```
83 |
84 | ## Response Types
85 |
86 | The SDK provides structured types to help you work with API responses more effectively. These types allow you to easily access and manipulate the data returned by the API.
87 |
88 | ### Available Types
89 |
90 | - `MondayApiResponse`: Represents the full response from a Monday API query, including data and account information.
91 | - `Data`: Holds the core data returned from the API, such as boards, items, and complexity details.
92 | - `Board`: Represents a Monday board, including items, updates, and activity logs.
93 | - `Item`: Represents an item on a board, including its details and associated subitems.
94 | - `Column`, `ColumnValue`: Represents columns and their values for an item.
95 | - `Group`: Represents a group within a board.
96 | - `User`: Represents a user associated with an update or activity log.
97 | - `Update`: Represents an update on an item.
98 | - `ActivityLog`: Represents an activity log entry on a board.
99 | - `ItemsPage`: Represents a paginated collection of items.
100 |
101 | ### Example Usage
102 |
103 | Here is an example of how to use these types with the SDK to deserialize API responses:
104 | ```python
105 | from monday_sdk import MondayClient
106 |
107 | client = MondayClient(token="your_token")
108 | items = client.boards.fetch_all_items_by_board_id(board_id="your_board_id")
109 | first_item_name = items[0].name
110 | print(f"First item name: {first_item_name}")
111 | ```
112 | By using these types, you can ensure type safety and better code completion support in your IDE, making your work with the Monday API more efficient and error-free.
113 |
--------------------------------------------------------------------------------
/pylintrc:
--------------------------------------------------------------------------------
1 | [MAIN]
2 | max-args = 6
3 | py-version = 3.8
4 | [FORMAT]
5 | max-line-length=120
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = ["setuptools >= 61.0"]
3 | build-backend = "setuptools.build_meta"
4 |
5 | [project]
6 | name = "monday-api-python-sdk"
7 | requires-python = ">=3.8"
8 | dynamic = ["version"]
9 | dependencies = [
10 | "dacite",
11 | "requests",
12 | ]
13 | authors = [
14 | {name = "Michael Imas", email = "michaelim@monday.com"},
15 | ]
16 | maintainers = [
17 | {name = "Rafał Zawadzki", email = "rafalza@monday.com"},
18 | ]
19 | readme = "README.md"
20 | description = "A Python SDK for interacting with Monday's GraphQL API."
21 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [options]
2 | package_dir =
3 | = src
4 | [metadata]
5 | license_files = LICENSE
6 | [flake8]
7 | max-line-length=120
8 |
9 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | """A setuptools based setup module.
2 | """
3 |
4 | # Always prefer setuptools over distutils
5 | from setuptools import setup, find_packages
6 | import pathlib
7 |
8 | here = pathlib.Path(__file__).parent.resolve()
9 |
10 | # Get the long description from the README file
11 | long_description = (here / "README.md").read_text(encoding="utf-8")
12 |
13 | # Arguments marked as "Required" below must be included for upload to PyPI.
14 | # Fields marked as "Optional" may be commented out.
15 |
16 | setup(
17 | name="monday-api-python-sdk", # Required
18 | version="1.3.1", # Required
19 | description="A Python SDK for interacting with Monday's GraphQL API", # Optional
20 | long_description=long_description, # Optional
21 | long_description_content_type="text/markdown", # Optional (see note above)
22 | url="https://github.com/mondaycom/monday-api-python-sdk", # Optional
23 | author="Michael Imas",
24 | author_email="michaelim@monday.com",
25 | license_files=("LICENSE",),
26 | classifiers=[ # Optional
27 | "Development Status :: 5 - Production/Stable",
28 | "Intended Audience :: Developers",
29 | "Topic :: Software Development :: Build Tools",
30 | # Pick your license as you wish
31 | # "License :: OSI Approved :: MIT License",
32 | # Specify the Python versions you support here. In particular, ensure
33 | # that you indicate you support Python 3. These classifiers are *not*
34 | # checked by 'pip install'. See instead 'python_requires' below.
35 | "Programming Language :: Python :: 3",
36 | "Programming Language :: Python :: 3.8",
37 | "Programming Language :: Python :: 3.9",
38 | "Programming Language :: Python :: 3.10",
39 | "Programming Language :: Python :: 3 :: Only",
40 | ],
41 | # This field adds keywords for your project which will appear on the
42 | # project page. What does your project relate to?
43 | #
44 | # Note that this is a list of additional keywords, separated
45 | # by commas, to be used to assist searching for the distribution in a
46 | # larger catalog.
47 | keywords="sample, setuptools, development", # Optional
48 | # When your source code is in a subdirectory under the project root, e.g.
49 | # `src/`, it is necessary to specify the `package_dir` argument.
50 | package_dir={"": "src"}, # Optional
51 | # You can just specify package directories manually here if your project is
52 | # simple. Or you can use find_packages().
53 | #
54 | # Alternatively, if you just want to distribute a single Python file, use
55 | # the `py_modules` argument instead as follows, which will expect a file
56 | # called `my_module.py` to exist:
57 | #
58 | # py_modules=["my_module"],
59 | #
60 | packages=find_packages(where="src"), # Required
61 | # Specify which Python versions you support. In contrast to the
62 | # 'Programming Language' classifiers above, 'pip install' will check this
63 | # and refuse to install the project if the version does not match. See
64 | # https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
65 | python_requires=">=3.7, <4",
66 | # This field lists other packages that your project depends on to run.
67 | # Any package you put here will be installed by pip when your project is
68 | # installed, so they must be valid existing projects.
69 | #
70 | # For an analysis of "install_requires" vs pip's requirements files see:
71 | # https://packaging.python.org/discussions/install-requires-vs-requirements/
72 | install_requires=["dacite", "requests"], # Optional
73 | # List additional groups of dependencies here (e.g. development
74 | # dependencies). Users will be able to install these using the "extras"
75 | # syntax, for example:
76 | #
77 | # $ pip install sampleproject[dev]
78 | #
79 | # Similar to `install_requires` above, these must be valid existing
80 | # projects.
81 | # extras_require={ # Optional
82 | # "dev": ["check-manifest"],
83 | # "test": ["coverage"],
84 | # },
85 | # If there are data files included in your packages that need to be
86 | # installed, specify them here.
87 | # package_data={ # Optional
88 | # "sample": ["package_data.dat"],
89 | # },
90 | # Entry points. The following would provide a command called `sample` which
91 | # executes the function `main` from this package when invoked:
92 | # entry_points={ # Optional
93 | # "console_scripts": [
94 | # "sample=sample:main",
95 | # ],
96 | # },
97 | # List additional URLs that are relevant to your project as a dict.
98 | #
99 | # This field corresponds to the "Project-URL" metadata fields:
100 | # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use
101 | #
102 | # Examples listed include a pattern for specifying where the package tracks
103 | # issues, where the source is hosted, where to say thanks to the package
104 | # maintainers, and where to support the project financially. The key is
105 | # what's used to render the link text on PyPI.
106 | # project_urls={ # Optional
107 | # "Bug Reports": "https://github.com/pypa/sampleproject/issues",
108 | # "Funding": "https://donate.pypi.org",
109 | # "Say Thanks!": "http://saythanks.io/to/example",
110 | # "Source": "https://github.com/pypa/sampleproject/",
111 | # },
112 | )
113 |
--------------------------------------------------------------------------------
/src/monday_sdk/__init__.py:
--------------------------------------------------------------------------------
1 | from .client import MondayClient
2 | from .types import *
3 | from .utils import *
--------------------------------------------------------------------------------
/src/monday_sdk/client.py:
--------------------------------------------------------------------------------
1 | from .types import MondayClientSettings
2 | from .modules import BoardModule, ItemModule, UpdateModule, CustomModule, ActivityLogModule
3 | from .constants import API_VERSION, DEFAULT_MAX_RETRY_ATTEMPTS
4 |
5 | BASE_HEADERS = {"API-Version": API_VERSION}
6 |
7 |
8 | class MondayClient:
9 | def __init__(self, token, headers=None, debug_mode=False, max_retry_attempts=DEFAULT_MAX_RETRY_ATTEMPTS):
10 |
11 | headers = headers or BASE_HEADERS.copy()
12 | self.settings = MondayClientSettings(token, headers, debug_mode, max_retry_attempts)
13 |
14 | self.boards = BoardModule(self.settings)
15 | self.items = ItemModule(self.settings)
16 | self.updates = UpdateModule(self.settings)
17 | self.activity_logs = ActivityLogModule(self.settings)
18 | self.custom = CustomModule(self.settings)
19 |
--------------------------------------------------------------------------------
/src/monday_sdk/constants.py:
--------------------------------------------------------------------------------
1 | API_URL = "https://api.monday.com/v2"
2 | API_VERSION = "2023-10"
3 | TOKEN_HEADER = "Authorization"
4 | MAX_COMPLEXITY = 10000000 # Monday's API complexity limit per minute
5 | BASE_HEADERS = {"API-Version": API_VERSION}
6 |
7 | DEFAULT_MAX_RETRY_ATTEMPTS = 3
8 | DEFAULT_PAGE_LIMIT_ITEMS = 500
9 | DEFAULT_PAGE_LIMIT_UPDATES = 1000
10 | DEFAULT_PAGE_LIMIT_BOARDS = 50
11 | DEFAULT_PAGE_LIMIT_ACTIVITY_LOGS = 1000
12 |
--------------------------------------------------------------------------------
/src/monday_sdk/exceptions.py:
--------------------------------------------------------------------------------
1 | class MondayError(Exception):
2 | pass
3 |
4 |
5 | class MondayQueryError(MondayError):
6 | def __init__(self, message, original_errors=None):
7 | super().__init__(message)
8 | self.original_errors = original_errors or []
9 |
--------------------------------------------------------------------------------
/src/monday_sdk/graphql_handler.py:
--------------------------------------------------------------------------------
1 | import dacite
2 | import requests
3 | import json
4 | import time
5 |
6 | from .exceptions import MondayQueryError
7 | from .constants import API_URL, TOKEN_HEADER
8 | from .types import MondayApiResponse, MondayClientSettings
9 |
10 |
11 | class MondayGraphQL:
12 | """
13 | GraphQL client that handles API interactions, response serialization, and error handling.
14 | """
15 |
16 | def __init__(self, settings: MondayClientSettings):
17 | self.endpoint = API_URL
18 | self.token = settings.token
19 | self.headers = settings.headers
20 | self.debug_mode = settings.debug_mode
21 | self.max_retry_attempts = settings.max_retry_attempts
22 |
23 | def execute(self, query: str) -> MondayApiResponse:
24 | """
25 | Executes a GraphQL query and handles errors and rate limits.
26 |
27 | Args:
28 | query (str): The GraphQL query to execute.
29 |
30 | Returns:
31 | MondayApiResponse: The deserialized response from the Monday API.
32 | """
33 | current_attempt = 0
34 |
35 | while current_attempt < self.max_retry_attempts:
36 |
37 | if self.debug_mode:
38 | print(f"[debug_mode] about to execute query: {query}")
39 |
40 | try:
41 | response = self._send(query)
42 |
43 | if self.debug_mode:
44 | print(f"[debug_mode] response: {response}")
45 |
46 | if response.status_code == 429:
47 | print("Rate limit exceeded, response code 429 - sleeping for 30 seconds")
48 | time.sleep(30)
49 | current_attempt += 1
50 | continue
51 |
52 | response.raise_for_status()
53 | response_data = response.json()
54 |
55 | if response_data.get("error_code") == "ComplexityException":
56 | time.sleep(2)
57 | print("ComplexityException: retrying query")
58 | current_attempt += 1
59 | continue
60 |
61 | if "errors" in response_data:
62 | raise MondayQueryError(response_data["errors"][0]["message"], response_data["errors"])
63 |
64 | try:
65 | serialized_result = dacite.from_dict(data_class=MondayApiResponse, data=response_data)
66 | return serialized_result
67 |
68 | except dacite.DaciteError as e:
69 | print(f"Error while deserializing response: {e}")
70 | raise MondayQueryError("Error while deserializing response", response_data)
71 |
72 | except (requests.HTTPError, json.JSONDecodeError, MondayQueryError) as e:
73 | print(f"Error while executing query: {e}")
74 | current_attempt += 1
75 |
76 | def _send(self, query: str):
77 | payload = {"query": query}
78 | headers = self.headers.copy()
79 |
80 | if self.token is not None:
81 | headers[TOKEN_HEADER] = self.token
82 |
83 | return requests.request("POST", self.endpoint, headers=headers, json=payload)
84 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/__init__.py:
--------------------------------------------------------------------------------
1 | from .boards import BoardModule
2 | from .items import ItemModule
3 | from .updates import UpdateModule
4 | from .custom import CustomModule
5 | from .activity_logs import ActivityLogModule
6 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/activity_logs.py:
--------------------------------------------------------------------------------
1 | from ..query_templates import get_activity_logs_query
2 | from ..types import MondayApiResponse, ActivityLog
3 | from ..graphql_handler import MondayGraphQL
4 | from ..constants import DEFAULT_PAGE_LIMIT_ACTIVITY_LOGS
5 | from typing import Optional, Union, List
6 |
7 |
8 | class ActivityLogModule(MondayGraphQL):
9 |
10 | def fetch_activity_logs_from_board(
11 | self,
12 | board_ids: Union[int, str],
13 | page: Optional[int] = 1,
14 | limit: Optional[int] = DEFAULT_PAGE_LIMIT_ACTIVITY_LOGS,
15 | from_date: Optional[str] = None,
16 | to_date: Optional[str] = None,
17 | ) -> MondayApiResponse:
18 | query = get_activity_logs_query(board_ids, limit, page, from_date, to_date)
19 | return self.execute(query)
20 |
21 | def fetch_all_activity_logs_from_board(
22 | self,
23 | board_ids: Union[int, str],
24 | from_date: Optional[str] = None,
25 | to_date: Optional[str] = None,
26 | limit: Optional[int] = DEFAULT_PAGE_LIMIT_ACTIVITY_LOGS,
27 | events_filter: Optional[List[str]] = None,
28 | ) -> List[ActivityLog]:
29 | page = 1
30 | activity_logs = []
31 | while True:
32 | response = self.fetch_activity_logs_from_board(
33 | board_ids=board_ids, limit=limit, page=page, from_date=from_date, to_date=to_date
34 | )
35 | current_activity_logs = response.data.boards[0].activity_logs
36 | if not current_activity_logs: # ATM is the only way to check if there are no more activity logs
37 | break
38 | else:
39 | relevant_activity_logs = (
40 | current_activity_logs
41 | if events_filter is None
42 | else [log for log in current_activity_logs if log.event in events_filter]
43 | )
44 | activity_logs.extend(relevant_activity_logs)
45 | page += 1
46 |
47 | return activity_logs
48 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/boards.py:
--------------------------------------------------------------------------------
1 | from typing import List, Optional, Union, Any, Mapping
2 |
3 | from ..graphql_handler import MondayGraphQL
4 | from ..query_templates import get_boards_query, get_board_by_id_query, get_board_items_query, get_columns_by_board_query
5 | from ..types import MondayApiResponse, Item, ItemsPage, BoardKind, BoardState, BoardsOrderBy
6 | from ..utils import sleep_according_to_complexity, construct_updated_at_query_params
7 | from ..constants import DEFAULT_PAGE_LIMIT_BOARDS, DEFAULT_PAGE_LIMIT_ITEMS
8 |
9 |
10 | class BoardModule(MondayGraphQL):
11 | def fetch_boards(
12 | self,
13 | limit: Optional[int] = DEFAULT_PAGE_LIMIT_BOARDS,
14 | page: Optional[int] = None,
15 | ids: Optional[List[int]] = None,
16 | board_kind: Optional[BoardKind] = None,
17 | state: Optional[BoardState] = None,
18 | order_by: Optional[BoardsOrderBy] = None,
19 | ) -> MondayApiResponse:
20 | query = get_boards_query(ids=ids, limit=limit, page=page, board_kind=board_kind, state=state, order_by=order_by)
21 | return self.execute(query)
22 |
23 | def fetch_boards_by_id(self, board_id: Union[int, str]) -> MondayApiResponse:
24 | query = get_board_by_id_query(board_id)
25 | return self.execute(query)
26 |
27 | def fetch_all_items_by_board_id(
28 | self,
29 | board_id: Union[int, str],
30 | query_params: Optional[Mapping[str, Any]] = None,
31 | limit: Optional[int] = DEFAULT_PAGE_LIMIT_ITEMS,
32 | ) -> List[Item]:
33 | """
34 | Fetches all items from a board by board ID, includes paginating
35 | todo: add support for multiple board IDs
36 | """
37 | items: List[Item] = []
38 | cursor = None
39 |
40 | while True:
41 | query = get_board_items_query(board_id, query_params=query_params, cursor=cursor, limit=limit)
42 | response = self.execute(query)
43 | items_page = response.data.boards[0].items_page if cursor is None else response.data.next_items_page
44 |
45 | items.extend(items_page.items)
46 | complexity = response.data.complexity.query
47 | cursor = items_page.cursor
48 |
49 | if cursor:
50 | sleep_according_to_complexity(complexity)
51 | else:
52 | break
53 |
54 | return items
55 |
56 | def fetch_item_by_board_id_by_update_date(
57 | self,
58 | board_id: Union[int, str],
59 | updated_after: str,
60 | updated_before: str,
61 | limit: Optional[int] = DEFAULT_PAGE_LIMIT_ITEMS,
62 | ) -> List[Item]:
63 | """
64 | Fetches items from a board by board ID by update date, useful for incremental fetching
65 | todo: add type hints for updated_after and updated_before and validate them
66 | """
67 | if not updated_after and not updated_before:
68 | raise ValueError(
69 | "Either updated_after or updated_before must be provided when fetching items by update date"
70 | )
71 | query_params = construct_updated_at_query_params(updated_after, updated_before)
72 | return self.fetch_all_items_by_board_id(board_id, query_params=query_params, limit=limit)
73 |
74 | def fetch_columns_by_board_id(self, board_id: Union[int, str]) -> MondayApiResponse:
75 | query = get_columns_by_board_query(board_id)
76 | return self.execute(query)
77 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/custom.py:
--------------------------------------------------------------------------------
1 | from ..graphql_handler import MondayGraphQL
2 |
3 |
4 | class CustomModule(MondayGraphQL):
5 | def execute_custom_query(self, custom_query):
6 | return self.execute(custom_query)
7 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/items.py:
--------------------------------------------------------------------------------
1 | from typing import Union, Dict, Any, List
2 | import datetime
3 |
4 | from ..graphql_handler import MondayGraphQL
5 | from ..query_templates import create_item_query, get_item_query, change_column_value_query, get_item_by_id_query, update_multiple_column_values_query, create_subitem_query, delete_item_query, archive_item_query, move_item_to_group_query, change_simple_column_value_query
6 | from ..types import Item
7 |
8 |
9 | class ItemModule(MondayGraphQL):
10 | """ "
11 | todo: add types for this module
12 | """
13 |
14 | def change_custom_column_value(
15 | self, board_id: Union[str, int], item_id: Union[str, int], column_id: str, value: Dict[str, Any]
16 | ):
17 | """
18 | for text columns, use change_simple_column_value
19 | for status columns, use change_status_column_value
20 | for date columns, use change_date_column_value
21 | for other columns, use this method, for example, for checkbox columns pass {'checked': True}
22 | """
23 | query = change_column_value_query(board_id, item_id, column_id, value)
24 | return self.execute(query)
25 |
26 | def change_simple_column_value(
27 | self, board_id: Union[str, int], item_id: Union[str, int], column_id: str, value: str
28 | ):
29 | query = change_simple_column_value_query(board_id, item_id, column_id, value)
30 | return self.execute(query)
31 |
32 | def change_status_column_value(
33 | self, board_id: Union[str, int], item_id: Union[str, int], column_id: str, value: str
34 | ):
35 | dict_value = {"label": value}
36 | return self.change_custom_column_value(board_id, item_id, column_id, dict_value)
37 |
38 | def change_date_column_value(
39 | self, board_id: Union[str, int], item_id: Union[str, int], column_id: str, timestamp: datetime
40 | ):
41 | dict_value = {"date": timestamp.strftime("%Y-%m-%d"), "time": timestamp.strftime("%H:%M:%S")}
42 | return self.change_custom_column_value(board_id, item_id, column_id, dict_value)
43 |
44 | def create_item(
45 | self,
46 | board_id: Union[str, int],
47 | group_id: Union[str, int],
48 | item_name: str,
49 | column_values: Dict[str, Any] = None,
50 | create_labels_if_missing=False,
51 | ):
52 | query = create_item_query(board_id, group_id, item_name, column_values, create_labels_if_missing)
53 | return self.execute(query)
54 |
55 | def create_subitem(
56 | self,
57 | parent_item_id: Union[str, int],
58 | subitem_name: str,
59 | column_values: Dict[str, Any] = None,
60 | create_labels_if_missing=False,
61 | ):
62 | query = create_subitem_query(parent_item_id, subitem_name, column_values, create_labels_if_missing)
63 | return self.execute(query)
64 |
65 | def fetch_items_by_column_value(
66 | self, board_id: Union[str, int], column_id: str, value: str, limit: int = None, cursor: str = None
67 | ):
68 | query = get_item_query(board_id, column_id, value, limit, cursor)
69 | return self.execute(query)
70 |
71 | def fetch_items_by_id(self, ids: Union[str, int, List[Union[str, int]]]) -> List[Item]:
72 | if isinstance(ids, (list, set)):
73 | ids_str = ", ".join(map(str, ids))
74 | ids_str = f"[{ids_str}]"
75 | else:
76 | ids_str = str(ids)
77 | query = get_item_by_id_query(ids_str)
78 | response = self.execute(query)
79 | return response.data.items
80 |
81 | def change_multiple_column_values(
82 | self,
83 | board_id: Union[str, int],
84 | item_id: Union[str, int],
85 | column_values: Dict[str, Any],
86 | create_labels_if_missing: bool = False,
87 | ):
88 | query = update_multiple_column_values_query(board_id, item_id, column_values, create_labels_if_missing)
89 | return self.execute(query)
90 |
91 | def move_item_to_group(self, item_id: Union[str, int], group_id: Union[str, int]):
92 | query = move_item_to_group_query(item_id, group_id)
93 | return self.execute(query)
94 |
95 | def archive_item_by_id(self, item_id: Union[str, int]):
96 | query = archive_item_query(item_id)
97 | return self.execute(query)
98 |
99 | def delete_item_by_id(self, item_id: Union[str, int]):
100 | query = delete_item_query(item_id)
101 | return self.execute(query)
102 |
--------------------------------------------------------------------------------
/src/monday_sdk/modules/updates.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | from typing import List, Optional
3 |
4 | from ..query_templates import create_update_query, delete_update_query, get_update_query, get_updates_for_item_query, get_updates_for_board
5 | from ..types import MondayApiResponse, Update
6 | from ..graphql_handler import MondayGraphQL
7 |
8 | class UpdateModule(MondayGraphQL):
9 | def create_update(self, item_id, update_value) -> MondayApiResponse:
10 | query = create_update_query(item_id, update_value)
11 | return self.execute(query)
12 |
13 | def delete_update(self, item_id) -> MondayApiResponse:
14 | query = delete_update_query(item_id)
15 | return self.execute(query)
16 |
17 | def fetch_updates(self, limit, page=None) -> MondayApiResponse:
18 | query = get_update_query(limit, page)
19 | return self.execute(query)
20 |
21 | def fetch_updates_for_item(self, item_id, limit=100) -> MondayApiResponse:
22 | query = get_updates_for_item_query(item_id=item_id, limit=limit)
23 | return self.execute(query)
24 |
25 | def fetch_board_updates_page(self, board_id, limit=100, page=1) -> List[Update]:
26 | query = get_updates_for_board(board_id, limit, page)
27 | response: MondayApiResponse = self.execute(query)
28 | return response.data.boards[0].updates
29 |
30 | def fetch_board_updates(
31 | self,
32 | board_ids: str,
33 | updated_after: Optional[str] = None,
34 | updated_before: Optional[str] = None,
35 | ) -> List[Update]:
36 | """
37 | Fetches all updates from a board (with optional date filtering).
38 | - Paginates through all pages until no more updates.
39 | - If from_date or to_date are provided, filters out updates outside that window.
40 | """
41 | start_dt = datetime.fromisoformat(updated_after) if updated_after else None
42 | end_dt = datetime.fromisoformat(updated_before) if updated_before else None
43 |
44 | all_updates = []
45 | page = 1
46 |
47 | while True:
48 | updates = self.fetch_board_updates_page(board_ids, page=page)
49 | if not updates:
50 | break
51 |
52 | if start_dt or end_dt:
53 | updates = [
54 | u for u in updates
55 | if (
56 | u.updated_at
57 | and (start_dt is None or datetime.fromisoformat(u.updated_at) >= start_dt)
58 | and (end_dt is None or datetime.fromisoformat(u.updated_at) <= end_dt)
59 | )
60 | ]
61 |
62 | all_updates.extend(updates)
63 | page += 1
64 |
65 | return all_updates
--------------------------------------------------------------------------------
/src/monday_sdk/query_templates.py:
--------------------------------------------------------------------------------
1 | import json
2 | from enum import Enum
3 | from typing import List, Union, Optional, Mapping, Any
4 |
5 | from .types import BoardKind, BoardState, BoardsOrderBy
6 | from .utils import monday_json_stringify, gather_params
7 |
8 |
9 | # todo: divide into separate files, take into account that multiple resources can use the same query
10 |
11 |
12 | def get_board_items_query(
13 | board_ids: Union[int, str],
14 | limit: int,
15 | query_params: Optional[Mapping[str, Any]] = None,
16 | cursor: Optional[str] = None,
17 | ) -> str:
18 | if cursor is None:
19 | return get_board_items_first_page_query(board_ids, query_params=query_params, limit=limit)
20 | else:
21 | return get_board_items_pagination_query(cursor=cursor, limit=limit)
22 |
23 |
24 | def get_board_items_first_page_query(
25 | board_id: Union[str, int], limit: int, query_params: Optional[Mapping[str, Any]] = None
26 | ) -> str:
27 | raw_params = locals().items()
28 | items_page_params = gather_params(raw_params, excluded_params=["board_id"])
29 | wrapped_params = f"({items_page_params})" if items_page_params else ""
30 |
31 | query = """{
32 | complexity {
33 | query
34 | after
35 | }
36 | boards(ids: %s){
37 | name
38 | items_page %s {
39 | cursor
40 | items {
41 | id
42 | name
43 | group {
44 | id
45 | title
46 | }
47 | column_values {
48 | ... on MirrorValue {
49 | display_value
50 | }
51 | ... on BoardRelationValue {
52 | display_value
53 | }
54 | ... on DependencyValue {
55 | display_value
56 | }
57 | value
58 | text
59 | type
60 | column {
61 | id
62 | title
63 | }
64 | }
65 | subitems {
66 | name
67 | id
68 | parent_item {
69 | id
70 | }
71 | group {
72 | id
73 | title
74 | }
75 | column_values {
76 | ... on MirrorValue {
77 | display_value
78 | }
79 | ... on DependencyValue {
80 | display_value
81 | }
82 | ... on BoardRelationValue {
83 | display_value
84 | }
85 | text
86 | type
87 | column {
88 | id
89 | title
90 | }
91 | }
92 | }
93 | }
94 | }
95 | }
96 | }""" % (
97 | board_id,
98 | wrapped_params,
99 | )
100 | return query
101 |
102 |
103 | def get_board_items_pagination_query(cursor: str, limit: int) -> str:
104 |
105 | query = """{
106 | complexity {
107 | query
108 | after
109 | }
110 | next_items_page(limit: %s, cursor: "%s") {
111 | cursor
112 | items {
113 | id
114 | name
115 | group {
116 | id
117 | title
118 | }
119 | column_values {
120 | ... on MirrorValue {
121 | display_value
122 | }
123 | ... on BoardRelationValue {
124 | display_value
125 | }
126 | ... on DependencyValue {
127 | display_value
128 | }
129 | value
130 | text
131 | type
132 | column {
133 | id
134 | title
135 | }
136 | }
137 | subitems {
138 | name
139 | id
140 | group {
141 | id
142 | title
143 | }
144 | column_values {
145 | ... on MirrorValue {
146 | display_value
147 | }
148 | ... on DependencyValue {
149 | display_value
150 | }
151 | ... on BoardRelationValue {
152 | display_value
153 | }
154 | text
155 | type
156 | column {
157 | id
158 | title
159 | }
160 | }
161 | }
162 | }
163 | }
164 | }""" % (
165 | limit,
166 | cursor,
167 | )
168 | return query
169 |
170 |
171 | # ITEM RESOURCE QUERIES
172 | def create_item_query(board_id, group_id, item_name, column_values, create_labels_if_missing):
173 | # Monday does not allow passing through non-JSON null values here,
174 | # so if you choose not to specify column values, need to set column_values to empty object.
175 | column_values = column_values or {}
176 |
177 | query = """mutation
178 | {
179 | create_item (
180 | board_id: %s,
181 | group_id: "%s",
182 | item_name: "%s",
183 | column_values: %s,
184 | create_labels_if_missing: %s
185 | ) {
186 | id
187 | }
188 | }""" % (
189 | board_id,
190 | group_id,
191 | item_name,
192 | monday_json_stringify(column_values),
193 | str(create_labels_if_missing).lower(),
194 | )
195 |
196 | return query
197 |
198 |
199 | def create_subitem_query(parent_item_id, subitem_name, column_values, create_labels_if_missing):
200 | column_values = column_values or {}
201 |
202 | return """mutation
203 | {
204 | create_subitem (
205 | parent_item_id: %s,
206 | item_name: "%s",
207 | column_values: %s,
208 | create_labels_if_missing: %s
209 | ) {
210 | id,
211 | name,
212 | column_values {
213 | id,
214 | text
215 | },
216 | board {
217 | id,
218 | name
219 | }
220 | }
221 | }""" % (
222 | parent_item_id,
223 | subitem_name,
224 | monday_json_stringify(column_values),
225 | str(create_labels_if_missing).lower(),
226 | )
227 |
228 |
229 | def get_item_query(board_id, column_id, value, limit, cursor=None):
230 | columns = [{"column_id": str(column_id), "column_values": [str(value)]}] if not cursor else None
231 |
232 | raw_params = locals().items()
233 | items_page_params = gather_params(raw_params, excluded_params=["column_id", "value"])
234 |
235 | query = (
236 | """query
237 | {
238 | items_page_by_column_values (%s) {
239 | cursor
240 | items {
241 | id
242 | name
243 | updates {
244 | id
245 | body
246 | }
247 | group {
248 | id
249 | title
250 | }
251 | column_values {
252 | id
253 | text
254 | value
255 | }
256 | }
257 | }
258 | }"""
259 | % items_page_params
260 | )
261 |
262 | return query
263 |
264 |
265 | def get_item_by_id_query(ids):
266 | query = """{
267 | complexity {
268 | query
269 | after
270 | }
271 | items(ids: %s){
272 | id
273 | name
274 | state
275 | group {
276 | id
277 | title
278 | }
279 | column_values {
280 | ... on MirrorValue {
281 | display_value
282 | }
283 | ... on BoardRelationValue {
284 | display_value
285 | }
286 | ... on DependencyValue {
287 | display_value
288 | }
289 | value
290 | text
291 | type
292 | column {
293 | id
294 | title
295 | }
296 | }
297 | subitems {
298 | name
299 | id
300 | parent_item {
301 | id
302 | }
303 | group {
304 | id
305 | title
306 | }
307 | column_values {
308 | ... on MirrorValue {
309 | display_value
310 | }
311 | ... on DependencyValue {
312 | display_value
313 | }
314 | ... on BoardRelationValue {
315 | display_value
316 | }
317 | text
318 | type
319 | column {
320 | id
321 | title
322 | }
323 | }
324 | }
325 | }
326 | }""" % (
327 | ids
328 | )
329 |
330 | return query
331 |
332 |
333 | def change_column_value_query(board_id, item_id, column_id, value):
334 | query = """mutation
335 | {
336 | change_column_value(
337 | board_id: %s,
338 | item_id: %s,
339 | column_id: "%s",
340 | value: %s
341 | ) {
342 | id
343 | name
344 | column_values {
345 | id
346 | text
347 | value
348 | }
349 | }
350 | }""" % (
351 | board_id,
352 | item_id,
353 | column_id,
354 | monday_json_stringify(value),
355 | )
356 |
357 | return query
358 |
359 |
360 | def change_simple_column_value_query(board_id, item_id, column_id, value):
361 | query = """mutation
362 | {
363 | change_simple_column_value (
364 | board_id: %s,
365 | item_id: %s,
366 | column_id: "%s",
367 | value: "%s"
368 | ) {
369 | id
370 | }
371 | }""" % (
372 | board_id,
373 | item_id,
374 | column_id,
375 | value,
376 | )
377 |
378 | return query
379 |
380 |
381 | def move_item_to_group_query(item_id, group_id):
382 | query = """
383 | mutation
384 | {
385 | move_item_to_group (item_id: %s, group_id: "%s")
386 | {
387 | id
388 | }
389 | }""" % (
390 | item_id,
391 | group_id,
392 | )
393 | return query
394 |
395 |
396 | def archive_item_query(item_id):
397 | query = (
398 | """
399 | mutation
400 | {
401 | archive_item (item_id: %s)
402 | {
403 | id
404 | }
405 | }"""
406 | % item_id
407 | )
408 | return query
409 |
410 |
411 | def delete_item_query(item_id):
412 | query = (
413 | """
414 | mutation
415 | {
416 | delete_item (item_id: %s)
417 | {
418 | id
419 | }
420 | }"""
421 | % item_id
422 | )
423 | return query
424 |
425 |
426 | def get_columns_by_board_query(board_id):
427 | return (
428 | """query
429 | {
430 | boards(ids: %s) {
431 | id
432 | name
433 | groups {
434 | id
435 | title
436 | }
437 | columns {
438 | title
439 | id
440 | type
441 | settings_str
442 | }
443 | }
444 | }"""
445 | % board_id
446 | )
447 |
448 |
449 | def update_multiple_column_values_query(board_id, item_id, column_values, create_labels_if_missing=False):
450 | query = """mutation
451 | {
452 | change_multiple_column_values (
453 | board_id: %s,
454 | item_id: %s,
455 | column_values: %s,
456 | create_labels_if_missing: %s
457 | ) {
458 | id
459 | name
460 | column_values {
461 | id
462 | text
463 | }
464 | }
465 | }""" % (
466 | board_id,
467 | item_id,
468 | monday_json_stringify(column_values),
469 | str(create_labels_if_missing).lower(),
470 | )
471 |
472 | return query
473 |
474 |
475 | # UPDATE RESOURCE QUERIES
476 | def create_update_query(item_id, update_value):
477 | query = """mutation
478 | {
479 | create_update(
480 | item_id: %s,
481 | body: %s
482 | ) {
483 | id
484 | }
485 | }""" % (
486 | item_id,
487 | json.dumps(update_value),
488 | )
489 |
490 | return query
491 |
492 |
493 | def delete_update_query(item_id):
494 | query = (
495 | """mutation {
496 | delete_update (id: %s) {
497 | id
498 | }
499 | }"""
500 | % item_id
501 | )
502 |
503 | return query
504 |
505 |
506 | def get_updates_for_item_query(item_id, limit: int):
507 | query = """query{
508 | items(ids: %s){
509 | updates (limit: %s) {
510 | id,
511 | body,
512 | created_at,
513 | updated_at,
514 | creator {
515 | id,
516 | name,
517 | email
518 | },
519 | assets {
520 | id,
521 | name,
522 | url,
523 | file_extension,
524 | file_size
525 | },
526 | replies {
527 | id,
528 | body,
529 | creator{
530 | id,
531 | name,
532 | email
533 | },
534 | created_at,
535 | updated_at
536 | }
537 | }
538 | }
539 | }""" % (
540 | item_id,
541 | limit,
542 | )
543 |
544 | return query
545 |
546 |
547 | def get_updates_for_board(board_id, limit: int, page=1):
548 | query = """query
549 | {
550 | boards(ids: %s) {
551 | updates(limit: %s, page: %s) {
552 | id,
553 | text_body,
554 | item_id,
555 | updated_at,
556 | created_at,
557 | creator {
558 | name,
559 | id
560 | }
561 | }
562 | }
563 | }""" % (
564 | board_id,
565 | limit,
566 | page,
567 | )
568 |
569 | return query
570 |
571 |
572 | def get_update_query(limit, page=1):
573 | query = """query
574 | {
575 | updates (
576 | limit: %s,
577 | page: %s
578 | ) {
579 | id,
580 | body
581 | }
582 | }""" % (
583 | limit,
584 | page,
585 | )
586 |
587 | return query
588 |
589 |
590 | def get_boards_query(
591 | ids: List[int],
592 | limit: int,
593 | page: int = 1,
594 | board_kind: BoardKind = None,
595 | state: BoardState = None,
596 | order_by: BoardsOrderBy = None,
597 | ):
598 | parameters = locals().items()
599 | query_params = []
600 | for k, v in parameters:
601 | if v is not None:
602 | value = v
603 | if isinstance(v, Enum):
604 | value = v.value
605 | query_params.append("%s: %s" % (k, value))
606 | joined_params = f"({', '.join(query_params)})" if query_params else ""
607 |
608 | query = (
609 | """query
610 | {
611 | boards %s {
612 | id
613 | name
614 | permissions
615 | tags {
616 | id
617 | name
618 | }
619 | groups {
620 | id
621 | title
622 | }
623 | columns {
624 | id
625 | title
626 | type
627 | }
628 | }
629 | }"""
630 | % joined_params
631 | )
632 |
633 | return query
634 |
635 |
636 | def get_board_by_id_query(board_id: Union[int, str]):
637 | return (
638 | """query
639 | {
640 | boards (ids: %s) {
641 | id
642 | name
643 | permissions
644 | tags {
645 | id
646 | name
647 | }
648 | groups {
649 | id
650 | title
651 | }
652 | columns {
653 | id
654 | title
655 | type
656 | settings_str
657 | }
658 | }
659 | }"""
660 | % board_id
661 | )
662 |
663 |
664 | def get_items_by_group_query(board_id: Union[int, str], group_id: str, limit: int, cursor: Optional[str] = None):
665 | raw_params = locals().items()
666 | items_page_params = gather_params(raw_params, excluded_params=["board_id", "group_id"])
667 | wrapped_params = f"({items_page_params})" if items_page_params else ""
668 |
669 | query = """query
670 | {
671 | boards(ids: %s) {
672 | groups(ids: "%s") {
673 | id
674 | title
675 | items_page %s {
676 | cursor
677 | items {
678 | id
679 | name
680 | }
681 | }
682 | }
683 | }
684 | }""" % (
685 | board_id,
686 | group_id,
687 | wrapped_params,
688 | )
689 | return query
690 |
691 |
692 | def get_complexity_query():
693 | query = """
694 | query
695 | {
696 | complexity {
697 | after,
698 | reset_in_x_seconds
699 | }
700 | }"""
701 |
702 | return query
703 |
704 |
705 | def get_activity_logs_query(
706 | board_id: Union[int, str],
707 | limit: int,
708 | page: Optional[int] = 1,
709 | from_date: Optional[str] = None,
710 | to_date: Optional[str] = None,
711 | ):
712 | raw_params = locals().items()
713 | activity_logs_params = gather_params(raw_params, excluded_params=["board_id", "from_date", "to_date"])
714 |
715 | # Monday API excepts "from" and "to" and the function parameters couldn't be named that way because of Python's reserved words
716 | if from_date:
717 | activity_logs_params += f', from: "{from_date}"'
718 | if to_date:
719 | activity_logs_params += f', to: "{to_date}"'
720 |
721 | wrapped_params = f"({activity_logs_params})" if activity_logs_params else ""
722 |
723 | query = """{
724 | complexity {
725 | query
726 | after
727 | }
728 | boards(ids: %s) {
729 | activity_logs %s {
730 | id
731 | account_id
732 | created_at
733 | data
734 | entity
735 | event
736 | user_id
737 | }
738 | }
739 | }""" % (
740 | board_id,
741 | wrapped_params,
742 | )
743 |
744 | return query
745 |
--------------------------------------------------------------------------------
/src/monday_sdk/types/__init__.py:
--------------------------------------------------------------------------------
1 | from .api_response_types import (
2 | MondayApiResponse,
3 | Data,
4 | Complexity,
5 | Board,
6 | ItemsPage,
7 | Item,
8 | Column,
9 | ColumnValue,
10 | Group,
11 | Update,
12 | ActivityLog,
13 | User,
14 | )
15 | from .monday_enums import BoardKind, BoardState, BoardsOrderBy, Operator
16 | from .client_settings import MondayClientSettings
17 |
--------------------------------------------------------------------------------
/src/monday_sdk/types/api_response_types.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass, field
2 | from typing import Optional, List
3 |
4 |
5 | @dataclass
6 | class Column:
7 | id: Optional[str] = field(default=None)
8 | title: Optional[str] = field(default=None)
9 |
10 |
11 | @dataclass
12 | class ColumnValue:
13 | value: Optional[str] = field(default=None)
14 | text: Optional[str] = field(default=None)
15 | type: Optional[str] = field(default=None)
16 | column: Optional[Column] = field(default=None)
17 |
18 |
19 | @dataclass
20 | class Group:
21 | id: Optional[str] = field(default=None)
22 | title: Optional[str] = field(default=None)
23 |
24 |
25 | @dataclass
26 | class Item:
27 | id: Optional[str] = field(default=None)
28 | state: Optional[str] = field(default=None)
29 | name: Optional[str] = field(default=None)
30 | updated_at: Optional[str] = field(default=None)
31 | group: Optional[Group] = field(default=None)
32 | subitems: Optional[List["Item"]] = field(default_factory=list)
33 | parent_item: Optional["Item"] = field(default=None) # only relevant for subitems
34 | column_values: Optional[List[ColumnValue]] = field(default_factory=list)
35 |
36 |
37 | @dataclass
38 | class CreatedItem:
39 | id: Optional[str] = field(default=None)
40 |
41 |
42 | @dataclass
43 | class User:
44 | name: Optional[str] = field(default=None)
45 | id: Optional[str] = field(default=None)
46 |
47 |
48 | @dataclass
49 | class Update:
50 | id: Optional[str] = field(default=None)
51 | text_body: Optional[str] = field(default=None)
52 | item_id: Optional[str] = field(default=None)
53 | created_at: Optional[str] = field(default=None)
54 | updated_at: Optional[str] = field(default=None)
55 | creator: Optional[User] = field(default=None)
56 |
57 |
58 | @dataclass
59 | class ItemsPage:
60 | cursor: Optional[str] = field(default=None)
61 | items: Optional[List[Item]] = field(default_factory=list)
62 |
63 |
64 | @dataclass
65 | class Complexity:
66 | query: Optional[int] = field(default=None)
67 | after: Optional[int] = field(default=None)
68 |
69 |
70 | @dataclass
71 | class ActivityLog:
72 | id: str
73 | account_id: str
74 | created_at: str
75 | data: str
76 | entity: str
77 | event: str
78 | user_id: str
79 |
80 |
81 | @dataclass
82 | class Board:
83 | name: Optional[str] = field(default=None)
84 | items_page: Optional[ItemsPage] = field(default=None)
85 | updates: Optional[List[Update]] = field(default_factory=list)
86 | activity_logs: Optional[List[ActivityLog]] = field(default_factory=list)
87 |
88 |
89 | @dataclass
90 | class Data:
91 | complexity: Optional[Complexity] = field(default=None)
92 | boards: Optional[List[Board]] = field(default_factory=list)
93 | items: Optional[List[Item]] = field(default_factory=list)
94 | next_items_page: Optional[ItemsPage] = field(default=None)
95 | items_page_by_column_values: Optional[ItemsPage] = field(default=None)
96 | create_item: Optional[CreatedItem] = field(default=None)
97 |
98 |
99 | @dataclass
100 | class MondayApiResponse:
101 | data: Data
102 | account_id: int
--------------------------------------------------------------------------------
/src/monday_sdk/types/client_settings.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | from typing import Dict
3 |
4 |
5 | @dataclass
6 | class MondayClientSettings:
7 | token: str
8 | headers: Dict[str, str]
9 | debug_mode: bool
10 | max_retry_attempts: int
11 |
--------------------------------------------------------------------------------
/src/monday_sdk/types/monday_enums.py:
--------------------------------------------------------------------------------
1 | from enum import Enum
2 |
3 |
4 | class ColumnType(Enum):
5 | AUTO_NUMBER = "auto_number" # Number items according to their order in the group/board
6 | CHECKBOX = "checkbox" # Check off items and see what's done at a glance
7 | COUNTRY = "country" # Choose a country
8 | COLOR_PICKER = "color_picker" # Manage a design system using a color palette
9 | CREATION_LOG = "creation_log" # Add the item's creator and creation date automatically
10 | DATE = "date" # Add dates like deadlines to ensure you never drop the ball
11 | DEPENDENCY = "dependency" # Set up dependencies between items in the board
12 | DROPDOWN = "dropdown" # Create a dropdown list of options
13 | EMAIL = "email" # Email team members and clients directly from your board
14 | FILE = "file" # Add files & docs to your item
15 | HOUR = "hour" # Add times to manage and schedule tasks, shifts and more
16 | ITEM_ID = "item_id" # Show a unique ID for each item
17 | LAST_UPDATED = "last_updated" # Add the person that last updated the item and the date
18 | LINK = "link" # Simply hyperlink to any website
19 | LOCATION = "location" # Place multiple locations on a geographic map
20 | LONG_TEXT = "long_text" # Add large amounts of text without changing column width
21 | NUMBERS = "numbers" # Add revenue, costs, time estimations and more
22 | PEOPLE = "people" # Assign people to improve team work
23 | PHONE = "phone" # Call your contacts directly from monday.com
24 | PROGRESS = "progress" # Show progress by combining status columns in a battery
25 | RATING = "rating" # Rate or rank anything visually
26 | STATUS = "status" # Get an instant overview of where things stand
27 | TEAM = "team" # Assign a full team to an item
28 | TAGS = "tags" # Add tags to categorize items across multiple boards
29 | TEXT = "text" # Add textual information e.g. addresses, names or keywords
30 | TIMELINE = "timeline" # Visually see a breakdown of your team's workload by time
31 | TIME_TRACKING = "time_tracking" # Easily track time spent on each item, group, and board
32 | VOTE = "vote" # Vote on an item e.g. pick a new feature or a favorite lunch place
33 | WEEK = "week" # Select the week on which each item should be completed
34 | WORLD_CLOCK = "world_clock" # Keep track of the time anywhere in the world
35 |
36 |
37 | class Operator(Enum):
38 | GREATER_THAN_OR_EQUALS = "greater_than_or_equals"
39 | LESS_THAN_OR_EQUALS = "lower_than_or_equal"
40 |
41 |
42 | class BoardKind(Enum):
43 | """Board kinds"""
44 |
45 | PUBLIC = "public"
46 | PRIVATE = "private"
47 | SHARE = "share"
48 |
49 |
50 | class BoardState(Enum):
51 | """Board available states"""
52 |
53 | ALL = "all"
54 | ACTIVE = "active"
55 | ARCHIVED = "archived"
56 | DELETED = "deleted"
57 |
58 |
59 | class BoardsOrderBy(Enum):
60 | """Order to retrieve boards"""
61 |
62 | CREATED_AT = "created_at"
63 | USED_AT = "used_at"
64 |
--------------------------------------------------------------------------------
/src/monday_sdk/utils.py:
--------------------------------------------------------------------------------
1 | import json
2 | import time
3 |
4 | from enum import Enum
5 | from typing import List, Iterable, Tuple, Any, Optional, Union
6 | from .types import Item, Operator
7 | from .constants import MAX_COMPLEXITY
8 |
9 |
10 | def extract_column_value_by_title(item: Item, column_name: str) -> Union[str, bool]:
11 | item_column_values = item.column_values
12 | for column_value in item_column_values:
13 | if column_value.column.title == column_name:
14 | if column_value.type == "checkbox":
15 | # Parse the JSON string into a dictionary
16 | value_dict = json.loads(column_value.value)
17 | return value_dict["checked"]
18 | else:
19 | return column_value.text
20 | return ""
21 |
22 |
23 | def extract_column_value_by_id(item: Item, column_id: str) -> Union[str, bool]:
24 | item_column_values = item.column_values
25 | for column_value in item_column_values:
26 | if column_value.column.id == column_id:
27 | if column_value.type == "checkbox":
28 | # Parse the JSON string into a dictionary
29 | value_dict = json.loads(column_value.value)
30 | return value_dict["checked"]
31 | else:
32 | return column_value.text
33 | return ""
34 |
35 |
36 | def extract_column_id_by_title(item: Item, column_name: str) -> Union[str, None]:
37 | item_column_values = item.column_values
38 | for column_value in item_column_values:
39 | if column_value.column.title == column_name:
40 | return column_value.column.id
41 | return None
42 |
43 |
44 | def monday_json_stringify(value):
45 | # Monday's required format: "{\"label\":\"Done\"}"
46 | return json.dumps(json.dumps(value))
47 |
48 |
49 | def gather_params(params: Iterable[Tuple[str, Any]], excluded_params: Optional[List[str]] = None, exclude_none: bool = True) -> str:
50 | valid_params = [
51 | f"{param}: {format_param_value(value)}"
52 | for param, value in params
53 | if not ((excluded_params and param in excluded_params) or (value is None and exclude_none))
54 | ]
55 | return ", ".join(valid_params)
56 |
57 |
58 | def format_param_value(value: Any) -> str:
59 | if value is None:
60 | return "null"
61 | if isinstance(value, str):
62 | return f'"{value}"'
63 | if isinstance(value, Enum):
64 | return str(value.value)
65 | if isinstance(value, dict):
66 | return f"{{{gather_params(value.items(), exclude_none=False)}}}"
67 | if isinstance(value, list):
68 | return f"[{', '.join(format_param_value(val) for val in value)}]"
69 | return str(value)
70 |
71 |
72 | def sleep_according_to_complexity(query_complexity) -> None:
73 | """
74 | monday complexity is limited per minute, so the sleep is according to the "cost" of the current query
75 | """
76 | sleep_time = (query_complexity / MAX_COMPLEXITY) * 60
77 | time.sleep(sleep_time)
78 |
79 |
80 | def construct_updated_at_query_params(start_date: str, end_date: str) -> dict:
81 | query_params = {"rules": []}
82 | if start_date:
83 | query_params["rules"].append(
84 | {
85 | "column_id": "__last_updated__",
86 | "compare_value": ["EXACT", start_date],
87 | "operator": Operator.GREATER_THAN_OR_EQUALS,
88 | "compare_attribute": "UPDATED_AT",
89 | }
90 | )
91 | if end_date:
92 | query_params["rules"].append(
93 | {
94 | "column_id": "__last_updated__",
95 | "compare_value": ["EXACT", end_date],
96 | "operator": Operator.LESS_THAN_OR_EQUALS,
97 | "compare_attribute": "UPDATED_AT",
98 | }
99 | )
100 | return query_params
101 |
--------------------------------------------------------------------------------