merge-api / merge-python-client Goto Github PK
View Code? Open in Web Editor NEWThe Python SDK for accessing various Merge Unified APIs
License: Other
The Python SDK for accessing various Merge Unified APIs
License: Other
It would be amazing if the items composing these constants could be sorted to make it easier / faster to find the one I need.
Thanks
chunks = self.client.filestorage.files.download_retrieve(id=file.id)
By using the code above, I'm able to download around ~6 files and would run into 502 error. Is this expected or is there a workaround? I need to download the file in file storages in byte in order to process it in the backend.
Hi, I'm getting pydantic.error_wrappers.ValidationError
when using the code below. It used to work before so I'm guessing that there has been some change in serverside json response, which is not reflected in merge-python-client
. Can you guys take a look at it and let me know? Thanks
Code
from merge.client import Merge
client = Merge(api_key=MERGE_API_KEY, account_token=ACCOUNT_TOKEN)
res = client.filestorage.files.list(page_size=100, cursor=None)
print(res)
Error
Traceback (most recent call last):
File "/Users/hwuiwon/Desktop/test.py", line 5, in <module>
res = client.filestorage.files.list(page_size=100, cursor=None)
File "/usr/local/anaconda3/envs/prism/lib/python3.10/site-packages/merge/resources/filestorage/resources/files/client.py", line 106, in list
return pydantic.parse_obj_as(PaginatedFileList, _response.json()) # type: ignore
File "pydantic/tools.py", line 38, in pydantic.tools.parse_obj_as
File "pydantic/main.py", line 341, in pydantic.main.BaseModel.__init__
pydantic.error_wrappers.ValidationError: 6 validation errors for ParsingModel[PaginatedFileList]
__root__ -> results -> 0 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 1 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 2 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 3 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 4 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 5 -> permissions -> 0
str type expected (type=type_error.str)
Would it be possible to update httpx in the pyproject.toml to use ^0.24.0
? or >= 0.23.3
if your library is compatible with higher versions
We'd like to try out 0.2.0
of your library, but the version of httpx
is too old to be compatible with our app, which is using the latest version 0.24.1
Hi Merge team, Lucas from Materia here. Could you update your library to use pydantic 2.0? Currently it is using the 2.0 library but the 1.0 classes. This actually makes it hard to work with in our system, we need to do a good bit of extra work to convert the objects into things that play properly with our system which is built entirely around 2.0. Pydantic has released great 1.0 -> 2.0 migration scripts (and seems like Fern should just be able to regenerate it all according to pydantic 2.0 spec?). Would be appreciated!
Hi, we're trying to integrate with merge API. I don't see any asyncio support which is a problem for event loop based programs. I noticed some httpx usage with AsyncClient. Any guidance would be helpful or an update to the README :)
When creating a link token we have the option to specify a specific integration. It would be nice if this value was typed so that we don't have to guess at the underlying values that the api accepts.
diff --git a/example.py b/example.py
index 31ef560..3fd57e9 100644
--- a/example.py
+++ b/example.py
@@ -1,9 +1,9 @@
-from merge.resources.crm.types import CategoriesEnum
+from merge.resources.crm.types import CategoriesEnum, IntegrationsEnum
merge_client.crm.link_token.create(
end_user_email_address="[email protected]",
end_user_organization_name="An org",
end_user_origin_id="some-euoid",
categories=[CategoriesEnum.CRM],
- integration="salesforce",
+ integration=IntegrationsEnum.Salesforce,
)
Question isn't specifically about this client but not sure where to ask dev questions about merge.dev.
I want to include a linkedin url for a candidate and I'm not seeing which values are allowed for url_type
. If I look at data I see 'LinkedIn' as a raw_value but the value is MERGE_NONSTANDARD_VALUE. Assume that means I can read and not set it.
is there any specific need to lock pydantic to <2.5.0
? version 2.5.2
has already been released and it clashes with other packages. would seem more reasonable to me, locking pydantic to <3.0.0
.
here a copy of the poetry error message:
Because no versions of mergepythonclient match >1.0.5,<2.0.0
and mergepythonclient (1.0.5) depends on pydantic (>=1.9.2,<2.5.0), mergepythonclient (>=1.0.5,<2.0.0) requires pydantic (>=1.9.2,<2.5.0).
So, because conversa depends on both pydantic (^2.5.2) and mergepythonclient (^1.0.5), version solving failed.```
The example in the docs:
from merge import Merge
merge = Merge(
# defaults to os.environ.get("MERGE_API_KEY")
api_key=api_key,
)
account_detail = merge.hris.account_details.retrieve()
doesn't show an account token. I passed in my api key and got this error:
AuthenticationError: Error code: 401 - {'detail': 'Account Token must be passed in as an X-Account-Token header.'}
As a library it's a bit challenging for the pydantic dependency to be pinned to v1. Would it be possible to support both versions?
Here is one approach I see another library took in order to support both versions since all v1 functionality is still available in v2 (just under a different namespace):
Hi we're utilizing a helper class to parse over the paginated lists as so:
from typing import Any, Callable, ParamSpec, TypeVar
from merge.client import Merge
from merge.core import ApiError
from merge.resources.hris import Employee, Group
_T = ParamSpec("_T")
_R = TypeVar("_R", covariant=True)
class Middleware:
def __init__(self, merge_client: Merge):
self.merge_client = merge_client
def _executor(self, func: Callable[_T, _R], *args: _T.args, **kwargs: _T.kwargs) -> list[Any]:
"""Exhausts a paginated API until all data is retrieved"""
data = []
cursor = ""
while cursor is not None:
try:
next_page = func(*args, **kwargs, cursor=cursor) # type: ignore[arg-type]
for result in next_page.results: # type: ignore[attr-defined]
data.append(result)
cursor = next_page.next # type: ignore[attr-defined]
except Exception as e:
logger.error(
f"Error while fetching users from Merge. Breaking pagination early: {e}"
)
break
return data
def get_users(self) -> list[Employee]:
return self._executor(self.merge_client.hris.employees.list)
Noticing the mypy type ignores, we're having issues with the ParamSpec variable and the return type generic TypeVar covariant. It would be great if all return list return types could subclass from a base Pydantic model as all paginated pydantic models shown are like:
class PaginatedEmployeeList(pydantic.BaseModel):
next: typing.Optional[str]
previous: typing.Optional[str]
results: typing.Optional[typing.List[Employee]]
where the only difference is the "Employee" model which could easily be made a template variable. This way, we can make the return type the base pagination list Pydantic model instead of a generic TypeVar and remove the type ignores.
Thanks:)
Hi team, there seems to be an issue with the latest release. It looks like the PermissionRequest
in filestorage does not have all of the existing fields defined on the model, and also has extra = pydantic_v1.Extra.forbid
. This is making all calls to files.list fail.
mergepythonclient 1.0.10
pydantic 2.7.4
python: 3.12.4
In [3]: res = await self.client.filestorage.files.list()
---------------------------------------------------------------------------
ValidationError Traceback (most recent call last)
Cell In[3], line 1
----> 1 res = await self.client.filestorage.files.list()
File ~/Repos/materia-services/.venv/lib/python3.12/site-packages/merge/resources/filestorage/resources/files/client.py:456, in AsyncFilesClient.list(self, created_after, created_before, cursor, drive_id, expand, folder_id, include_deleted_data, include_remote_data, mime_type, modified_after, modified_before, name, page_size, remote_id, request_options)
434 _response = await self._client_wrapper.httpx_client.request(
435 "filestorage/v1/files",
436 method="GET",
(...)
453 request_options=request_options,
454 )
455 if 200 <= _response.status_code < 300:
--> 456 return pydantic_v1.parse_obj_as(PaginatedFileList, _response.json()) # type: ignore
457 try:
458 _response_json = _response.json()
File ~/Repos/materia-services/.venv/lib/python3.12/site-packages/pydantic/v1/tools.py:38, in parse_obj_as(type_, obj, type_name)
36 def parse_obj_as(type_: Type[T], obj: Any, *, type_name: Optional[NameFactory] = None) -> T:
37 model_type = _get_parsing_type(type_, type_name=type_name) # type: ignore[arg-type]
---> 38 return model_type(__root__=obj).__root__
File ~/Repos/materia-services/.venv/lib/python3.12/site-packages/pydantic/v1/main.py:341, in BaseModel.__init__(__pydantic_self__, **data)
339 values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data)
340 if validation_error:
--> 341 raise validation_error
342 try:
343 object_setattr(__pydantic_self__, '__dict__', values)
ValidationError: 420 validation errors for ParsingModel[PaginatedFileList]
__root__ -> results -> 0 -> permissions
str type expected (type=type_error.str)
__root__ -> results -> 0 -> permissions
value is not a valid dict (type=type_error.dict)
__root__ -> results -> 0 -> permissions -> 0
str type expected (type=type_error.str)
__root__ -> results -> 0 -> permissions -> 0 -> created_at
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 0 -> id
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 0 -> modified_at
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 1
str type expected (type=type_error.str)
__root__ -> results -> 0 -> permissions -> 1 -> created_at
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 1 -> id
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 1 -> modified_at
extra fields not permitted (type=value_error.extra)
__root__ -> results -> 0 -> permissions -> 2
str type expected (type=type_error.str)
__root__ -> results -> 0 -> permissions -> 2 -> created_at
extra fields not permitted (type=value_error.extra)
....
The download
function of file_storage
Files
class returns and casts to None when it should return the downloaded bytes of the file. Code here.
If you change that to:
return self._get(
f"/filestorage/v1/files/{id}/download",
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
#cast_to=NoneType,
cast_to=httpx.Response,
)
You can get the Httpx.Response
object and access response.content
to get the actual data. Otherwise None is returned and you can't download anything.
This code will return an error below.
Code
from merge.client import Merge
client = Merge(api_key=MERGE_API_KEY, account_token=MY_ACCOUNT_TOKEN)
res = client.filestorage.users.list(is_me=True)
print(res)
Error
raise ApiError(status_code=_response.status_code, body=_response_json)
merge.core.api_error.ApiError: status_code: 400, body: {'non_field_errors': ['Provided filters are invalid.']}
I believe that this code should work or am I missing something here?
mergepythonclient = "^0.2.2"
When using the Expand enum it sends to the URL the written name of the object
OpportunitiesListRequestExpand.STAGE
instead of just "stage"
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.