Repository: gazebosim/gz-mujoco (language: python)

Issue:
Use a single namespace and subpackages
The PR moves the current packages under a common [native namespace ](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#native-namespace-packages) named `sdformat_mjcf`.

With the change, we might want to reconsider the way of invoking our imports, probably need to work using the schema `from sdformat_mjcf.sdformat_to_mjcf import foo` since the installation using PYPI is probably installing the code using that directory layout. By now, things keep working since we are injecting `PYTHONPATH` in CI to point to the subpackages.

I've manually uploaded a test to test.pypi.org using the initial state of this PR https://test.pypi.org/project/sdformat-mjcf/. I'll send a second PR with the automated code for this.

Use a single namespace and subpackages
The PR moves the current packages under a common [native namespace ](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#native-namespace-packages) named `sdformat_mjcf`.

With the change, we might want to reconsider the way of invoking our imports, probably need to work using the schema `from sdformat_mjcf.sdformat_to_mjcf import foo` since the installation using PYPI is probably installing the code using that directory layout. By now, things keep working since we are injecting `PYTHONPATH` in CI to point to the subpackages.

I've manually uploaded a test to test.pypi.org using the initial state of this PR https://test.pypi.org/project/sdformat-mjcf/. I'll send a second PR with the automated code for this.

Use a single namespace and subpackages
The PR moves the current packages under a common [native namespace ](https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#native-namespace-packages) named `sdformat_mjcf`.

With the change, we might want to reconsider the way of invoking our imports, probably need to work using the schema `from sdformat_mjcf.sdformat_to_mjcf import foo` since the installation using PYPI is probably installing the code using that directory layout. By now, things keep working since we are injecting `PYTHONPATH` in CI to point to the subpackages.

I've manually uploaded a test to test.pypi.org using the initial state of this PR https://test.pypi.org/project/sdformat-mjcf/. I'll send a second PR with the automated code for this.



Discussion / hints:
# [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) Report
> Merging [#39](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (ed9e471) into [main](https://codecov.io/gh/gazebosim/gz-mujoco/commit/7f0a3060c201b9dc875686a6d15ac39a0bcdb66b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (7f0a306) will **increase** coverage by `1.12%`.
> The diff coverage is `n/a`.

> :exclamation: Current head ed9e471 differs from pull request most recent head 12231f4. Consider uploading reports for the commit 12231f4 to get more accurate results

```diff
@@            Coverage Diff             @@
##             main      #39      +/-   ##
==========================================
+ Coverage   96.94%   98.06%   +1.12%     
==========================================
  Files          11       22      +11     
  Lines         327     1187     +860     
==========================================
+ Hits          317     1164     +847     
- Misses         10       23      +13     
```


| [Impacted Files](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | Coverage Δ | |
|---|---|---|
| [...rmat\_mjcf/sdformat\_to\_mjcf/sdformat\_to\_mjcf/cli.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY2xpLnB5) | `90.90% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/geometry.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9nZW9tZXRyeS5weQ==) | `92.42% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/joint.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9qb2ludC5weQ==) | `96.92% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/light.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saWdodC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/link.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saW5rLnB5) | `100.00% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/material.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tYXRlcmlhbC5weQ==) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/model.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tb2RlbC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/root.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9yb290LnB5) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/world.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy93b3JsZC5weQ==) | `100.00% <ø> (ø)` | |
| [...dformat\_to\_mjcf/sdformat\_to\_mjcf/sdf\_kinematics.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2Yvc2RmX2tpbmVtYXRpY3MucHk=) | `94.73% <ø> (ø)` | |
| ... and [23 more](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Last update [7f0a306...12231f4](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).

> Right now both `sdformat_to_mjcf` and `sdformat_mjcf_utils` have a setup.py file. Do we need that if we're putting them all in one PyPI package?

Oh, that is right, I think we don't need to ship more `setup.py` than the one in root. I went a bit crazy and do the following in [12231f4](https://github.com/gazebosim/gz-mujoco/pull/39/commits/12231f4b1ca2e1e672c289ab26806f659d086cb4):

 * Get rid of the duplicate directories `sdformat_to_mjcf/sdformat_to_mjcf` move all files to the upper dir
 * Remove all __init__.py but leave the ones in real packages, otherwise they are recognized as packages and installed
 * Remove setup.py, LICENSE, README, setup.cfg, etc. from subpackages, leave just one in the root dir
 * Change setup.py to install the `sdformat2mjcf` script in entry
 * Change cli.py to get the new paths (**TODO**: we probably need to extend the new syntax in all files).

With this, I'm able to do the following:
```
> virtualenv foo && source foo/bin/activate && pip install .
> sdformat2mjcf
```
And `python3 setup.py sdist bdist bdist_wheel` output also looks good to me.

What I think it is missing:
 * Change all the imports to the new layout `sdformat_mfjc.$package`
 * Probably leave a single tox.ini file covering both packages


Okay, but now this puts files in the root directory `gz-mujoco`. We don't want `gz-mujoco` to be a python package. If we're putting them all in one package, we should just have `sdformat_mjcf` as the only directory in the root of the repo and no other files for now.
# [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) Report
> Merging [#39](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (ed9e471) into [main](https://codecov.io/gh/gazebosim/gz-mujoco/commit/7f0a3060c201b9dc875686a6d15ac39a0bcdb66b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (7f0a306) will **increase** coverage by `1.12%`.
> The diff coverage is `n/a`.

> :exclamation: Current head ed9e471 differs from pull request most recent head 12231f4. Consider uploading reports for the commit 12231f4 to get more accurate results

```diff
@@            Coverage Diff             @@
##             main      #39      +/-   ##
==========================================
+ Coverage   96.94%   98.06%   +1.12%     
==========================================
  Files          11       22      +11     
  Lines         327     1187     +860     
==========================================
+ Hits          317     1164     +847     
- Misses         10       23      +13     
```


| [Impacted Files](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | Coverage Δ | |
|---|---|---|
| [...rmat\_mjcf/sdformat\_to\_mjcf/sdformat\_to\_mjcf/cli.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY2xpLnB5) | `90.90% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/geometry.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9nZW9tZXRyeS5weQ==) | `92.42% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/joint.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9qb2ludC5weQ==) | `96.92% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/light.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saWdodC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/link.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saW5rLnB5) | `100.00% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/material.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tYXRlcmlhbC5weQ==) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/model.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tb2RlbC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/root.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9yb290LnB5) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/world.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy93b3JsZC5weQ==) | `100.00% <ø> (ø)` | |
| [...dformat\_to\_mjcf/sdformat\_to\_mjcf/sdf\_kinematics.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2Yvc2RmX2tpbmVtYXRpY3MucHk=) | `94.73% <ø> (ø)` | |
| ... and [23 more](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Last update [7f0a306...12231f4](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).

> Right now both `sdformat_to_mjcf` and `sdformat_mjcf_utils` have a setup.py file. Do we need that if we're putting them all in one PyPI package?

Oh, that is right, I think we don't need to ship more `setup.py` than the one in root. I went a bit crazy and do the following in [12231f4](https://github.com/gazebosim/gz-mujoco/pull/39/commits/12231f4b1ca2e1e672c289ab26806f659d086cb4):

 * Get rid of the duplicate directories `sdformat_to_mjcf/sdformat_to_mjcf` move all files to the upper dir
 * Remove all __init__.py but leave the ones in real packages, otherwise they are recognized as packages and installed
 * Remove setup.py, LICENSE, README, setup.cfg, etc. from subpackages, leave just one in the root dir
 * Change setup.py to install the `sdformat2mjcf` script in entry
 * Change cli.py to get the new paths (**TODO**: we probably need to extend the new syntax in all files).

With this, I'm able to do the following:
```
> virtualenv foo && source foo/bin/activate && pip install .
> sdformat2mjcf
```
And `python3 setup.py sdist bdist bdist_wheel` output also looks good to me.

What I think it is missing:
 * Change all the imports to the new layout `sdformat_mfjc.$package`
 * Probably leave a single tox.ini file covering both packages


Okay, but now this puts files in the root directory `gz-mujoco`. We don't want `gz-mujoco` to be a python package. If we're putting them all in one package, we should just have `sdformat_mjcf` as the only directory in the root of the repo and no other files for now.
# [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) Report
> Merging [#39](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (ed9e471) into [main](https://codecov.io/gh/gazebosim/gz-mujoco/commit/7f0a3060c201b9dc875686a6d15ac39a0bcdb66b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) (7f0a306) will **increase** coverage by `1.12%`.
> The diff coverage is `n/a`.

> :exclamation: Current head ed9e471 differs from pull request most recent head 12231f4. Consider uploading reports for the commit 12231f4 to get more accurate results

```diff
@@            Coverage Diff             @@
##             main      #39      +/-   ##
==========================================
+ Coverage   96.94%   98.06%   +1.12%     
==========================================
  Files          11       22      +11     
  Lines         327     1187     +860     
==========================================
+ Hits          317     1164     +847     
- Misses         10       23      +13     
```


| [Impacted Files](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | Coverage Δ | |
|---|---|---|
| [...rmat\_mjcf/sdformat\_to\_mjcf/sdformat\_to\_mjcf/cli.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY2xpLnB5) | `90.90% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/geometry.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9nZW9tZXRyeS5weQ==) | `92.42% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/joint.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9qb2ludC5weQ==) | `96.92% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/light.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saWdodC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/link.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9saW5rLnB5) | `100.00% <ø> (ø)` | |
| [...at\_to\_mjcf/sdformat\_to\_mjcf/converters/material.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tYXRlcmlhbC5weQ==) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/model.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9tb2RlbC5weQ==) | `100.00% <ø> (ø)` | |
| [...format\_to\_mjcf/sdformat\_to\_mjcf/converters/root.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy9yb290LnB5) | `100.00% <ø> (ø)` | |
| [...ormat\_to\_mjcf/sdformat\_to\_mjcf/converters/world.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2YvY29udmVydGVycy93b3JsZC5weQ==) | `100.00% <ø> (ø)` | |
| [...dformat\_to\_mjcf/sdformat\_to\_mjcf/sdf\_kinematics.py](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim#diff-c2Rmb3JtYXRfbWpjZi9zZGZvcm1hdF90b19tamNmL3NkZm9ybWF0X3RvX21qY2Yvc2RmX2tpbmVtYXRpY3MucHk=) | `94.73% <ø> (ø)` | |
| ... and [23 more](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Last update [7f0a306...12231f4](https://codecov.io/gh/gazebosim/gz-mujoco/pull/39?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=gazebosim).

> Right now both `sdformat_to_mjcf` and `sdformat_mjcf_utils` have a setup.py file. Do we need that if we're putting them all in one PyPI package?

Oh, that is right, I think we don't need to ship more `setup.py` than the one in root. I went a bit crazy and do the following in [12231f4](https://github.com/gazebosim/gz-mujoco/pull/39/commits/12231f4b1ca2e1e672c289ab26806f659d086cb4):

 * Get rid of the duplicate directories `sdformat_to_mjcf/sdformat_to_mjcf` move all files to the upper dir
 * Remove all __init__.py but leave the ones in real packages, otherwise they are recognized as packages and installed
 * Remove setup.py, LICENSE, README, setup.cfg, etc. from subpackages, leave just one in the root dir
 * Change setup.py to install the `sdformat2mjcf` script in entry
 * Change cli.py to get the new paths (**TODO**: we probably need to extend the new syntax in all files).

With this, I'm able to do the following:
```
> virtualenv foo && source foo/bin/activate && pip install .
> sdformat2mjcf
```
And `python3 setup.py sdist bdist bdist_wheel` output also looks good to me.

What I think it is missing:
 * Change all the imports to the new layout `sdformat_mfjc.$package`
 * Probably leave a single tox.ini file covering both packages


Okay, but now this puts files in the root directory `gz-mujoco`. We don't want `gz-mujoco` to be a python package. If we're putting them all in one package, we should just have `sdformat_mjcf` as the only directory in the root of the repo and no other files for now.

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 48c079e..266daf9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -28,24 +28,13 @@ jobs:
         sudo apt-get install -y libsdformat13-dev python3-ignition-math7 python3-sdformat13
     - name: Install test dependencies
       run: python3 -m pip install -U tox
-    - name: Test sdformat_mjcf_utils
-      env:
-        PYTHONPATH: ${{ env.pythonLocation }}/lib/python${{ matrix.python }}/site-packages:/usr/lib/python3/dist-packages
-      run: |
-        cd sdformat_mjcf_utils
-        python3 -m tox -e py
-    - name: Test sdformat_to_mjcf
+    - name: Test sdformat_mjcf
       env:
+        # Set PYTHONPATH since the SDFormat python bindings will be installed in the system python library location
         PYTHONPATH: ${{ env.pythonLocation }}/lib/python${{ matrix.python }}/site-packages:/usr/lib/python3/dist-packages
         MUJOCO_GL: egl
       run: |
-        cd sdformat_to_mjcf
-        python3 -m tox -e py
-    - name: Test mjcf_to_sdformat
-      env:
-        PYTHONPATH: ${{ env.pythonLocation }}/lib/python${{ matrix.python }}/site-packages:/usr/lib/python3/dist-packages
-      run: |
-        cd mjcf_to_sdformat
+        cd sdformat_mjcf
         python3 -m tox -e py
     - name: Upload Coverage to Codecov
       uses: codecov/codecov-action@v2
diff --git a/mjcf_to_sdformat/README.md b/mjcf_to_sdformat/README.md
deleted file mode 100644
index ad32de3..0000000
--- a/mjcf_to_sdformat/README.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Tools for converting between MJCF and SDFormat
-
-To start development, create a python3 virtual environment, upgrade pip and
-install dm-control
-
-```
-python3 -m venv path/to/venv --system-site-packages
-. path/to/venv/bin/activate
-
-pip install -U pip
-pip install dm-control
-```
-
-Install `python3-ignition-math7` from the
-[nightly](https://gazebosim.org/docs/all/release#type-of-releases) repo.
-
-Build `libsdformat` from source from the `ahcorde/python/all` branch and add
-the installation path to your `LD_LIBRARY_PATH` and `PYTHONPATH`.
-
-```
-export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$INSTALL_DIR/lib"
-export PYTHONPATH="$PYTHONPATH:$INSTALL_DIR/lib/python"
-```
-
-where `$INSTALL_DIR` is the installation directory you used when building
-libsdformat.
-
-Install the `mjcf_to_sdformat` packages in "editable" mode
-
-```
-pip install -e path/to/mjcf_to_sdformat
-```
-
-To convert an SDFormat file to mjcf:
-
-```
-mjcf2sdformat path/to/file.xml new_file.sdf
-```
-
-To run the sdf file in GazeboSim, follow [this instructions to install Gazebo Sim](https://gazebosim.org/docs/latest/install)
-
-```
-ign gazebo new_file.xml
-```
-
-### Running tests
-
-To run tests, either run the test files individually, eg:
-
-```
-python tests/test_add_geometry.py
-```
-
-or run `pytest` from the root directory.
diff --git a/mjcf_to_sdformat/setup.py b/mjcf_to_sdformat/setup.py
deleted file mode 100644
index ae41ed5..0000000
--- a/mjcf_to_sdformat/setup.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from setuptools import setup, find_packages
-import pathlib
-
-here = pathlib.Path(__file__).parent.resolve()
-long_description = (here / "README.md").read_text(encoding="utf-8")
-license_content = (here / "LICENSE").read_text(encoding="utf-8")
-
-
-setup(
-    name='mjcf_to_sdformat',
-    version='0.0.1',
-    description='Tool to convert MJCF file to SDFormat',
-    long_description=long_description,
-    long_description_content_type="text/markdown",
-    author='Open Robotics',
-    author_email='info@openrobotics.org',
-    url='https://github.com/ignitionrobotics/gz-mujoco',
-    license=license_content,
-    packages=find_packages(exclude=('tests', 'docs')),
-    test_suite='tests',
-    entry_points={
-        'console_scripts': [
-            'mjcf2sdformat = mjcf_to_sdformat.cli:main',
-        ],
-    },
-)
diff --git a/mjcf_to_sdformat/tox.ini b/mjcf_to_sdformat/tox.ini
deleted file mode 100644
index 30058ed..0000000
--- a/mjcf_to_sdformat/tox.ini
+++ /dev/null
@@ -1,29 +0,0 @@
-# See https://github.com/pypa/sampleproject/blob/main/tox.ini
-# for the original commented file
-
-[tox]
-envlist = py{37,38,39,310}
-
-minversion = 3.3.0
-isolated_build = true
-
-[testenv]
-# pythonpath has to be passed through to the tox to get python3-ignition-mathX and python3-sdformatX
-passenv = PYTHONPATH
-deps =
-    check-manifest >= 0.42
-    flake8
-    numpy
-    dm_control
-    coverage
-    ../sdformat_mjcf_utils
-commands =
-    check-manifest --ignore 'tox.ini,tests/**'
-    python setup.py check -m -s
-    python3 -m flake8 .
-    coverage run -m unittest {posargs}
-    coverage xml
-
-[flake8]
-exclude = .tox,*.egg
-select = E,W,F
diff --git a/mjcf_to_sdformat/LICENSE b/sdformat_mjcf/LICENSE
similarity index 100%
rename from mjcf_to_sdformat/LICENSE
rename to sdformat_mjcf/LICENSE
diff --git a/sdformat_to_mjcf/README.md b/sdformat_mjcf/README.md
similarity index 77%
rename from sdformat_to_mjcf/README.md
rename to sdformat_mjcf/README.md
index a48f67d..525ce52 100644
--- a/sdformat_to_mjcf/README.md
+++ b/sdformat_mjcf/README.md
@@ -25,11 +25,10 @@ export PYTHONPATH="$PYTHONPATH:$INSTALL_DIR/lib/python"
 where `$INSTALL_DIR` is the installation directory you used when building
 libsdformat.
 
-Install the `sdformat_to_mjcf` packages in "editable" mode
+Install the `sdformat-mjcf` package in "editable" mode
 
 ```bash
-pip install -e path/to/sdformat_to_mjcf
-pip install -e path/to/sdformat_mjcf_utils
+pip install -e path/to/sdformat_mjcf
 ```
 
 ### Running tests
@@ -47,7 +46,7 @@ A tox (environment manager) run of tests with multiple python versions:
 ### Run the application
 
 After the editable install in the first part of this section, to convert an 
-SDFormat file to mjcf, run:
+SDFormat file to MJCF, run:
 
 ```
 sdformat2mjcf path/to/file.sdf new_file.xml
@@ -59,3 +58,16 @@ extract the contents and run
 ```
 <path/to/mujoco>/bin/simulate new_file.xml
 ```
+
+To convert an MJCF file to SDFormat:
+
+```
+mjcf2sdformat path/to/file.xml new_file.sdf
+```
+
+To run the SDFormat file in GazeboSim, follow [these instructions to install Gazebo Sim](https://gazebosim.org/docs/latest/install)
+
+```
+ign gazebo new_file.sdf
+```
+
diff --git a/mjcf_to_sdformat/pyproject.toml b/sdformat_mjcf/pyproject.toml
similarity index 100%
rename from mjcf_to_sdformat/pyproject.toml
rename to sdformat_mjcf/pyproject.toml
diff --git a/mjcf_to_sdformat/setup.cfg b/sdformat_mjcf/setup.cfg
similarity index 100%
rename from mjcf_to_sdformat/setup.cfg
rename to sdformat_mjcf/setup.cfg
diff --git a/sdformat_to_mjcf/setup.py b/sdformat_mjcf/setup.py
similarity index 74%
rename from sdformat_to_mjcf/setup.py
rename to sdformat_mjcf/setup.py
index 7e673bd..35efe34 100644
--- a/sdformat_to_mjcf/setup.py
+++ b/sdformat_mjcf/setup.py
@@ -9,7 +9,7 @@
 
 
 setup(
-    name='sdformat_to_mjcf',
+    name='sdformat_mjcf',
     version='0.0.1',
     description='Tool to convert MJCF file to SDFormat',
     long_description=long_description,
@@ -18,11 +18,13 @@
     author_email='info@openrobotics.org',
     url='https://github.com/gazebosim/gz-mujoco',
     license=license_content,
-    packages=find_packages(exclude=('tests', 'docs')),
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
     test_suite='tests',
     entry_points={
         'console_scripts': [
-            'sdformat2mjcf = sdformat_to_mjcf.cli:main',
+            'sdformat2mjcf = sdformat_mjcf.sdformat_to_mjcf.cli:main',
+            'mjcf2sdformat = sdformat_mjcf.mjcf_to_sdformat.cli:main',
         ],
     },
 )
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/__init__.py
similarity index 100%
rename from mjcf_to_sdformat/mjcf_to_sdformat/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/__init__.py
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/__version__.py b/sdformat_mjcf/src/sdformat_mjcf/__version__.py
similarity index 100%
rename from mjcf_to_sdformat/mjcf_to_sdformat/__version__.py
rename to sdformat_mjcf/src/sdformat_mjcf/__version__.py
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/__init__.py
similarity index 100%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/__init__.py
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/cli.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/cli.py
similarity index 94%
rename from mjcf_to_sdformat/mjcf_to_sdformat/cli.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/cli.py
index 28e1692..14b366b 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/cli.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/cli.py
@@ -14,7 +14,9 @@
 
 import sys
 import argparse
-from mjcf_to_sdformat.mjcf_to_sdformat import mjcf_file_to_sdformat
+from sdformat_mjcf.mjcf_to_sdformat.mjcf_to_sdformat import (
+    mjcf_file_to_sdformat,
+)
 
 
 def main(argv=None):
diff --git a/mjcf_to_sdformat/tests/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/__init__.py
similarity index 100%
rename from mjcf_to_sdformat/tests/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/__init__.py
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/geometry.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/geometry.py
similarity index 99%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/geometry.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/geometry.py
index 012d784..7de04d1 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/geometry.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/geometry.py
@@ -17,7 +17,7 @@
 from ignition.math import Vector2d, Vector3d
 
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 VISUAL_NUMBER = 0
 COLLISION_NUMBER = 0
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/joint.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/joint.py
similarity index 98%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/joint.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/joint.py
index 7259e9e..57605b4 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/joint.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/joint.py
@@ -16,7 +16,7 @@
 import logging
 import math
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 def add_fixed_joint(parent_name, child_name):
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/light.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/light.py
similarity index 98%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/light.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/light.py
index e122d2b..6d576ac 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/light.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/light.py
@@ -16,7 +16,7 @@
 
 import math
 
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 import sdformat as sdf
 
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/link.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/link.py
similarity index 94%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/link.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/link.py
index 38bd21b..a16a143 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/link.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/link.py
@@ -15,14 +15,18 @@
 from ignition.math import (Inertiald, MassMatrix3d, Vector3d, Pose3d,
                            Quaterniond)
 
-from mjcf_to_sdformat.converters.geometry import (mjcf_visual_to_sdf,
-                                                  mjcf_collision_to_sdf)
-from mjcf_to_sdformat.converters.light import mjcf_light_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.geometry import (
+    mjcf_visual_to_sdf,
+    mjcf_collision_to_sdf,
+)
+from sdformat_mjcf.mjcf_to_sdformat.converters.light import mjcf_light_to_sdf
 
-from mjcf_to_sdformat.converters.material import mjcf_material_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.material import (
+    mjcf_material_to_sdf,
+)
 
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 NUMBER_OF_SDF_LINK = 0
 COLLISION_GEOM_GROUP = 3
@@ -36,7 +40,7 @@ def mjcf_body_to_sdf(body, physics, body_parent_name=None, modifiers=None):
     :param mjcf.Element body: The MJCF body
     :param mujoco.Physics physics: Mujoco Physics
     :param mjcf.Element inertial: Inertial of the body
-    :param sdformat_mjcf_utils.MjcfModifiers modifiers: Modifiers that apply
+    :param sdformat_mjcf.utils.MjcfModifiers modifiers: Modifiers that apply
     default classes to elements.
     :return: The newly created SDFormat link.
     :rtype: sdf.Link
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/material.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/material.py
similarity index 98%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/material.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/material.py
index 29be04e..f321bee 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/material.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/material.py
@@ -16,7 +16,7 @@
 
 import sdformat as sdf
 
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 def _get_filename_on_disk(texture):
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/sensor.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/sensor.py
similarity index 99%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/sensor.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/sensor.py
index 270d61c..6ce527f 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/sensor.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/sensor.py
@@ -19,7 +19,7 @@
 import math
 
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 CAMERA_INDEX = 0
 IMU_INDEX = 0
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/converters/world.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/world.py
similarity index 91%
rename from mjcf_to_sdformat/mjcf_to_sdformat/converters/world.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/world.py
index 42bd708..fcb441a 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/converters/world.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/converters/world.py
@@ -14,16 +14,16 @@
 
 from ignition.math import Vector3d
 
-from mjcf_to_sdformat.converters.joint import (mjcf_joint_to_sdf,
-                                               add_fixed_joint)
-from mjcf_to_sdformat.converters.light import mjcf_light_to_sdf
-from mjcf_to_sdformat.converters.link import mjcf_body_to_sdf
-from mjcf_to_sdformat.converters.sensor import (
+from sdformat_mjcf.mjcf_to_sdformat.converters.joint import (mjcf_joint_to_sdf,
+                                                             add_fixed_joint)
+from sdformat_mjcf.mjcf_to_sdformat.converters.light import mjcf_light_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.link import mjcf_body_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.sensor import (
     mjcf_camera_sensor_to_sdf, mjcf_accelerometer_gyro_sensor_to_sdf,
     mjcf_force_torque_sensor_to_sdf)
 
-import sdformat_mjcf_utils.sdf_utils as su
-from sdformat_mjcf_utils.defaults import MjcfModifiers
+import sdformat_mjcf.utils.sdf_utils as su
+from sdformat_mjcf.utils.defaults import MjcfModifiers
 
 import sdformat as sdf
 
diff --git a/mjcf_to_sdformat/mjcf_to_sdformat/mjcf_to_sdformat.py b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/mjcf_to_sdformat.py
similarity index 93%
rename from mjcf_to_sdformat/mjcf_to_sdformat/mjcf_to_sdformat.py
rename to sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/mjcf_to_sdformat.py
index 302e22a..0c4bb7a 100644
--- a/mjcf_to_sdformat/mjcf_to_sdformat/mjcf_to_sdformat.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/mjcf_to_sdformat/mjcf_to_sdformat.py
@@ -15,7 +15,9 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
 
 import sdformat as sdf
 
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/__init__.py
similarity index 100%
rename from sdformat_to_mjcf/sdformat_to_mjcf/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/__init__.py
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/cli.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/cli.py
similarity index 93%
rename from sdformat_to_mjcf/sdformat_to_mjcf/cli.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/cli.py
index 2f0c320..bf01866 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/cli.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/cli.py
@@ -14,7 +14,9 @@
 
 import sys
 import argparse
-from sdformat_to_mjcf.sformat_to_mjcf import sdformat_file_to_mjcf
+from sdformat_mjcf.sdformat_to_mjcf.sformat_to_mjcf import (
+    sdformat_file_to_mjcf,
+)
 
 
 def main(argv=None):
diff --git a/sdformat_mjcf_utils/sdformat_mjcf_utils/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/__init__.py
similarity index 100%
rename from sdformat_mjcf_utils/sdformat_mjcf_utils/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/__init__.py
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/geometry.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/geometry.py
similarity index 99%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/geometry.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/geometry.py
index d296e56..0fb2721 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/geometry.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/geometry.py
@@ -16,7 +16,7 @@
 
 import os
 
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 COLLISION_GEOM_GROUP = 3
 VISUAL_GEOM_GROUP = 0
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/joint.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/joint.py
similarity index 96%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/joint.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/joint.py
index 1a16b25..167671a 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/joint.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/joint.py
@@ -19,9 +19,12 @@
 import sdformat as sdf
 from ignition.math import Pose3d
 
-from sdformat_to_mjcf.converters.sensor import add_sensor
-from sdformat_to_mjcf.sdf_kinematics import FreeJoint, StaticFixedJoint
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.sdformat_to_mjcf.converters.sensor import add_sensor
+from sdformat_mjcf.sdformat_to_mjcf.sdf_kinematics import (
+    FreeJoint,
+    StaticFixedJoint,
+)
+import sdformat_mjcf.utils.sdf_utils as su
 
 JOINT_DEFAULT_UPPER_LIMIT = 1e16
 JOINT_DEFAULT_LOWER_LIMIT = -1e16
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/light.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/light.py
similarity index 97%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/light.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/light.py
index 43cbf7f..ccda56a 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/light.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/light.py
@@ -15,7 +15,7 @@
 """Module to convert SDFormat Lights to MJCF"""
 
 
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 import sdformat as sdf
 
 
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/link.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/link.py
similarity index 91%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/link.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/link.py
index d9e346d..7122bf1 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/link.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/link.py
@@ -12,11 +12,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from sdformat_to_mjcf.converters.geometry import add_collision, add_visual
-from sdformat_to_mjcf.converters.light import add_light
-from sdformat_to_mjcf.converters.material import add_material
-from sdformat_to_mjcf.converters.sensor import add_sensor
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.sdformat_to_mjcf.converters.geometry import (
+    add_collision,
+    add_visual,
+)
+from sdformat_mjcf.sdformat_to_mjcf.converters.light import add_light
+from sdformat_mjcf.sdformat_to_mjcf.converters.material import add_material
+from sdformat_mjcf.sdformat_to_mjcf.converters.sensor import add_sensor
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 def add_link(body, link, parent_name="world", link_pose=None):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/material.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/material.py
similarity index 100%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/material.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/material.py
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/model.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/model.py
similarity index 91%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/model.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/model.py
index 574f266..a187f81 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/model.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/model.py
@@ -14,10 +14,13 @@
 
 from dm_control import mjcf
 
-from sdformat_to_mjcf.sdf_kinematics import KinematicHierarchy, FreeJoint
-from sdformat_to_mjcf.converters.link import add_link
-from sdformat_to_mjcf.converters.joint import add_joint
-from sdformat_mjcf_utils.sdf_utils import graph_resolver
+from sdformat_mjcf.sdformat_to_mjcf.sdf_kinematics import (
+    KinematicHierarchy,
+    FreeJoint,
+)
+from sdformat_mjcf.sdformat_to_mjcf.converters.link import add_link
+from sdformat_mjcf.sdformat_to_mjcf.converters.joint import add_joint
+from sdformat_mjcf.utils.sdf_utils import graph_resolver
 import sdformat as sdf
 
 
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/root.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/root.py
similarity index 93%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/root.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/root.py
index 39c0ebc..715e930 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/root.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/root.py
@@ -14,8 +14,8 @@
 
 
 from dm_control import mjcf
-from sdformat_to_mjcf.converters.model import add_model
-from sdformat_to_mjcf.converters.world import add_world
+from sdformat_mjcf.sdformat_to_mjcf.converters.model import add_model
+from sdformat_mjcf.sdformat_to_mjcf.converters.world import add_world
 
 
 def add_root(root):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/sensor.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/sensor.py
similarity index 99%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/sensor.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/sensor.py
index 52d9f75..d307af3 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/sensor.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/sensor.py
@@ -14,7 +14,7 @@
 
 import logging
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 def add_sensor(body, sensor):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/world.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/world.py
similarity index 88%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/world.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/world.py
index 093e557..45c3bf1 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/converters/world.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/converters/world.py
@@ -12,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from sdformat_to_mjcf.converters.light import add_light
-from sdformat_to_mjcf.converters.model import add_model
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.sdformat_to_mjcf.converters.light import add_light
+from sdformat_mjcf.sdformat_to_mjcf.converters.model import add_model
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 def add_world(mjcf_out, world):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/sdf_kinematics.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sdf_kinematics.py
similarity index 99%
rename from sdformat_to_mjcf/sdformat_to_mjcf/sdf_kinematics.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sdf_kinematics.py
index 71e34ef..69c7c37 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/sdf_kinematics.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sdf_kinematics.py
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 import sdformat as sdf
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 class StaticFixedJoint(sdf.Joint):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py
similarity index 95%
rename from sdformat_to_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py
rename to sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py
index 8d3b9c6..093f06e 100644
--- a/sdformat_to_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/sdformat_to_mjcf/sformat_to_mjcf.py
@@ -17,7 +17,7 @@
 
 import sdformat as sdf
 from dm_control.mjcf.export_with_assets import export_with_assets
-from sdformat_to_mjcf.converters.root import add_root
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
 
 
 def sdformat_file_to_mjcf(input_file, output_file):
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/converters/__init__.py b/sdformat_mjcf/src/sdformat_mjcf/utils/__init__.py
similarity index 100%
rename from sdformat_to_mjcf/sdformat_to_mjcf/converters/__init__.py
rename to sdformat_mjcf/src/sdformat_mjcf/utils/__init__.py
diff --git a/sdformat_mjcf_utils/sdformat_mjcf_utils/defaults.py b/sdformat_mjcf/src/sdformat_mjcf/utils/defaults.py
similarity index 99%
rename from sdformat_mjcf_utils/sdformat_mjcf_utils/defaults.py
rename to sdformat_mjcf/src/sdformat_mjcf/utils/defaults.py
index 0bfc76e..982f994 100644
--- a/sdformat_mjcf_utils/sdformat_mjcf_utils/defaults.py
+++ b/sdformat_mjcf/src/sdformat_mjcf/utils/defaults.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 from dm_control import mjcf
+
 # Based on https://github.com/deepmind/mujoco/blob/d7ae7f54338a8ea02c34f4a969722182481eb72b/unity/Runtime/Importer/MjXmlModifiers.cs  # noqa
 
 
diff --git a/sdformat_mjcf_utils/sdformat_mjcf_utils/sdf_utils.py b/sdformat_mjcf/src/sdformat_mjcf/utils/sdf_utils.py
similarity index 100%
rename from sdformat_mjcf_utils/sdformat_mjcf_utils/sdf_utils.py
rename to sdformat_mjcf/src/sdformat_mjcf/utils/sdf_utils.py
diff --git a/sdformat_mjcf_utils/tox.ini b/sdformat_mjcf/tox.ini
similarity index 100%
rename from sdformat_mjcf_utils/tox.ini
rename to sdformat_mjcf/tox.ini
diff --git a/sdformat_mjcf_utils/LICENSE b/sdformat_mjcf_utils/LICENSE
deleted file mode 100644
index 5d56e05..0000000
--- a/sdformat_mjcf_utils/LICENSE
+++ /dev/null
@@ -1,16 +0,0 @@
-Software License Agreement (Apache License)
-
-Copyright 2022 Open Source Robotics Foundation
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-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.
-
diff --git a/sdformat_mjcf_utils/README.md b/sdformat_mjcf_utils/README.md
deleted file mode 100644
index 49d6b0f..0000000
--- a/sdformat_mjcf_utils/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Utils for converting between MJCF and SDFormat
-
-To start development, create a python3 virtual environment, upgrade pip and
-install dm-control
-
-```
-python3 -m venv path/to/venv --system-site-packages
-. path/to/venv/bin/activate
-
-pip install -U pip
-pip install dm-control
-```
-
-Install `python3-ignition-math7` from the
-[nightly](https://gazebosim.org/docs/all/release#type-of-releases) repo.
-
-Build `libsdformat` from source from the `ahcorde/python/all` branch and add
-the installation path to your `LD_LIBRARY_PATH` and `PYTHONPATH`.
-
-```
-export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$INSTALL_DIR/lib"
-export PYTHONPATH="$PYTHONPATH:$INSTALL_DIR/lib/python"
-```
-
-where `$INSTALL_DIR` is the installation directory you used when building
-libsdformat.
-
-Install the `sdformat_mjcf_utils` packages in "editable" mode
-
-```
-pip install -e path/to/sdformat_mjcf_utils
-```
diff --git a/sdformat_mjcf_utils/pyproject.toml b/sdformat_mjcf_utils/pyproject.toml
deleted file mode 100644
index 9ebf206..0000000
--- a/sdformat_mjcf_utils/pyproject.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-[build-system]
-# These are the assumed default build requirements from pip:
-# https://pip.pypa.io/en/stable/reference/pip/#pep-517-and-518-support
-requires = ["setuptools>=43.0.0", "wheel"]
-build-backend = "setuptools.build_meta"
diff --git a/sdformat_mjcf_utils/sdformat_mjcf_utils/__version__.py b/sdformat_mjcf_utils/sdformat_mjcf_utils/__version__.py
deleted file mode 100644
index 8b29c93..0000000
--- a/sdformat_mjcf_utils/sdformat_mjcf_utils/__version__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-VERSION = (0, 0, 1)
-
-__version__ = '.'.join(map(str, VERSION))
diff --git a/sdformat_mjcf_utils/setup.cfg b/sdformat_mjcf_utils/setup.cfg
deleted file mode 100644
index 5838cae..0000000
--- a/sdformat_mjcf_utils/setup.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-[metadata]
-# This includes the license file(s) in the wheel.
-# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
-license_files = LICENSE
diff --git a/sdformat_mjcf_utils/setup.py b/sdformat_mjcf_utils/setup.py
deleted file mode 100644
index ba1067b..0000000
--- a/sdformat_mjcf_utils/setup.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from setuptools import setup, find_packages
-import pathlib
-
-here = pathlib.Path(__file__).parent.resolve()
-long_description = (here / "README.md").read_text(encoding="utf-8")
-license_content = (here / "LICENSE").read_text(encoding="utf-8")
-
-
-setup(
-    name='sdformat_mjcf_utils',
-    version='0.0.1',
-    description='Utils to convert MJCF file to SDFormat',
-    long_description=long_description,
-    long_description_content_type="text/markdown",
-    author='Open Robotics',
-    author_email='info@openrobotics.org',
-    url='https://github.com/gazebosim/gz-mujoco',
-    license=license_content,
-    packages=find_packages(exclude=('tests', 'docs')),
-    test_suite='tests',
-)
diff --git a/sdformat_to_mjcf/LICENSE b/sdformat_to_mjcf/LICENSE
deleted file mode 100644
index 5d56e05..0000000
--- a/sdformat_to_mjcf/LICENSE
+++ /dev/null
@@ -1,16 +0,0 @@
-Software License Agreement (Apache License)
-
-Copyright 2022 Open Source Robotics Foundation
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-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.
-
diff --git a/sdformat_to_mjcf/pyproject.toml b/sdformat_to_mjcf/pyproject.toml
deleted file mode 100644
index 9ebf206..0000000
--- a/sdformat_to_mjcf/pyproject.toml
+++ /dev/null
@@ -1,5 +0,0 @@
-[build-system]
-# These are the assumed default build requirements from pip:
-# https://pip.pypa.io/en/stable/reference/pip/#pep-517-and-518-support
-requires = ["setuptools>=43.0.0", "wheel"]
-build-backend = "setuptools.build_meta"
diff --git a/sdformat_to_mjcf/sdformat_to_mjcf/__version__.py b/sdformat_to_mjcf/sdformat_to_mjcf/__version__.py
deleted file mode 100644
index 8b29c93..0000000
--- a/sdformat_to_mjcf/sdformat_to_mjcf/__version__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-VERSION = (0, 0, 1)
-
-__version__ = '.'.join(map(str, VERSION))
diff --git a/sdformat_to_mjcf/setup.cfg b/sdformat_to_mjcf/setup.cfg
deleted file mode 100644
index 5838cae..0000000
--- a/sdformat_to_mjcf/setup.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-[metadata]
-# This includes the license file(s) in the wheel.
-# https://wheel.readthedocs.io/en/stable/user_guide.html#including-license-files-in-the-generated-wheel-file
-license_files = LICENSE
diff --git a/sdformat_to_mjcf/tox.ini b/sdformat_to_mjcf/tox.ini
deleted file mode 100644
index 30058ed..0000000
--- a/sdformat_to_mjcf/tox.ini
+++ /dev/null
@@ -1,29 +0,0 @@
-# See https://github.com/pypa/sampleproject/blob/main/tox.ini
-# for the original commented file
-
-[tox]
-envlist = py{37,38,39,310}
-
-minversion = 3.3.0
-isolated_build = true
-
-[testenv]
-# pythonpath has to be passed through to the tox to get python3-ignition-mathX and python3-sdformatX
-passenv = PYTHONPATH
-deps =
-    check-manifest >= 0.42
-    flake8
-    numpy
-    dm_control
-    coverage
-    ../sdformat_mjcf_utils
-commands =
-    check-manifest --ignore 'tox.ini,tests/**'
-    python setup.py check -m -s
-    python3 -m flake8 .
-    coverage run -m unittest {posargs}
-    coverage xml
-
-[flake8]
-exclude = .tox,*.egg
-select = E,W,F


Test patch:
diff --git a/mjcf_to_sdformat/tests/helpers.py b/mjcf_to_sdformat/tests/helpers.py
deleted file mode 100644
index ab77a1f..0000000
--- a/mjcf_to_sdformat/tests/helpers.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2022 Open Source Robotics Foundation
-
-# Licensed under the Apache License, version 2.0 (the "License")
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-
-#       http://www.apache.org/licenses/LICENSE-2.0
-
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# 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.
-
-"""Test helpers"""
-
-import pathlib
-
-TEST_RESOURCES_DIR = pathlib.Path(__file__).resolve().parent / 'resources'
diff --git a/sdformat_to_mjcf/tests/__init__.py b/sdformat_mjcf/tests/__init__.py
similarity index 100%
rename from sdformat_to_mjcf/tests/__init__.py
rename to sdformat_mjcf/tests/__init__.py
diff --git a/sdformat_to_mjcf/tests/helpers.py b/sdformat_mjcf/tests/helpers.py
similarity index 93%
rename from sdformat_to_mjcf/tests/helpers.py
rename to sdformat_mjcf/tests/helpers.py
index 8c96e3c..5a20656 100644
--- a/sdformat_to_mjcf/tests/helpers.py
+++ b/sdformat_mjcf/tests/helpers.py
@@ -18,9 +18,11 @@
 import unittest
 from contextlib import contextmanager
 
-from sdformat_mjcf_utils import sdf_utils as su
+from sdformat_mjcf.utils import sdf_utils as su
 
-TEST_RESOURCES_DIR = pathlib.Path(__file__).resolve().parent / 'resources'
+
+def get_resources_dir():
+    return pathlib.Path(__file__).resolve().parent / "resources"
 
 
 class TestGraphResolverImpl(su.GraphResolverImplBase):
diff --git a/sdformat_to_mjcf/tests/resources/box_obj/textures/albedo_map.png b/sdformat_mjcf/tests/mjcf_to_sdformat/__init__.py
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box_obj/textures/albedo_map.png
rename to sdformat_mjcf/tests/mjcf_to_sdformat/__init__.py
diff --git a/mjcf_to_sdformat/tests/test_add_mjcf_geometry_to_sdf.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_geometry_to_sdf.py
similarity index 98%
rename from mjcf_to_sdformat/tests/test_add_mjcf_geometry_to_sdf.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_geometry_to_sdf.py
index 82b3d0e..1c469e6 100644
--- a/mjcf_to_sdformat/tests/test_add_mjcf_geometry_to_sdf.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_geometry_to_sdf.py
@@ -19,9 +19,9 @@
 from ignition.math import Vector3d
 from dm_control import mjcf
 
-from mjcf_to_sdformat.converters import geometry as geometry_conv
+from sdformat_mjcf.mjcf_to_sdformat.converters import geometry as geometry_conv
 
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 class GeometryTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_add_mjcf_light_to_sdf.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_light_to_sdf.py
similarity index 98%
rename from mjcf_to_sdformat/tests/test_add_mjcf_light_to_sdf.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_light_to_sdf.py
index 41081a3..c820fe6 100644
--- a/mjcf_to_sdformat/tests/test_add_mjcf_light_to_sdf.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_light_to_sdf.py
@@ -20,7 +20,7 @@
 
 import sdformat as sdf
 
-from mjcf_to_sdformat.converters import light as light_conv
+from sdformat_mjcf.mjcf_to_sdformat.converters import light as light_conv
 
 
 class LightTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_add_mjcf_worldbody_to_sdf.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_worldbody_to_sdf.py
similarity index 98%
rename from mjcf_to_sdformat/tests/test_add_mjcf_worldbody_to_sdf.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_worldbody_to_sdf.py
index 3383f0d..9088da4 100644
--- a/mjcf_to_sdformat/tests/test_add_mjcf_worldbody_to_sdf.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_add_mjcf_worldbody_to_sdf.py
@@ -23,10 +23,14 @@
 
 import sdformat as sdf
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
+import sdformat_mjcf.utils.sdf_utils as su
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class ModelTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_defaults.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_defaults.py
similarity index 96%
rename from mjcf_to_sdformat/tests/test_defaults.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_defaults.py
index 0a6e97e..7dfa354 100644
--- a/mjcf_to_sdformat/tests/test_defaults.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_defaults.py
@@ -17,11 +17,15 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
 
 import sdformat as sdf
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class DefaultsTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_force_torque.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_force_torque.py
similarity index 94%
rename from mjcf_to_sdformat/tests/test_force_torque.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_force_torque.py
index 12c9077..c97d623 100644
--- a/mjcf_to_sdformat/tests/test_force_torque.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_force_torque.py
@@ -20,11 +20,14 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf)
 
 import sdformat as sdf
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class ForceTorqueTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_imu.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_imu.py
similarity index 94%
rename from mjcf_to_sdformat/tests/test_imu.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_imu.py
index 03cdf51..262fe26 100644
--- a/mjcf_to_sdformat/tests/test_imu.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_imu.py
@@ -20,11 +20,14 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf)
 
 import sdformat as sdf
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class ImuTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_mjcf_material_to_sdf.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_material_to_sdf.py
similarity index 93%
rename from mjcf_to_sdformat/tests/test_mjcf_material_to_sdf.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_material_to_sdf.py
index e482bd5..5ea59d1 100644
--- a/mjcf_to_sdformat/tests/test_mjcf_material_to_sdf.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_material_to_sdf.py
@@ -19,12 +19,18 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.material import mjcf_material_to_sdf
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.material import (
+    mjcf_material_to_sdf,
+)
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
 
 import sdformat as sdf
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class MaterialTest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_mjcf_sensor_to_sdf.py b/sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_sensor_to_sdf.py
similarity index 93%
rename from mjcf_to_sdformat/tests/test_mjcf_sensor_to_sdf.py
rename to sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_sensor_to_sdf.py
index 893972e..e2bd4f7 100644
--- a/mjcf_to_sdformat/tests/test_mjcf_sensor_to_sdf.py
+++ b/sdformat_mjcf/tests/mjcf_to_sdformat/test_mjcf_sensor_to_sdf.py
@@ -19,13 +19,17 @@
 
 from ignition.math import Vector3d
 
-from mjcf_to_sdformat.converters import sensor as sensor_conv
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters import sensor as sensor_conv
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
 
 import sdformat as sdf
 
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class SensorTest(unittest.TestCase):
diff --git a/sdformat_to_mjcf/tests/resources/box/model.config b/sdformat_mjcf/tests/resources/box/model.config
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box/model.config
rename to sdformat_mjcf/tests/resources/box/model.config
diff --git a/sdformat_to_mjcf/tests/resources/box/model.sdf b/sdformat_mjcf/tests/resources/box/model.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box/model.sdf
rename to sdformat_mjcf/tests/resources/box/model.sdf
diff --git a/sdformat_to_mjcf/tests/resources/box_obj/meshes/box.mtl b/sdformat_mjcf/tests/resources/box_obj/meshes/box.mtl
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box_obj/meshes/box.mtl
rename to sdformat_mjcf/tests/resources/box_obj/meshes/box.mtl
diff --git a/sdformat_to_mjcf/tests/resources/box_obj/meshes/box.obj b/sdformat_mjcf/tests/resources/box_obj/meshes/box.obj
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box_obj/meshes/box.obj
rename to sdformat_mjcf/tests/resources/box_obj/meshes/box.obj
diff --git a/sdformat_to_mjcf/tests/resources/box_obj/model.sdf b/sdformat_mjcf/tests/resources/box_obj/model.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/box_obj/model.sdf
rename to sdformat_mjcf/tests/resources/box_obj/model.sdf
diff --git a/sdformat_mjcf/tests/resources/box_obj/textures/albedo_map.png b/sdformat_mjcf/tests/resources/box_obj/textures/albedo_map.png
new file mode 100644
index 0000000..e69de29
diff --git a/sdformat_to_mjcf/tests/resources/double_pendulum.sdf b/sdformat_mjcf/tests/resources/double_pendulum.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/double_pendulum.sdf
rename to sdformat_mjcf/tests/resources/double_pendulum.sdf
diff --git a/sdformat_to_mjcf/tests/resources/double_pendulum/double_pendulum-1.5.sdf b/sdformat_mjcf/tests/resources/double_pendulum/double_pendulum-1.5.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/double_pendulum/double_pendulum-1.5.sdf
rename to sdformat_mjcf/tests/resources/double_pendulum/double_pendulum-1.5.sdf
diff --git a/sdformat_to_mjcf/tests/resources/double_pendulum/model.config b/sdformat_mjcf/tests/resources/double_pendulum/model.config
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/double_pendulum/model.config
rename to sdformat_mjcf/tests/resources/double_pendulum/model.config
diff --git a/sdformat_to_mjcf/tests/resources/invalid_xml_syntax.sdf b/sdformat_mjcf/tests/resources/invalid_xml_syntax.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/invalid_xml_syntax.sdf
rename to sdformat_mjcf/tests/resources/invalid_xml_syntax.sdf
diff --git a/sdformat_to_mjcf/tests/resources/lights.sdf b/sdformat_mjcf/tests/resources/lights.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/lights.sdf
rename to sdformat_mjcf/tests/resources/lights.sdf
diff --git a/sdformat_to_mjcf/tests/resources/model_mass_zero.sdf b/sdformat_mjcf/tests/resources/model_mass_zero.sdf
similarity index 100%
rename from sdformat_to_mjcf/tests/resources/model_mass_zero.sdf
rename to sdformat_mjcf/tests/resources/model_mass_zero.sdf
diff --git a/mjcf_to_sdformat/tests/resources/tennis_ball.png b/sdformat_mjcf/tests/resources/tennis_ball.png
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/tennis_ball.png
rename to sdformat_mjcf/tests/resources/tennis_ball.png
diff --git a/mjcf_to_sdformat/tests/resources/tennis_ball.xml b/sdformat_mjcf/tests/resources/tennis_ball.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/tennis_ball.xml
rename to sdformat_mjcf/tests/resources/tennis_ball.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_defaults.xml b/sdformat_mjcf/tests/resources/test_defaults.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_defaults.xml
rename to sdformat_mjcf/tests/resources/test_defaults.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_defaults_inheritance.xml b/sdformat_mjcf/tests/resources/test_defaults_inheritance.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_defaults_inheritance.xml
rename to sdformat_mjcf/tests/resources/test_defaults_inheritance.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_force_torque.xml b/sdformat_mjcf/tests/resources/test_force_torque.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_force_torque.xml
rename to sdformat_mjcf/tests/resources/test_force_torque.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_imu.xml b/sdformat_mjcf/tests/resources/test_imu.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_imu.xml
rename to sdformat_mjcf/tests/resources/test_imu.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_joints.xml b/sdformat_mjcf/tests/resources/test_joints.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_joints.xml
rename to sdformat_mjcf/tests/resources/test_joints.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_mujoco.xml b/sdformat_mjcf/tests/resources/test_mujoco.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_mujoco.xml
rename to sdformat_mjcf/tests/resources/test_mujoco.xml
diff --git a/mjcf_to_sdformat/tests/resources/test_no_gravity.xml b/sdformat_mjcf/tests/resources/test_no_gravity.xml
similarity index 100%
rename from mjcf_to_sdformat/tests/resources/test_no_gravity.xml
rename to sdformat_mjcf/tests/resources/test_no_gravity.xml
diff --git a/sdformat_mjcf/tests/sdformat_to_mjcf/__init__.py b/sdformat_mjcf/tests/sdformat_to_mjcf/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/sdformat_to_mjcf/tests/test_add_geometry.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_geometry.py
similarity index 96%
rename from sdformat_to_mjcf/tests/test_add_geometry.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_geometry.py
index 47b102e..9eecdc6 100644
--- a/sdformat_to_mjcf/tests/test_add_geometry.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_geometry.py
@@ -23,8 +23,9 @@
 from dm_control import mjcf
 
 from tests import helpers
-from sdformat_to_mjcf.converters import geometry as geometry_conv
-from sdformat_to_mjcf.converters.root import add_root
+from tests.helpers import get_resources_dir
+from sdformat_mjcf.sdformat_to_mjcf.converters import geometry as geometry_conv
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
 
 
 class GeometryTest(helpers.TestCase):
@@ -120,9 +121,8 @@ def test_heightmap(self):
     def test_mesh(self):
         mesh = sdf.Mesh()
         mesh.set_uri("meshes/box.obj")
-        mesh.set_file_path(os.path.join(
-                           os.path.dirname(os.path.abspath(__file__)),
-                           "resources/box_obj/model.sdf"))
+        mesh.set_file_path(
+            os.path.join(get_resources_dir(), "box_obj", "model.sdf"))
 
         geometry = sdf.Geometry()
         geometry.set_mesh_shape(mesh)
diff --git a/sdformat_to_mjcf/tests/test_add_joint.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_joint.py
similarity index 98%
rename from sdformat_to_mjcf/tests/test_add_joint.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_joint.py
index 08f52db..d0f5b9e 100644
--- a/sdformat_to_mjcf/tests/test_add_joint.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_joint.py
@@ -21,9 +21,12 @@
 from ignition.math import Pose3d, Vector3d
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.joint import add_joint
-from sdformat_to_mjcf.sdf_kinematics import FreeJoint, StaticFixedJoint
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.sdformat_to_mjcf.converters.joint import add_joint
+from sdformat_mjcf.sdformat_to_mjcf.sdf_kinematics import (
+    FreeJoint,
+    StaticFixedJoint,
+)
+import sdformat_mjcf.utils.sdf_utils as su
 from tests import helpers
 
 
diff --git a/sdformat_to_mjcf/tests/test_add_light.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_light.py
similarity index 97%
rename from sdformat_to_mjcf/tests/test_add_light.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_light.py
index 492324e..e084f41 100644
--- a/sdformat_to_mjcf/tests/test_add_light.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_light.py
@@ -22,8 +22,8 @@
 
 import sdformat as sdf
 
-from sdformat_to_mjcf.converters.light import add_light
-from sdformat_to_mjcf.converters.link import add_link
+from sdformat_mjcf.sdformat_to_mjcf.converters.light import add_light
+from sdformat_mjcf.sdformat_to_mjcf.converters.link import add_link
 
 from tests import helpers
 
diff --git a/sdformat_to_mjcf/tests/test_add_link.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_link.py
similarity index 98%
rename from sdformat_to_mjcf/tests/test_add_link.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_link.py
index 54360b9..7ed092f 100644
--- a/sdformat_to_mjcf/tests/test_add_link.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_link.py
@@ -20,8 +20,8 @@
 from ignition.math import Color, Inertiald, Pose3d, MassMatrix3d, Vector3d
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.link import add_link
-from sdformat_to_mjcf.converters.root import add_root
+from sdformat_mjcf.sdformat_to_mjcf.converters.link import add_link
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
 from tests import helpers
 
 
diff --git a/sdformat_to_mjcf/tests/test_add_material.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_material.py
similarity index 88%
rename from sdformat_to_mjcf/tests/test_add_material.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_material.py
index 28027cb..b7891b6 100644
--- a/sdformat_to_mjcf/tests/test_add_material.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_material.py
@@ -21,8 +21,9 @@
 
 import sdformat as sdf
 
-from sdformat_to_mjcf.converters.material import add_material
+from sdformat_mjcf.sdformat_to_mjcf.converters.material import add_material
 from tests import helpers
+from tests.helpers import get_resources_dir
 
 
 class MaterialTest(helpers.TestCase):
@@ -31,9 +32,9 @@ def test_material_pbr(self):
         pbr = sdf.Pbr()
         workflow = sdf.PbrWorkflow()
         workflow.set_type(sdf.PbrWorkflowType.METAL)
-        workflow.set_albedo_map(os.path.join(
-                                os.path.dirname(os.path.abspath(__file__)),
-                                "resources/box_obj/textures/albedo_map.png"))
+        workflow.set_albedo_map(
+            os.path.join(get_resources_dir(), "box_obj", "textures",
+                         "albedo_map.png"))
         pbr.set_workflow(workflow.type(), workflow)
 
         material = sdf.Material()
@@ -68,9 +69,9 @@ def test_material_pbr_bad_extension(self):
         pbr = sdf.Pbr()
         workflow = sdf.PbrWorkflow()
         workflow.set_type(sdf.PbrWorkflowType.METAL)
-        workflow.set_albedo_map(os.path.join(
-                                os.path.dirname(os.path.abspath(__file__)),
-                                "resources/box_obj/textures/albedo_map"))
+        workflow.set_albedo_map(
+            os.path.join(get_resources_dir(), "box_obj", "textures",
+                         "albedo_map"))
         pbr.set_workflow(workflow.type(), workflow)
 
         material = sdf.Material()
diff --git a/sdformat_to_mjcf/tests/test_add_model.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_model.py
similarity index 97%
rename from sdformat_to_mjcf/tests/test_add_model.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_model.py
index 2cbd67d..db10291 100644
--- a/sdformat_to_mjcf/tests/test_add_model.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_model.py
@@ -20,9 +20,9 @@
 from ignition.math import Pose3d
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.model import add_model
-from sdformat_to_mjcf.converters.root import add_root
-import sdformat_mjcf_utils.sdf_utils as su
+from sdformat_mjcf.sdformat_to_mjcf.converters.model import add_model
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
+import sdformat_mjcf.utils.sdf_utils as su
 from tests import helpers
 
 
diff --git a/sdformat_to_mjcf/tests/test_add_root.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_root.py
similarity index 96%
rename from sdformat_to_mjcf/tests/test_add_root.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_root.py
index b567c61..7981389 100644
--- a/sdformat_to_mjcf/tests/test_add_root.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_root.py
@@ -19,7 +19,7 @@
 from ignition.math import Pose3d
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.root import add_root
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
 from tests import helpers
 
 
diff --git a/sdformat_to_mjcf/tests/test_add_sensor.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_sensor.py
similarity index 99%
rename from sdformat_to_mjcf/tests/test_add_sensor.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_sensor.py
index 0174a38..3b5d964 100644
--- a/sdformat_to_mjcf/tests/test_add_sensor.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_sensor.py
@@ -20,7 +20,7 @@
 from ignition.math import Pose3d
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.sensor import add_sensor
+from sdformat_mjcf.sdformat_to_mjcf.converters.sensor import add_sensor
 from tests import helpers
 
 
diff --git a/sdformat_to_mjcf/tests/test_add_world.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_world.py
similarity index 91%
rename from sdformat_to_mjcf/tests/test_add_world.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_add_world.py
index 38cac83..78b219c 100644
--- a/sdformat_to_mjcf/tests/test_add_world.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_add_world.py
@@ -19,9 +19,10 @@
 import sdformat as sdf
 from dm_control import mjcf
 
-from sdformat_to_mjcf.converters.world import add_world
+from sdformat_mjcf.sdformat_to_mjcf.converters.world import add_world
 from tests import helpers
-import sdformat_mjcf_utils.sdf_utils as su
+from tests.helpers import get_resources_dir
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 class WorldTest(helpers.TestCase):
@@ -32,9 +33,7 @@ def setUp(self):
 
     def test_world(self):
         root = sdf.Root()
-        root.load(os.path.join(
-                  os.path.dirname(os.path.abspath(__file__)),
-                  "resources/lights.sdf"))
+        root.load(os.path.join(get_resources_dir(), "lights.sdf"))
 
         world = root.world_by_index(0)
 
@@ -96,9 +95,7 @@ def test_world(self):
 
     def test_world_link_mass_zero(self):
         root = sdf.Root()
-        root.load(os.path.join(
-                  os.path.dirname(os.path.abspath(__file__)),
-                  "resources/model_mass_zero.sdf"))
+        root.load(os.path.join(get_resources_dir(), "model_mass_zero.sdf"))
 
         world = root.world_by_index(0)
         with self.assertRaises(RuntimeError):
diff --git a/sdformat_to_mjcf/tests/test_cli.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_cli.py
similarity index 94%
rename from sdformat_to_mjcf/tests/test_cli.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_cli.py
index 5c83c21..e495d51 100644
--- a/sdformat_to_mjcf/tests/test_cli.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_cli.py
@@ -20,8 +20,10 @@
 import numpy as np
 from dm_control import mujoco
 
-from sdformat_to_mjcf import cli
-from tests.helpers import TEST_RESOURCES_DIR
+from sdformat_mjcf.sdformat_to_mjcf import cli
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class CLITest(unittest.TestCase):
diff --git a/mjcf_to_sdformat/tests/test_joints.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_joints.py
similarity index 96%
rename from mjcf_to_sdformat/tests/test_joints.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_joints.py
index cc75b64..c2e91b1 100644
--- a/mjcf_to_sdformat/tests/test_joints.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_joints.py
@@ -19,11 +19,15 @@
 from dm_control import mjcf
 from dm_control import mujoco
 
-from mjcf_to_sdformat.converters.world import mjcf_worldbody_to_sdf
+from sdformat_mjcf.mjcf_to_sdformat.converters.world import (
+    mjcf_worldbody_to_sdf,
+)
 
 import sdformat as sdf
 
-from tests.helpers import TEST_RESOURCES_DIR
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class JointTest(unittest.TestCase):
diff --git a/sdformat_to_mjcf/tests/test_name_collisions.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_name_collisions.py
similarity index 97%
rename from sdformat_to_mjcf/tests/test_name_collisions.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_name_collisions.py
index d54995d..20f03a8 100644
--- a/sdformat_to_mjcf/tests/test_name_collisions.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_name_collisions.py
@@ -18,8 +18,8 @@
 from tests import helpers
 
 from dm_control import mjcf
-from sdformat_to_mjcf.converters.geometry import add_collision
-from sdformat_to_mjcf.converters.root import add_root
+from sdformat_mjcf.sdformat_to_mjcf.converters.geometry import add_collision
+from sdformat_mjcf.sdformat_to_mjcf.converters.root import add_root
 
 
 class NameCollisionTest(helpers.TestCase):
diff --git a/sdformat_to_mjcf/tests/test_sdf_kinematics.py b/sdformat_mjcf/tests/sdformat_to_mjcf/test_sdf_kinematics.py
similarity index 93%
rename from sdformat_to_mjcf/tests/test_sdf_kinematics.py
rename to sdformat_mjcf/tests/sdformat_to_mjcf/test_sdf_kinematics.py
index 7bbb4b7..95b4980 100644
--- a/sdformat_to_mjcf/tests/test_sdf_kinematics.py
+++ b/sdformat_mjcf/tests/sdformat_to_mjcf/test_sdf_kinematics.py
@@ -15,8 +15,10 @@
 import unittest
 
 import sdformat as sdf
-from sdformat_to_mjcf.sdf_kinematics import KinematicHierarchy
-from tests.helpers import TEST_RESOURCES_DIR
+from sdformat_mjcf.sdformat_to_mjcf.sdf_kinematics import KinematicHierarchy
+from tests.helpers import get_resources_dir
+
+TEST_RESOURCES_DIR = get_resources_dir()
 
 
 class TreeTest(unittest.TestCase):
diff --git a/sdformat_mjcf_utils/tests/test_sdf_utils.py b/sdformat_mjcf/tests/test_sdf_utils.py
similarity index 97%
rename from sdformat_mjcf_utils/tests/test_sdf_utils.py
rename to sdformat_mjcf/tests/test_sdf_utils.py
index 6a69466..7ae7100 100644
--- a/sdformat_mjcf_utils/tests/test_sdf_utils.py
+++ b/sdformat_mjcf/tests/test_sdf_utils.py
@@ -18,7 +18,7 @@
 from ignition.math import Pose3d, Vector3d
 
 from tests import helpers
-import sdformat_mjcf_utils.sdf_utils as su
+import sdformat_mjcf.utils.sdf_utils as su
 
 
 class GraphResolverTest(unittest.TestCase):