diff --git a/client/i18n/locales/english/intro.json b/client/i18n/locales/english/intro.json index 5aac2749891..f49e50b3a6c 100644 --- a/client/i18n/locales/english/intro.json +++ b/client/i18n/locales/english/intro.json @@ -4257,9 +4257,11 @@ "In this workshop, you'll practice working with dictionaries and sets while validating a collection of medical data." ] }, - "lab-placeholder-dictionaries-and-sets": { - "title": "Placeholder - waiting for title", - "intro": [""] + "lab-user-configuration-manager": { + "title": "Build a User Configuration Manager", + "intro": [ + "In this lab, you will practice working with dictionaries in Python." + ] }, "review-dictionaries-and-sets": { "title": "Dictionaries and Sets review", diff --git a/client/src/pages/learn/full-stack-developer/lab-user-configuration-manager/index.md b/client/src/pages/learn/full-stack-developer/lab-user-configuration-manager/index.md new file mode 100644 index 00000000000..aee911e6a75 --- /dev/null +++ b/client/src/pages/learn/full-stack-developer/lab-user-configuration-manager/index.md @@ -0,0 +1,9 @@ +--- +title: Introduction to the Build a User Configuration Manager +block: lab-user-configuration-manager +superBlock: full-stack-developer +--- + +## Introduction to the Build a User Configuration Manager + +In this lab you will practice dictionaries in Python by building a small app that manages user configuration settings. diff --git a/curriculum/challenges/_meta/lab-user-configuration-manager/meta.json b/curriculum/challenges/_meta/lab-user-configuration-manager/meta.json new file mode 100644 index 00000000000..b58a7b07723 --- /dev/null +++ b/curriculum/challenges/_meta/lab-user-configuration-manager/meta.json @@ -0,0 +1,15 @@ +{ + "name": "Build a User Configuration Manager", + "isUpcomingChange": true, + "dashedName": "lab-user-configuration-manager", + "superBlock": "full-stack-developer", + "challengeOrder": [ + { + "id": "684aaf9ec670c68d20efd0d0", + "title": "Build a User Configuration Manager" + } + ], + "blockLayout": "link", + "blockType": "lab", + "helpCategory": "Python" +} diff --git a/curriculum/challenges/english/25-front-end-development/lab-user-configuration-manager/684aaf9ec670c68d20efd0d0.md b/curriculum/challenges/english/25-front-end-development/lab-user-configuration-manager/684aaf9ec670c68d20efd0d0.md new file mode 100644 index 00000000000..8ec432e9de9 --- /dev/null +++ b/curriculum/challenges/english/25-front-end-development/lab-user-configuration-manager/684aaf9ec670c68d20efd0d0.md @@ -0,0 +1,457 @@ +--- +id: 684aaf9ec670c68d20efd0d0 +title: Build a User Configuration Manager +challengeType: 27 +dashedName: build-a-user-configuration-manager +--- + +# --description-- + +In this lab, you will build a User Configuration Manager that allows users to manage their settings such as theme, language, and notifications. You will implement functions to add, update, delete, and view user settings. + +**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab. + +**User Stories:** + +1. You should define a function named `add_setting` with two parameters representing a dictionary of settings and a tuple containing a key-value pair + +1. `add_setting` function should: + + - Convert the key and value to lowercase. + - If the key setting exists, return `Setting '[key]' already exists! Cannot add a new setting with this name.` + - If the key setting doesn't exist, add the key-value pair to the given dictionary of settings and return `Setting '[key]' added with value '[value]' successfully!`. + - The messages returned should have the key and value in lowercase. + +1. You should define a function named `update_setting` with two parameters representing a dictionary of settings and a tuple containing a key-value pair. + +1. `update_setting` function should: + + - Convert the key and value to lowercase. + - If the key setting exists, update its value in the given dictionary of settings and return: `Setting '[key]' updated to '[value]' successfully!` + - If the key setting doesn't exist, return `Setting '[key]' does not exist! Cannot update a non-existing setting.` + - The messages returned should have the key and value in lowercase. + + +1. You should define a function named `delete_setting` with two parameters representing a dictionary of settings and a key. + +1. `delete_setting` function should: + + - Convert the key passed to lowercase. + - If the key setting exists, remove the key-value pair from the given dictionary of settings and return `Setting '[key]' deleted successfully!` + - If the key setting does not exist, return `Setting not found!` + - The messages returned should have the key in lowercase. + +1. You should define a function named `view_settings` with one parameter representing a dictionary of settings. + +1. `view_settings` function should: + + - Return `No settings available.` if the given dictionary of settings is empty. + - If the dictionary contains any settings, return a string displaying the settings. The string should start with `Current User Settings:` followed by the key-value pairs, each on a new line and with the key capitalized. For example, `view_settings({'theme': 'dark', 'notifications': 'enabled', 'volume': 'high'})` should return: + + ```md + Current User Settings: + Theme: dark + Notifications: enabled + Volume: high + + ``` + +1. For testing the code, you should create a dictionary named `test_settings` to store some user configuration preferences. + +# --hints-- + +You should create a dictionary named `test_settings` and add some values to it. + +```js +({ + test: () => runPython(` + is_dict = isinstance(test_settings, dict) + length = len(test_settings) + assert is_dict and length > 0 + `) +}) +``` + +You should define a function named `add_setting`. + +```js +({ test: () => assert(runPython(`_Node(_code).has_function("add_setting")`)) }) +``` + +The `add_setting` function should have two parameters. + +```js +({ + test: () => runPython(` + import inspect + sig = inspect.signature(add_setting) + assert len(sig.parameters) == 2 + `) +}) +``` + +`add_setting` should convert the key to lowercase. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = add_setting(settings_in_test, ("VOLUME", "high")) + assert "volume" in settings_in_test + assert "VOLUME" not in settings_in_test + `) +}) +``` + +`add_setting` should convert the value to lowercase. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = add_setting(settings_in_test, ("volume", "HIGH")) + assert settings_in_test["volume"] == "high" + `) +}) +``` + +`add_setting({'theme': 'light'}, ('THEME': 'dark'))` should return the error message `Setting 'theme' already exists! Cannot add a new setting with this name.`. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = add_setting(settings_in_test, ("THEME", "dark")) + expected_msg = "Setting 'theme' already exists! Cannot add a new setting with this name." + assert result == expected_msg + `) +}) +``` + +`add_setting({'theme': 'light'}, ('volume', 'high')` should add a new key-value pair and return the success message `Setting 'volume' added with value 'high' successfully!`. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = add_setting(settings_in_test, ("volume", "high")) + expected_msg = "Setting 'volume' added with value 'high' successfully!" + assert result == expected_msg + assert settings_in_test["volume"] == "high" + `) +}) +``` + +`add_setting` should correctly add the given key-value pair to the dictionary. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = add_setting(settings_in_test, ("os", "Ubuntu")) + assert "os" in settings_in_test + assert settings_in_test["os"] == "ubuntu" + `) +}) +``` + +You should define a function named `update_setting`. + +```js +({ + test: () => runPython(` + assert _Node(_code).has_function('update_setting') + `) +}) +``` + +The `update_setting` function should have two parameters. + +```js +({ + test: () => runPython(` + import inspect + sig = inspect.signature(update_setting) + assert len(sig.parameters) == 2 + `) +}) +``` + +The `update_setting` function should convert key to lowercase. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = update_setting(settings_in_test, ("THEME", "dark")) + assert "THEME" not in settings_in_test + assert "theme" in settings_in_test + assert settings_in_test["theme"] == "dark" + `) +}) +``` + +The `update_setting` function should convert value to lowercase. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + # Use the existing "theme" key but an uppercase value + result = update_setting(settings_in_test, ("theme", "HIGH")) + assert settings_in_test["theme"] == "high" + `) +}) +``` + +`update_setting({'theme': 'light'}, ('theme', 'dark'))` should update an existing key and return the success message `Setting 'theme' updated to 'dark' successfully!`. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = update_setting(settings_in_test, ("theme", "dark")) + expected_msg = "Setting 'theme' updated to 'dark' successfully!" + assert result == expected_msg + assert settings_in_test["theme"] == "dark" + `) +}) +``` + +`update_setting({'theme': 'light'}, ('volume', 'high'))` should return the error message `Setting 'volume' does not exist! Cannot update a non-existing setting.` when the key doesn't exist. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = update_setting(settings_in_test, ("volume", "high")) + expected_msg = "Setting 'volume' does not exist! Cannot update a non-existing setting." + assert result == expected_msg + `) +}) +``` + +`update_setting` should correctly update the given key-value pair in the dictionary. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = update_setting(settings_in_test, ("language", "spanish")) + assert "language" in settings_in_test + assert settings_in_test["language"] == "spanish" + `) +}) +``` + +You should define a function named `delete_setting`. + +```js +({ + test: () => runPython(` + assert _Node(_code).has_function('delete_setting') + `) +}) +``` + +The `delete_setting` function should have two parameters. + +```js +({ + test: () => runPython(` + import inspect + sig = inspect.signature(delete_setting) + assert len(sig.parameters) == 2 + `) +}) +``` + +`delete_setting` should convert the key to lowercase. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = delete_setting(settings_in_test, "THEME") + assert "theme" not in settings_in_test + assert "THEME" not in settings_in_test + `) +}) +``` + +`delete_setting({'theme': 'light'}, 'theme')` should remove the existing key and return the success message `Setting 'theme' deleted successfully!`. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = delete_setting(settings_in_test, "theme") + expected_msg = "Setting 'theme' deleted successfully!" + assert result == expected_msg + assert "theme" not in settings_in_test + `) +}) +``` + +`delete_setting` should return the error message `Setting not found!` when the key doesn't exist. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light"} + result = delete_setting(settings_in_test, "volume") + expected_msg = "Setting not found!" + assert result == expected_msg + `) +}) +``` + +`delete_setting` should correctly remove the given key from the dictionary. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English"} + result = delete_setting(settings_in_test, "language") + assert "language" not in settings_in_test + `) +}) +``` + +You should define a function named `view_settings`. + +```js +({ + test: () => runPython(` + assert _Node(_code).has_function('view_settings') + `) +}) +``` + +The `view_settings` function should have one parameter. + +```js +({ + test: () => runPython(` + import inspect + sig = inspect.signature(view_settings) + assert len(sig.parameters) == 1 + `) +}) +``` + +`view_settings` should return the message `No settings available.` if the given dictionary is empty. + +```js +({ + test: () => runPython(` + empty_settings = {} + result = view_settings(empty_settings) + expected_msg = "No settings available." + assert result == expected_msg + `) +}) +``` + +`view_settings` should return formatted settings for non-empty dictionary. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "dark", "notifications": "enabled", "volume": "high"} + result = view_settings(settings_in_test) + assert result.startswith("Current User Settings:") + assert "Theme: dark" in result + assert "Notifications: enabled" in result + assert "Volume: high" in result + `) +}) +``` + +`view_settings` should capitalize the first letter of each setting name. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "dark", "volume": "high"} + result = view_settings(settings_in_test) + assert "Theme:" in result + assert "Volume:" in result + assert "theme:" not in result + assert "volume:" not in result + `) +}) +``` + +`view_settings` should display the correct results and end with a newline character. + +```js +({ + test: () => runPython(` + settings_in_test = {"theme": "light", "language": "English", "notifications": "enabled"} + result = view_settings(settings_in_test) + assert result == "Current User Settings:\\nTheme: light\\nLanguage: English\\nNotifications: enabled\\n" + `) +}) + +``` + +# --seed-- + +## --seed-contents-- + +```py + +``` + +# --solutions-- + +```py +def add_setting(settings, key_value): + key, value = key_value + key = key.lower() + value = value.lower() + if key in settings: + return f"Setting '{key}' already exists! Cannot add a new setting with this name." + else: + settings[key] = value + return f"Setting '{key}' added with value '{value}' successfully!" + +def update_setting(settings, key_value): + key, value = key_value + key = key.lower() + value = value.lower() + if key in settings: + settings[key] = value + return f"Setting '{key}' updated to '{value}' successfully!" + else: + return f"Setting '{key}' does not exist! Cannot update a non-existing setting." + +def delete_setting(settings, key): + key = key.lower() + if key in settings: + del settings[key] + return f"Setting '{key}' deleted successfully!" + else: + return "Setting not found!" + +def view_settings(settings): + if not settings: + return "No settings available." + else: + settings_str = "Current User Settings:\n" + for key, value in settings.items(): + settings_str += f"{key.capitalize()}: {value}\n" + return settings_str + +test_settings = { + "theme": "light", + "language": "English", + "notifications": "enabled" +} + +print(add_setting(test_settings, ("VOLUME", "HIGH"))) +print(update_setting(test_settings, ("theme", "dark"))) +print(delete_setting(test_settings, "language")) +print(view_settings(test_settings)) +``` diff --git a/curriculum/superblock-structure/full-stack.json b/curriculum/superblock-structure/full-stack.json index 4be74a08731..dee389d2a8f 100644 --- a/curriculum/superblock-structure/full-stack.json +++ b/curriculum/superblock-structure/full-stack.json @@ -1308,7 +1308,7 @@ { "dashedName": "lecture-working-with-dictionaries-and-sets" }, { "dashedName": "lecture-working-with-modules" }, { "dashedName": "workshop-medical-data-validator" }, - { "dashedName": "lab-placeholder-dictionaries-and-sets" }, + { "dashedName": "lab-user-configuration-manager" }, { "dashedName": "review-dictionaries-and-sets" }, { "dashedName": "quiz-dictionaries-and-sets" } ]