codecov[bot]: # [Codecov](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=h1) Report
> Merging [#38](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=desc) into [master](https://codecov.io/gh/MarquezProject/marquez-python/commit/298185dbc774d94b8390dfb74255524cd5391128?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/MarquezProject/marquez-python/pull/38/graphs/tree.svg?width=650&token=dfwvCu2sEl&height=150&src=pr)](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master      #38      +/-   ##
==========================================
+ Coverage   99.49%   99.49%   +<.01%     
==========================================
  Files           3        4       +1     
  Lines         197      198       +1     
==========================================
+ Hits          196      197       +1     
  Misses          1        1
```


| [Impacted Files](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [marquez\_client/client.py](https://codecov.io/gh/MarquezProject/marquez-python/pull/38/diff?src=pr&el=tree#diff-bWFycXVlel9jbGllbnQvY2xpZW50LnB5) | `99.34% <100%> (ø)` | :arrow_up: |
| [\_\_init\_\_.py](https://codecov.io/gh/MarquezProject/marquez-python/pull/38/diff?src=pr&el=tree#diff-X19pbml0X18ucHk=) | `100% <0%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=footer). Last update [298185d...764a3d3](https://codecov.io/gh/MarquezProject/marquez-python/pull/38?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

sshah-wework: Ping?
ashulmanWeWork: @sshah-wework, this is an improvement that @wslulciuc and I wanted to get in to ease usability. Unfortunately we ran out of time and needed to focus on higher-priority items, so we decided to leave this here.

That being the case, it's ready to go, but while I'd like to see this get in, I realize it will also require some work updating marquez-airflow when @roaraya8 is ready to upgrade to this.

I think we can take this on when we circle back to updating the client with Willy's recent timestamp changes (among others).
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 3dd975f..c289d86 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -14,7 +14,7 @@ jobs:
       - run: pip install --user coverage
       - run: pip install --user -e .
       - run: pip install --user flake8
-      - run: python -m flake8
+      - run: python -m flake8 --extend-ignore=F401
 
   test:
     <<: *defaults
diff --git a/README.md b/README.md
index 2a8c44a..413ed4a 100644
--- a/README.md
+++ b/README.md
@@ -20,16 +20,16 @@ Python 3.5.0+
 ## Installation & Usage
 ### pip install
 
-If the python package is hosted on Github, you can install directly from Github
+Marquez-Python is hosted on PyPi and can be installed from that repository.
 
 ```sh
-pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git
+pip install marquez-python
 ```
-(you may need to run `pip` with root permission: `sudo pip install git+https://github.com/GIT_USER_ID/GIT_REPO_ID.git`)
+(you may need to run `pip` with root permission: `sudo pip install marquez-python`)
 
 Then import the package:
 ```python
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 ```
 
 ### Setuptools
@@ -44,7 +44,7 @@ python setup.py install --user
 Then import the package:
 ```python
 
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 ```
 
 ## Getting Started
@@ -68,12 +68,12 @@ For more information about API calls, please see the Marquez API documentation.
 
 #### Instantiating the client
 ```
-mc = Client(host="localhost", port="8080")
+mc = MarquezClient(host="localhost", port="8080")
 ```
 
 #### Instantiating the client to use a default existing namespace
 ```
-mc = Client(
+mc = MarquezClient(
     host="localhost",
     port="8080",
     namespace_name="accounting_team")
@@ -87,7 +87,7 @@ The constructor-specified value will take precedence over
 the environmental variable. If neither is provided, the default
 namespace `default` is used. 
 ```
-mc = Client(
+mc = MarquezClient(
     host="localhost",
     port="8080")
 ```
diff --git a/marquez_client/__init__.py b/marquez_client/__init__.py
index 4d9a924..c37a484 100644
--- a/marquez_client/__init__.py
+++ b/marquez_client/__init__.py
@@ -9,3 +9,4 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+from marquez_client.client import MarquezClient
diff --git a/marquez_client/client.py b/marquez_client/client.py
index ba642bd..383b214 100644
--- a/marquez_client/client.py
+++ b/marquez_client/client.py
@@ -21,7 +21,7 @@ _DEFAULT_TIMEOUT_MS = 5000
 _DEFAULT_NAMESPACE_NAME = "default"
 
 
-class Client(object):
+class MarquezClient(object):
     def __init__(self, host=None, port=None,
                  namespace_name=None, timeout_ms=None):
         host = host or os.environ.get('MARQUEZ_HOST')

Rename client class to MarquezClient()
diff --git a/tests/integration/integration_test.py b/tests/integration/integration_test.py
index 92789d3..80a83a8 100644
--- a/tests/integration/integration_test.py
+++ b/tests/integration/integration_test.py
@@ -15,7 +15,7 @@ import sys
 
 import pytest
 import requests
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from marquez_client.constants import NOT_FOUND
 from requests import ReadTimeout
 from urllib3.exceptions import MaxRetryError
@@ -43,21 +43,21 @@ def wait_for_marquez():
 
 
 def test_bad_host(wait_for_marquez):
-    c = Client(host="bad-host", port=MARQUEZ_PORT)
+    c = MarquezClient(host="bad-host", port=MARQUEZ_PORT)
     with pytest.raises(requests.exceptions.ConnectionError) as e:
         c.get_namespace("no_connection")
     assert isinstance(e.value.args[0], MaxRetryError)
 
 
 def test_bad_port(wait_for_marquez):
-    c = Client(host=MARQUEZ_HOST, port="6000")
+    c = MarquezClient(host=MARQUEZ_HOST, port="6000")
     with pytest.raises(requests.exceptions.ConnectionError) as e:
         c.get_namespace("no_connection")
     assert isinstance(e.value.args[0], MaxRetryError)
 
 
 def test_timeout(wait_for_marquez, broken_network):
-    c = Client(host=MARQUEZ_HOST, port=MARQUEZ_PORT, timeout_ms=1)
+    c = MarquezClient(host=MARQUEZ_HOST, port=MARQUEZ_PORT, timeout_ms=1)
 
     expected_namespace = "timeout_test"
     with pytest.raises(ReadTimeout):
@@ -65,7 +65,7 @@ def test_timeout(wait_for_marquez, broken_network):
 
 
 def test_namespace_not_found(wait_for_marquez):
-    c = Client(host=MARQUEZ_HOST, port=MARQUEZ_PORT)
+    c = MarquezClient(host=MARQUEZ_HOST, port=MARQUEZ_PORT)
 
     expected_namespace = "not_found"
     assert c.get_namespace(expected_namespace) == NOT_FOUND
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index 82cac8a..eff6c81 100644
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -13,8 +13,9 @@
 import os
 
 import pytest
-from marquez_client import client
-from marquez_client.client import Client
+from marquez_client import MarquezClient
+from marquez_client.client import _DEFAULT_NAMESPACE_NAME
+from marquez_client.client import _DEFAULT_TIMEOUT_MS
 from pytest import fixture
 
 
@@ -25,87 +26,89 @@ def clear_env():
 
 def test_marquez_host_required(clear_env):
     with pytest.raises(ValueError):
-        Client(port=8080)
+        MarquezClient(port=8080)
 
 
 def test_marquez_port_required(clear_env):
     with pytest.raises(ValueError):
-        Client(host="localhost")
+        MarquezClient(host="localhost")
 
 
 def test_default_namespace(clear_env):
-    m = Client(host="localhost", port=8080)
-    assert m.namespace == client._DEFAULT_NAMESPACE_NAME
+    m = MarquezClient(host="localhost", port=8080)
+    assert m.namespace == _DEFAULT_NAMESPACE_NAME
 
 
 def test_namespace_name_from_env(clear_env):
     os.environ["MARQUEZ_NAMESPACE"] = "ns_from_env"
 
-    m = Client(host="localhost", port=8080)
+    m = MarquezClient(host="localhost", port=8080)
     assert m.namespace == "ns_from_env"
 
 
 def test_namespace_name_override(clear_env):
     os.environ["MARQUEZ_NAMESPACE"] = "ns_from_env"
 
-    m = Client(host="localhost", namespace_name="from_constructor", port=8080)
+    m = MarquezClient(
+        host="localhost", namespace_name="from_constructor", port=8080)
     assert m.namespace == "from_constructor"
 
 
 def test_set_client_namespace(clear_env):
     namespace_name = "someRandomNS"
-    m = Client(host="localhost", port=8080, namespace_name=namespace_name)
+    m = MarquezClient(
+        host="localhost", port=8080, namespace_name=namespace_name)
     assert m.namespace == namespace_name
 
 
 def test_host_override(clear_env):
     os.environ["MARQUEZ_HOST"] = "env_host"
-    m = Client(host="specified_host", port=8080)
+    m = MarquezClient(host="specified_host", port=8080)
     assert m._api_base == "http://specified_host:8080/api/v1"
 
 
 def test_host_from_env(clear_env):
     os.environ["MARQUEZ_HOST"] = "env_host"
-    m = Client(port=8080)
+    m = MarquezClient(port=8080)
     assert m._api_base == "http://env_host:8080/api/v1"
 
 
 def test_port_override(clear_env):
     os.environ["MARQUEZ_PORT"] = "9000"
-    m = Client(host="localhost", port=8080)
+    m = MarquezClient(host="localhost", port=8080)
     assert m._api_base == "http://localhost:8080/api/v1"
 
 
 def test_port_from_env(clear_env):
     os.environ["MARQUEZ_PORT"] = "9000"
-    m = Client(host="localhost")
+    m = MarquezClient(host="localhost")
     assert m._api_base == "http://localhost:9000/api/v1"
 
 
 def test_mixed_configuration(clear_env):
     os.environ["MARQUEZ_HOST"] = "localhost"
-    m = Client(port=9000)
+    m = MarquezClient(port=9000)
     assert m._api_base == "http://localhost:9000/api/v1"
 
 
 def test_timeout_from_env(clear_env):
     os.environ["MARQUEZ_TIMEOUT_MS"] = "3000"
-    m = Client(host="localhost", port=8080)
+    m = MarquezClient(host="localhost", port=8080)
     assert m._timeout == 3
 
 
 def test_default_timeout(clear_env):
-    m = Client(host="localhost", port=8080)
-    assert m._timeout == client._DEFAULT_TIMEOUT_MS / 1000.0
+    m = MarquezClient(host="localhost", port=8080)
+    assert m._timeout == _DEFAULT_TIMEOUT_MS / 1000.0
 
 
 def test_timeout_override(clear_env):
     os.environ["MARQUEZ_TIMEOUT_MS"] = "3000"
-    m = Client(host="localhost", port=8080, timeout_ms=7000)
+    m = MarquezClient(host="localhost", port=8080, timeout_ms=7000)
     assert m._timeout == 7.0
 
 
 def test_timeout_not_truncated(clear_env):
     os.environ["MARQUEZ_TIMEOUT_MS"] = "3500"
-    m = Client(host="localhost", port=8080)
+    m = MarquezClient(host="localhost", port=8080)
     assert m._timeout == 3.5
diff --git a/tests/test_datasets.py b/tests/test_datasets.py
index e38f000..58c3c22 100644
--- a/tests/test_datasets.py
+++ b/tests/test_datasets.py
@@ -11,7 +11,7 @@
 # limitations under the License.
 import pytest
 import vcr
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from marquez_client.constants import NOT_FOUND
 from marquez_client.utils import InvalidRequestError
 from pytest import fixture
@@ -24,14 +24,14 @@ def namespace_name():
 
 @fixture(scope='class')
 def marquez_client_default_ns():
-    return Client(host="localhost",
-                  port=8080)
+    return MarquezClient(host="localhost",
+                         port=8080)
 
 
 @fixture(scope='class')
 def marquez_client(namespace):
-    return Client(host="localhost", namespace_name=namespace['name'],
-                  port=8080)
+    return MarquezClient(host="localhost", namespace_name=namespace['name'],
+                         port=8080)
 
 
 @fixture(scope='class')
diff --git a/tests/test_datasources.py b/tests/test_datasources.py
index e819bbc..d7e7aeb 100755
--- a/tests/test_datasources.py
+++ b/tests/test_datasources.py
@@ -12,21 +12,21 @@
 
 import pytest
 import vcr
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from marquez_client.utils import InvalidRequestError
 from pytest import fixture
 
 
 @fixture(scope='class')
 def marquez_client():
-    return Client(host="localhost",
-                  port=8080)
+    return MarquezClient(host="localhost",
+                         port=8080)
 
 
 @fixture(scope='class')
 def marquez_client_with_timeout():
-    return Client(host="localhost",
-                  port=8080, timeout_ms=4000)
+    return MarquezClient(host="localhost",
+                         port=8080, timeout_ms=4000)
 
 
 @fixture(scope='class')
diff --git a/tests/test_jobruns.py b/tests/test_jobruns.py
index 6837e86..e086bc4 100644
--- a/tests/test_jobruns.py
+++ b/tests/test_jobruns.py
@@ -13,7 +13,7 @@
 import datetime
 
 import vcr
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from pytest import fixture
 
 
@@ -24,8 +24,8 @@ def namespace_name():
 
 @fixture(scope='class')
 def marquez_client_default_ns():
-    return Client(host="localhost",
-                  port=8080)
+    return MarquezClient(host="localhost",
+                         port=8080)
 
 
 @fixture(scope='class')
@@ -41,8 +41,8 @@ def existing_namespace(marquez_client_default_ns, namespace_name):
 
 @fixture(scope='class')
 def marquez_client(namespace_name):
-    return Client(host="localhost", namespace_name=namespace_name,
-                  port=8080)
+    return MarquezClient(host="localhost", namespace_name=namespace_name,
+                         port=8080)
 
 
 @fixture(scope='class')
diff --git a/tests/test_jobs.py b/tests/test_jobs.py
index 3ec6cfe..553d011 100644
--- a/tests/test_jobs.py
+++ b/tests/test_jobs.py
@@ -10,7 +10,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 import vcr
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from marquez_client.constants import NOT_FOUND
 from pytest import fixture
 
@@ -25,7 +25,7 @@ def namespace_name():
 def namespace(namespace_name):
     owner_name = "some_owner"
     description = "this is a very nice namespace."
-    basic_marquez_client = Client(host="localhost", port=8080)
+    basic_marquez_client = MarquezClient(host="localhost", port=8080)
     created_ns = basic_marquez_client.create_namespace(
         namespace_name, owner_name, description)
     return created_ns
@@ -33,13 +33,13 @@ def namespace(namespace_name):
 
 @fixture(scope='class')
 def marquez_client_with_ns(namespace_name):
-    return Client(host="localhost", namespace_name=namespace_name,
-                  port=8080)
+    return MarquezClient(host="localhost", namespace_name=namespace_name,
+                         port=8080)
 
 
 @fixture(scope='class')
 def marquez_client_with_default_ns():
-    return Client(host="localhost", port=8080)
+    return MarquezClient(host="localhost", port=8080)
 
 
 @fixture(scope='class')
@@ -62,7 +62,7 @@ def job(marquez_client_with_ns, job_name):
 @vcr.use_cassette(
     'tests/fixtures/vcr/test_jobs/job_default_ns_for_jobs_test.yaml')
 def job_default_ns(job_name):
-    marquez_client = Client(host="localhost", port=8080)
+    marquez_client = MarquezClient(host="localhost", port=8080)
 
     input_datset_urns = ['input1a', 'input2a']
     output_datset_urns = ['output1a', 'output2a']
diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py
index f6154da..a2a6bef 100644
--- a/tests/test_namespaces.py
+++ b/tests/test_namespaces.py
@@ -15,7 +15,7 @@ from unittest.mock import MagicMock
 
 import pytest
 import vcr
-from marquez_client.client import Client
+from marquez_client import MarquezClient
 from marquez_client.constants import NO_CONTENT_RESPONSE, NOT_FOUND
 from marquez_client.utils import APIError, InvalidRequestError
 from pytest import fixture
@@ -23,8 +23,8 @@ from pytest import fixture
 
 @fixture(scope='class')
 def marquez_client():
-    return Client(host="localhost",
-                  port=8080)
+    return MarquezClient(host="localhost",
+                         port=8080)
 
 
 @fixture(scope='function')

pip install -e .
parse_log_pytest
requirements.txt
pytest coverage nose pluggy py randomize urllib3 vcrpy pytest-cov codecov
apt-get update apt-get install -y gcc
3.9
test-requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
charset-normalizer==3.4.1
codecov==2.1.13
coverage==7.8.0
exceptiongroup==1.2.2
idna==3.10
iniconfig==2.1.0
-e git+https://github.com/MarquezProject/marquez-python.git@cc1fc666ada9b2a3e07dd6c4dd7b41b081ada945#egg=marquez_python
multidict==6.2.0
nose==1.3.7
packaging==24.2
pluggy==1.5.0
propcache==0.3.1
py==1.11.0
pytest==8.3.5
pytest-cov==6.0.0
PyYAML==6.0.2
randomize==0.14
requests==2.32.3
tomli==2.2.1
typing_extensions==4.13.0
urllib3==1.26.20
vcrpy==7.0.0
wrapt==1.17.2
yarl==1.18.3

name: marquez-python
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - codecov==2.1.13
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - idna==3.10
      - iniconfig==2.1.0
      - multidict==6.2.0
      - nose==1.3.7
      - packaging==24.2
      - pluggy==1.5.0
      - propcache==0.3.1
      - py==1.11.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - pyyaml==6.0.2
      - randomize==0.14
      - requests==2.32.3
      - tomli==2.2.1
      - typing-extensions==4.13.0
      - urllib3==1.26.20
      - vcrpy==7.0.0
      - wrapt==1.17.2
      - yarl==1.18.3
prefix: /opt/conda/envs/marquez-python

tests/test_configuration.py::test_marquez_host_required tests/test_configuration.py::test_marquez_port_required tests/test_configuration.py::test_default_namespace tests/test_configuration.py::test_namespace_name_from_env tests/test_configuration.py::test_namespace_name_override tests/test_configuration.py::test_set_client_namespace tests/test_configuration.py::test_host_override tests/test_configuration.py::test_host_from_env tests/test_configuration.py::test_port_override tests/test_configuration.py::test_port_from_env tests/test_configuration.py::test_mixed_configuration tests/test_configuration.py::test_timeout_from_env tests/test_configuration.py::test_default_timeout tests/test_configuration.py::test_timeout_override tests/test_configuration.py::test_timeout_not_truncated tests/test_datasets.py::test_create_dataset tests/test_datasets.py::test_get_dataset tests/test_datasets.py::test_get_dataset_specify_ns tests/test_datasets.py::test_get_dataset_default_ns tests/test_datasets.py::test_get_dataset_malformed_urn tests/test_datasets.py::test_list_datasets tests/test_datasets.py::test_list_datasets_default_ns tests/test_datasources.py::test_create_datasource tests/test_datasources.py::test_create_datasource_with_timeout tests/test_datasources.py::test_get_datasource tests/test_datasources.py::test_get_datasources tests/test_datasources.py::test_get_datasources_with_timeout tests/test_datasources.py::test_get_datasources_with_limit tests/test_datasources.py::test_get_datasources_with_offset tests/test_datasources.py::test_get_namespace_with_invalid_dictionary tests/test_datasources.py::test_get_datasources_with_limit_and_offset tests/test_datasources.py::test_get_namespaces_with_invalid_dictionary tests/test_jobruns.py::test_create_jobrun tests/test_jobruns.py::test_get_jobrun tests/test_jobruns.py::test_jobrun_can_be_marked_aborted tests/test_jobruns.py::test_jobrun_can_be_marked_failed tests/test_jobruns.py::test_jobrun_can_be_marked_completed tests/test_jobs.py::test_create_job tests/test_jobs.py::test_get_job tests/test_jobs.py::test_list_jobs tests/test_jobs.py::test_list_jobs_with_namespace_client tests/test_jobs.py::test_list_jobs_specify_namespace tests/test_jobs.py::test_list_jobs_no_such_namespace tests/test_jobs.py::test_create_job_with_special_chars_no_spaces tests/test_jobs.py::test_create_job_with_forward_slash tests/test_jobs.py::test_create_job_with_forward_slashes tests/test_jobs.py::test_create_job_with_forward_slashes_and_space tests/test_jobs.py::test_create_job_with_special_chars_with_spaces tests/test_namespaces.py::test_create_namespace tests/test_namespaces.py::test_get_namespace tests/test_namespaces.py::test_get_namespace_invalid_input tests/test_namespaces.py::test_create_namespace_missing_owner tests/test_namespaces.py::test_namespace_internal_service_error tests/test_namespaces.py::test_namespace_204_no_content_response tests/test_namespaces.py::test_namespace_general_error tests/test_namespaces.py::test_get_no_such_namespace tests/test_namespaces.py::test_list_namespaces tests/test_namespaces.py::test_namespace_not_set
marquez_client/client.py README.md .circleci/config.yml marquez_client/__init__.py
marquez_client/client.py README.md .circleci/config.yml marquez_client/__init__.py