Repository: ddionrails/ddionrails

Issue:
Move import_path() method into mixin
### Subject of the issue

The System and Study model both implement the same `import_path()` method.



Discussion:

Resolving patch:
diff --git a/ddionrails/base/mixins.py b/ddionrails/base/mixins.py
--- a/ddionrails/base/mixins.py
+++ b/ddionrails/base/mixins.py
@@ -2,9 +2,11 @@
 
 """ Mixins for ddionrails.base app """
 
+import pathlib
 from typing import Dict
 
 from django import forms
+from django.conf import settings
 
 from config.helpers import render_markdown
 
@@ -145,6 +147,16 @@ def __str__(self):
         return "/".join(result)
 
 
+class ImportPathMixin:
+    """ A mixin for models to return an import_path based on their name attribute """
+
+    def import_path(self) -> pathlib.Path:
+        """ Returns the instance's import path """
+        return pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
+            self.name, settings.IMPORT_SUB_DIRECTORY
+        )
+
+
 class AdminMixin:
     """ A mixin for ModelAdmins to query related models via methods """
 
diff --git a/ddionrails/base/models.py b/ddionrails/base/models.py
--- a/ddionrails/base/models.py
+++ b/ddionrails/base/models.py
@@ -4,13 +4,13 @@
 
 from __future__ import annotations
 
-import pathlib
-
 from django.conf import settings
 from django.db import models
 
+from .mixins import ImportPathMixin
+
 
-class System(models.Model):
+class System(ImportPathMixin, models.Model):
     """ Stores a single system instance """
 
     name = settings.SYSTEM_NAME
@@ -21,12 +21,6 @@ def repo_url() -> str:
         """ Returns the system's repo url from the settings """
         return settings.SYSTEM_REPO_URL
 
-    def import_path(self) -> pathlib.Path:
-        """ Returns the system's import path """
-        return pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
-            self.name, settings.IMPORT_SUB_DIRECTORY
-        )
-
     @classmethod
     def get(cls) -> System:
         """ Returns a single system instance """
diff --git a/ddionrails/studies/models.py b/ddionrails/studies/models.py
--- a/ddionrails/studies/models.py
+++ b/ddionrails/studies/models.py
@@ -11,7 +11,7 @@
 from django.urls import reverse
 from model_utils.models import TimeStampedModel
 
-from ddionrails.base.mixins import ModelMixin
+from ddionrails.base.mixins import ImportPathMixin, ModelMixin
 
 
 class TopicList(models.Model):
@@ -35,7 +35,7 @@ class TopicList(models.Model):
     )
 
 
-class Study(ModelMixin, TimeStampedModel):
+class Study(ImportPathMixin, ModelMixin, TimeStampedModel):
     """
     Stores a single study,
     related to :model:`data.Dataset`, :model:`instruments.Instrument`,
@@ -102,12 +102,6 @@ def get_absolute_url(self) -> str:
         """ Returns a canonical URL for the model using the "name" field """
         return reverse("study_detail", kwargs={"study_name": self.name})
 
-    def import_path(self):
-        path = os.path.join(
-            settings.IMPORT_REPO_PATH, self.name, settings.IMPORT_SUB_DIRECTORY
-        )
-        return path
-
     def repo_url(self) -> str:
         if settings.GIT_PROTOCOL == "https":
             return f"https://{self.repo}.git"


Test patch:
diff --git a/tests/base/test_mixins.py b/tests/base/test_mixins.py
--- a/tests/base/test_mixins.py
+++ b/tests/base/test_mixins.py
@@ -3,12 +3,14 @@
 
 """ Test cases for mixins in ddionrails.base app """
 
+import pathlib
+
 import pytest
 from django.db import models
 from django.forms import ModelForm
 
 import ddionrails.base
-from ddionrails.base.mixins import AdminMixin, ModelMixin
+from ddionrails.base.mixins import AdminMixin, ImportPathMixin, ModelMixin
 from ddionrails.concepts.models import Concept
 
 pytestmark = [pytest.mark.ddionrails, pytest.mark.mixins]  # pylint: disable=invalid-name
@@ -113,6 +115,17 @@ def test_string_method_multiple_id_field(self):
         assert expected == str(mixin)
 
 
+class TestImportPathMixin:
+    def test_import_path_method(self, settings):
+        mixin = ImportPathMixin()
+        mixin.name = "name"
+        result = mixin.import_path()
+        expected = pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
+            mixin.name, settings.IMPORT_SUB_DIRECTORY
+        )
+        assert expected == result
+
+
 @pytest.fixture
 def admin_mixin():
     """ An instantiated admin mixin"""
diff --git a/tests/base/test_models.py b/tests/base/test_models.py
--- a/tests/base/test_models.py
+++ b/tests/base/test_models.py
@@ -16,13 +16,6 @@ class TestSystemModel:
     def test_repo_url_method(self, system, settings):
         assert system.repo_url() + settings.SYSTEM_REPO_URL
 
-    def test_import_path_method(self, system, settings):
-        result = system.import_path()
-        expected = pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
-            system.name, settings.IMPORT_SUB_DIRECTORY
-        )
-        assert expected == result
-
     def test_get_method(self, system):  # pylint: disable=unused-argument
         result = System.get()
         assert isinstance(result, System)
diff --git a/tests/imports/test_imports.py b/tests/imports/test_imports.py
--- a/tests/imports/test_imports.py
+++ b/tests/imports/test_imports.py
@@ -59,10 +59,9 @@ def test_read_file_method(self, study, mocker):
     def test_import_path_method_with_study(self, study, settings):
         importer = Import(filename="DUMMY.csv", study=study)
         result = importer.import_path()
-        path = pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
+        expected = pathlib.Path(settings.IMPORT_REPO_PATH).joinpath(
             study.name, settings.IMPORT_SUB_DIRECTORY
         )
-        expected = str(path) + "/"
         assert expected == result
 
     def test_import_path_method_without_study(self, system, settings):
diff --git a/tests/studies/test_models.py b/tests/studies/test_models.py
--- a/tests/studies/test_models.py
+++ b/tests/studies/test_models.py
@@ -21,17 +21,6 @@ def test_get_absolute_url_method(self, study):
         expected = "/" + study.name
         assert expected == study.get_absolute_url()
 
-    def test_import_path_method(self, study, settings):
-        expected = (
-            str(
-                pathlib.Path(settings.IMPORT_REPO_PATH)
-                / study.name
-                / settings.IMPORT_SUB_DIRECTORY
-            )
-            + "/"
-        )
-        assert expected == study.import_path()
-
     def test_repo_url_method_https(self, study, settings):
         settings.GIT_PROTOCOL = "https"
         repo_url = study.repo_url()