Repository: doccano/doccano-client (language: python)

Issue:
Integrating Our Version of doccano-client?
Feature description
---------
Hey y'all,

First of all I just wanna say: Great job on this client!

Our company actually has been working on and maintaining a `doccano-client` as well around the time progress on this client started. It's currently internal, but we could easily open source it--hardly any of it is opinionated to our company's use cases.

The problem is, we don't have the hands at the moment to consistently maintain the package and keep it up to date with all the updates Doccano receives. It looks like this package has been able to, however, thanks to the open source visibility!

An idea: What are ya'll's thoughts on uniting the two? We can move our code to a fork of this repo, and create a major PR that integrates it right into this package if you like the results!

We believe our version of the client has a lot of features that this one can greatly benefit from:

1. Versioning lines up with Doccano release tags, so it is always clear when it will be compatible with which release of Doccano's API.
2. All interactions with the API are pythonic, rather than based on raw json. Example below.
3. VERY heavily unit tested.
4. Black, Isort, Flake8, Pydocstyle, Pylint, and Mypy compliant

```python
project_controllers = client.projects.all()

my_project_name_controller = next(controller for controller in project_controllers if controller.project.name == "My Project Name")

my_project_name_controller.labels.update([Label(...), Label(...)])

test_example = models.Example(text="This is an example text")
my_project_name_controller.examples.create(test_example)

```

Would you be interested in this style? There are a few more layers so may take a bit more code to maintain in some ways, but it should cut a lot of tech debt, making it easier to scale. If you're interested, we can port our code to a fork of this repo so you can take a look.

Thank you for your time!


Discussion / hints:
@Hironsan Hey thank you so much for the quick response on this and the merge!

But now I'm curious for how you recommend we move forward with contributing to this. Can you answer these questions for me?

1. The primary client functionality is updated to compatibility with Doccano v1.6.x, correct? The new stuff we just merged is compatible with Doccano v.1.5.x. I set the new versioning in the `setup.py` to match our internal version, at 1.5.1. What do you think the version should be set to--should it match the new beta code or the main code interface? Or should we align them first, then set the version? Personally, I'm veering towards keeping it in the 1.5.x range until `doccano-client` is released at least once in that range (maybe set it to 1.5.5 at release to match the last stable Doccano release). Then we can switch to 1.6.x versioning here as well.
2. Should we add pytest to CI checking? My team can integrate that if it makes sense.
3. Once we have pytest verified as passing, when can we expect a release on this? If my team can start using this package once we confirm it's reasonably stable, we can stop using our internal package entirely and start contributing to this one directly instead.

Thanks!
Your welcome. Thank you for your great work!

1. > The primary client functionality is updated to compatibility with Doccano v1.6.x, correct?

Yes.

I think we can replace the current code with the beta code after supporting v1.6.x compatibility. The new code is great.
In this case, the version of `doccano-client` will be v2.0.0 (the current version is v1.0.3) because there are incompatible API changes.
- https://semver.org/

2. Yes!
3. Choices are:
  - v1.1.0(the current code and the beta code). In this case, I can release the package soon.
  - v2.0.0(only the beta code with v1.6.x compatibility)

>I think we can replace the current code with the beta code after supporting v1.6.x compatibility. The new code is great.

Oh wow that'd be a major stride and extremely humbling :)

2. Awesome! We'll get some cycles on this very soon. Probably in the next week or two--we're also gonna try to make the connection to the beta. Afterwards I think we'll be good to release this.
3. Re:the semver stuff from earlier too, yeah I hear what you're saying regarding fundamental API changes. The goal overall though with the versioning is that the Major and Minor version should have parity with Doccano release numbers, right?

What would you suggest would be the cleanest strategy to both follow good semver practices and also try to align with Doccano releases eventually too?

One idea would be to have them independent until Doccano is at 2.0.0, THEN bring this to 2.0.0 and leave only the beta code. That might be a while though.

Another option may be to have the next few versions of doccano-client bump minor version one-by-one (so 1.1.0, 1.2.0...1.6.0, until it matches Doccano's 1.6, then bring it back to Patch version bumping after).

Any other ideas?
I do not think it is necessary to align the doccano and doccano-client versions. This is because increasing the version of doccano does not necessarily cause changes in the API(e.g. patch version update by some bug fixes). In my opinion, the doccano and doccano-client versions should be independent. It is hard to align them.

I have checked several project versions:

- [TensorFlow](https://github.com/tensorflow/tensorflow) v2.8.0 vs [TFX](https://github.com/tensorflow/tfx) v1.7.1
- [spaCy](https://github.com/explosion/spaCy) v3.1.6 vs [spaCy Transformers](https://github.com/explosion/spacy-transformers) v1.1.5

> One idea would be to have them independent until Doccano is at 2.0.0, THEN bring this to 2.0.0 and leave only the beta code. That might be a while though.

Yes. You are right. It may take a long time.

Best
Gotcha. What do you think is another way we can clearly define API compatibility, in that case?

For example, should we add it to the changelog instead, and just rely on that + the comment block in the setup.py?

I am content with them being independent as long as we are defining that clearly. So that, for example, someone using Doccano 1.5.x knows not to upgrade their `doccano-client` version to a certain new version if it's optimized for a new API structure.
Writing the compatibility to the documentation and comment is good.
In another way, how about letting the user specify the version? For example:

```python
client = build_client(version="1.5", endpoint="http://")
client.login()
```

This is an analogy of [google-api-python-client](https://developers.google.com/docs/api/quickstart/python).

However, it might be troublesome to specify the version.
Yeah that'd probably be more challenging. Would involve supporting multiple versions of the Doccano API at once in possibly quite a lot of long-term permutations.

Anyway, thanks for the recommendations! We're gonna make one or two more PRs (the pytest CI inclusion, a bit more intuitive tie-in of the beta stuff into the existing documentation/module importing) and then I think we should be good for a release!

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1c52cf7..d0ca492 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -30,3 +30,6 @@ jobs:
       run: |
         find . -name "*.py" | xargs pipenv run darglint
       working-directory: ./doccano_api_client
+    - name: Test with Pytest
+      run: |
+        pipenv run pytest
diff --git a/Pipfile b/Pipfile
index ac88056..3e59b1e 100644
--- a/Pipfile
+++ b/Pipfile
@@ -10,12 +10,12 @@ mypy = "*"
 darglint = "*"
 black = "*"
 responses = "*"
-dataclasses-json = "*"
 types-requests = "*"
 pytest = "*"
 
 [packages]
 requests = "*"
+dataclasses-json = "*"
 
 [requires]
 python_version = "3.8"
diff --git a/Pipfile.lock b/Pipfile.lock
index 120ea24..14a81df 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "40646fcd17193c9406cc5536d7f2270fbefcb56cfa231a6751002059c9f5775e"
+            "sha256": "da2429534d4ba08ae1971be8d6bd7ebb3d7f932cddc7ddf4e905b1e23a791d23"
         },
         "pipfile-spec": 6,
         "requires": {
@@ -31,6 +31,14 @@
             "markers": "python_version >= '3'",
             "version": "==2.0.12"
         },
+        "dataclasses-json": {
+            "hashes": [
+                "sha256:bc285b5f892094c3a53d558858a88553dd6a61a11ab1a8128a0e554385dcc5dd",
+                "sha256:c2c11bc8214fbf709ffc369d11446ff6945254a7f09128154a7620613d8fda90"
+            ],
+            "index": "pypi",
+            "version": "==0.5.7"
+        },
         "idna": {
             "hashes": [
                 "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff",
@@ -39,6 +47,44 @@
             "markers": "python_version >= '3'",
             "version": "==3.3"
         },
+        "marshmallow": {
+            "hashes": [
+                "sha256:2aaaab4f01ef4f5a011a21319af9fce17ab13bf28a026d1252adab0e035648d5",
+                "sha256:ff79885ed43b579782f48c251d262e062bce49c65c52412458769a4fb57ac30f"
+            ],
+            "markers": "python_version >= '3.7'",
+            "version": "==3.15.0"
+        },
+        "marshmallow-enum": {
+            "hashes": [
+                "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58",
+                "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"
+            ],
+            "version": "==1.5.1"
+        },
+        "mypy-extensions": {
+            "hashes": [
+                "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
+                "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
+            ],
+            "version": "==0.4.3"
+        },
+        "packaging": {
+            "hashes": [
+                "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
+                "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==21.3"
+        },
+        "pyparsing": {
+            "hashes": [
+                "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea",
+                "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==3.0.7"
+        },
         "requests": {
             "hashes": [
                 "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61",
@@ -47,6 +93,22 @@
             "index": "pypi",
             "version": "==2.27.1"
         },
+        "typing-extensions": {
+            "hashes": [
+                "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
+                "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
+            ],
+            "markers": "python_version >= '3.6'",
+            "version": "==4.1.1"
+        },
+        "typing-inspect": {
+            "hashes": [
+                "sha256:047d4097d9b17f46531bf6f014356111a1b6fb821a24fe7ac909853ca2a782aa",
+                "sha256:3cd7d4563e997719a710a3bfe7ffb544c6b72069b6812a02e9b414a8fa3aaa6b",
+                "sha256:b1f56c0783ef0f25fb064a01be6e5407e54cf4a4bf4f3ba3fe51e0bd6dcea9e5"
+            ],
+            "version": "==0.7.1"
+        },
         "urllib3": {
             "hashes": [
                 "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
@@ -67,32 +129,32 @@
         },
         "black": {
             "hashes": [
-                "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2",
-                "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71",
-                "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6",
-                "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5",
-                "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912",
-                "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866",
-                "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d",
-                "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0",
-                "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321",
-                "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8",
-                "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd",
-                "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3",
-                "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba",
-                "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0",
-                "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5",
-                "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a",
-                "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28",
-                "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c",
-                "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1",
-                "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab",
-                "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f",
-                "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61",
-                "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"
+                "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b",
+                "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176",
+                "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09",
+                "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a",
+                "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015",
+                "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79",
+                "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb",
+                "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20",
+                "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464",
+                "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968",
+                "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82",
+                "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21",
+                "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0",
+                "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265",
+                "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b",
+                "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a",
+                "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72",
+                "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce",
+                "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0",
+                "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a",
+                "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163",
+                "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad",
+                "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"
             ],
             "index": "pypi",
-            "version": "==22.1.0"
+            "version": "==22.3.0"
         },
         "certifi": {
             "hashes": [
@@ -111,11 +173,11 @@
         },
         "click": {
             "hashes": [
-                "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
-                "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
+                "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e",
+                "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"
             ],
-            "markers": "python_version >= '3.6'",
-            "version": "==8.0.4"
+            "markers": "python_version >= '3.7'",
+            "version": "==8.1.2"
         },
         "darglint": {
             "hashes": [
@@ -125,14 +187,6 @@
             "index": "pypi",
             "version": "==1.8.1"
         },
-        "dataclasses-json": {
-            "hashes": [
-                "sha256:1d7f3a284a49d350ddbabde0e7d0c5ffa34a144aaf1bcb5b9f2c87673ff0c76e",
-                "sha256:1f60be3405dee30b86ffbf6a436db8ba5efaeeb676bfda358e516a97aa7dfce4"
-            ],
-            "index": "pypi",
-            "version": "==0.5.6"
-        },
         "flake8": {
             "hashes": [
                 "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d",
@@ -164,21 +218,6 @@
             "index": "pypi",
             "version": "==5.10.1"
         },
-        "marshmallow": {
-            "hashes": [
-                "sha256:2aaaab4f01ef4f5a011a21319af9fce17ab13bf28a026d1252adab0e035648d5",
-                "sha256:ff79885ed43b579782f48c251d262e062bce49c65c52412458769a4fb57ac30f"
-            ],
-            "markers": "python_version >= '3.7'",
-            "version": "==3.15.0"
-        },
-        "marshmallow-enum": {
-            "hashes": [
-                "sha256:38e697e11f45a8e64b4a1e664000897c659b60aa57bfa18d44e226a9920b6e58",
-                "sha256:57161ab3dbfde4f57adeb12090f39592e992b9c86d206d02f6bd03ebec60f072"
-            ],
-            "version": "==1.5.1"
-        },
         "mccabe": {
             "hashes": [
                 "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
@@ -188,32 +227,32 @@
         },
         "mypy": {
             "hashes": [
-                "sha256:080097eee5393fd740f32c63f9343580aaa0fb1cda0128fd859dfcf081321c3d",
-                "sha256:0d3bcbe146247997e03bf030122000998b076b3ac6925b0b6563f46d1ce39b50",
-                "sha256:0dd441fbacf48e19dc0c5c42fafa72b8e1a0ba0a39309c1af9c84b9397d9b15a",
-                "sha256:108f3c7e14a038cf097d2444fa0155462362c6316e3ecb2d70f6dd99cd36084d",
-                "sha256:3bada0cf7b6965627954b3a128903a87cac79a79ccd83b6104912e723ef16c7b",
-                "sha256:3cf77f138efb31727ee7197bc824c9d6d7039204ed96756cc0f9ca7d8e8fc2a4",
-                "sha256:42c216a33d2bdba08098acaf5bae65b0c8196afeb535ef4b870919a788a27259",
-                "sha256:465a6ce9ca6268cadfbc27a2a94ddf0412568a6b27640ced229270be4f5d394d",
-                "sha256:6a8e1f63357851444940351e98fb3252956a15f2cabe3d698316d7a2d1f1f896",
-                "sha256:745071762f32f65e77de6df699366d707fad6c132a660d1342077cbf671ef589",
-                "sha256:818cfc51c25a5dbfd0705f3ac1919fff6971eb0c02e6f1a1f6a017a42405a7c0",
-                "sha256:8e5974583a77d630a5868eee18f85ac3093caf76e018c510aeb802b9973304ce",
-                "sha256:8eaf55fdf99242a1c8c792247c455565447353914023878beadb79600aac4a2a",
-                "sha256:98f61aad0bb54f797b17da5b82f419e6ce214de0aa7e92211ebee9e40eb04276",
-                "sha256:b2ce2788df0c066c2ff4ba7190fa84f18937527c477247e926abeb9b1168b8cc",
-                "sha256:b30d29251dff4c59b2e5a1fa1bab91ff3e117b4658cb90f76d97702b7a2ae699",
-                "sha256:bf446223b2e0e4f0a4792938e8d885e8a896834aded5f51be5c3c69566495540",
-                "sha256:cbcc691d8b507d54cb2b8521f0a2a3d4daa477f62fe77f0abba41e5febb377b7",
-                "sha256:d051ce0946521eba48e19b25f27f98e5ce4dbc91fff296de76240c46b4464df0",
-                "sha256:d61b73c01fc1de799226963f2639af831307fe1556b04b7c25e2b6c267a3bc76",
-                "sha256:eea10982b798ff0ccc3b9e7e42628f932f552c5845066970e67cd6858655d52c",
-                "sha256:f79137d012ff3227866222049af534f25354c07a0d6b9a171dba9f1d6a1fdef4",
-                "sha256:fc5ecff5a3bbfbe20091b1cad82815507f5ae9c380a3a9bf40f740c70ce30a9b"
+                "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e",
+                "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16",
+                "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2",
+                "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c",
+                "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67",
+                "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5",
+                "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b",
+                "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6",
+                "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58",
+                "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d",
+                "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17",
+                "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0",
+                "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca",
+                "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6",
+                "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322",
+                "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534",
+                "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3",
+                "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db",
+                "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904",
+                "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c",
+                "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46",
+                "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8",
+                "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"
             ],
             "index": "pypi",
-            "version": "==0.941"
+            "version": "==0.942"
         },
         "mypy-extensions": {
             "hashes": [
@@ -303,27 +342,27 @@
         },
         "responses": {
             "hashes": [
-                "sha256:3fc29c3117e14136b833a0a6d4e7f1217c6301bf08b6086db468e12f1e3290e2",
-                "sha256:53354b5de163aa2074312c71d8ebccb8bd1ab336cff7053abb75e84dc5637abe"
+                "sha256:18831bc2d72443b67664d98038374a6fa1f27eaaff4dd9a7d7613723416fea3c",
+                "sha256:644905bc4fb8a18fa37e3882b2ac05e610fe8c2f967d327eed669e314d94a541"
             ],
             "index": "pypi",
-            "version": "==0.19.0"
+            "version": "==0.20.0"
         },
         "tomli": {
             "hashes": [
                 "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
                 "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
             ],
-            "markers": "python_version >= '3.7'",
+            "markers": "python_version < '3.11'",
             "version": "==2.0.1"
         },
         "types-requests": {
             "hashes": [
-                "sha256:5d6f77f3c7565659bdb7b7bce1d33d1abb7d0b056138cac714860e13da2f19df",
-                "sha256:cf0646031dd6307113b37814f743c04f0707a3357378c2bb1326f848412f5ba9"
+                "sha256:2437a5f4d16c0c8bd7539a8126d492b7aeb41e6cda670d76b286c7f83a658d42",
+                "sha256:c8010c18b291a7efb60b1452dbe12530bc25693dd657e70c62803fcdc4bffe9b"
             ],
             "index": "pypi",
-            "version": "==2.27.13"
+            "version": "==2.27.16"
         },
         "types-urllib3": {
             "hashes": [
@@ -337,17 +376,9 @@
                 "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
                 "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
             ],
-            "markers": "python_version < '3.10'",
+            "markers": "python_version >= '3.6'",
             "version": "==4.1.1"
         },
-        "typing-inspect": {
-            "hashes": [
-                "sha256:047d4097d9b17f46531bf6f014356111a1b6fb821a24fe7ac909853ca2a782aa",
-                "sha256:3cd7d4563e997719a710a3bfe7ffb544c6b72069b6812a02e9b414a8fa3aaa6b",
-                "sha256:b1f56c0783ef0f25fb064a01be6e5407e54cf4a4bf4f3ba3fe51e0bd6dcea9e5"
-            ],
-            "version": "==0.7.1"
-        },
         "urllib3": {
             "hashes": [
                 "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14",
diff --git a/README.md b/README.md
index 75babf9..e151058 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ A simple client wrapper for the doccano API.
   - [Usage](#usage)
   - [Completion](#completion)
   - [To-Do](#to-do)
+- [Doccano API BETA Client](#doccano-api-beta-client)
 
 ## Installation
 
@@ -82,3 +83,9 @@ Endpoint Names:
 
 - investigate more secure alternatives to plaintext login
 - improve docstrings
+
+# Doccano API BETA Client
+
+We're introducing a newly revamped Doccano API Client that features more Pythonic interaction as well as more testing and documentation. It also adds more regulated compatibility with specific Doccano release versions.
+
+You can find the documentation on usage of the beta client [here](./doccano_api_client/beta/README.md).
diff --git a/doccano_api_client/beta_pythonic_client/README.md b/doccano_api_client/beta/README.md
similarity index 76%
rename from doccano_api_client/beta_pythonic_client/README.md
rename to doccano_api_client/beta/README.md
index 7c2228d..d3b7358 100644
--- a/doccano_api_client/beta_pythonic_client/README.md
+++ b/doccano_api_client/beta/README.md
@@ -1,11 +1,17 @@
+# Doccano API BETA Client
+
+A beta version of a new design for the Doccano client, featuring more Pythonic interaction, as well as thorough testing and documentation.
+
+Currently tested for compatibility against Doccano v1.5.0-1.5.5.
+
 ### Usage
 
 The client can be instatiated with a base URL referring to the target Doccano instance. Once instantiated, you can login using your Doccano username and password.
 
 ```python
-from doccano_api_client.beta_pythonic_client import Client, controllers
+from doccano_api_client.beta import DoccanoClient, controllers
 
-client = Client("your_instance_url_here")
+client = DoccanoClient("your_instance_url_here")
 client.login("my_username", "my_password")
 ```
 
@@ -36,3 +42,4 @@ pipenv run test --runintegrationtest
 
 - Upgrade to 1.6.x compatibility
 - Potentially adding Pydantic for tighter field validation
+- Add missing functionality that the primary Doccano client offers
diff --git a/doccano_api_client/beta/__init__.py b/doccano_api_client/beta/__init__.py
new file mode 100644
index 0000000..78ea114
--- /dev/null
+++ b/doccano_api_client/beta/__init__.py
@@ -0,0 +1,3 @@
+from .client import DoccanoClient
+
+__all__ = ["DoccanoClient"]
diff --git a/doccano_api_client/beta_pythonic_client/client.py b/doccano_api_client/beta/client.py
similarity index 98%
rename from doccano_api_client/beta_pythonic_client/client.py
rename to doccano_api_client/beta/client.py
index 3299952..692a864 100644
--- a/doccano_api_client/beta_pythonic_client/client.py
+++ b/doccano_api_client/beta/client.py
@@ -4,7 +4,7 @@
 from .utils.response import verbose_raise_for_status
 
 
-class Client:
+class DoccanoClient:
     """Base client for interacting with the Doccano API"""
 
     __slots__ = ["_base_url", "client_session"]
diff --git a/doccano_api_client/beta_pythonic_client/controllers/__init__.py b/doccano_api_client/beta/controllers/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/__init__.py
rename to doccano_api_client/beta/controllers/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/controllers/annotation.py b/doccano_api_client/beta/controllers/annotation.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/annotation.py
rename to doccano_api_client/beta/controllers/annotation.py
diff --git a/doccano_api_client/beta_pythonic_client/controllers/comment.py b/doccano_api_client/beta/controllers/comment.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/comment.py
rename to doccano_api_client/beta/controllers/comment.py
diff --git a/doccano_api_client/beta_pythonic_client/controllers/example.py b/doccano_api_client/beta/controllers/example.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/example.py
rename to doccano_api_client/beta/controllers/example.py
diff --git a/doccano_api_client/beta_pythonic_client/controllers/label.py b/doccano_api_client/beta/controllers/label.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/label.py
rename to doccano_api_client/beta/controllers/label.py
diff --git a/doccano_api_client/beta_pythonic_client/controllers/project.py b/doccano_api_client/beta/controllers/project.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/controllers/project.py
rename to doccano_api_client/beta/controllers/project.py
diff --git a/doccano_api_client/beta_pythonic_client/models/__init__.py b/doccano_api_client/beta/models/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/__init__.py
rename to doccano_api_client/beta/models/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/models/annotations.py b/doccano_api_client/beta/models/annotations.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/annotations.py
rename to doccano_api_client/beta/models/annotations.py
diff --git a/doccano_api_client/beta_pythonic_client/models/comments.py b/doccano_api_client/beta/models/comments.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/comments.py
rename to doccano_api_client/beta/models/comments.py
diff --git a/doccano_api_client/beta_pythonic_client/models/examples.py b/doccano_api_client/beta/models/examples.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/examples.py
rename to doccano_api_client/beta/models/examples.py
diff --git a/doccano_api_client/beta_pythonic_client/models/labels.py b/doccano_api_client/beta/models/labels.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/labels.py
rename to doccano_api_client/beta/models/labels.py
diff --git a/doccano_api_client/beta_pythonic_client/models/projects.py b/doccano_api_client/beta/models/projects.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/models/projects.py
rename to doccano_api_client/beta/models/projects.py
diff --git a/doccano_api_client/beta_pythonic_client/py.typed b/doccano_api_client/beta/py.typed
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/py.typed
rename to doccano_api_client/beta/py.typed
diff --git a/doccano_api_client/beta_pythonic_client/utils/__init__.py b/doccano_api_client/beta/utils/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/utils/__init__.py
rename to doccano_api_client/beta/utils/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/utils/response.py b/doccano_api_client/beta/utils/response.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/utils/response.py
rename to doccano_api_client/beta/utils/response.py
diff --git a/doccano_api_client/beta_pythonic_client/__init__.py b/doccano_api_client/beta_pythonic_client/__init__.py
deleted file mode 100644
index 1d6af8d..0000000
--- a/doccano_api_client/beta_pythonic_client/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .client import Client
-
-__all__ = ["Client"]
diff --git a/setup.py b/setup.py
index ff3bd4a..a01e3de 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,10 @@
 from setuptools import setup
 
-base_packages = ["requests"]
+base_packages = [
+    "requests",
+    "dataclasses>=0.7,<1; python_version<'3.7'",
+    "dataclasses-json>=0.5.0,<1.0.0",
+]
 
 dev_packages = [
     "black>=19.3b0",
@@ -11,17 +15,14 @@
     "flake8-docstrings==1.5.0",
     "darglint==1.4.0",
     "pre-commit>=2.2.0",
-    "dataclasses>=0.7,<1; python_version<'3.7'",
-    "dataclasses-json>=0.5.0,<1.0.0",
     "types-dataclasses>=0.1.3,<1; python_version<'3.7'",
     "types-requests>=0.1.8,<1",
+    "pytest>=6.1.2,<7",
 ]
 
 setup(
     name="doccano-client",
-    # Semver for this package should match Doccano release tags to denote compatibility
-    # up to the minor version (patch version can be more flexible)
-    version="1.5.1",  # Tested for compatibility against Doccano >=1.5.0, <=1.5.5
+    version="1.1.0",  # Beta Client Tested for compatibility against Doccano >=1.5.0, <=1.5.5
     setup_requires=["setuptools_scm"],
     description="A simple client wrapper for the doccano API.",
     long_description="This simple API wrapper allows users to easily get data \


Test patch:
diff --git a/doccano_api_client/beta_pythonic_client/tests/__init__.py b/doccano_api_client/beta/tests/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/__init__.py
rename to doccano_api_client/beta/tests/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/conftest.py b/doccano_api_client/beta/tests/conftest.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/conftest.py
rename to doccano_api_client/beta/tests/conftest.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/__init__.py b/doccano_api_client/beta/tests/controllers/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/__init__.py
rename to doccano_api_client/beta/tests/controllers/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/__init__.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/__init__.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/annotations.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/annotations.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/annotations.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/annotations.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/bad.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/bad.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/bad.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/bad.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/comments.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/comments.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/comments.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/comments.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/examples.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/examples.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/examples.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/examples.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/labels.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/labels.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/labels.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/labels.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/projects.py b/doccano_api_client/beta/tests/controllers/mock_api_responses/projects.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/mock_api_responses/projects.py
rename to doccano_api_client/beta/tests/controllers/mock_api_responses/projects.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/test_annotation.py b/doccano_api_client/beta/tests/controllers/test_annotation.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/test_annotation.py
rename to doccano_api_client/beta/tests/controllers/test_annotation.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/test_comment.py b/doccano_api_client/beta/tests/controllers/test_comment.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/test_comment.py
rename to doccano_api_client/beta/tests/controllers/test_comment.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/test_example.py b/doccano_api_client/beta/tests/controllers/test_example.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/test_example.py
rename to doccano_api_client/beta/tests/controllers/test_example.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/test_label.py b/doccano_api_client/beta/tests/controllers/test_label.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/test_label.py
rename to doccano_api_client/beta/tests/controllers/test_label.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/controllers/test_project.py b/doccano_api_client/beta/tests/controllers/test_project.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/controllers/test_project.py
rename to doccano_api_client/beta/tests/controllers/test_project.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/test_client.py b/doccano_api_client/beta/tests/test_client.py
similarity index 95%
rename from doccano_api_client/beta_pythonic_client/tests/test_client.py
rename to doccano_api_client/beta/tests/test_client.py
index 824d231..49f9b0b 100644
--- a/doccano_api_client/beta_pythonic_client/tests/test_client.py
+++ b/doccano_api_client/beta/tests/test_client.py
@@ -3,7 +3,7 @@
 
 import responses
 
-from ..client import Client
+from ..client import DoccanoClient
 from ..models import Example
 from ..utils.response import DoccanoAPIError
 from .controllers.mock_api_responses import examples as mock_examples
@@ -12,7 +12,7 @@
 
 class ClientTest(TestCase):
     def setUp(self):
-        self.client = Client("https://doccano.notaningress.com")
+        self.client = DoccanoClient("https://doccano.notaningress.com")
 
     def test_url_properties(self):
         self.assertEqual(self.client.login_url, "https://doccano.notaningress.com/v1/auth/login/")
diff --git a/doccano_api_client/beta_pythonic_client/tests/test_full_integration_tests.py b/doccano_api_client/beta/tests/test_full_integration_tests.py
similarity index 97%
rename from doccano_api_client/beta_pythonic_client/tests/test_full_integration_tests.py
rename to doccano_api_client/beta/tests/test_full_integration_tests.py
index a1dc343..04d786d 100644
--- a/doccano_api_client/beta_pythonic_client/tests/test_full_integration_tests.py
+++ b/doccano_api_client/beta/tests/test_full_integration_tests.py
@@ -2,7 +2,7 @@
 
 import pytest
 
-from ..client import Client
+from ..client import DoccanoClient
 from ..models import Example, Label, Project
 
 DOCCANO_ENDPOINT = "http://0.0.0.0"  # TODO: Make this a pytest parameter
@@ -17,7 +17,7 @@ class IntegrationTests(TestCase):
 
     @classmethod
     def setUpClass(cls) -> None:
-        cls.client = Client(DOCCANO_ENDPOINT)
+        cls.client = DoccanoClient(DOCCANO_ENDPOINT)
         cls.client.login("admin", "password")
         cls.projects_controller = cls.client.projects
 
diff --git a/doccano_api_client/beta_pythonic_client/tests/utils/__init__.py b/doccano_api_client/beta/tests/utils/__init__.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/utils/__init__.py
rename to doccano_api_client/beta/tests/utils/__init__.py
diff --git a/doccano_api_client/beta_pythonic_client/tests/utils/test_response.py b/doccano_api_client/beta/tests/utils/test_response.py
similarity index 100%
rename from doccano_api_client/beta_pythonic_client/tests/utils/test_response.py
rename to doccano_api_client/beta/tests/utils/test_response.py
diff --git a/pytest.ini b/pytest.ini
new file mode 100644
index 0000000..e69de29