diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 5c50b59..e987269 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,8 +18,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- - name: Upgrade pip
- run: python -m pip install --upgrade pip setuptools
- name: Install dependencies
run: |
pip install .[dev]
diff --git a/.hatch_build.py b/.hatch_build.py
new file mode 100644
index 0000000..e6bef8a
--- /dev/null
+++ b/.hatch_build.py
@@ -0,0 +1,22 @@
+# https://hatch.pypa.io/latest/how-to/config/dynamic-metadata/
+import os
+import typing as t
+
+from hatchling.metadata.plugin.interface import MetadataHookInterface
+
+HERE = os.path.dirname(__file__)
+
+
+class MetaDataHook(MetadataHookInterface):
+ def update(self, metadata: dict[str, t.Any]) -> None:
+ about = load_about()
+ metadata["version"] = about["__version__"]
+
+
+def load_about() -> dict[str, str]:
+ about: dict[str, str] = {}
+ with open(
+ os.path.join(HERE, "tutorcredentials", "__about__.py"), "rt", encoding="utf-8"
+ ) as f:
+ exec(f.read(), about) # pylint: disable=exec-used
+ return about
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 51775a3..0000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-recursive-include tutorcredentials/patches *
-recursive-include tutorcredentials/templates *
diff --git a/README.rst b/README.rst
index d27cc21..8d8c7f2 100644
--- a/README.rst
+++ b/README.rst
@@ -107,7 +107,7 @@ This plugin was initially developed and open sourced to the community thanks to
Troubleshooting
---------------
-This Tutor plugin is maintained by Muhammad Faraz Maqsood from `Edly `__. Community support is available from the official `Open edX forum `__. Do you need help with this plugin? See the `troubleshooting `__ section from the Tutor documentation.
+This Tutor plugin is maintained by Muhammad Labeeb from `Edly `__. Community support is available from the official `Open edX forum `__. Do you need help with this plugin? See the `troubleshooting `__ section from the Tutor documentation.
License
-------
diff --git a/changelog.d/20250127_130934_mlabeeb03_pyproject_toml.md b/changelog.d/20250127_130934_mlabeeb03_pyproject_toml.md
new file mode 100644
index 0000000..70478ae
--- /dev/null
+++ b/changelog.d/20250127_130934_mlabeeb03_pyproject_toml.md
@@ -0,0 +1,2 @@
+- [Improvement] Migrate packaging from setup.py/setuptools to pyproject.toml/hatch. (by @mlabeeb03)
+ - For more details view tutor core PR: https://github.com/overhangio/tutor/pull/1163
diff --git a/pyproject.toml b/pyproject.toml
index d1e6ae6..4631800 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,2 +1,71 @@
+# https://packaging.python.org/en/latest/tutorials/packaging-projects/
+# https://hatch.pypa.io/latest/config/build/
+
+[project]
+name = "tutor-credentials"
+license = { text = "AGPL-3.0-only" }
+authors = [
+ {name = "Lawrence McDaniel"},
+ {email = "lpm0073@gmail.com"},
+]
+maintainers = [
+ {name = "Muhammad Labeeb"},
+ {email = "muhammad.labeeb@arbisoft.com"},
+]
+description = "A Tutor plugin for Open edX Credentials service"
+readme = {file = "README.rst", content-type = "text/x-rst"}
+requires-python = ">= 3.9"
+classifiers = [
+ "Development Status :: 5 - Production/Stable",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: GNU Affero General Public License v3",
+ "Operating System :: OS Independent",
+ "Programming Language :: Python",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
+]
+dependencies = [
+ "tutor>=19.0.0,<20.0.0",
+ "tutor-discovery>=19.0.0,<20.0.0",
+ "tutor-mfe>=19.0.0,<20.0.0"
+]
+# these fields will be set by hatch_build.py
+dynamic = ["version"]
+
+[project.optional-dependencies]
+dev = [
+ "tutor[dev]>=19.0.0,<20.0.0",
+ "pylint",
+ "black"
+]
+
+[project.entry-points."tutor.plugin.v1"]
+credentials = "tutorcredentials.plugin"
+
+# https://packaging.python.org/en/latest/specifications/well-known-project-urls/#well-known-labels
+[project.urls]
+Homepage = "https://docs.tutor.edly.io/"
+Documentation = "https://docs.tutor.edly.io/"
+Code = "https://github.com/overhangio/tutor-credentials"
+Issues = "https://github.com/overhangio/tutor-credentials.git/issues"
+Changelog = "https://github.com/overhangio/tutor-credentials/blob/release/CHANGELOG.md"
+Community = "https://discuss.openedx.org/tag/tutor"
+
+# hatch-specific configuration
+[tool.hatch.metadata.hooks.custom]
+path = ".hatch_build.py"
+
[build-system]
-requires = ["setuptools", "wheel"]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[tool.hatch.build.targets.sdist]
+# Disable strict naming, otherwise twine is not able to detect name/version
+strict-naming = false
+include = [ "/tutorcredentials"]
+exclude = ["tests*"]
+
+[tool.hatch.build.targets.wheel]
+packages = ["tutorcredentials"]
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 9136d05..0000000
--- a/setup.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import io
-import os
-from setuptools import setup, find_packages
-
-HERE = os.path.abspath(os.path.dirname(__file__))
-
-
-def load_readme():
- with io.open(os.path.join(HERE, "README.rst"), "rt", encoding="utf8") as f:
- return f.read()
-
-
-def load_about():
- about = {}
- with io.open(
- os.path.join(HERE, "tutorcredentials", "__about__.py"),
- "rt",
- encoding="utf-8",
- ) as f:
- exec(f.read(), about) # pylint: disable=exec-used
- return about
-
-
-ABOUT = load_about()
-
-
-setup(
- name="tutor-credentials",
- version=ABOUT["__version__"],
- url="https://github.com/overhangio/tutor-credentials.git",
- project_urls={
- "Code": "https://github.com/overhangio/tutor-credentials.git",
- "Issue tracker": "https://github.com/overhangio/tutor-credentials.git/issues",
- "Community": "https://discuss.overhang.io",
- },
- license="AGPLv3",
- author="Lawrence McDaniel",
- author_email="lpm0073@gmail.com",
- maintainer="Edly",
- maintainer_email="faraz.maqsood@arbisoft.com",
- description="A Tutor plugin for Open edX Credentials service",
- long_description=load_readme(),
- long_description_content_type="text/x-rst",
- packages=find_packages(exclude=["tests*"]),
- include_package_data=True,
- python_requires=">=3.9",
- install_requires=["tutor>=19.0.0,<20.0.0", "tutor-discovery>=19.0.0,<20.0.0", "tutor-mfe>=19.0.0,<20.0.0"],
- extras_require={"dev": ["tutor[dev]>=19.0.0,<20.0.0"]},
- entry_points={"tutor.plugin.v1": ["credentials = tutorcredentials.plugin"]},
- classifiers=[
- "Development Status :: 5 - Production/Stable",
- "Intended Audience :: Developers",
- "License :: OSI Approved :: GNU Affero General Public License v3",
- "Operating System :: OS Independent",
- "Programming Language :: Python",
- "Programming Language :: Python :: 3.9",
- "Programming Language :: Python :: 3.10",
- "Programming Language :: Python :: 3.11",
- "Programming Language :: Python :: 3.12",
- ],
-)
diff --git a/tutorcredentials/plugin.py b/tutorcredentials/plugin.py
index 9396fc7..476a80f 100644
--- a/tutorcredentials/plugin.py
+++ b/tutorcredentials/plugin.py
@@ -5,9 +5,10 @@ import typing as t
from glob import glob
import importlib_resources
+from tutormfe.hooks import MFE_APPS, MFE_ATTRS_TYPE
+
from tutor import hooks as tutor_hooks
from tutor.__about__ import __version_suffix__
-from tutormfe.hooks import MFE_APPS, MFE_ATTRS_TYPE
from .__about__ import __version__
@@ -68,7 +69,7 @@ tutor_hooks.Filters.CONFIG_OVERRIDES.add_items(
@MFE_APPS.add() # type: ignore
def _add_learner_record_mfe(
- apps: dict[str, MFE_ATTRS_TYPE]
+ apps: dict[str, MFE_ATTRS_TYPE],
) -> dict[str, MFE_ATTRS_TYPE]:
apps.update(
{