labii-sdk 1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,16 @@
1
+ An SDK for the Labii ELN & LIMS platform (https://www.labii.com)
2
+ that provides interaction with the Labii API.
3
+ Copyright (C) 2022 Labii Inc.
4
+
5
+ This program is free software: you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License as published by
7
+ the Free Software Foundation, either version 3 of the License, or
8
+ (at your option) any later version.
9
+
10
+ This program is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ GNU General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.1
2
+ Name: Labii-sdk
3
+ Version: 1.0
4
+ Summary: An SDK for the Labii ELN & LIMS platform (https://www.labii.com) that provides interaction with the Labii API.
5
+ Home-page: https://gitlab.com/labii-dev/labii-sdk
6
+ Author: Labii Inc.
7
+ Author-email: developer@labii.com
8
+ License: GNU GPLv3
9
+ Project-URL: Bug Tracker, https://gitlab.com/labii-dev/labii-sdk/-/issues?sort=created_date&state=opened
10
+ Platform: UNKNOWN
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # Labii SDK
16
+
17
+ An SDK for the [Labii ELN & LIMS platform](https://www.labii.com) that provides interaction with the [Labii API](https://docs.labii.com/api/overview).
18
+
19
+ ![Labii screenshot](https://www.labii.com/media/screenshots/labii-richtext-editor.webp)
20
+
21
+ This package contains two modules, __api_client__ and __sdk__.
22
+ * Python API clients help you perform Labii API calls, such as authentication, get, patch, post, and delete. Learn more at [APICLIENT.md](./docs/APICLIENT.md)
23
+ * SDK is the toolkit with prebuilt Labii components that developers use to interact with Labii APIs. Learn more at [SDK.md](./docs/SDK.md)
24
+
25
+ # Install
26
+ ```
27
+ pip install labii-sdk
28
+ ```
29
+
30
+ # About Labii
31
+ [Labii](https://www.labii.com) facilitates research and development by providing a user-friendly, customizable Electronic Lab Notebook (ELN) and Laboratory Information Management System (LIMS) to document, manage, and interpret data. Labii ELN & LIMS can be configured for any type of data, and the functions can easily be enhanced and expanded by stand-alone applications. We address the unique needs of each of our customers and are the trusted provider of hundreds of biotech companies and academic labs.
32
+
33
+
@@ -0,0 +1,18 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ Labii_SDK.egg-info/PKG-INFO
6
+ Labii_SDK.egg-info/SOURCES.txt
7
+ Labii_SDK.egg-info/dependency_links.txt
8
+ Labii_SDK.egg-info/requires.txt
9
+ Labii_SDK.egg-info/top_level.txt
10
+ Labii_sdk.egg-info/PKG-INFO
11
+ Labii_sdk.egg-info/SOURCES.txt
12
+ Labii_sdk.egg-info/dependency_links.txt
13
+ Labii_sdk.egg-info/requires.txt
14
+ Labii_sdk.egg-info/top_level.txt
15
+ labii_sdk/__init__.py
16
+ labii_sdk/api_client.py
17
+ labii_sdk/files_watch.py
18
+ labii_sdk/sdk.py
@@ -0,0 +1,2 @@
1
+ requests>=2.27.1
2
+ boto3>=1.20.38
@@ -0,0 +1 @@
1
+ labii_sdk
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.1
2
+ Name: Labii sdk
3
+ Version: 1.0
4
+ Summary: An SDK for the Labii ELN & LIMS platform (https://www.labii.com) that provides interaction with the Labii API.
5
+ Home-page: https://gitlab.com/labii-dev/labii-sdk
6
+ Author: Labii Inc.
7
+ Author-email: developer@labii.com
8
+ License: GNU GPLv3
9
+ Project-URL: Bug Tracker, https://gitlab.com/labii-dev/labii-sdk/-/issues?sort=created_date&state=opened
10
+ Platform: UNKNOWN
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+
15
+ # Labii SDK
16
+
17
+ An SDK for the [Labii ELN & LIMS platform](https://www.labii.com) that provides interaction with the [Labii API](https://docs.labii.com/api/overview).
18
+
19
+ ![Labii screenshot](https://www.labii.com/media/screenshots/labii-richtext-editor.webp)
20
+
21
+ This package contains two modules, __api_client__ and __sdk__.
22
+ * Python API clients help you perform Labii API calls, such as authentication, get, patch, post, and delete. Learn more at [APICLIENT.md](./docs/APICLIENT.md)
23
+ * SDK is the toolkit with prebuilt Labii components that developers use to interact with Labii APIs. Learn more at [SDK.md](./docs/SDK.md)
24
+
25
+ # Install
26
+ ```
27
+ pip install labii-sdk
28
+ ```
29
+
30
+ # About Labii
31
+ [Labii](https://www.labii.com) facilitates research and development by providing a user-friendly, customizable Electronic Lab Notebook (ELN) and Laboratory Information Management System (LIMS) to document, manage, and interpret data. Labii ELN & LIMS can be configured for any type of data, and the functions can easily be enhanced and expanded by stand-alone applications. We address the unique needs of each of our customers and are the trusted provider of hundreds of biotech companies and academic labs.
32
+
33
+
@@ -0,0 +1,17 @@
1
+ # Labii SDK
2
+
3
+ An SDK for the [Labii ELN & LIMS platform](https://www.labii.com) that provides interaction with the [Labii API](https://docs.labii.com/api/overview).
4
+
5
+ ![Labii screenshot](https://www.labii.com/media/screenshots/labii-richtext-editor.webp)
6
+
7
+ This package contains two modules, __api_client__ and __sdk__.
8
+ * Python API clients help you perform Labii API calls, such as authentication, get, patch, post, and delete. Learn more at [APICLIENT.md](./docs/APICLIENT.md)
9
+ * SDK is the toolkit with prebuilt Labii components that developers use to interact with Labii APIs. Learn more at [SDK.md](./docs/SDK.md)
10
+
11
+ # Install
12
+ ```
13
+ pip install labii-sdk
14
+ ```
15
+
16
+ # About Labii
17
+ [Labii](https://www.labii.com) facilitates research and development by providing a user-friendly, customizable Electronic Lab Notebook (ELN) and Laboratory Information Management System (LIMS) to document, manage, and interpret data. Labii ELN & LIMS can be configured for any type of data, and the functions can easily be enhanced and expanded by stand-alone applications. We address the unique needs of each of our customers and are the trusted provider of hundreds of biotech companies and academic labs.
File without changes
@@ -0,0 +1,314 @@
1
+ """ api related functions """
2
+ import requests
3
+ import json
4
+ import getpass
5
+
6
+ class APIObject:
7
+ base_url = "https://www.labii.dev"
8
+ email = None
9
+ password = None
10
+ token = None
11
+ organization__sid = None
12
+ user = None
13
+
14
+ def __init__(self, base_url="https://www.labii.dev", email=None, password=None, token=None, organization__sid=None, user=None):
15
+ self.base_url = base_url
16
+ self.email = email
17
+ self.password = password
18
+ self.token = token
19
+ self.organization__sid = organization__sid
20
+ self.user = user
21
+
22
+ ######
23
+ # url
24
+ def get_list_url(self, app, object, level="organization", sid=None, serializer='list', query=""):
25
+ """ return the list url """
26
+ if sid is None:
27
+ sid = self.organization__sid
28
+ return f"/{app}/{object}/list/{level}/{sid}/{serializer}/{'' if query == '' else '?'}{query}"
29
+
30
+ def get_detail_url(self, app, object, sid, query=""):
31
+ """ return the detail url """
32
+ return f"/{app}/{object}/detail/{sid}/{'' if query == '' else '?'}{query}"
33
+
34
+ ######
35
+ # auth
36
+ def get_headers(self, is_authorized=True):
37
+ """Return necessary headers for API functions
38
+
39
+ Returns:
40
+ dict: header objects
41
+ """
42
+ headers = {
43
+ "X-Forwarded-For": "batch",
44
+ "Content-Type": "application/json"
45
+ }
46
+ if is_authorized and self.token != None:
47
+ headers["Authorization"] = f"Token {self.token}"
48
+ return headers
49
+
50
+ def login(self, email="", password=""):
51
+ """Get authentication token based on user input
52
+ - self.login()
53
+ - login with saved email/password
54
+ - get email/password if not saved
55
+ - self.login(email=xxx, password=xxx): login with new email/password
56
+
57
+ Args:
58
+ email (str): email to use to login
59
+ password (str): password to use to login
60
+ """
61
+ # get email or password
62
+ if email != "" and password != "":
63
+ self.email = email
64
+ self.password = password
65
+ else:
66
+ if self.email is None or self.password is None:
67
+ self.email = input("Email: ")
68
+ self.password = getpass.getpass('Password: ')
69
+ # get token
70
+ data = {
71
+ "username": self.email,
72
+ "password": self.password
73
+ }
74
+ response = self.post("/accounts/auth/", data, is_authorized=False)
75
+ if "token" in response:
76
+ self.token = response["token"]
77
+ elif "secret" in response:# two step authentication
78
+ # use email to verify
79
+ self.post("/accounts/mfa/code/", {"option": "email", "secret": j["secret"]}, is_authorized=False)
80
+ code = input("MFA enabled for the account. Please check your email and provide authentication code: ")
81
+ data = self.post("/accounts/mfa/verify/", {"code": code, "secret": response["secret"]}, is_authorized=False)
82
+ if "token" in data:
83
+ self.token = data["token"]
84
+ self.user = data
85
+ else:
86
+ raise RuntimeError(data)
87
+ else:
88
+ raise RuntimeError(response)
89
+
90
+ def check_token(self):
91
+ """Check if the exist token is valid. If not valid, it will genereate a new token
92
+ Labii token expires after 30 minutes of no activity. If your program take more than 30 minutes to run. Use this function to get a new token.
93
+ """
94
+ data = self.get("/accounts/checktoken/")
95
+ if data["detail"] != "Valid token.":
96
+ self.login()
97
+
98
+ ######
99
+ # api post
100
+ def post(self, url, data, is_authorized=True):
101
+ """A function to do POST for labii api
102
+
103
+ Args:
104
+ url (str): API URL
105
+ data (dict): data to POST, see API documentation (https://docs.labii.com/api/overview) for the format
106
+ is_authorized (bool): should use the authrized token
107
+
108
+ Returns:
109
+ dict: created object
110
+ """
111
+ response = requests.post(url=f"{self.base_url}{url}", data=json.dumps(data, separators=(',',':')), headers=self.get_headers(is_authorized))
112
+ try:
113
+ data = json.loads(response.text)
114
+ return data
115
+ except:
116
+ raise RuntimeError(response)
117
+
118
+ def patch(self, url, data, is_authorized=True):
119
+ """A function to do PATCH for labii api
120
+
121
+ Args:
122
+ url (str): API URL
123
+ data (dict): data to update, see API documentation (https://docs.labii.com/api/overview) for the format
124
+ is_authorized (bool): should use the authrized token
125
+
126
+ Returns:
127
+ dict: return of the api
128
+ """
129
+ response = requests.patch(url=f"{self.base_url}{url}", data=json.dumps(data, separators=(',',':')), headers=self.get_headers(is_authorized))
130
+ try:
131
+ data = json.loads(response.text)
132
+ return data
133
+ except:
134
+ raise RuntimeError(response)
135
+
136
+ def get(self, url, all=False, is_authorized=True):
137
+ """A function to do GET for labii api
138
+
139
+ Args:
140
+ url (str): API URL
141
+ all (bool): should download all
142
+ is_authorized (bool): should use the authrized token
143
+
144
+ Returns:
145
+ dict: result of the url
146
+ """
147
+ if all is False:
148
+ response = requests.get(url=f"{self.base_url}{url}", headers=self.get_headers(is_authorized))
149
+ try:
150
+ data = json.loads(response.text)
151
+ return data
152
+ except:
153
+ raise RuntimeError(response)
154
+ else:
155
+ page = 1
156
+ page_size = 10
157
+ # update url
158
+ if "page" in url or "page_size" in url:
159
+ query = url.split("?")[1].split("&")
160
+ query_updated = []
161
+ for item in query:
162
+ if not "page" in item and not "page_size" in item:
163
+ query_updated.append(item)
164
+ if len(query_updated) > 0:
165
+ url = f"{url.split('?')[0]}?{'&'.join(query_updated)}"
166
+ else:
167
+ url = url.split("?")[0]
168
+ if "?" in url:
169
+ url_with_page = f"{url}&page={page}&page_size={page_size}"
170
+ else:
171
+ url_with_page = f"{url}?page={page}&page_size={page_size}"
172
+ response = requests.get(url=f"{self.base_url}{url_with_page}", headers=self.get_headers(is_authorized))
173
+ data = json.loads(response.text)
174
+ count = data["count"]
175
+ results = data["results"]
176
+ print(f"Total records: {count}")
177
+ print("Downloading page 1...")
178
+ while len(results) < count:
179
+ page += 1
180
+ print(f"Downloading page {page}...")
181
+ if "?" in url:
182
+ url_with_page = f"{url}&page={page}&page_size={page_size}"
183
+ else:
184
+ url_with_page = f"{url}?page={page}&page_size={page_size}"
185
+ response = requests.get(url=f"{self.base_url}{url_with_page}", headers=self.get_headers(is_authorized))
186
+ results = results + json.loads(response.text)["results"]
187
+ data["results"] = data
188
+ return data
189
+
190
+ def delete(self, url, is_authorized=True):
191
+ """A function to do delete for labii api
192
+
193
+ Args:
194
+ url (str): API URL
195
+ is_authorized (bool): should use the authrized token
196
+
197
+ Returns:
198
+ dict: result of the url
199
+ """
200
+ response = requests.delete(url=f"{self.base_url}{url}", headers=self.get_headers(is_authorized))
201
+ if response.status_code != 200:
202
+ raise RuntimeError(response.text)
203
+
204
+ #
205
+ # def labii_update_row(token, organization__sid, table__sid, data, base_url=base_url):
206
+ # """Get or update a row.
207
+ # - if 'sid' is provided, the row will be updated
208
+ # - if 'sid' is not provied, a new row will be created
209
+ #
210
+ # Args:
211
+ # token (str): the authentification token
212
+ # organization__sid (str): the sid of your organization
213
+ # table__sid (str): the sid of the table
214
+ # data (dict): other attributions, in json format
215
+ # base_url (str): the base_url
216
+ #
217
+ # Returns:
218
+ # dict: the row object.
219
+ # """
220
+ # if "sid" in data:# update the row
221
+ # sid = str(data["sid"])
222
+ # url = f"/tables/row/detail/{sid}/"
223
+ # data.pop("sid")
224
+ # return labii_patch(url, data, token, base_url)
225
+ # elif "name" in data:
226
+ # rows = labii_get(f"/tables/row/list/organization/{organization__sid}/name/?table__sid={table__sid}&name={data['name']}", token, base_url)
227
+ # if rows["count"] == 0: # if not exists
228
+ # url = f"/tables/row/list/organization/{organization__sid}/detail/?table__sid={table__sid}"
229
+ # return labii_post(url, data, token, base_url)
230
+ # else:
231
+ # url = f"/tables/row/detail/{rows['results'][0]['sid']}/"
232
+ # return labii_patch(url, data, token, base_url)
233
+ # else:
234
+ # raise ValueError("Error: sid or name is required!")
235
+ #
236
+ # def labii_update_cell(token, organization__sid, row__sid, column__sid, data, base_url=base_url):
237
+ # """update the data for a cell, create the cell if not exists
238
+ #
239
+ # Args:
240
+ # token (str): authentication token
241
+ # organization__sid (str): the sid of the organization
242
+ # row__sid (str): the sid of the row
243
+ # column__sid (str): the sid of the column
244
+ # data (dict): data for the cell, example: {"data": "xxx"}
245
+ # base_url (str): the base_url
246
+ #
247
+ # Returns:
248
+ # dict: the cell data
249
+ # """
250
+ # cells = labii_get(f"/tables/cell/list/organization/{organization__sid}/name/?row__sid={row__sid}&column__sid={column__sid}", token, base_url)
251
+ # if cells["count"] == 0: # if not exists
252
+ # url = f"/tables/cell/list/organization/{organization__sid}/detail/?row__sid={row__sid}&column__sid={column__sid}"
253
+ # labii_post(url, data, token, base_url)
254
+ # else:
255
+ # url = f"/tables/cell/detail/{cells['results'][0]['sid']}/"
256
+ # labii_patch(url, data, token, base_url)
257
+ #
258
+ # def labii_update_section(token, organization__sid, row__sid, widget__sid, data, base_url=base_url):
259
+ # """update the data for a section, create the section if not exists
260
+ #
261
+ # Args:
262
+ # token (str): authentication token
263
+ # organization__sid (str): sid of a organization
264
+ # row__sid (str): the sid of a row
265
+ # widget__sid (str): the sid of widget
266
+ # data (dict): the section data
267
+ # base_url (str): the base_url
268
+ #
269
+ # Returns:
270
+ # dict: the section object
271
+ # """
272
+ # sections = labii_get(f"/tables/section/list/organization/{organization__sid}/name/?row__sid={row__sid}&name={data['name'].replace('&', ' ')}", token, base_url)
273
+ # if "count" in sections:
274
+ # if sections["count"] == 0: # if not exists
275
+ # url = f"/tables/section/list/organization/{organization__sid}/detail/?row__sid={row__sid}&widget__sid={widget__sid}"
276
+ # labii_post(url, data, token, base_url)
277
+ # else:
278
+ # url = f"/tables/section/detail/{sections['results'][0]['sid']}/"
279
+ # labii_patch(url, data, token, base_url)
280
+ # else:
281
+ # raise ValueError("Error in updating section")
282
+ #
283
+ # def labii_json_list_to_tsv(results):
284
+ # """conver the list result in json format into tsv format
285
+ #
286
+ # Args:
287
+ # results (array): the results from response
288
+ #
289
+ # Returns:
290
+ # string: tsv data
291
+ # """
292
+ # if len(results) > 0:
293
+ # should_collect_title = True
294
+ # titles = [] # collect list of titles
295
+ # data = [] # the data of all
296
+ # for r in results:
297
+ # d = [] # the data of one row
298
+ # for field in r:
299
+ # if field == "column_set":
300
+ # for f in r["column_set"]:
301
+ # d.append(str(f["data"]).replace("\n","").replace("\r",""))
302
+ # if should_collect_title:
303
+ # titles.append(f["column"]["name"])
304
+ # elif field != "section_set":
305
+ # d.append(str(r[field]).replace("\n","").replace("\r",""))
306
+ # if should_collect_title:
307
+ # titles.append(field)
308
+ # if should_collect_title:
309
+ # data.append("\t".join(titles))
310
+ # should_collect_title = False
311
+ # data.append("\t".join(d))
312
+ # return "\n".join(data)
313
+ # else:
314
+ # return "";
@@ -0,0 +1,27 @@
1
+ from api import *
2
+ import os, json
3
+
4
+ def files_watch(configuration_file="configuration.json"):
5
+ """
6
+ """
7
+ # collect configuration
8
+ configuration = collect_configuration(configuration_file)
9
+
10
+
11
+ def collect_configuration(configuration_file):
12
+ """
13
+ """
14
+ # read configuration.json
15
+ configuration = {}
16
+ if os.path.isfile(configuration_file):
17
+ with open(configuration_file) as json_file:
18
+ configuration = json.load(json_file)
19
+ # collect email and password
20
+ for i in ["email", "password"]:
21
+ if not i in configuration:
22
+ v = input(f"{i.title()}: ")
23
+ configuration[i] = v
24
+ # update the configuration
25
+ with open(configuration_file, 'w') as outfile:
26
+ json.dump(d, outfile)
27
+ return configuration
@@ -0,0 +1,90 @@
1
+ """ python api functions """
2
+ #from api import *
3
+ import requests
4
+ import json
5
+ import getpass
6
+ from labii_sdk.api_client import APIObject
7
+
8
+ class LabiiObject:
9
+ api = None
10
+
11
+ def __init__(self,
12
+ organization__sid,
13
+ base_url="https://www.labii.dev",
14
+ email=None,
15
+ password=None,
16
+ token=None,
17
+ user=None
18
+ ):
19
+ self.api = APIObject(base_url=base_url, email=email, password=password, token=token, organization__sid=organization__sid, user=user)
20
+ self.Organization = self.APIResource(self, "organizations", "organization")
21
+ self.People = self.APIResource(self, "organizations", "personnel")
22
+ self.Team = self.APIResource(self, "organizations", "team")
23
+ self.SAML = self.APIResource(self, "organizations", "saml")
24
+ self.Project = self.APIResource(self, "projects", "project")
25
+ self.ProjectMember = self.APIResource(self, "projects", "member")
26
+ self.Table = self.APIResource(self, "tables", "table")
27
+ self.Column = self.APIResource(self, "tables", "column")
28
+ self.Section = self.APIResource(self, "tables", "section")
29
+ self.Row = self.APIResource(self, "tables", "row")
30
+ self.Cell = self.APIResource(self, "tables", "cell")
31
+ self.Version = self.APIResource(self, "tables", "version")
32
+ self.Visitor = self.APIResource(self, "tables", "visitor")
33
+
34
+ class APIResource:
35
+ """ abstract class """
36
+ app = None
37
+ object = None
38
+
39
+ class Meta:
40
+ abstract = True
41
+
42
+ def __init__(self, instance, app, object):
43
+ """
44
+ - instance, the outer instance
45
+ """
46
+ self.instance = instance
47
+ self.app = app
48
+ self.object = object
49
+
50
+ def create(self, data={}):
51
+ """ Create a object """
52
+ return self.instance.api.post(self.instance.api.get_list_url(self.app, self.object, serializer="detail"))
53
+
54
+ def retrieve(self, sid):
55
+ """ Return an object """
56
+ return self.instance.api.get(self.instance.api.get_detail_url(self.app, self.object, sid=sid))
57
+
58
+ def list(self, page=1, page_size=10, all=False, level="organization", serializer="list", query=""):
59
+ """ Return list of objects """
60
+ if all is True:
61
+ url = self.instance.api.get_list_url(
62
+ self.app,
63
+ self.object,
64
+ sid=self.instance.api.organization__sid,
65
+ level=level,
66
+ serializer=serializer,
67
+ query=query
68
+ )
69
+ return self.instance.api.get(url, True)
70
+ else:
71
+ url = self.instance.api.get_list_url(
72
+ self.app,
73
+ self.object,
74
+ sid=self.instance.api.organization__sid,
75
+ level=level,
76
+ serializer=serializer,
77
+ query=f"page={page}&page_size={page_size}{'' if query == '' else '&'}{query}"
78
+ )
79
+ return self.instance.api.get(url)
80
+
81
+ def modify(self, sid, data={}):
82
+ """ Change one object """
83
+ if self.can_patch:
84
+ return self.instance.api.patch(self.instance.api.get_detail_url(self.app, self.object, sid=sid), data)
85
+ else:
86
+ print("Method not supported!")
87
+
88
+ def delete(self, sid):
89
+ """ Delete a object """
90
+ self.instance.api.delete(self.instance.api.get_detail_url(self.app, self.object, sid=sid))
@@ -0,0 +1,6 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=42",
4
+ "wheel"
5
+ ]
6
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ import setuptools
2
+
3
+ long_description = open("README.md").read()
4
+ required = ["requests>=2.27.1", "boto3>=1.20.38"] # Comma seperated dependent libraries name
5
+
6
+ setuptools.setup(
7
+ name="Labii sdk",
8
+ version="1.0", # eg:1.0.0
9
+ author="Labii Inc.",
10
+ author_email="developer@labii.com",
11
+ license="GNU GPLv3",
12
+ description="An SDK for the Labii ELN & LIMS platform (https://www.labii.com) that provides interaction with the Labii API.",
13
+ long_description=long_description,
14
+ long_description_content_type="text/markdown",
15
+ url="https://gitlab.com/labii-dev/labii-sdk",
16
+ packages = ['labii_sdk'],
17
+ # project_urls is optional
18
+ project_urls={
19
+ "Bug Tracker": "https://gitlab.com/labii-dev/labii-sdk/-/issues?sort=created_date&state=opened",
20
+ },
21
+ key_words="Labii, Labii ELN & LIMS, ELN, LIMS, SDK, Electronic Lab Notebook, Laboratory Information Management System",
22
+ install_requires=required,
23
+ #packages=setuptools.find_packages(where="labii"),
24
+ python_requires=">=3.8",
25
+ )