### Get Surveys and Questions Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Example of retrieving a list of surveys and their associated questions using the Citric client. ```python surveys = client.get_surveys() for survey in surveys: questions = client.get_questions(survey_id=survey["sid"]) print(f"Survey: {survey['survey_name']}, Questions: {questions}") ``` -------------------------------- ### Install Dependencies Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Installs necessary libraries including boto3 and citric. Use this at the beginning of your notebook. ```python !pip install --upgrade pip boto3 citric --quiet ``` -------------------------------- ### Install Libraries Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/pandas_sqlite.ipynb Installs or upgrades the required Python packages: citric, pip, pandas, faker, and sqlalchemy. The --quiet flag suppresses verbose output. ```python !pip install --upgrade citric pip pandas faker sqlalchemy --quiet ``` -------------------------------- ### Setup S3 Client and Upload File Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Initializes an S3 client, creates a bucket (if it doesn't exist), and uploads a survey file from the local path to S3. Replace 'testing' with your actual bucket name. ```python s3 = boto3.client("s3") # use your own bucket name here s3.create_bucket(Bucket="testing") s3.upload_file("../../examples/survey.lss", "testing", "survey.lss") ``` -------------------------------- ### Install Citric using pip Source: https://github.com/edgarrmondragon/citric/blob/main/README.md Install the Citric library from PyPI using pip. This is the standard method for installing Python packages. ```sh pip install citric ``` -------------------------------- ### Install Dependencies Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Installs necessary Python packages including citric, duckdb-engine, faker, jupysql, and sqlalchemy. This is a prerequisite for running the subsequent code. ```python !pip install --upgrade pip citric duckdb-engine faker jupysql sqlalchemy --quiet ``` -------------------------------- ### Install Citric using Conda Source: https://github.com/edgarrmondragon/citric/blob/main/README.md Install the Citric library from the conda-forge channel using Conda. This is an alternative installation method for users who prefer Conda environments. ```sh conda install -c conda-forge citric ``` -------------------------------- ### Get Uploaded Files and Move to S3 Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Retrieves files uploaded to a survey in LimeSurvey and demonstrates how to move them to an S3 bucket. ```python from io import BytesIO file_data = client.get_uploaded_file(survey_id=survey_id, file_id=file_id) # Example: Upload to S3 using boto3 (not included) # s3_client.upload_fileobj(BytesIO(file_data["content"]), "my-bucket", "path/to/file.txt") ``` -------------------------------- ### Get Survey Response Statistics with Citric Client Source: https://context7.com/edgarrmondragon/citric/llms.txt Use `get_summary` to retrieve all aggregate token and response statistics for a survey, or `get_summary_stat` to fetch a single specific metric. ```python from citric import Client with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 123456 summary = client.get_summary(survey_id) if summary: print(f"Completed: {summary['completed_responses']}") print(f"Incomplete: {summary['incomplete_responses']}") print(f"Tokens sent: {summary['token_sent']}") # Fetch a single statistic completed = client.get_summary_stat(survey_id, "completed_responses") print(f"Total completed responses: {completed}") ``` -------------------------------- ### Get and Set Survey Properties with Citric Client Source: https://context7.com/edgarrmondragon/citric/llms.txt Use `get_survey_properties` to read survey settings and `set_survey_properties` to update them. Specify properties to read specific settings. ```python from citric import Client with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 123456 # Read all properties props = client.get_survey_properties(survey_id) print(props["active"], props["anonymized"], props["language"]) # Read specific properties only props = client.get_survey_properties(survey_id, properties=["active", "expires", "startdate"]) # Update properties updated = client.set_survey_properties( survey_id, anonymized="Y", datestamp="Y", ipaddr="N", alloweditaftercompletion="N", ) print(updated) # {"anonymized": True, "datestamp": True, ...} ``` -------------------------------- ### Find Longest Response Durations in DuckDB Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Use SQL within a notebook to calculate and display the top 10 longest response durations by subtracting the start date from the submission date. ```sql SELECT token, submitdate - startdate AS duration FROM responses ORDER BY 2 DESC LIMIT 10 ``` -------------------------------- ### Initialize Client and Basic Usage Source: https://context7.com/edgarrmondragon/citric/llms.txt Demonstrates basic client initialization using a context manager for automatic session cleanup. Shows how to retrieve server version, site name, and default language. Supports custom authentication plugins and integration with `requests.Session` for features like caching. ```python from citric import Client from citric.exceptions import LimeSurveyStatusError # Basic usage — context manager ensures session key is released on exit with Client( "https://mylimesite.example.com/index.php/admin/remotecontrol", "iamadmin", "secret", ) as client: print(client.get_server_version()) # e.g. "6.3.7" print(client.get_site_name()) # e.g. "My LimeSurvey" print(client.get_default_language()) # e.g. "en" # LDAP / custom auth plugin client = Client( "https://example.com/index.php/admin/remotecontrol", "iamadmin", "secret", auth_plugin="AuthLDAP", ) # Custom requests.Session (e.g. with caching) import requests_cache cached_session = requests_cache.CachedSession(expire_after=60, allowable_methods=["POST"]) client = Client( "https://example.com/index.php/admin/remotecontrol", "iamadmin", "secret", requests_session=cached_session, ) surveys = client.list_surveys("iamadmin") # responses cached for 60 s ``` -------------------------------- ### Connect to DuckDB Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Establishes a connection to a DuckDB in-memory database. This command prepares the environment for subsequent SQL queries. ```python %sql duckdb:// ``` -------------------------------- ### Create a New Survey with Client.add_survey Source: https://context7.com/edgarrmondragon/citric/llms.txt Creates a new survey with a specified title and language. Requires a Client instance. The survey can be configured with different formats like GROUP_BY_GROUP. ```python from citric import Client from citric.enums import NewSurveyType with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: # Group-by-group format (default) survey_id = client.add_survey(0, "Employee Feedback 2025", "en", NewSurveyType.GROUP_BY_GROUP) print(f"Created survey with ID: {survey_id}") # Add a question group to the new survey group_id = client.add_group(survey_id, "Section 1: General", "Please answer the following questions.") print(f"Created group with ID: {group_id}") # Activate the survey result = client.activate_survey(survey_id) print(result["status"]) ``` -------------------------------- ### Initialize Citric Client Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/pandas_sqlite.ipynb Creates an instance of the Citric Client to interact with the LimeSurvey API. Replace placeholder URL and credentials with your actual server details. ```python # Use your own server's parameters here client = citric.Client( "http://localhost:8001/index.php/admin/remotecontrol", "iamadmin", "secret", ) ``` -------------------------------- ### Build and Import Questions Programmatically with Dataclasses Source: https://context7.com/edgarrmondragon/citric/llms.txt Use the `Question`, `QuestionL10n`, and `AnswerOption` dataclasses to construct questions in Python and export them as LSQ XML. This method supports multilingual text, subquestions, and answer options. The `to_lsq()` method converts the dataclass instance to the required XML format for `client.import_question()`. ```python from citric import Client from citric.objects import AnswerOption, Question, QuestionL10n with Client("http://localhost:8001/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = client.list_surveys()[0]["sid"] group_id = client.list_groups(survey_id)[0]["id"] # Single-choice list question with multilingual text and answer options list_question = Question( title="Q01", type="L", l10ns={ "en": QuestionL10n(question="What is your favourite colour?"), "es": QuestionL10n(question="¿Cual es tu color favorito?"), }, answer_options=[ AnswerOption(code="R", l10ns={"en": "Red", "es": "Rojo"}), AnswerOption(code="G", l10ns={"en": "Green", "es": "Verde"}), AnswerOption(code="B", l10ns={"en": "Blue", "es": "Azul"}), ], ) qid = client.import_question(list_question.to_lsq(), survey_id, group_id) print(f"Imported list question: {qid}") # Multiple-choice question with subquestions mc_question = Question( title="Q02", type="M", l10ns={"en": QuestionL10n(question="Which languages do you use?")}, subquestions=[ Question(title="SQ001", type="T", l10ns={"en": QuestionL10n(question="Python")}), Question(title="SQ002", type="T", l10ns={"en": QuestionL10n(question="R")}), Question(title="SQ003", type="T", l10ns={"en": QuestionL10n(question="Julia")}), ], ) qid = client.import_question(mc_question.to_lsq(), survey_id, group_id) print(f"Imported multiple-choice question: {qid}") ``` -------------------------------- ### Run All Tests with Nox Source: https://github.com/edgarrmondragon/citric/blob/main/docs/contributing/testing.md Execute all defined test suites using the nox command. Ensure your environment is set up correctly before running. ```shell nox -s tests ``` -------------------------------- ### Import Libraries Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Imports essential libraries for S3 interaction, logging, and citric client. ```python import io import logging import boto3 from IPython.display import HTML import citric ``` -------------------------------- ### Run Dependency Checks with Nox Source: https://github.com/edgarrmondragon/citric/blob/main/docs/contributing/testing.md Execute dependency checks using the nox command. ```shell nox -s deps ``` -------------------------------- ### Build Questions Programmatically Source: https://context7.com/edgarrmondragon/citric/llms.txt Dataclasses for constructing LimeSurvey questions in Python and exporting them as LSQ-format XML streams for use with `client.import_question()`. Supports multilingual questions, subquestions, and answer options. ```APIDOC ## `Question`, `QuestionL10n`, `AnswerOption` — Build questions programmatically Dataclasses for constructing LimeSurvey questions in Python and exporting them as LSQ-format XML streams for use with `client.import_question()`. Supports multilingual questions, subquestions, and answer options. ```python from citric import Client from citric.objects import AnswerOption, Question, QuestionL10n with Client("http://localhost:8001/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = client.list_surveys()[0]["sid"] group_id = client.list_groups(survey_id)[0]["id"] # Single-choice list question with multilingual text and answer options list_question = Question( title="Q01", type="L", l10ns={ "en": QuestionL10n(question="What is your favourite colour?"), "es": QuestionL10n(question="¿Cual es tu color favorito?"), }, answer_options=[ AnswerOption(code="R", l10ns={"en": "Red", "es": "Rojo"}), AnswerOption(code="G", l10ns={"en": "Green", "es": "Verde"}), AnswerOption(code="B", l10ns={"en": "Blue", "es": "Azul"}), ], ) qid = client.import_question(list_question.to_lsq(), survey_id, group_id) print(f"Imported list question: {qid}") # Multiple-choice question with subquestions mc_question = Question( title="Q02", type="M", l10ns={"en": QuestionL10n(question="Which languages do you use?")}, subquestions=[ Question(title="SQ001", type="T", l10ns={"en": QuestionL10n(question="Python")}), Question(title="SQ002", type="T", l10ns={"en": QuestionL10n(question="R")}), Question(title="SQ003", type="T", l10ns={"en": QuestionL10n(question="Julia")}), ], ) qid = client.import_question(mc_question.to_lsq(), survey_id, group_id) print(f"Imported multiple-choice question: {qid}") ``` ``` -------------------------------- ### Configure Logging Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Sets up a stream handler for logging citric events. Useful for debugging. ```python formatter = logging.Formatter("{asctime} {levelname} {message}", style="{") handler = logging.StreamHandler() handler.setFormatter(formatter) logger = logging.getLogger("citric") logger.addHandler(handler) logger.setLevel(logging.DEBUG) ``` -------------------------------- ### Import Survey Structures with Client Source: https://context7.com/edgarrmondragon/citric/llms.txt Use this to import surveys, question groups, and questions from exported LimeSurvey files (LSS, LSA, LSG, LSQ). Ensure the file paths are correct and the client is initialized with valid credentials and URL. ```python from citric import Client with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: # Import a survey from an LSS file with open("survey_backup.lss", "rb") as f: new_survey_id = client.import_survey(f, file_type="lss", survey_name="Imported Survey") print(f"New survey ID: {new_survey_id}") # Import a group into the new survey with open("group.lsg", "rb") as f: group_id = client.import_group(f, new_survey_id, name="Demographics") print(f"New group ID: {group_id}") # Import a question into the group with open("question.lsq", "rb") as f: question_id = client.import_question( f, new_survey_id, group_id, mandatory=True, new_question_title="Q_AGE", ) print(f"New question ID: {question_id}") ``` -------------------------------- ### List Local Files Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Lists files in the local directory. Useful for verifying file existence before upload. ```python !ls ../../examples ``` -------------------------------- ### Activate a Survey with Client.activate_survey Source: https://context7.com/edgarrmondragon/citric/llms.txt Activates a survey to make it accessible to respondents. Allows configuration of activation settings like IP recording and anonymization. Also initializes the participant token table. ```python from citric import Client with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 123456 result = client.activate_survey( survey_id, user_activation_settings={ "anonymized": True, "datestamp": True, "ipaddr": False, "ipanonymize": False, "refurl": False, "savetimings": True, }, ) print(result["status"]) # Initialize participant (token) table so participants can be added token_result = client.activate_tokens(survey_id, attributes=[1, 2]) print(token_result["status"]) ``` -------------------------------- ### Import Libraries Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/pandas_sqlite.ipynb Imports necessary modules from pathlib, pandas, faker, sqlalchemy, and citric for file path manipulation, data handling, fake data generation, database interaction, and survey management. ```python import io from pathlib import Path import pandas as pd from faker import Faker from sqlalchemy import create_engine import citric ``` -------------------------------- ### Create and Import Questions Programmatically Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Composes questions using `citric.objects.Question` and imports them into LimeSurvey using `client.import_question()`. ```python from citric.objects import Question question_data = { "question": { "survey_id": survey_id, "question_code": "my_new_question", "question_type": "T", "question": "What is your favorite color?", "answers": { "1": {"code": "R", "answer": "Red"}, "2": {"code": "G", "answer": "Green"}, "3": {"code": "B", "answer": "Blue"} } } } question = Question.from_dict(question_data) client.import_question(question) ``` -------------------------------- ### Connect to LimeSurvey and list surveys Source: https://github.com/edgarrmondragon/citric/blob/main/README.md Connect to a LimeSurvey instance using the Client class and retrieve the titles of all available surveys. Ensure you have the correct URL, username, and password for your LimeSurvey instance. ```python from citric import Client # Connect to your LimeSurvey instance client = Client( "https://mylimesite.limequery.com/admin/remotecontrol", "myusername", "mypassword", ) # Print the LimeSurvey version print(client.get_server_version()) # Print every survey's title for survey in client.list_surveys(): print(survey["surveyls_title"]) ``` -------------------------------- ### Configure Integration Tests with .env File Source: https://github.com/edgarrmondragon/citric/blob/main/docs/contributing/testing.md Set environment variables in a .env file to customize integration test configurations, such as database type and Docker image tag. ```shell LS_DATABASE_TYPE=mysql LS_IMAGE_TAG=6.6.4-240923-apache ``` -------------------------------- ### Manage Survey Participants with Client.add_participants and Client.list_participants Source: https://context7.com/edgarrmondragon/citric/llms.txt Adds participants to a survey's token table and retrieves them with optional filtering. Requires participant data including email and optionally other attributes. Can create tokens during addition. ```python from citric import Client with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 123456 # Add participants new_participants = client.add_participants( survey_id, participant_data=[ {"firstname": "Alice", "lastname": "Smith", "email": "alice@example.com"}, {"firstname": "Bob", "lastname": "Jones", "email": "bob@example.com"}, ], create_tokens=True, ) for p in new_participants: print(p["token"], p["tid"]) # Expected: T00001 1 / T00002 2 # List participants with extra attributes participants = client.list_participants( survey_id, start=0, limit=50, attributes=["email", "completed"], conditions={"completed": "N"}, ) for p in participants: print(p["token"], p["participant_info"]["email"]) ``` -------------------------------- ### Activate Survey and Load Responses Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Activates the survey using the obtained 'survey_id', enables datestamping, activates participant tokens, and then adds the generated fake responses to the survey. Returns the number of responses added. ```python client.activate_survey( survey_id, user_activation_settings={ "datestamp": True, }, ) client.activate_tokens(survey_id) result = client.add_responses(survey_id, fake_responses) len(result) ``` -------------------------------- ### Manually Close Client Session Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Demonstrates how to manually close the client session using the `close()` method when not using a context manager. ```python client = Client() # Use client here client.close() ``` -------------------------------- ### Use a Different Authentication Plugin Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Configures the client to use an alternative authentication plugin, such as LDAP or web server authentication, instead of the default database authentication. ```python from citric.auth import AuthLDAP client = Client(auth_plugin=AuthLDAP(ldap_url="ldap://localhost:389")) ``` -------------------------------- ### Manage Quotas with Citric Client Source: https://context7.com/edgarrmondragon/citric/llms.txt Use `add_quota` to create quotas, `list_quotas` to retrieve them, `get_quota_properties` and `set_quota_properties` to manage their settings, and `delete_quota` to remove them. Requires LimeSurvey 6.0+. ```python from citric import Client from citric.enums import QuotaAction with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 123456 # Create a quota that terminates when 100 responses are collected quota_id = client.add_quota( survey_id, name="Max 100 Respondents", limit=100, active=True, action=QuotaAction.TERMINATE, message="Thank you, we have enough responses.", url="https://example.com/thank-you", ) print(f"Created quota ID: {quota_id}") # List all quotas for the survey for quota in client.list_quotas(survey_id): print(quota["id"], quota["name"], quota["limit"]) # Get and update quota properties props = client.get_quota_properties(quota_id) print(props["qlimit"], props["active"]) client.set_quota_properties(quota_id, qlimit=200, active=1) # Delete a quota client.delete_quota(quota_id) ``` -------------------------------- ### Run Integration Tests with Nox Source: https://github.com/edgarrmondragon/citric/blob/main/docs/contributing/testing.md Execute integration tests. This requires the Docker daemon to be running and the Docker CLI to be available. ```shell nox -s integration ``` -------------------------------- ### Import Libraries Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Imports essential Python libraries: Path for file operations, Faker for generating fake data, and the citric library for interacting with the survey client. ```python from pathlib import Path from faker import Faker import citric ``` -------------------------------- ### Load SQL Extension Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/duckdb.ipynb Loads the SQL extension for Jupyter, enabling the use of SQL magic commands within the notebook. ```python %load_ext sql ``` -------------------------------- ### Run Doctests with Nox Source: https://github.com/edgarrmondragon/citric/blob/main/docs/contributing/testing.md Execute doctests using the nox command with the xdoctest session. ```shell nox -s xdoctest ``` -------------------------------- ### Automatically Close Session with Context Manager Source: https://github.com/edgarrmondragon/citric/blob/main/docs/how-to.md Use a context manager to ensure the client session is automatically closed. This is the recommended way to manage sessions. ```python with Client() as client: # Use client here pass ``` -------------------------------- ### Client.get_uploaded_file_objects / Client.download_files Source: https://context7.com/edgarrmondragon/citric/llms.txt Handle files uploaded by respondents to a survey. `get_uploaded_file_objects` iterates over file objects, each containing metadata and a content stream. `download_files` downloads all files to a specified directory, with options to filter by token. ```APIDOC ## `Client.get_uploaded_file_objects` / `Client.download_files` — Handle uploaded files Iterates over or downloads files that respondents uploaded to a survey. Each file object contains metadata and a `BytesIO` content stream. ```python import boto3 from citric import Client # Stream uploaded files directly to S3 s3 = boto3.client("s3") with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 12345 for file in client.get_uploaded_file_objects(survey_id): s3.upload_fileobj( file["content"], "my-s3-bucket", f"uploads/sid={survey_id}/qid={file['meta']['question']['qid']}/{file['meta']['filename']}", ) # Or download all files to a local directory paths = client.download_files("./downloads", survey_id) print(f"Downloaded: {[str(p) for p in paths]}") # Filter by participant token paths = client.download_files("./downloads", survey_id, token="T00001") ``` ``` -------------------------------- ### Handle Uploaded Files with Citric Client Source: https://context7.com/edgarrmondragon/citric/llms.txt Iterate over or download files uploaded by respondents. File objects contain metadata and a BytesIO content stream. Supports streaming to S3 or downloading to a local directory. ```python import boto3 from citric import Client # Stream uploaded files directly to S3 s3 = boto3.client("s3") with Client("https://myls.example.com/index.php/admin/remotecontrol", "admin", "secret") as client: survey_id = 12345 for file in client.get_uploaded_file_objects(survey_id): s3.upload_fileobj( file["content"], "my-s3-bucket", f"uploads/sid={survey_id}/qid={file['meta']['question']['qid']}/{file['meta']['filename']}", ) # Or download all files to a local directory paths = client.download_files("./downloads", survey_id) print(f"Downloaded: {[str(p) for p in paths]}") # Filter by participant token paths = client.download_files("./downloads", survey_id, token="T00001") ``` -------------------------------- ### Download from S3 and Import Survey Source: https://github.com/edgarrmondragon/citric/blob/main/docs/notebooks/import_s3.ipynb Downloads a survey file from S3 using a BytesIO object, then imports it into LimeSurvey using the citric client. Ensure your LimeSurvey server details and credentials are correct. ```python # Use your own server's parameters here with citric.Client( "http://localhost:8001/index.php/admin/remotecontrol", "iamadmin", "secret", ) as client: file_object = io.BytesIO() s3.download_fileobj("testing", "survey.lss", file_object) file_object.seek(0) survey_id = client.import_survey(file_object) questions = client.list_questions(survey_id) for question in questions: display(HTML(question["question"] + question["help"] + "