Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Support For Apache JSON and Binary Data #139

Merged
merged 60 commits into from
Oct 26, 2020
Merged

Conversation

JonnoFTW
Copy link
Contributor

@JonnoFTW JonnoFTW commented Oct 1, 2020

#13 Added support for apache json, so that apache thrift server/clients can talk to thriftpy2 server/clients.
#136 Added support for binary data fields, I'm not sure what ramifications this would have on python2.

@codecov
Copy link

codecov bot commented Oct 1, 2020

Codecov Report

Merging #139 into master will increase coverage by 0.91%.
The diff coverage is 88.49%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #139      +/-   ##
==========================================
+ Coverage   83.14%   84.05%   +0.91%     
==========================================
  Files          43       44       +1     
  Lines        3921     4133     +212     
==========================================
+ Hits         3260     3474     +214     
+ Misses        661      659       -2     
Impacted Files Coverage Δ
thriftpy2/contrib/aio/rpc.py 84.44% <ø> (ø)
thriftpy2/contrib/aio/protocol/binary.py 55.73% <21.42%> (-2.07%) ⬇️
thriftpy2/contrib/aio/protocol/compact.py 60.17% <50.00%> (-0.82%) ⬇️
thriftpy2/protocol/binary.py 89.25% <76.47%> (-1.06%) ⬇️
thriftpy2/protocol/compact.py 84.39% <89.47%> (+2.13%) ⬆️
thriftpy2/protocol/apache_json.py 97.51% <97.51%> (ø)
thriftpy2/protocol/__init__.py 87.50% <100.00%> (+0.83%) ⬆️
thriftpy2/protocol/json.py 96.63% <100.00%> (+13.88%) ⬆️
thriftpy2/thrift.py 88.88% <100.00%> (ø)
... and 3 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 17a66b5...89c4cb1. Read the comment docs.

@ethe
Copy link
Member

ethe commented Oct 9, 2020

Some CI has failed, could you please fix it?

@JonnoFTW
Copy link
Contributor Author

JonnoFTW commented Oct 9, 2020

@ethe don't merge yet, I have some problems in my own codebase where TApacheJSONProtocol does not work with THttpClient

@ethe ethe changed the title Added Support For Apache JSON and Binary Data [WIP] Added Support For Apache JSON and Binary Data Oct 12, 2020
@JonnoFTW JonnoFTW changed the title [WIP] Added Support For Apache JSON and Binary Data Added Support For Apache JSON and Binary Data Oct 13, 2020
@JonnoFTW
Copy link
Contributor Author

@ethe feel free to check it out now

thriftpy2/__init__.py Outdated Show resolved Hide resolved
thriftpy2/protocol/__init__.py Outdated Show resolved Hide resolved
thriftpy2/thrift.py Show resolved Hide resolved
This reverts commit 18dd0fb
@aisk
Copy link
Member

aisk commented Oct 22, 2020

Hi @JonnoFTW I approved this PR, thanks!

@JonnoFTW
Copy link
Contributor Author

@ethe are you happy to merge now? All tests pass along with those in my interoperability repo.

@ethe ethe merged commit 1e61072 into Thriftpy:master Oct 26, 2020
@ethe
Copy link
Member

ethe commented Oct 26, 2020

Merged, thank you for your patience and contribution.

unmade added a commit to unmade/thrift-pyi that referenced this pull request Oct 28, 2020
Added TType.Binary support

Relevant to this pull request to add binary support to thriftpy2: Thriftpy/thriftpy2#139
@dmulter
Copy link

dmulter commented Jan 20, 2021

I've been using Thriftpy2 with a private Thrift server for a long time now, and this latest addition has broken things for me. Sorry I can't share the Thrift files, but here's the error when making an RPC call:

.virtualenv/lib/python3.8/site-packages/thriftpy2/thrift.py:219: in _req
    return self._recv(_api)
.virtualenv/lib/python3.8/site-packages/thriftpy2/thrift.py:231: in _recv
    fname, mtype, rseqid = self._iprot.read_message_begin()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

>   ???
E   cybin.ProtocolError: No protocol version header

thriftpy2/protocol/cybin/cybin.pyx:454: ProtocolError

@JonnoFTW
Copy link
Contributor Author

@dmulter are you able to provide a test case to recreate this? Also did you install from pypi or from git?

@dmulter
Copy link

dmulter commented Jan 20, 2021

Normally I would provide a test case, but I'm not sure I can in this case. I'm not responsible for the server, it's complex, and under NDA. It uses TCompactProtocol and TMemoryBuffer transport. I will see what I can do. It just started failing when I did the update.

I install your package from PyPI. I do a pretty standard make_client and the first Thrift function I call fails with this error. I've seen this error is typical when the transport is wrong somehow. I'm sure you hear this all the time, but nothing else has changed and I've produced numerous production releases of my client for many years.

@JonnoFTW
Copy link
Contributor Author

Can you try installing from git?

@dmulter
Copy link

dmulter commented Jan 20, 2021

Fails the same way.

@JonnoFTW
Copy link
Contributor Author

@dmulter can you please give a minimum working example or just tell me exactly what combination of client/server protocols and transports you are using on each end. I'll add it to the tests and see if I can recreate the problem.

@ethe
Copy link
Member

ethe commented Jan 21, 2021

@dmulter could you please provide a sample IDL file? we need to reproduce it.

@JonnoFTW
Copy link
Contributor Author

JonnoFTW commented Jan 25, 2021

@dmulter I'm unable to replicate the problem you are having, here's my test case (it still passes if I use TCompactProtocol):

Spec:

struct BinarySpec {
    1: map<string, binary> str2bin,
    2: map<string, string> str2str,
}

service BinaryService {
    BinarySpec run(1: BinarySpec b_spec);
}
import time
from thriftpy2 import load
from thriftpy2.transport.memory import TCyMemoryBuffer
from thriftpy2.protocol import cybin
from thriftpy2.thrift import TType
from thriftpy2.rpc import make_client, make_server
from multiprocessing import Process

def test_tcompact_memory_buffer():
    spec = load("binary_test.thrift")

    factory = cybin.TCyBinaryProtocolFactory()
    obj = spec.BinarySpec(
        str2bin={"key": b"Binary Value"},
        str2str={"key": "String Value"}
    )

    class Handler:
        def run(self, b_spec):
            print("\nServer received:")
            print(b_spec)
            return b_spec

    def run_server():
        server = make_server(
            service=spec.BinaryService,
            handler=Handler(),
            proto_factory=factory,
        )
        server.serve()

    proc = Process(target=run_server)
    try:
        proc.start()
        time.sleep(0.5)
        client = make_client(spec.BinaryService, proto_factory=factory)
        res = client.run(obj)
        assert res
        print("Server sent:")
        print(res)
    finally:
        proc.kill()
    time.sleep(0.2)

Gives the output:

Server received:
BinarySpec(str2bin={'key': b'Binary Value'}, str2str={'key': 'String Value'})
Server sent:
BinarySpec(str2bin={'key': b'Binary Value'}, str2str={'key': 'String Value'})

If you could modify this test so that it fails in the same way your code does, that would be very useful in fixing the issue.

@dmulter
Copy link

dmulter commented Jan 25, 2021

Some additional status:

  • I thought I had installed from a Git clone, but just tried as part of my testing and I get the following error during build: clang: error: no such file or directory: 'thriftpy2/transport/cybase.c'
  • I verified that the test you created above works fine. I had to change things a bit to avoid multiprocessing errors that are also included in the next bullet item code.
  • I created a version that makes the specific service call and it also works fine. See code at the end.
  • Seems clear to me that the issue requires the actual server implementation since local tests are not exposing the problem. My strategy now is trying to identify why the Thriftpy2-0.4.13 release broke when talking to the server. I'm trying to build a local version that I can use for debugging the returned bytes to help identify what the code is choking on. I first have to solve the first item above. Note that I can't give access to the real server since it is not ours and is both private and protected via a layer of complex authentication that must be performed first. I experimented with various other transports and was not able to find a way to make the test pass.

xxx.thrift:

enum ApiVersion
{
    kApiVersion1 = 1;
    kApiVersion2;
    kApiVersion3;
}
const ApiVersion kServerApiVersion_Current = ApiVersion.kApiVersion2;

service PrivateService
{
    void openSession
        (
        1: string sessionId,
        2: ApiVersion clientVersion
        )
}

test_xxx.py:

import time
import sys
from thriftpy2 import load
from thriftpy2.rpc import make_client, make_server
from multiprocessing import Process

class Handler:
    def openSession(self, sessionId, clientVersion):
        print(f"\nServer received: sessionId={sessionId} clientVersion={clientVersion}")
        sys.stdout.flush()

def run_server():
    print("Starting server...")
    server = make_server(
        service=spec.PrivateService,
        handler=Handler(),
    )
    server.serve()

spec = load("xxx.thrift")

def test_private_service():
    proc = Process(target=run_server)
    try:
        proc.start()
        time.sleep(0.5)

        print("Calling openSession...")
        client = make_client(service=spec.PrivateService)
        session_id = "xxx"
        client.openSession(session_id, spec.kServerApiVersion_Current)
        assert False, "tests actually worked" # so we can see print output
    finally:
        proc.kill()
    time.sleep(0.2)

@dmulter
Copy link

dmulter commented Jan 25, 2021

Installed Cython and built from source. Currently experimenting with what's returned from the server. Not sure if it helps, but the size value it expects for the protocol version header has a value of 3c68746d. Trying to get the full server response...

@dmulter
Copy link

dmulter commented Jan 25, 2021

Found the problem and it was not this PR, but a different change on 0.4.13. The protocol error was because HTML for an error page was being returned. The breaking change was due to an inserted path separator after port as I'm passing a parsed URL as follows:

    from urllib.parse import urlparse

    url = urlparse(full_url)
    client = make_client(
        service=spec.TestService,
        scheme=url.scheme,
        host=url.netloc,
        path=url.path,
        port="443"
    )

And the change was faf1055

@JonnoFTW
Copy link
Contributor Author

@ethe considering that the @dmulter 's issue didn't come from this pull request, can we merge it back in? The slash problem can be fixed separately.

@ethe
Copy link
Member

ethe commented Jan 27, 2021

@JonnoFTW yeah your merge does not break compact protocol, however, there is another problem, see #156

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants