diff --git a/.vscode/settings.json b/.vscode/settings.json index bbda5188d..66af31ed7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -119,8 +119,9 @@ "editor.defaultFormatter": "charliermarsh.ruff", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.fixAll.ruff": true, - "source.organizeImports.ruff": true + "source.fixAll.ruff": "explicit", + "source.organizeImports.ruff": "explicit" } - } + }, + "cSpell.words": ["unittests"] } diff --git a/collaboration/README.md b/collaboration/README.md index 20889b951..c4bab199f 100644 --- a/collaboration/README.md +++ b/collaboration/README.md @@ -1,5 +1,65 @@ -# Collaboration +# 🌟Our Group Norms🌟 - +We are committed to fostering a respectful, inclusive, and +collaborative environment that values trust, open communication, +and mutual support. These norms will guide our interactions and +help us achieve our shared goals while accommodating individual +differences and challenges. By adhering to these principles, we +aim to create a team culture that drives success and personal +growth. + + + +## πŸ“‹ Group Norms for Collaboration + + **πŸ’Œ Foster a Safe and Inclusive Environment** + Create a supportive space where everyone feels comfortable + sharing ideas, asking questions, and expressing challenges. + Include mental health concerns without fear of judgment. + + **🀝 Build and Maintain Trust** + Commit to delivering quality work, meeting deadlines, and + keeping promises. Encourage openness and collaboration by + sharing expertise and asking for help when needed. + + **πŸ’‘ Resolve Issues Constructively** + Approach challenges with empathy and focus on solutions. Use + open, non-confrontational communication. Involve mediation + if necessary to maintain professionalism and respect. + + **βš–οΈ Balance Collaboration and Decision-Making** + Use discussions for brainstorming and debates for decisions. + Ensure all perspectives are valued, and disagreements are + handled constructively. + + **⏰ Respect Each Member’s Time** + Plan meetings only when essential and provide agendas early. + Use a shared calender to accommodate schedules and streamline + communication. + +**πŸ“’ Ensure Transparent Communication** + Discussions and Progress Tracking: GitHub Issues, Pull Requests, project board. + + Quick Updates: Slack. + + Planning and Documentation: Shared Google Docs. + + Synchronous Meetings: Zoom for discussions or decision-making. + + **πŸŽ‰ Celebrate Contributions and Milestones** + Recognize and celebrate team achievements. Foster a positive + and motivating atmosphere for all members. + + **πŸ”„ Adapt and Support Flexibility** + Be adaptable to personal challenges or unforeseen issues. + Maintain a forgiving and understanding spirit. + + **πŸ” Reflect and Improve Together** + Regularly review team processes and suggest improvements to + enhance collaboration, productivity, and growth. + + **πŸš€ Strive for Shared Purpose and Growth** + Align individual and team goals to ensure meaningful work. + Foster development, purpose, and shared accomplishments. diff --git a/collaboration/communication.md b/collaboration/communication.md index 484652e0f..1747dd379 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -1,54 +1,98 @@ - - # Communication -______________________________________________________________________ +--- ## Communication Schedule -| Day | How | The topic of discussion | | --- | :-: | ----------------------- | -| | | | +| **Day** | **How** | **Topic of Discussion** | +|---------------|-------------------|---------------------------------| +| Friday/Sunday | Video call (Zoom) | Updates, discussions, decisions | +| Everyday | Slack | Quick questions, announcements | + +--- ## Communication Channels -how often will we get in touch on each channel, and what we will discuss there: +**How often will we use each channel and what for:** -- **Issues**: -- **Pull Requests**: -- **Slack/Discord**: -- **Video Calls**: +- **Issues**: + - **Frequency**: Daily or as needed. + - **Topics**: Bugs, features, docs, and project discussions. -______________________________________________________________________ +- **Pull Requests**: + - **Frequency**: When ready for review. + - **Topics**: Code feedback, changes, and approval. -## Availability +- **Slack/Discord**: + - **Frequency**: Continuously. + - **Topics**: Questions, updates, links, and team bonding. -### Availability for calling/messaging +- **Video Calls**: + - **Frequency**: Weekly or bi-weekly. + - **Topics**: Planning, retrospectives, and complex issues. -| Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | | ------- | :----: | :-----: | :-------: | :------: | :----: | :------: | :----: | -| _name_ | | | | | | | | +--- -### How many hours everyone has per day +## Availability -- name: _5h_; -- name: _6h_; -- name: _5h_; -- name: _4h_; -- name: _3h_; +### Availability for Calling/Messaging + +| **Day** | **Mon** | **Tue** | **Wed** | **Thu** | **Fri** | +|-----------|:-------:|:-------:|:-------:|:-------:|:-------:| +| Derek | βœ” | βœ” | βœ” | βœ” | βœ” | +| Safaa | βœ” | βœ” | βœ” | ✘ | ✘ | +| Frankline | βœ” | βœ” | βœ” | βœ” | βœ” | +| Tibyan | ✘ | βœ” | ✘ | ✘ | βœ” | +| Azza | βœ” | βœ” | βœ” | ✘ | ✘ | +| Kareiman | βœ” | βœ” | βœ” | βœ” | βœ” | +| Eman | βœ” | βœ” | βœ” | βœ” | βœ” | +| Shima | βœ” | ✘ | βœ” | βœ” | βœ” | + +| **Day** | **Sat** | **Sun** | +|-----------|:-------:|:-------:| +| Derek | βœ” | βœ” | +| Safaa | ✘ | ✘ | +| Frankline | ✘ | ✘ | +| Tibyan | βœ” | βœ” | +| Azza | βœ” | βœ” | +| Kareiman | βœ” | βœ” | +| Eman | βœ” | βœ” | +| Shima | βœ” | ✘ | + +--- + +### Hours Available Per Day + +| **Name** | **Mon** | **Tue** | **Wed** | **Thu** | **Fri** | +|------------|---------|---------|---------|---------|---------| +| Ambetsa | 2 | 2 | 2 | 2 | 2 | +| Derek | 2 | 2 | 2 | 2 | 2 | +| Safaa | 2 | 2 | 2 | ✘ | ✘ | +| Shima | 2 | ✘ | 3 | 3 | 3 | +| Tibyan | 1 | 6 | 1 | 1 | 6 | +| Azza | 2 | 7 | 7 | ✘ | ✘ | +| Kareiman | 6 | 6 | 6 | 6 | 3 | +| Eman | 2 | 2 | 2 | 2 | 2 | + +| **Name** | **Sat** | **Sun** | +|------------|---------|---------| +| Ambetsa | ✘ | ✘ | +| Derek | 2 | 2 | +| Safaa | 2 | 2 | +| Shima | 3 | ✘ | +| Tibyan | 6 | 6 | +| Azza | 2 | 7 | +| Kareiman | 4 | 4 | +| Eman | 3 | 3 | + +--- ## Asking for Help -There's a fine line between confidently learning from your mistakes, and -stubbornly getting no where. Here is a general guide for when to ask for help -based on how long you've been stuck on the same problem: +Guidelines for asking help: + +1. **0-30 min**: Try solving independently. +2. **30-60 min**: Ask group members for help. +3. **60+ min**: Tag coaches on Slack/GitHub. -1. _0 -> 30 min_: Try on your own -1. _30 -> 60 min_: Ask your group for help -1. _60+ min_: Tag your coaches in Slack or GitHub +--- diff --git a/collaboration/constraints.md b/collaboration/constraints.md index 24079505c..f2da8cdd1 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -1,34 +1,66 @@ - +# βš™οΈ Project Boundaries & Constraints -# Constraints +## 🚧 Clear Boundaries for Efficiency -Some boundaries around our project. +To ensure efficiency and balanced contributions,the project should have +clear boundaries. -## External +Roles and responsibilities should be well-defined to prevent +overlapping efforts. - +Expectations should be set for balanced contributions, considering +members' constraints. -## Internal: Involuntary +A culture of constructive feedback and solution-focused discussions +should be established. - +A clear process for resolving conflicts is essential. -## Internal: Voluntary +These boundaries aim to create a productive and supportive +environment for the team - +## 🌍 External Constraints + +The team faces several external constraints impacting collaboration: + +* **🌍 Timezones:** Remote work across different timezones can +be challenging. +* **🌐 Internet Access:** Limited or unstable internet access complicates +communication and online collaboration. +* **πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ Family & Work:** Some members are constrained by family and work +responsibilities. +* **πŸ“š Academic Commitments:** Others face time limitations due to +university exams. + +## βš™οΈ Internal Involuntary Constraints + +'''The team faces several **internal involuntary constraints** that affect +their progress:''' + +* **πŸ“‚ Git & GitHub Knowledge:** Many members lack prior knowledge or +experience with Git and GitHub. +* **πŸ› οΈ Technical Expertise:** Limited technical expertise, combined with +new skills +required, is a challenge to the team members. +* **⏳ Time Availability:** Balancing professional commitments and personal +responsibilities limits availability. + +These factors create hurdles in both **skill development** and +**team collaboration**. + +## πŸ› οΈ Internal Voluntary Constraints + +Members commit to the following **voluntary constraints** to ensure +steady progress: + +* **πŸ“ Daily Progress Updates:** Members will provide daily updates on +their progress. +* **πŸ’» Medium-level Coding Challenges:** Focus on coding challenges that +match everyone's skill level to promote learning. +* **βš–οΈ Balancing Commitments:** Prioritizing a balance between project +work and other commitments. +* **πŸ“¬ Asynchronous Communication:** Emphasis on using asynchronous methods +like GitHub issues and pull requests. + +These guidelines aim to foster effective teamwork, skill development, and +steady project progress. diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index 11c583d2b..8cf6c5bcd 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -1,5 +1,51 @@ # Learning Goals -## Collective +## πŸ† Collective Objectives πŸ† -## Individual +### πŸ§‘β€πŸ’» Seamless Collaboration and Version Control + +- Use Git and GitHub effectively for version control and +collaboration in group projects. +- Enhance team dynamics through effective use of GitHub features like +pull requests and issue tracking. +- Implement best practices for version control, code reviews, +and continuous integration. + +### 🀝 Strengthen Team Collaboration and Communication + +- Build strong teamwork through mutual support, exchanging ideas, +and solving problems together. +- Foster open communication and feedback to improve group performance. +- Navigate and manage conflicts in group settings to strengthen collaboration. + +### 🎯 Deliver Exceptional Outcomes + +- Maintain high standards in code quality, documentation, and achieve project +milestones through collective effort. +- Participate in constructive code reviews and refine solutions collectively. + +### 🌐 Expand Professional Networks + +- Strengthen team connections for future opportunities and collaborations. +- Build relationships that support professional growth within and outside the team. + +## πŸš€ Individual Objectives πŸš€ + +Each team member will pursue the following professional development objectives: + +- Practice Python to improve skills, write clean and readable code, and learn +from good examples. +- Explore computer science topics, focusing on debugging, testing, and unit testing. +- Apply Python in data analysis and science. + +- Learn and effectively use Git and GitHub for collaboration and group projects. +- Gain confidence in debugging with tools like pdb,the VSCode debugger, and the +trace module. + +- Work well in groups, exchange ideas, and improve through feedback and code reviews. +- Build connections and improve communication skills. + +- Practice coding, documenting, testing, and debugging by solving challenges. + +- Practice writing Python code using new language features. +- Explore academic topics and non-academic skills to build diverse expertise. diff --git a/solutions/README.md b/solutions/README.md index 9852346d2..a3f85b77b 100644 --- a/solutions/README.md +++ b/solutions/README.md @@ -1 +1,30 @@ # Solutions + +## Merge Dictionaries Solution + +This repository contains a Python solution to merge two dictionaries. +The solution merges two dictionaries by resolving conflicts based on an optional + conflict resolution function. + +### Features + +- Merges two dictionaries. +- Resolves conflicts with a custom function, or by default, `dict2` overwrites `dict1`. + +### How to Run + +1. Clone the repository. +2. Install dependencies (if any). +3. Run the tests: + + ```bash + python -m unittest solutions/tests/test_merge_dictionaries.py + ``` + +### Example + +```python +dict1 = {"a": 1, "b": 2} +dict2 = {"b": 3, "c": 4} +merged = merge_dictionaries(dict1, dict2) +print(merged) # Output: {'a': 1, 'b': 3, 'c': 4} diff --git a/solutions/__init__.py b/solutions/__init__.py index 8b1378917..e69de29bb 100644 --- a/solutions/__init__.py +++ b/solutions/__init__.py @@ -1 +0,0 @@ - diff --git a/solutions/merge_dictionaries.py b/solutions/merge_dictionaries.py new file mode 100644 index 000000000..c70d95c3d --- /dev/null +++ b/solutions/merge_dictionaries.py @@ -0,0 +1,59 @@ +""" +This module contains the implementation of the `merge_dictionaries` function. + +The `merge_dictionaries` function allows merging two dictionaries into one, +with support for resolving key conflicts through a custom resolution function. + +Created on 15 01 2025 +@author: Frankline Ambetsa +""" + + +def merge_dictionaries(dict1, dict2, conflict_resolution=None): + """ + Merge two dictionaries into one. + + If keys conflict, a conflict resolution function can be provided + to decide which value to keep. If no function is provided, the value + from `dict2` will overwrite the value from `dict1`. + + Parameters: + dict1 (dict): The first dictionary. + dict2 (dict): The second dictionary. + conflict_resolution (function, optional): A function that takes + two arguments (value1, value2) and returns the resolved value. + + Returns: + dict: A merged dictionary. + + Raises: + AssertionError: If `dict1` or `dict2` is not a dictionary. + AssertionError: If `conflict_resolution` is not callable when provided. + + Examples: + >>> merge_dictionaries({'a': 1}, {'a': 2, 'b': 3}) + {'a': 2, 'b': 3} + >>> merge_dictionaries({'a': 1}, {'a': 2, 'b': 3}, max) + {'a': 2, 'b': 3} + >>> merge_dictionaries({'x': 1}, {'y': 2}) + {'x': 1, 'y': 2} + """ + # Defensive assertions + assert isinstance(dict1, dict), "dict1 must be a dictionary." + assert isinstance(dict2, dict), "dict2 must be a dictionary." + if conflict_resolution is not None: + assert callable(conflict_resolution), ( + "conflict_resolution must be a callable function." + ) + + merged = dict1.copy() # Start with a copy of the first dictionary + + for key, value in dict2.items(): + if key in merged and conflict_resolution: + # Resolve conflict using the provided function + merged[key] = conflict_resolution(merged[key], value) + else: + # Add or overwrite key with dict2's value + merged[key] = value + + return merged diff --git a/solutions/tests/README.md b/solutions/tests/README.md index 007eb9551..647035671 100644 --- a/solutions/tests/README.md +++ b/solutions/tests/README.md @@ -1 +1,34 @@ # Tests + +## Tests for Dictionary Merging with Conflict Resolution + +This folder contains unit tests for the dictionary merging and conflict resolution + functionalities implemented in the `merge_dictionaries.py` script. + +## Purpose + +The purpose of the tests is to ensure that the dictionary merging logic, +including handling conflicts, works as expected. The tests verify that: + +- Dictionaries are merged correctly. +- Conflict resolution logic (e.g., using the `max` function) + is applied properly when keys conflict. +- Edge cases and various scenarios are handled appropriately. + +## Test File Structure + +- `test_merge_dictionaries.py`: Contains unit tests for the `merge_dictionaries` + function. It includes tests for: + - Default dictionary merging (where dictionary B overwrites dictionary A). + - Conflict resolution merging (using the `max` value). + - Various edge cases, such as empty dictionaries, overlapping keys, and more. + +## Running the Tests + +To run the tests, follow these steps: + +1. **Navigate to the project root directory** (where the `solutions` folder is located): + + ```bash + cd /path/to/your/project + python -m unittest discover -s solutions/tests diff --git a/solutions/tests/test_merge_dictionaries.py b/solutions/tests/test_merge_dictionaries.py new file mode 100644 index 000000000..fbbba371f --- /dev/null +++ b/solutions/tests/test_merge_dictionaries.py @@ -0,0 +1,83 @@ +# solutions/tests/test_merge_dictionaries.py + +""" +Unit tests for the `merge_dictionaries` function. + +These tests ensure correct behavior of the `merge_dictionaries` function, +including standard merging, conflict resolution, edge cases, and input validation. + +Created on 15 01 2025 +@author: Frankline Ambetsa +""" + +import unittest +from solutions.merge_dictionaries import merge_dictionaries + + +class TestMergeDictionaries(unittest.TestCase): + """Unit tests for the `merge_dictionaries` function.""" + + def test_no_conflicts(self): + """It should merge dictionaries with no conflicting keys.""" + dict1 = {"a": 1, "b": 2} + dict2 = {"c": 3, "d": 4} + expected = {"a": 1, "b": 2, "c": 3, "d": 4} + self.assertEqual(merge_dictionaries(dict1, dict2), expected) + + def test_overwrite_conflicts(self): + """It should overwrite conflicting keys with values from dict2.""" + dict1 = {"a": 1, "b": 2} + dict2 = {"b": 3, "c": 4} + expected = {"a": 1, "b": 3, "c": 4} + self.assertEqual(merge_dictionaries(dict1, dict2), expected) + + def test_conflict_resolution_max(self): + """It should resolve conflicts using the max function.""" + dict1 = {"a": 1, "b": 5} + dict2 = {"b": 3, "c": 4} + expected = {"a": 1, "b": 5, "c": 4} + self.assertEqual(merge_dictionaries(dict1, dict2, max), expected) + + def test_conflict_resolution_min(self): + """It should resolve conflicts using the min function.""" + dict1 = {"a": 1, "b": 5} + dict2 = {"b": 3, "c": 4} + expected = {"a": 1, "b": 3, "c": 4} + self.assertEqual(merge_dictionaries(dict1, dict2, min), expected) + + def test_empty_dicts(self): + """It should return an empty dictionary when both inputs are empty.""" + dict1 = {} + dict2 = {} + expected = {} + self.assertEqual(merge_dictionaries(dict1, dict2), expected) + + def test_one_empty_dict(self): + """It should return the non-empty dictionary when one input is empty.""" + dict1 = {"a": 1, "b": 2} + dict2 = {} + expected = {"a": 1, "b": 2} + self.assertEqual(merge_dictionaries(dict1, dict2), expected) + + def test_only_conflicts(self): + """It should overwrite keys with values from dict2 for conflicting keys.""" + dict1 = {"a": 1} + dict2 = {"a": 2} + expected = {"a": 2} + self.assertEqual(merge_dictionaries(dict1, dict2), expected) + + def test_non_dict_inputs(self): + """It should raise a TypeError for non-dictionary inputs.""" + with self.assertRaises(AssertionError): + merge_dictionaries([], {"a": 1}) + with self.assertRaises(AssertionError): + merge_dictionaries({"a": 1}, 42) + + def test_invalid_conflict_resolution(self): + """It should raise a ValueError for non-callable conflict resolution.""" + with self.assertRaises(AssertionError): + merge_dictionaries({"a": 1}, {"a": 2}, conflict_resolution=42) + + +if __name__ == "__main__": + unittest.main()