Skip to content

Commit

Permalink
feat: Support DestSurveyID parameter to RPC method copy_survey
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarrmondragon committed Oct 29, 2023
1 parent 4447345 commit b167d1e
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 27 deletions.
11 changes: 3 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,15 @@ repos:
- id: check-readthedocs

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.1
rev: v0.1.3
hooks:
- id: ruff
name: Ruff lint
args: [--fix, --exit-non-zero-on-fix, --show-fixes]
- id: ruff
name: Ruff format
entry: ruff format

- repo: https://github.com/psf/black
rev: 23.10.0
hooks:
- id: black
language_version: python3.11

- repo: https://github.com/codespell-project/codespell
rev: v2.2.6
hooks:
Expand Down Expand Up @@ -77,6 +72,6 @@ repos:
args: [--all]

- repo: https://github.com/tox-dev/pyproject-fmt
rev: "1.2.0"
rev: "1.3.0"
hooks:
- id: pyproject-fmt
35 changes: 35 additions & 0 deletions docs/_ext/limesurvey_future.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ def run(self) -> list[nodes.Node]:
return [self.admonition_type("", nodes.paragraph(text=text))]


class UnreleasedParameter(Directive):
"""A directive for development-only parameters.
Adds a warning to method parameters that are only available in the next minor
release of LimeSurvey.
"""

required_arguments = 2
message = (
"The parameter {parameter} is only supported in LimeSurvey >= {next_version} "
"(currently in development)."
)
admonition_type = nodes.warning

def run(self) -> list[nodes.Node]:
next_version, parameter = self.arguments[:2]
text = self.message.format(next_version=next_version, parameter=parameter)
return [self.admonition_type("", nodes.paragraph(text=text))]


class ReleasedFeature(UnreleasedFeature):
"""A directive for released features.
Expand All @@ -43,9 +63,24 @@ class ReleasedFeature(UnreleasedFeature):
admonition_type = nodes.note


class ReleasedParameter(UnreleasedParameter):
"""A directive for released parameters.
Adds a note to method parameters that are only available after some release of
LimeSurvey.
"""

message = (
"The parameter {parameter} is only supported in LimeSurvey >= {next_version}."
)
admonition_type = nodes.note


def setup(app: Sphinx) -> dict[str, t.Any]:
app.add_directive("future", UnreleasedFeature)
app.add_directive("futureparam", UnreleasedParameter)
app.add_directive("minlimesurvey", ReleasedFeature)
app.add_directive("minlimesurveyparam", ReleasedParameter)

return {
"version": "0.1",
Expand Down
32 changes: 18 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,20 @@ docs = [
line-length = 88

[tool.ruff]
include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"]
line-length = 88
src = ["src", "tests", "docs"]
target-version = "py38"

[tool.ruff.lint]
explicit-preview-rules = false
ignore = [
"ANN101", # missing-type-self
"DJ", # flake8-django
"FIX002", # line-contains-todo
"COM812", # missing-trailing-comma
"ISC001", # single-line-implicit-string-concatenation
]
include = ["*.py", "*.pyi", "**/pyproject.toml", "*.ipynb"]
line-length = 88
preview = true
select = [
"F", # Pyflakes
Expand Down Expand Up @@ -138,8 +144,6 @@ select = [
"LOG", # flake8-logging
"RUF", # Ruff-specific rules
]
src = ["src", "tests", "docs"]
target-version = "py38"
unfixable = [
"ERA", # Don't remove commented out code
]
Expand Down Expand Up @@ -170,40 +174,40 @@ unfixable = [
# Enable preview style formatting.
preview = true

[tool.ruff.flake8-quotes]
[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
inline-quotes = "double"
multiline-quotes = "double"

[tool.ruff.flake8-annotations]
[tool.ruff.lint.flake8-annotations]
allow-star-arg-any = true
mypy-init-return = true
suppress-dummy-args = true

[tool.ruff.flake8-errmsg]
[tool.ruff.lint.flake8-errmsg]
max-string-length = 30

[tool.ruff.flake8-import-conventions]
[tool.ruff.lint.flake8-import-conventions]
banned-from = ["typing"]

[tool.ruff.flake8-import-conventions.extend-aliases]
[tool.ruff.lint.flake8-import-conventions.extend-aliases]
typing = "t"

[tool.ruff.flake8-pytest-style]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
mark-parentheses = false

[tool.ruff.isort]
[tool.ruff.lint.isort]
known-first-party = ["citric"]
required-imports = ["from __future__ import annotations"]

[tool.ruff.mccabe]
[tool.ruff.lint.mccabe]
max-complexity = 5

[tool.ruff.pydocstyle]
[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.ruff.pylint]
[tool.ruff.lint.pylint]
max-args = 10

[tool.pytest.ini_options]
Expand Down
30 changes: 30 additions & 0 deletions src/citric/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,33 @@ def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Callable:
return wrapper

return decorate


def future_parameter(version: str, parameter: str) -> t.Callable:
"""Mark a function as only available in the current development build of LimeSurvey.
Args:
version: The earliest version of LimeSurvey that this parameter is
available in.
parameter: The parameter that is only available in the current development
build of LimeSurvey.
Returns:
The wrapped function.
"""
message = _warning_message(version)

def decorate(fn: t.Callable) -> t.Callable:
@wraps(fn)
def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Callable:
if parameter in kwargs:
warnings.warn(
f"Parameter {parameter} {''.join(message)}",
FutureVersionWarning,
stacklevel=2,
)
return fn(*args, **kwargs)

return wrapper

return decorate
16 changes: 14 additions & 2 deletions src/citric/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import requests

from citric import enums
from citric._compat import future_parameter
from citric.exceptions import LimeSurveyStatusError
from citric.session import Session

Expand Down Expand Up @@ -488,21 +489,32 @@ def update_response(self, survey_id: int, response_data: dict[str, t.Any]) -> bo
data = self._map_response_keys(response_data, questions)
return self.session.update_response(survey_id, data)

def copy_survey(self, survey_id: int, name: str) -> dict[str, t.Any]:
@future_parameter("6.3.0", "destination_survey_id")
def copy_survey(
self,
survey_id: int,
name: str,
destination_survey_id: int | None = None,
) -> dict[str, t.Any]:
"""Copy a survey.
Calls :rpc_method:`copy_survey`.
Args:
survey_id: ID of the source survey.
name: Name of the new survey.
destination_survey_id: ID of the new survey. If already used a, random one
will be generated.
Returns:
Dictionary of status message and the new survey ID.
.. versionadded:: 0.0.10
.. versionchanged:: NEXT_VERSION
The ``target_survey_id`` optional parameter was added.
.. futureparam:: 6.4.0 destination_survey_id
"""
return self.session.copy_survey(survey_id, name)
return self.session.copy_survey(survey_id, name, destination_survey_id)

def import_cpdb_participants(
self,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ def test_add_survey(client: MockClient):

def test_copy_survey(client: MockClient):
"""Test copy_survey client method."""
assert_client_session_call(client, "copy_survey", 1, NEW_SURVEY_NAME)
assert_client_session_call(client, "copy_survey", 1, NEW_SURVEY_NAME, None)


def test_delete_group(client: MockClient):
Expand Down
21 changes: 19 additions & 2 deletions tests/test_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,35 @@

import pytest

from citric._compat import FutureVersionWarning, future
from citric._compat import FutureVersionWarning, future, future_parameter


@future("4.0.0")
def my_function() -> None:
"""A simple function."""


@future_parameter("4.0.0", "new_param")
def function_new_param(new_param: str | None = None) -> None:
"""A simple function."""


def test_dev_only():
"""Test that dev_only raises a warning."""
"""Test that calling a dev-only functions raise a warning."""
with pytest.warns(
FutureVersionWarning,
match="Method my_function is only supported .* 4.0.0",
):
my_function()


def test_dev_only_param():
"""Test that calling a dev-only function parameters raise a warning."""
# Calling with the default value should not raise a warning
function_new_param()

with pytest.warns(
FutureVersionWarning,
match="Parameter new_param is only supported .* 4.0.0",
):
function_new_param(new_param="test")
28 changes: 28 additions & 0 deletions tests/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,34 @@ def test_survey(client: citric.Client):
assert new_props["format"] == enums.NewSurveyType.ALL_ON_ONE_PAGE


def test_copy_survey_destination_id(
request: pytest.FixtureRequest,
client: citric.Client,
server_version: semver.Version,
):
"""Test copying a survey with a destination survey ID."""
request.applymarker(
pytest.mark.xfail(
server_version < (6, 4, 0, "dev"),
reason=(
"The destination_survey_id parameter is only supported in LimeSurvey "
f"{server_version} < 6.4.0-dev"
),
raises=requests.exceptions.HTTPError,
),
)

# Copy a survey, specifying a new survey ID
copied = client.copy_survey(
survey_id,
NEW_SURVEY_NAME,
destination_survey_id=9797,
)
assert copied["status"] == "OK"
copied_survey = client.get_survey_properties(9797)
assert copied_survey["sid"] == "9797"


@pytest.mark.integration_test
def test_group(client: citric.Client, survey_id: int):
"""Test group methods."""
Expand Down

0 comments on commit b167d1e

Please sign in to comment.