From 6ca52e5248fe4f98b667681492aac54dd8697eee Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Sun, 22 Dec 2024 23:13:07 +0000 Subject: [PATCH 001/139] README file Updated! --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index e69de29bb..2418f8fef 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,48 @@ +# Collab Coders + +> Welcome to the **Collab Coders** repository! 🚀 +We are a team of passionate Junior developers From MIT. +> dedicated to building impactful solutions through collaboration and innovation. + +--- + +## 🌟 About Us + +> At **Collab Coders**, we believe in the power of teamwork: + +- to tackle complex challenges and create meaningful projects. +- This repository serves as a hub for our collaborative efforts. +- where ideas turn into reality. + +--- + +## 📂 Repository Structure + +Here’s how the repository is organized: + +- `main`: The primary branch containing stable and reviewed code. +- `feature-branches`: Each team member has their own branch +- for working on features or tasks. +- Branches are named after it is functionality for clarity +- (e.g., `feature-factorial-function`, `feature-sort-list`). + +--- + +## 🛠️ Technologies Used + +> Our team use stack of tools and technologies +> based on the program specifications and requirements: + +- **Languages**: Python, Markdown +- **Frameworks**: N/A +- **Tools**: Github,Git, VS Code +- **Communication_channels**: Slack, Google Meet, Zoom, Whatsapp + +--- + +## 🌱 How to Contribute + +1. Clone the repository: + + ```bash + git clone From aa7b099bd877528ac18306a01cc6c7908439ec7d Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:16:28 +0000 Subject: [PATCH 002/139] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2418f8fef..335ead914 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Collab Coders > Welcome to the **Collab Coders** repository! 🚀 -We are a team of passionate Junior developers From MIT. +We are a team of passionate Junior developers From M_E_T. > dedicated to building impactful solutions through collaboration and innovation. --- From cdf1de683bbe4cdda15c9480ff17c0d0af9a525e Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:18:14 +0000 Subject: [PATCH 003/139] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 335ead914..7b1247743 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Collab Coders > Welcome to the **Collab Coders** repository! 🚀 -We are a team of passionate Junior developers From M_E_T. +We are a team of passionate Junior developers From MET. > dedicated to building impactful solutions through collaboration and innovation. --- From 614506270a8238f0a9e1148f5bed543ed0c2750f Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:30:08 +0000 Subject: [PATCH 004/139] Update .markdownlint.yml disable the ( MK0013 ) line-length rule for specific scenarios. to extend the line-length. --- .markdownlint.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.markdownlint.yml b/.markdownlint.yml index ee6205f5c..9f5895330 100644 --- a/.markdownlint.yml +++ b/.markdownlint.yml @@ -1,3 +1,11 @@ ignore: - venv - .github + + { + "MD013": { + "line_length": 150, + "ignore_urls": true + } +} + From a68fa85fa5645971cecb6b3bd089e5187c7dd260 Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:36:08 +0000 Subject: [PATCH 005/139] Update .markdownlint.yml Markdown linter to disable the (MK0013) line-length rule for specific scenarios. --- .markdownlint.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.markdownlint.yml b/.markdownlint.yml index 9f5895330..1212d186b 100644 --- a/.markdownlint.yml +++ b/.markdownlint.yml @@ -2,10 +2,8 @@ ignore: - venv - .github - { - "MD013": { - "line_length": 150, - "ignore_urls": true - } -} + +MD013: + line_length: 150 + ignore_urls: true From 7b958a1b398122c8b37f45654eea8332f2255b98 Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Sun, 22 Dec 2024 23:47:38 +0000 Subject: [PATCH 006/139] Pytest CI check task disabled for starting of the project. --- .github/workflows/ci-checks.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index d56775453..00a06d350 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -51,13 +51,13 @@ jobs: run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" shell: bash - py_tests: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: python version - run: python --version - shell: bash - - name: Python - Run Tests - run: python -m unittest - shell: bash + # py_tests: + # runs-on: ubuntu-latest + # steps: + #- uses: actions/checkout@v4 + # - name: python version + # run: python --version + # shell: bash + # - name: Python - Run Tests + # run: python -m unittest + # shell: bash From d53d1024c6f613fc55d9b7ae1076f0fd76bbbd40 Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:43:08 +0000 Subject: [PATCH 007/139] Update ci-checks.yml --- .github/workflows/ci-checks.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 00a06d350..d6226bbe0 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -51,13 +51,14 @@ jobs: run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" shell: bash - # py_tests: - # runs-on: ubuntu-latest - # steps: - #- uses: actions/checkout@v4 - # - name: python version - # run: python --version - # shell: bash - # - name: Python - Run Tests - # run: python -m unittest - # shell: bash + py_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: python version + run: python --version + shell: bash + - name: Python - Run Tests + run: python -m unittest + shell: bash + From 456ccaf6c745f5dbbbcc56ad586895c69b51606b Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Wed, 25 Dec 2024 12:31:35 +0000 Subject: [PATCH 008/139] README update [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2418f8fef..fc141dc4d 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Here’s how the repository is organized: - `feature-branches`: Each team member has their own branch - for working on features or tasks. - Branches are named after it is functionality for clarity -- (e.g., `feature-factorial-function`, `feature-sort-list`). +- (e.g., `challenges/factorial-function`, `challenges/sort-list`). --- From dde4eff63e0671c84c6a4192dfd8fa4e0200166f Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Wed, 25 Dec 2024 15:11:24 +0000 Subject: [PATCH 009/139] inital modification --- collaboration/communication.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/collaboration/communication.md b/collaboration/communication.md index 484652e0f..fab95203c 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -13,7 +13,10 @@ ______________________________________________________________________ ## Communication Schedule -| Day | How | The topic of discussion | | --- | :-: | ----------------------- | +| Day | How | The topic of discussion | +| --- | :-: | ----------------------- | +| | | | +| | | | | | | | ## Communication Channels @@ -31,17 +34,29 @@ ______________________________________________________________________ ### Availability for calling/messaging -| Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | | ------- | :----: | :-----: | :-------: | :------: | :----: | :------: | :----: | -| _name_ | | | | | | | | +| Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | +|:------ | :----: | :-----: | :-------: | :------: | :----: | :------: | ----: | +| Hiba | | | | | | | | +| Jeffery | | | | | | | | +| Kelvin | | | | | | | | +| Mahdia | | | | | | | | +| Martha | | | | | | | | +| Osei | | | | | | | | +| Rina | | | | | | | | +| Shagun | | | | | | | | +| Yool | | | | | | | | ### How many hours everyone has per day -- name: _5h_; -- name: _6h_; -- name: _5h_; -- name: _4h_; -- name: _3h_; +- Hiba: +- Jeffery: +- Kelvin: +- Mahdia: +- Martha: +- Osei: +- Rina: +- Shagun: +- Yool: ## Asking for Help From 2bdcbc31e0851b48da6821e0dc5b528979be5c4b Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Wed, 25 Dec 2024 15:56:20 +0000 Subject: [PATCH 010/139] group learning goals updated! --- collaboration/learning_goals.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index 11c583d2b..90b0c67cc 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -1,5 +1,23 @@ -# Learning Goals +# Learning Goals 🧑🏽‍💻 -## Collective +## Collective Goals -## Individual +- Collaboration and productivity between team members in GitHub and Slack. +- Get used to Git and GitHub. +- Communicate effectively and have an inclusive and friendly environment. +- Learn more about documentation and testing in programming. +- Learn more about Python language features. + +## Individual Goals + +| **Name** | **Goals** | +| -------- | ------------------------------------------------------------------ | +| Mahdia | Enhance skills in Python for data analysis and automation scripts. | +| Jeffery | | +| Hiba | | +| Rina | | +| Yool | | +| Osei | | +| Shogun | | +| Martha | | +| Kelvin | | From e05d74ac0dc794c34619eb314ade195e8c119540 Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:11:53 +0000 Subject: [PATCH 011/139] Update ci-checks.yml to skip CI Conditional added for the Pytest job, to only run when the commits are not related to the markdown file. --- .github/workflows/ci-checks.yml | 50 +++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index d6226bbe0..a027c2e4a 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -1,22 +1,29 @@ name: ET CI Checks -on: [push, pull_request, workflow_dispatch] +on: + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: jobs: ls_linting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ls-lint/action@v2.2.3 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ls-lint/action@v2.2.3 md_formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: nosborn/github-action-markdown-cli@v3.3.0 - with: - files: . - config_file: .markdownlint.yml + - uses: actions/checkout@v4 + - uses: nosborn/github-action-markdown-cli@v3.3.0 + with: + files: . + config_file: .markdownlint.yml py_formatting: runs-on: ubuntu-latest @@ -44,21 +51,34 @@ jobs: if: always() - name: install pylint run: | - python - m pip install --upgrade pip + python -m pip install --upgrade pip pip install pylint shell: bash - name: Python - Check Linting - pylint - run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" + run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" shell: bash py_tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: python version - run: python --version - shell: bash + + # Determine if only Markdown files were changed + - name: Check for non-Markdown file changes + id: check_files + run: | + git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt + if ! grep -qv '\.md$' changed_files.txt; then + echo "Only Markdown files changed. Skipping py_tests." + echo "skip=true" >> $GITHUB_ENV + else + echo "Non-Markdown files changed. Proceeding with py_tests." + echo "skip=false" >> $GITHUB_ENV + + # Run Python tests only if non-Markdown files are changed - name: Python - Run Tests + if: env.skip == 'false' run: python -m unittest shell: bash + From eee33e2f7573e3cb0f81de1f44518ff3d4240bea Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 26 Dec 2024 13:29:42 +0000 Subject: [PATCH 012/139] updated plan --- collaboration/communication.md | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/collaboration/communication.md b/collaboration/communication.md index fab95203c..2257a1259 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -7,7 +7,7 @@ you can share the rest in confidence with you group by another channel --> -# Communication +# Communication 📬 ______________________________________________________________________ @@ -23,41 +23,30 @@ ______________________________________________________________________ how often will we get in touch on each channel, and what we will discuss there: -- **Issues**: -- **Pull Requests**: -- **Slack/Discord**: -- **Video Calls**: +- **Issues**: To track team progress, update as needed, and assign tasks where needed +- **Pull Requests**: Reviewed within 48 hours for feedback, approving the change and merging it to the main branch + +- **Slack**: For daily task updates and resolving small problems from team members +- **Video Calls**: Zoom/Google meet preferably for general group meetings and weekly updates ______________________________________________________________________ ## Availability -### Availability for calling/messaging +### Availability for calling/messaging(+how many hours each day in EST) | Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | |:------ | :----: | :-----: | :-------: | :------: | :----: | :------: | ----: | -| Hiba | | | | | | | | -| Jeffery | | | | | | | | +| Hiba | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | +| Jeffery | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | | Kelvin | | | | | | | | -| Mahdia | | | | | | | | +| Mahdia | 9-12 | 9-12 | 10-12 | 10-12 | 9-12 | 9-12 | 10-12 | | Martha | | | | | | | | | Osei | | | | | | | | | Rina | | | | | | | | | Shagun | | | | | | | | | Yool | | | | | | | | -### How many hours everyone has per day - -- Hiba: -- Jeffery: -- Kelvin: -- Mahdia: -- Martha: -- Osei: -- Rina: -- Shagun: -- Yool: - ## Asking for Help There's a fine line between confidently learning from your mistakes, and From 44a2f4771e57b5715d95bf466966e2f4e32c35e3 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Thu, 26 Dec 2024 20:20:24 +0000 Subject: [PATCH 013/139] All members learning_goals added --- collaboration/learning_goals.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index 90b0c67cc..b8382e171 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -10,14 +10,15 @@ ## Individual Goals -| **Name** | **Goals** | -| -------- | ------------------------------------------------------------------ | -| Mahdia | Enhance skills in Python for data analysis and automation scripts. | -| Jeffery | | -| Hiba | | -| Rina | | -| Yool | | -| Osei | | -| Shogun | | -| Martha | | -| Kelvin | | +| Name | Goals | +| ------- | ------------------------------------------------------------------ | +| Mahdia | Enhance skills in Python for data analysis and automation scripts. | +| Jeffery | Master foundational data analysis skills, build a portfolio with real-world projects, earn certifications to kickstart my career in data analysis. | +| Hiba | Enhance my collaboration skills and develop good programming habits like documenting. | +| Rina | Learn how to use GitHub and the basics of coding. | +| Yool | | +| Osei | | +| Shogun | | +| Martha | Master skills in version control for tracking changes, collaborating on projects, and improve my knowledge in Python for Data Analysis. | +| Kelvin | | +| Terry | Gain in-depth knowledge about Python programming and Git/GitHub, work effectively with my teammates, and use this opportunity to build a program that could help others or set the foundation for something great. | From 90023a083fd5ce061ea7fd708ad698b74fe158d8 Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:24:47 +0000 Subject: [PATCH 014/139] Update .markdownlint.yml --- .markdownlint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.markdownlint.yml b/.markdownlint.yml index 1212d186b..8cc0eea94 100644 --- a/.markdownlint.yml +++ b/.markdownlint.yml @@ -4,6 +4,6 @@ ignore: MD013: - line_length: 150 + line_length: 180 ignore_urls: true From 1489e7b2d5e6554ae963af4a5eb8c1ccb5f06acb Mon Sep 17 00:00:00 2001 From: yoolmalaak Date: Thu, 26 Dec 2024 23:39:16 +0200 Subject: [PATCH 015/139] group norms --- collaboration/Group_Norms Readme.md | 157 ++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 collaboration/Group_Norms Readme.md diff --git a/collaboration/Group_Norms Readme.md b/collaboration/Group_Norms Readme.md new file mode 100644 index 000000000..2f5dbd9ee --- /dev/null +++ b/collaboration/Group_Norms Readme.md @@ -0,0 +1,157 @@ +# Collaboration + + + +## Group norms for ET6-Foundation-group-09's project + +**These group norms will serve as the guidelines and directives, everyone is expected to comply with, +yet no repercussions will follow if they are disregarded.** + +## Communication + +### Primary communication channel + +Slack + +WhatsAPP + +GitHub + +Zoom Meeting + +Google meet + +#### Response Time + +Everyone is expected to response to the messages on all the communication channels within 24 hours. + +#### Language of communication + +The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. + +#### Official Meeting platforms + +Zoom Meeting + +Google Meet + +The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. + +The time will be discussed and agreed by all the participants on slack and WhatsAPP. + +All the meetings are expected to last for one hour. + +The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. + +All the participants who missed the meeting are advised to watch the recording before sharing their opinions. + +## Group Organization + +**The team organization will ensure effective communication among the group members, making informed decisions +and ensuring that everyone is working on the same goal.** + +### Organizational Structure + +### Project lead + +### Responsibilities + +Oversees the project, ensuring timely completion and making sure no member is left behind. + +The project lead has no absolute authority over the group members. + +Coordinates the resolution of key issues and pull requests + +### Head of the project Communication + +### Key Responsibilities + +Discussion management on Github and WhatsAPP + +Schedule and control the group meeting + +### Deputy Head of the project Communication + +Assist the Head of communication in implementing communication plan + +Provides supports to group members, helping in resolving issues and answering questions. + +### Technical lead + +Assist in code review and conflict resolution + +## Collaboration Norms + +### collaboration Tools + +Github + +Git + +Visual Code Studio (VS Code) + +### Task Assignment + +Each team member will assign him/her self to the task using Github issues + +Everyone is expected to work individually and push it to the branch upon completion + +### Code Review + +Team members will review and provide feedback on each others's code within 48 hours + +we anticipate everyone bear in mind that we are reviewing codes not individuals. + +### Branching and Merging + +we will use feature branches and pull request to manage different version of codes + +## Conflict Resolution + +### Open Communication + +All the members are expected to communicate their concerns and challenges + +### Constructive Feedback + +We encourage the culture of constructive feedback and respectful criticism + +Remember we are reviewing codes not people + +### Conflict resolution process + +All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding + +## Respect and Inclusion + +### Equality + +All the group members have equal rights and their opinion must be respected. + +We equal participation from all the group members. + +### Respectful Communication + +Group members are expected to communicate respectful and professionally by avoiding offensive language. + +### Decision Making + +All the team members will have their voices in decision making. + +### Diversity + +We endeavor to create an inclusive environment that fosters diversity. + + + +## Groups Norms List + +### Communication Norms + +### Organization norms + +### Collaboration_Norms + +### Conflict Resolution Norms + +### Respect and Inclusion Norms From a38abdd12a38195bf44291a2186e02c51b4b92fc Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Fri, 27 Dec 2024 10:15:07 +0000 Subject: [PATCH 016/139] Update ci-checks.yml --- .github/workflows/ci-checks.yml | 58 +++++++++++++++------------------ 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index a027c2e4a..95e90fb7a 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -1,29 +1,22 @@ name: ET CI Checks -on: - push: - branches: - - main - pull_request: - branches: - - main - workflow_dispatch: +on: [push, pull_request, workflow_dispatch] jobs: ls_linting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ls-lint/action@v2.2.3 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ls-lint/action@v2.2.3 md_formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: nosborn/github-action-markdown-cli@v3.3.0 - with: - files: . - config_file: .markdownlint.yml + - uses: actions/checkout@v4 + - uses: nosborn/github-action-markdown-cli@v3.3.0 + with: + files: . + config_file: .markdownlint.yml py_formatting: runs-on: ubuntu-latest @@ -51,33 +44,34 @@ jobs: if: always() - name: install pylint run: | - python -m pip install --upgrade pip + python - m pip install --upgrade pip pip install pylint shell: bash - name: Python - Check Linting - pylint - run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" + run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" shell: bash py_tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - # Determine if only Markdown files were changed - - name: Check for non-Markdown file changes - id: check_files + + - name: python version + run: python --version + shell: bash + + - name: Check for test files + id: check_tests run: | - git diff --name-only ${{ github.event.before }} ${{ github.sha }} > changed_files.txt - if ! grep -qv '\.md$' changed_files.txt; then - echo "Only Markdown files changed. Skipping py_tests." - echo "skip=true" >> $GITHUB_ENV + if find . -type f -name "test_*.py" | grep -q .; then + echo "has_tests=true" >> $GITHUB_OUTPUT else - echo "Non-Markdown files changed. Proceeding with py_tests." - echo "skip=false" >> $GITHUB_ENV - - # Run Python tests only if non-Markdown files are changed + echo "has_tests=false" >> $GITHUB_OUTPUT + fi + shell: bash + - name: Python - Run Tests - if: env.skip == 'false' + if: steps.check_tests.outputs.has_tests == 'true' run: python -m unittest shell: bash From dcf4ac272c5fe2ae1eafeb250a588611f9c0a546 Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Sun, 29 Dec 2024 20:37:44 +0000 Subject: [PATCH 017/139] communication --- collaboration/communication.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/collaboration/communication.md b/collaboration/communication.md index 2257a1259..6d82423b8 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -13,9 +13,9 @@ ______________________________________________________________________ ## Communication Schedule -| Day | How | The topic of discussion | +| Day & Time | How | The topic of discussion | | --- | :-: | ----------------------- | -| | | | +|Every Friday, 9 EST| Google Meet| Activity Updates| | | | | | | | | @@ -38,14 +38,15 @@ ______________________________________________________________________ | Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | |:------ | :----: | :-----: | :-------: | :------: | :----: | :------: | ----: | | Hiba | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | -| Jeffery | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | -| Kelvin | | | | | | | | -| Mahdia | 9-12 | 9-12 | 10-12 | 10-12 | 9-12 | 9-12 | 10-12 | -| Martha | | | | | | | | -| Osei | | | | | | | | -| Rina | | | | | | | | -| Shagun | | | | | | | | -| Yool | | | | | | | | +| Jeffery | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | +| Kelvin | | | | | | | | +| Mahdia | 9-12 | 9-12 | 10-12 | 10-12 | 9-12 | 9-12 | 10-12 | +| Martha | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | 9-12 | +| Osei | 10-13 |11-15 | 9-12 | 9-12 | 9-15 | 13-15 | 9-15| +| Rina | | 7-15 | | 7-15 | 7-15 | 9-15 | 9-15 | +| Terry | 9-11 | 9-11 | 9-11 | 6-9 | 9-11 | 9-12 | 9-11 | +| Yool | 9-12 | 9-12 | 10-13 | 8-12 | 9-12 | 10-13 | 10-13 | +|Shagun | | | | | | | | ## Asking for Help From f3c5412491bbfc9b9285bad9a2f33d528db24d56 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 11:22:26 +0000 Subject: [PATCH 018/139] Learning_goals for group 9 final update! --- collaboration/learning_goals.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index b8382e171..d18c97434 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -16,9 +16,8 @@ | Jeffery | Master foundational data analysis skills, build a portfolio with real-world projects, earn certifications to kickstart my career in data analysis. | | Hiba | Enhance my collaboration skills and develop good programming habits like documenting. | | Rina | Learn how to use GitHub and the basics of coding. | -| Yool | | -| Osei | | -| Shogun | | +| Yool | To have a deep understanding and a knowledge about Python programming, git, GitHub, and collaboration to enable me advance my career in computer science, build personal projects and gain experience through teamwork. | +| Osei | Learn the basics of Git and GitHub, how to send a pull request, The basics of python which includes documenting and testing. | | Martha | Master skills in version control for tracking changes, collaborating on projects, and improve my knowledge in Python for Data Analysis. | | Kelvin | | | Terry | Gain in-depth knowledge about Python programming and Git/GitHub, work effectively with my teammates, and use this opportunity to build a program that could help others or set the foundation for something great. | From b6edad1df8a09f90d98cd52357868eb409b2b0c8 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 11:43:58 +0000 Subject: [PATCH 019/139] Learning_goals for group 9 final update!! --- collaboration/learning_goals.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index d18c97434..bf41a3eba 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -10,14 +10,14 @@ ## Individual Goals -| Name | Goals | -| ------- | ------------------------------------------------------------------ | -| Mahdia | Enhance skills in Python for data analysis and automation scripts. | -| Jeffery | Master foundational data analysis skills, build a portfolio with real-world projects, earn certifications to kickstart my career in data analysis. | -| Hiba | Enhance my collaboration skills and develop good programming habits like documenting. | -| Rina | Learn how to use GitHub and the basics of coding. | -| Yool | To have a deep understanding and a knowledge about Python programming, git, GitHub, and collaboration to enable me advance my career in computer science, build personal projects and gain experience through teamwork. | -| Osei | Learn the basics of Git and GitHub, how to send a pull request, The basics of python which includes documenting and testing. | -| Martha | Master skills in version control for tracking changes, collaborating on projects, and improve my knowledge in Python for Data Analysis. | -| Kelvin | | -| Terry | Gain in-depth knowledge about Python programming and Git/GitHub, work effectively with my teammates, and use this opportunity to build a program that could help others or set the foundation for something great. | +| Name | Goals | +| ------- | ------------------------------------------------------------------------------------------------------------------------------ | +| Mahdia | Enhance skills in Python for data analysis and automation scripts. | +| Jeffery | Master foundational data analysis skills, build a portfolio with real-world projects, earn certifications to kickstart my career in data analysis.| +| Hiba | Enhance my collaboration skills and develop good programming habits like documenting. | +| Rina | Learn how to use GitHub and the basics of coding. | +| Yool | Gain a solid understanding of Python, Git, GitHub, and teamwork to advance my computer science career, build projects, gain collaborative experience.| +| Osei | Learn the basics of Git and GitHub, how to send a pull request, and the basics of Python, which include documenting and testing. | +| Martha | Master skills in version control for tracking changes, collaborating on projects, and improve my knowledge in Python for data analysis. | +| Kelvin | | +| Terry | Deepen Python and Git/GitHub skills, collaborate effectively with teammates, and create a program that helps others in the foundation for growth.| From b3dd350de5d792bdb257e0ca70a191d80826daf9 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 12:10:57 +0000 Subject: [PATCH 020/139] main branch ci changes keep reslove branch conflict! --- .github/workflows/ci-checks.yml | 35 ++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 8a98c28d8..e967f3f33 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -4,19 +4,19 @@ on: [push, pull_request, workflow_dispatch] jobs: ls_linting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ls-lint/action@v2.2.3 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ls-lint/action@v2.2.3 md_formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: nosborn/github-action-markdown-cli@v3.3.0 - with: - files: . - config_file: .markdownlint.yml + - uses: actions/checkout@v4 + - uses: nosborn/github-action-markdown-cli@v3.3.0 + with: + files: . + config_file: .markdownlint.yml py_formatting: runs-on: ubuntu-latest @@ -44,38 +44,33 @@ jobs: if: always() - name: install pylint run: | - python - m pip install --upgrade pip + python -m pip install --upgrade pip pip install pylint shell: bash - name: Python - Check Linting - pylint - run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" + run: "pylint solutions tests || echo '::warning title=Pylint Error(s)::Discuss solutions and trade-offs in code review.'" shell: bash py_tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - + - name: python version run: python --version shell: bash - + - name: Check for test files id: check_tests run: | - test_files=$(find ./solutions/tests -type f -name "test_*.py") - if [ -n "$test_files" ]; then - echo "Found test files:" - echo "$test_files" + if find . -type f -name "test_*.py" | grep -q .; then echo "has_tests=true" >> $GITHUB_OUTPUT else - echo "No test files found matching pattern ./solutions/tests/test_*.py" echo "has_tests=false" >> $GITHUB_OUTPUT fi shell: bash - + - name: Python - Run Tests if: steps.check_tests.outputs.has_tests == 'true' run: python -m unittest shell: bash - From 47a70c66b33944bf816f66e026d51ee2f3a0d990 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 13:02:22 +0000 Subject: [PATCH 021/139] challenge#1 for individual task! --- solutions/find_longest_palindrome.py | 87 +++++++++++ .../tests/test_find_longest_palindrome.py | 143 ++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 solutions/find_longest_palindrome.py create mode 100644 solutions/tests/test_find_longest_palindrome.py diff --git a/solutions/find_longest_palindrome.py b/solutions/find_longest_palindrome.py new file mode 100644 index 000000000..b91563bbe --- /dev/null +++ b/solutions/find_longest_palindrome.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for finding the longest palindromic substring in a string. + +Module contents: + - find_longest_palindrome: finds the longest palindrome within a string. + - is_palindrome: helper function to check if a string is a palindrome. + +Created on 28 12 2024 +@author: Mahdia Ahmadi +""" + +def find_longest_palindrome(text: str) -> str: + """ + Finds the longest palindromic substring within the input string. + + A palindrome reads the same forwards and backwards. This function returns + the first occurrence of the longest palindrome if multiple exist. + + Parameters: + text: str, the input string to search for palindromes + + Returns: + str: the longest palindromic substring found + + Raises: + AssertionError: if the input is not a string + + Examples: + >>> find_longest_palindrome("babad") + 'bab' + >>> find_longest_palindrome("racecar") + 'racecar' + >>> find_longest_palindrome("hello") + 'll' + >>> find_longest_palindrome("python") + 'p' + >>> find_longest_palindrome("") + '' + """ + # Input validation + assert isinstance(text, str), "Input must be a string" + + # Handle empty string and single characters + if len(text) <= 1: + return text + + # Initialize variables to track the longest palindrome + longest_start = 0 + longest_length = 1 + + # Check all possible substrings + for start in range(len(text)): + for end in range(start + longest_length, len(text) + 1): + substring = text[start:end] + # Only check if this could be a longer palindrome + if is_palindrome(substring) and len(substring) > longest_length: + longest_start = start + longest_length = len(substring) + + # Return the longest palindrome found + return text[longest_start:longest_start + longest_length] + + +def is_palindrome(text: str) -> bool: + """ + Checks if the input string is a palindrome. + + Parameters: + text: str, string to check + + Returns: + bool: True if the string is a palindrome, False otherwise + + Examples: + >>> is_palindrome("racecar") + True + >>> is_palindrome("hello") + False + >>> is_palindrome("a") + True + >>> is_palindrome("") + True + """ + # Compare string with its reverse + return text == text[::-1] diff --git a/solutions/tests/test_find_longest_palindrome.py b/solutions/tests/test_find_longest_palindrome.py new file mode 100644 index 000000000..cbf87542a --- /dev/null +++ b/solutions/tests/test_find_longest_palindrome.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for the longest palindrome finder functionality. + +This module contains unittest test cases for the find_longest_palindrome and +is_palindrome functions, including edge cases and invalid inputs. + +Created on 28 12 2024 +@author: Mahdia Ahmadi +""" + +import unittest +from find_longest_palindrome import find_longest_palindrome,is_palindrome + + +class TestPalindromeFinder(unittest.TestCase): + """ + Test suite for palindrome finding functions. + + This class contains unit tests for both the main palindrome finding function + and its helper function, covering normal cases, edge cases, and error conditions. + """ + + def test_empty_string(self): + """ + Test that an empty string returns an empty string. + """ + self.assertEqual(find_longest_palindrome(""), "") + + def test_single_character(self): + """ + Test that a single character string returns that character. + """ + self.assertEqual(find_longest_palindrome("a"), "a") + + def test_two_same_characters(self): + """ + Test string with two identical characters. + """ + self.assertEqual(find_longest_palindrome("aa"), "aa") + + def test_two_different_characters(self): + """ + Test string with two different characters returns first character. + """ + self.assertEqual(find_longest_palindrome("ab"), "a") + + def test_simple_odd_palindrome(self): + """ + Test finding a simple odd-length palindrome. + """ + self.assertEqual(find_longest_palindrome("racecar"), "racecar") + + def test_simple_even_palindrome(self): + """ + Test finding a simple even-length palindrome. + """ + self.assertEqual(find_longest_palindrome("abba"), "abba") + + def test_multiple_palindromes(self): + """ + Test string containing multiple palindromes returns the longest. + """ + self.assertEqual(find_longest_palindrome("abbaracecarxy"), "racecar") + + def test_overlapping_palindromes(self): + """ + Test string with overlapping palindromes. + """ + self.assertEqual(find_longest_palindrome("abababa"), "abababa") + + def test_no_long_palindrome(self): + """ + Test string with no palindromes longer than one character. + """ + self.assertEqual(find_longest_palindrome("python"), "p") + + def test_case_sensitive(self): + """ + Test that the function is case-sensitive. + """ + self.assertNotEqual(find_longest_palindrome("Racecar"), "Racecar") + + def test_with_spaces(self): + """ + Test string containing spaces. + """ + self.assertEqual(find_longest_palindrome("race car"), "r") + + def test_with_special_characters(self): + """ + Test string containing special characters. + """ + self.assertEqual(find_longest_palindrome("a!@#a"), "a") + + #defensive testcase + def test_invalid_input_type(self): + """ + Test that non-string input raises an AssertionError. + """ + with self.assertRaises(AssertionError): + find_longest_palindrome(123) + + +class TestIsPalindrome(unittest.TestCase): + """ + Test suite for the is_palindrome helper function. + """ + + def test_empty_string_palindrome(self): + """ + Test that an empty string is considered a palindrome. + """ + self.assertTrue(is_palindrome("")) + + def test_single_char_palindrome(self): + """ + Test that a single character is a palindrome. + """ + self.assertTrue(is_palindrome("x")) + + def test_simple_palindrome(self): + """ + Test a simple palindrome string. + """ + self.assertTrue(is_palindrome("level")) + + def test_non_palindrome(self): + """ + Test a non-palindrome string. + """ + self.assertFalse(is_palindrome("python")) + + def test_palindrome_with_spaces(self): + """ + Test that spaces affect palindrome detection. + """ + self.assertFalse(is_palindrome("race car")) + + +if __name__ == '__main__': + unittest.main() From 0235e1c048750c83791ac3ec5627d6764ebeaf8b Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 16:24:42 +0000 Subject: [PATCH 022/139] second individula task --- solutions/parse_email_alias.py | 169 ++++++++++++++++++++++ solutions/tests/test_parse_email_alias.py | 140 ++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 solutions/parse_email_alias.py create mode 100644 solutions/tests/test_parse_email_alias.py diff --git a/solutions/parse_email_alias.py b/solutions/parse_email_alias.py new file mode 100644 index 000000000..4abdbfc0d --- /dev/null +++ b/solutions/parse_email_alias.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for parsing and validating email aliases. + +Module contents: + - parse_email_alias: validates and extracts components of an email alias + +Created on 28 12 2024 +@author: Mahdia Ahamdi +""" + +def parse_email_alias(email: str) -> dict: + """ + Parse and validate an email address with optional alias tags. + + Validates email format and extracts components including the local part, + domain, and any alias tags. Supports Gmail-style + aliases and subdomain + addresses. + + Parameters: + email: str, the email address to parse + + Returns: + dict containing: + - valid: bool, whether the email is valid + - local_part: str, part before the @ (None if invalid) + - domain: str, part after the @ (None if invalid) + - tags: list[str], any alias tags found (empty if none) + - errors: list[str], any validation errors found + + Raises: + AssertionError: if the input is not a string + + Examples: + >>> # Test basic email + >>> result = parse_email_alias("user@example.com") + >>> result['valid'] + True + >>> result['local_part'] + 'user' + >>> result['domain'] + 'example.com' + >>> result['tags'] + [] + + >>> # Test with alias tag + >>> result = parse_email_alias("user+tag@example.com") + >>> result['valid'] + True + >>> result['local_part'] + 'user' + >>> result['tags'] + ['tag'] + + >>> # Test multiple tags + >>> result = parse_email_alias("user+tag1+tag2@example.com") + >>> result['tags'] + ['tag1', 'tag2'] + + >>> # Test subdomain + >>> result = parse_email_alias("user@sub.example.com") + >>> result['domain'] + 'sub.example.com' + + >>> # Test invalid email (no @) + >>> result = parse_email_alias("invalid.email") + >>> result['valid'] + False + >>> 'Missing @ symbol' in result['errors'] + True + + >>> # Test empty local part + >>> result = parse_email_alias("@domain.com") + >>> result['valid'] + False + >>> 'Empty local part' in result['errors'] + True + + >>> # Test invalid characters + >>> result = parse_email_alias("user<>@domain.com") + >>> result['valid'] + False + >>> 'Invalid characters in local part' in result['errors'] + True + + >>> # Test missing TLD + >>> result = parse_email_alias("user@sub.") + >>> result['valid'] + False + >>> 'Invalid domain (missing TLD)' in result['errors'] + True + + >>> # Test non-string input + >>> parse_email_alias(12345) + Traceback (most recent call last): + ... + AssertionError: Input must be a string + """ + #defensive assertion + assert isinstance(email, str), "Input must be a string" + + # Initialize result dictionary + result = { + 'valid': False, + 'local_part': None, + 'domain': None, + 'tags': [], + 'errors': [] + } + + # Basic validation for the input email + if not email: + result['errors'].append("Email cannot be empty") + return result + + # Check for @ symbol + if '@' not in email: + result['errors'].append("Missing @ symbol") + return result + + # Split into local part and domain + local_part, domain = email.split('@', 1) + + # Validate local part + if not local_part: + result['errors'].append("Empty local part") + return result + + # Check for invalid characters in local part + allowed_chars = set("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789.!#$%&'*+-/=?^_`{|}~") + if not all(c in allowed_chars for c in local_part): + result['errors'].append("Invalid characters in local part") + return result + + # Extract tags if present + base_local = local_part + tags = [] + if '+' in local_part: + base_local, *tags = local_part.split('+') + + # Validate domain + if not domain: + result['errors'].append("Empty domain") + return result + + if '..' in domain: + result['errors'].append("Invalid domain (consecutive dots)") + return result + + domain_parts = domain.split('.') + if len(domain_parts) == 1 or (len(domain_parts) > 1 and not domain_parts[-1]): + result['errors'].append("Invalid domain (missing TLD)") + return result + + if not all(part and all(c.isalnum() or c == '-' for c in part) + for part in domain_parts[:-1]) or not domain_parts[-1].isalnum(): + result['errors'].append("Invalid domain format") + return result + + # If we got here, email is valid + result['valid'] = True + result['local_part'] = base_local + result['domain'] = domain + result['tags'] = tags + + return result diff --git a/solutions/tests/test_parse_email_alias.py b/solutions/tests/test_parse_email_alias.py new file mode 100644 index 000000000..3254e40d6 --- /dev/null +++ b/solutions/tests/test_parse_email_alias.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Tests for the parse_email_alias module. + +This module contains unit tests for the parse_email_alias function, +including normal cases, edge cases, and error conditions. + +Created on 28 12 2024 +@author: Mahdia Ahmadi +""" + +import unittest +from parse_email_alias import parse_email_alias + +class TestParseEmailAlias(unittest.TestCase): + """ + Test suite for the parse_email_alias function. + + This class contains unit tests covering various email parsing scenarios, + including valid emails, invalid formats, and edge cases. + """ + + def test_valid_email(self): + """ + Test a basic valid email address. + + Verifies that the function correctly parses a standard email address. + """ + self.assertEqual(parse_email_alias("user@example.com")['valid'], True) + + def test_email_with_tags(self): + """ + Test an email with alias tags. + + Checks if the function properly handles Gmail-style + aliases. + """ + self.assertEqual(parse_email_alias("user+tag@example.com")['tags'], ['tag']) + + def test_multiple_tags(self): + """ + Test an email with multiple alias tags. + + Ensures the function can handle multiple + separated tags. + """ + self.assertEqual(parse_email_alias("user+tag1+tag2@example.com")['tags'], ['tag1', 'tag2']) + + def test_subdomain(self): + """ + Test an email with a subdomain. + + Verifies correct handling of domain names with subdomains. + """ + self.assertEqual(parse_email_alias("user@sub.example.com")['domain'], 'sub.example.com') + + def test_invalid_email_format(self): + """ + Test an email without @ symbol. + + Checks if the function correctly identifies missing @ as an error. + """ + self.assertIn("Missing @ symbol", parse_email_alias("invalid.email")['errors']) + + def test_empty_local_part(self): + """ + Test an email with empty local part. + + Ensures the function recognizes an empty local part as an error. + """ + self.assertIn("Empty local part", parse_email_alias("@example.com")['errors']) + + def test_invalid_characters_in_local_part(self): + """ + Test an email with invalid characters in the local part. + + Verifies that the function detects non-standard characters in the local part. + """ + self.assertIn("Invalid characters in local part", parse_email_alias("user<>@example.com")['errors']) + + def test_empty_domain(self): + """ + Test an email with empty domain. + + Checks if the function correctly identifies an empty domain as an error. + """ + self.assertIn("Empty domain", parse_email_alias("user@")['errors']) + + def test_missing_top_level_domain(self): + """ + Test an email with missing top-level domain. + + Verifies that the function detects domains without TLDs as invalid. + """ + self.assertIn("Invalid domain (missing TLD)", parse_email_alias("user@sub.")['errors']) + + def test_invalid_domain_format(self): + """ + Test an email with an invalid domain format. + + Checks if the function correctly identifies non-standard domain formats. + """ + self.assertIn("Invalid domain format", parse_email_alias("user@[192.168.1.1]")['errors']) + + def test_empty_email(self): + """ + Test an empty email string. + + Ensures the function handles empty inputs correctly. + """ + self.assertIn("Email cannot be empty", parse_email_alias("")['errors']) + + def test_non_string_input(self): + """ + Test non-string input to check defensive assertion. + + Verifies that the function raises an AssertionError for non-string inputs. + """ + with self.assertRaises(AssertionError): + parse_email_alias(123) + + def test_long_local_part(self): + """ + Test an email with a very long local part. + + Checks if the function can handle unusually long local parts. + """ + long_local = "a" * 1000 + self.assertTrue(parse_email_alias(f"{long_local}@example.com")['valid']) + + def test_long_domain(self): + """ + Test an email with a very long domain. + + Ensures the function can handle unusually long domain names. + """ + long_domain = "example.com" * 100 + self.assertTrue(parse_email_alias(f"user@{long_domain}")['valid']) + +if __name__ == '__main__': + unittest.main() From a845e4dc6abeb760ccf3564357b0c80ef26a0cde Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 16:59:28 +0000 Subject: [PATCH 023/139] merge branch remote to the local for the changes! --- solutions/parse_email_alias.py | 118 ++++++++++++---------- solutions/tests/test_parse_email_alias.py | 72 +++++++------ 2 files changed, 106 insertions(+), 84 deletions(-) diff --git a/solutions/parse_email_alias.py b/solutions/parse_email_alias.py index 4abdbfc0d..49fadab9c 100644 --- a/solutions/parse_email_alias.py +++ b/solutions/parse_email_alias.py @@ -10,17 +10,18 @@ @author: Mahdia Ahamdi """ + def parse_email_alias(email: str) -> dict: """ Parse and validate an email address with optional alias tags. - + Validates email format and extracts components including the local part, domain, and any alias tags. Supports Gmail-style + aliases and subdomain addresses. - + Parameters: email: str, the email address to parse - + Returns: dict containing: - valid: bool, whether the email is valid @@ -28,10 +29,10 @@ def parse_email_alias(email: str) -> dict: - domain: str, part after the @ (None if invalid) - tags: list[str], any alias tags found (empty if none) - errors: list[str], any validation errors found - + Raises: AssertionError: if the input is not a string - + Examples: >>> # Test basic email >>> result = parse_email_alias("user@example.com") @@ -43,7 +44,7 @@ def parse_email_alias(email: str) -> dict: 'example.com' >>> result['tags'] [] - + >>> # Test with alias tag >>> result = parse_email_alias("user+tag@example.com") >>> result['valid'] @@ -52,118 +53,125 @@ def parse_email_alias(email: str) -> dict: 'user' >>> result['tags'] ['tag'] - + >>> # Test multiple tags >>> result = parse_email_alias("user+tag1+tag2@example.com") >>> result['tags'] ['tag1', 'tag2'] - + >>> # Test subdomain >>> result = parse_email_alias("user@sub.example.com") >>> result['domain'] 'sub.example.com' - + >>> # Test invalid email (no @) >>> result = parse_email_alias("invalid.email") >>> result['valid'] False >>> 'Missing @ symbol' in result['errors'] True - + >>> # Test empty local part >>> result = parse_email_alias("@domain.com") >>> result['valid'] False >>> 'Empty local part' in result['errors'] True - + >>> # Test invalid characters >>> result = parse_email_alias("user<>@domain.com") >>> result['valid'] False >>> 'Invalid characters in local part' in result['errors'] True - + >>> # Test missing TLD >>> result = parse_email_alias("user@sub.") >>> result['valid'] False >>> 'Invalid domain (missing TLD)' in result['errors'] True - + >>> # Test non-string input >>> parse_email_alias(12345) Traceback (most recent call last): ... AssertionError: Input must be a string """ - #defensive assertion + # defensive assertion assert isinstance(email, str), "Input must be a string" - + # Initialize result dictionary result = { - 'valid': False, - 'local_part': None, - 'domain': None, - 'tags': [], - 'errors': [] + "valid": False, + "local_part": None, + "domain": None, + "tags": [], + "errors": [], } - + # Basic validation for the input email if not email: - result['errors'].append("Email cannot be empty") + result["errors"].append("Email cannot be empty") return result - + # Check for @ symbol - if '@' not in email: - result['errors'].append("Missing @ symbol") + if "@" not in email: + result["errors"].append("Missing @ symbol") return result - + # Split into local part and domain - local_part, domain = email.split('@', 1) - + local_part, domain = email.split("@", 1) + # Validate local part if not local_part: - result['errors'].append("Empty local part") + result["errors"].append("Empty local part") return result - + # Check for invalid characters in local part - allowed_chars = set("abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "0123456789.!#$%&'*+-/=?^_`{|}~") + allowed_chars = set( + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789.!#$%&'*+-/=?^_`{|}~" + ) if not all(c in allowed_chars for c in local_part): - result['errors'].append("Invalid characters in local part") + result["errors"].append("Invalid characters in local part") return result - + # Extract tags if present base_local = local_part tags = [] - if '+' in local_part: - base_local, *tags = local_part.split('+') - + if "+" in local_part: + base_local, *tags = local_part.split("+") + # Validate domain if not domain: - result['errors'].append("Empty domain") + result["errors"].append("Empty domain") return result - - if '..' in domain: - result['errors'].append("Invalid domain (consecutive dots)") + + if ".." in domain: + result["errors"].append("Invalid domain (consecutive dots)") return result - - domain_parts = domain.split('.') + + domain_parts = domain.split(".") if len(domain_parts) == 1 or (len(domain_parts) > 1 and not domain_parts[-1]): - result['errors'].append("Invalid domain (missing TLD)") + result["errors"].append("Invalid domain (missing TLD)") return result - - if not all(part and all(c.isalnum() or c == '-' for c in part) - for part in domain_parts[:-1]) or not domain_parts[-1].isalnum(): - result['errors'].append("Invalid domain format") + + if ( + not all( + part and all(c.isalnum() or c == "-" for c in part) + for part in domain_parts[:-1] + ) + or not domain_parts[-1].isalnum() + ): + result["errors"].append("Invalid domain format") return result - + # If we got here, email is valid - result['valid'] = True - result['local_part'] = base_local - result['domain'] = domain - result['tags'] = tags - + result["valid"] = True + result["local_part"] = base_local + result["domain"] = domain + result["tags"] = tags + return result diff --git a/solutions/tests/test_parse_email_alias.py b/solutions/tests/test_parse_email_alias.py index 3254e40d6..ef1b437f2 100644 --- a/solutions/tests/test_parse_email_alias.py +++ b/solutions/tests/test_parse_email_alias.py @@ -11,12 +11,14 @@ """ import unittest + from parse_email_alias import parse_email_alias + class TestParseEmailAlias(unittest.TestCase): """ Test suite for the parse_email_alias function. - + This class contains unit tests covering various email parsing scenarios, including valid emails, invalid formats, and edge cases. """ @@ -24,95 +26,106 @@ class TestParseEmailAlias(unittest.TestCase): def test_valid_email(self): """ Test a basic valid email address. - + Verifies that the function correctly parses a standard email address. """ - self.assertEqual(parse_email_alias("user@example.com")['valid'], True) + self.assertEqual(parse_email_alias("user@example.com")["valid"], True) def test_email_with_tags(self): """ Test an email with alias tags. - + Checks if the function properly handles Gmail-style + aliases. """ - self.assertEqual(parse_email_alias("user+tag@example.com")['tags'], ['tag']) + self.assertEqual(parse_email_alias("user+tag@example.com")["tags"], ["tag"]) def test_multiple_tags(self): """ Test an email with multiple alias tags. - + Ensures the function can handle multiple + separated tags. """ - self.assertEqual(parse_email_alias("user+tag1+tag2@example.com")['tags'], ['tag1', 'tag2']) + self.assertEqual( + parse_email_alias("user+tag1+tag2@example.com")["tags"], ["tag1", "tag2"] + ) def test_subdomain(self): """ Test an email with a subdomain. - + Verifies correct handling of domain names with subdomains. """ - self.assertEqual(parse_email_alias("user@sub.example.com")['domain'], 'sub.example.com') + self.assertEqual( + parse_email_alias("user@sub.example.com")["domain"], "sub.example.com" + ) def test_invalid_email_format(self): """ Test an email without @ symbol. - + Checks if the function correctly identifies missing @ as an error. """ - self.assertIn("Missing @ symbol", parse_email_alias("invalid.email")['errors']) + self.assertIn("Missing @ symbol", parse_email_alias("invalid.email")["errors"]) def test_empty_local_part(self): """ Test an email with empty local part. - + Ensures the function recognizes an empty local part as an error. """ - self.assertIn("Empty local part", parse_email_alias("@example.com")['errors']) + self.assertIn("Empty local part", parse_email_alias("@example.com")["errors"]) def test_invalid_characters_in_local_part(self): """ Test an email with invalid characters in the local part. - + Verifies that the function detects non-standard characters in the local part. """ - self.assertIn("Invalid characters in local part", parse_email_alias("user<>@example.com")['errors']) + self.assertIn( + "Invalid characters in local part", + parse_email_alias("user<>@example.com")["errors"], + ) def test_empty_domain(self): """ Test an email with empty domain. - + Checks if the function correctly identifies an empty domain as an error. """ - self.assertIn("Empty domain", parse_email_alias("user@")['errors']) + self.assertIn("Empty domain", parse_email_alias("user@")["errors"]) def test_missing_top_level_domain(self): """ Test an email with missing top-level domain. - + Verifies that the function detects domains without TLDs as invalid. """ - self.assertIn("Invalid domain (missing TLD)", parse_email_alias("user@sub.")['errors']) + self.assertIn( + "Invalid domain (missing TLD)", parse_email_alias("user@sub.")["errors"] + ) def test_invalid_domain_format(self): """ Test an email with an invalid domain format. - + Checks if the function correctly identifies non-standard domain formats. """ - self.assertIn("Invalid domain format", parse_email_alias("user@[192.168.1.1]")['errors']) + self.assertIn( + "Invalid domain format", parse_email_alias("user@[192.168.1.1]")["errors"] + ) def test_empty_email(self): """ Test an empty email string. - + Ensures the function handles empty inputs correctly. """ - self.assertIn("Email cannot be empty", parse_email_alias("")['errors']) + self.assertIn("Email cannot be empty", parse_email_alias("")["errors"]) def test_non_string_input(self): """ Test non-string input to check defensive assertion. - + Verifies that the function raises an AssertionError for non-string inputs. """ with self.assertRaises(AssertionError): @@ -121,20 +134,21 @@ def test_non_string_input(self): def test_long_local_part(self): """ Test an email with a very long local part. - + Checks if the function can handle unusually long local parts. """ long_local = "a" * 1000 - self.assertTrue(parse_email_alias(f"{long_local}@example.com")['valid']) + self.assertTrue(parse_email_alias(f"{long_local}@example.com")["valid"]) def test_long_domain(self): """ Test an email with a very long domain. - + Ensures the function can handle unusually long domain names. """ long_domain = "example.com" * 100 - self.assertTrue(parse_email_alias(f"user@{long_domain}")['valid']) + self.assertTrue(parse_email_alias(f"user@{long_domain}")["valid"]) + -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() From aec65b3d3433064bf208f9f1b6c09a213e938f88 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 17:20:39 +0000 Subject: [PATCH 024/139] pytest run job fix! --- .github/workflows/ci-checks.yml | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index fef95dfa8..aac6e9076 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -4,19 +4,19 @@ on: [push, pull_request, workflow_dispatch] jobs: ls_linting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ls-lint/action@v2.2.3 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ls-lint/action@v2.2.3 md_formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: nosborn/github-action-markdown-cli@v3.3.0 - with: - files: . - config_file: .markdownlint.yml + - uses: actions/checkout@v4 + - uses: nosborn/github-action-markdown-cli@v3.3.0 + with: + files: . + config_file: .markdownlint.yml py_formatting: runs-on: ubuntu-latest @@ -55,25 +55,27 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - + - name: python version run: python --version shell: bash - + - name: Check for test files id: check_tests run: | - if find . -type f -name "test_*.py" | grep -q .; then echo "has_tests=true" >> $GITHUB_OUTPUT else echo "has_tests=false" >> $GITHUB_OUTPUT fi shell: bash - - - name: Python - Run Tests + + - name: Set PYTHONPATH if: steps.check_tests.outputs.has_tests == 'true' - run: python -m unittest + run: echo "PYTHONPATH=$GITHUB_WORKSPACE" >> $GITHUB_ENV shell: bash - + - name: Python - Run Tests + if: steps.check_tests.outputs.has_tests == 'true' + run: python -m unittest discover -s solutions/tests -p "test_*.py" + shell: bash From 707952633b25c67ffd4a6697d3f8b9737f2a43d4 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 18:43:41 +0000 Subject: [PATCH 025/139] import error in test file fixed ! --- solutions/tests/test_parse_email_alias.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_parse_email_alias.py b/solutions/tests/test_parse_email_alias.py index ef1b437f2..b805da550 100644 --- a/solutions/tests/test_parse_email_alias.py +++ b/solutions/tests/test_parse_email_alias.py @@ -12,7 +12,7 @@ import unittest -from parse_email_alias import parse_email_alias +from solutions.parse_email_alias import parse_email_alias class TestParseEmailAlias(unittest.TestCase): From bb85da99e10c8ee353e2bfd706e20a0d9c67b9b2 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 19:03:41 +0000 Subject: [PATCH 026/139] import issue in test file fixed! --- .../tests/test_find_longest_palindrome.py | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/solutions/tests/test_find_longest_palindrome.py b/solutions/tests/test_find_longest_palindrome.py index cbf87542a..14b044dd0 100644 --- a/solutions/tests/test_find_longest_palindrome.py +++ b/solutions/tests/test_find_longest_palindrome.py @@ -3,7 +3,7 @@ """ Test module for the longest palindrome finder functionality. -This module contains unittest test cases for the find_longest_palindrome and +This module contains unittest test cases for the find_longest_palindrome and is_palindrome functions, including edge cases and invalid inputs. Created on 28 12 2024 @@ -11,90 +11,91 @@ """ import unittest -from find_longest_palindrome import find_longest_palindrome,is_palindrome + +from solutions.find_longest_palindrome import find_longest_palindrome, is_palindrome class TestPalindromeFinder(unittest.TestCase): """ Test suite for palindrome finding functions. - + This class contains unit tests for both the main palindrome finding function and its helper function, covering normal cases, edge cases, and error conditions. """ - + def test_empty_string(self): """ Test that an empty string returns an empty string. """ self.assertEqual(find_longest_palindrome(""), "") - + def test_single_character(self): """ Test that a single character string returns that character. """ self.assertEqual(find_longest_palindrome("a"), "a") - + def test_two_same_characters(self): """ Test string with two identical characters. """ self.assertEqual(find_longest_palindrome("aa"), "aa") - + def test_two_different_characters(self): """ Test string with two different characters returns first character. """ self.assertEqual(find_longest_palindrome("ab"), "a") - + def test_simple_odd_palindrome(self): """ Test finding a simple odd-length palindrome. """ self.assertEqual(find_longest_palindrome("racecar"), "racecar") - + def test_simple_even_palindrome(self): """ Test finding a simple even-length palindrome. """ self.assertEqual(find_longest_palindrome("abba"), "abba") - + def test_multiple_palindromes(self): """ Test string containing multiple palindromes returns the longest. """ self.assertEqual(find_longest_palindrome("abbaracecarxy"), "racecar") - + def test_overlapping_palindromes(self): """ Test string with overlapping palindromes. """ self.assertEqual(find_longest_palindrome("abababa"), "abababa") - + def test_no_long_palindrome(self): """ Test string with no palindromes longer than one character. """ self.assertEqual(find_longest_palindrome("python"), "p") - + def test_case_sensitive(self): """ Test that the function is case-sensitive. """ self.assertNotEqual(find_longest_palindrome("Racecar"), "Racecar") - + def test_with_spaces(self): """ Test string containing spaces. """ self.assertEqual(find_longest_palindrome("race car"), "r") - + def test_with_special_characters(self): """ Test string containing special characters. """ self.assertEqual(find_longest_palindrome("a!@#a"), "a") - #defensive testcase + # defensive testcase def test_invalid_input_type(self): """ Test that non-string input raises an AssertionError. @@ -107,31 +108,31 @@ class TestIsPalindrome(unittest.TestCase): """ Test suite for the is_palindrome helper function. """ - + def test_empty_string_palindrome(self): """ Test that an empty string is considered a palindrome. """ self.assertTrue(is_palindrome("")) - + def test_single_char_palindrome(self): """ Test that a single character is a palindrome. """ self.assertTrue(is_palindrome("x")) - + def test_simple_palindrome(self): """ Test a simple palindrome string. """ self.assertTrue(is_palindrome("level")) - + def test_non_palindrome(self): """ Test a non-palindrome string. """ self.assertFalse(is_palindrome("python")) - + def test_palindrome_with_spaces(self): """ Test that spaces affect palindrome detection. @@ -139,5 +140,5 @@ def test_palindrome_with_spaces(self): self.assertFalse(is_palindrome("race car")) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() From 4d1024cc42a943e734fb7a8fb59eba110eb38bd4 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Tue, 31 Dec 2024 23:31:47 +0000 Subject: [PATCH 027/139] Fix formatting issues with Ruff! --- .github/workflows/ci-checks.yml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index fef95dfa8..7c3287bd2 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -4,19 +4,19 @@ on: [push, pull_request, workflow_dispatch] jobs: ls_linting: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: ls-lint/action@v2.2.3 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ls-lint/action@v2.2.3 md_formatting: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: nosborn/github-action-markdown-cli@v3.3.0 - with: - files: . - config_file: .markdownlint.yml + - uses: actions/checkout@v4 + - uses: nosborn/github-action-markdown-cli@v3.3.0 + with: + files: . + config_file: .markdownlint.yml py_formatting: runs-on: ubuntu-latest @@ -25,7 +25,7 @@ jobs: - name: Python - Check Formatting uses: astral-sh/ruff-action@v1 with: - args: "format --check" + args: "format --fix" py_linting: runs-on: ubuntu-latest @@ -55,11 +55,11 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - + - name: python version run: python --version shell: bash - + - name: Check for test files id: check_tests run: | @@ -70,10 +70,8 @@ jobs: echo "has_tests=false" >> $GITHUB_OUTPUT fi shell: bash - + - name: Python - Run Tests if: steps.check_tests.outputs.has_tests == 'true' run: python -m unittest shell: bash - - From bc41df7521ae3e49d0e7283e859733609e494e0d Mon Sep 17 00:00:00 2001 From: Mahdia Ahmadi <154888935+MahdiaAhmadi@users.noreply.github.com> Date: Tue, 31 Dec 2024 23:35:48 +0000 Subject: [PATCH 028/139] Update ci-checks.yml --- .github/workflows/ci-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 7c3287bd2..030094abc 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -25,7 +25,7 @@ jobs: - name: Python - Check Formatting uses: astral-sh/ruff-action@v1 with: - args: "format --fix" + args: "format --check" py_linting: runs-on: ubuntu-latest From d8057ff70364c0ec4ad558bf3c37c394d0614791 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Wed, 1 Jan 2025 09:06:13 +0000 Subject: [PATCH 029/139] Fix formatting issues --- .github/workflows/ci-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 7c3287bd2..030094abc 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -25,7 +25,7 @@ jobs: - name: Python - Check Formatting uses: astral-sh/ruff-action@v1 with: - args: "format --fix" + args: "format --check" py_linting: runs-on: ubuntu-latest From bfbf6267e33cdaa06169555f7557db275eb2792f Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Wed, 1 Jan 2025 09:33:39 +0000 Subject: [PATCH 030/139] Fix formatting issues! --- solutions/find_longest_palindrome.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/solutions/find_longest_palindrome.py b/solutions/find_longest_palindrome.py index b91563bbe..8e9667c2b 100644 --- a/solutions/find_longest_palindrome.py +++ b/solutions/find_longest_palindrome.py @@ -11,22 +11,23 @@ @author: Mahdia Ahmadi """ + def find_longest_palindrome(text: str) -> str: """ Finds the longest palindromic substring within the input string. - + A palindrome reads the same forwards and backwards. This function returns the first occurrence of the longest palindrome if multiple exist. - + Parameters: text: str, the input string to search for palindromes - + Returns: str: the longest palindromic substring found - + Raises: AssertionError: if the input is not a string - + Examples: >>> find_longest_palindrome("babad") 'bab' @@ -41,15 +42,15 @@ def find_longest_palindrome(text: str) -> str: """ # Input validation assert isinstance(text, str), "Input must be a string" - + # Handle empty string and single characters if len(text) <= 1: return text - + # Initialize variables to track the longest palindrome longest_start = 0 longest_length = 1 - + # Check all possible substrings for start in range(len(text)): for end in range(start + longest_length, len(text) + 1): @@ -58,21 +59,21 @@ def find_longest_palindrome(text: str) -> str: if is_palindrome(substring) and len(substring) > longest_length: longest_start = start longest_length = len(substring) - + # Return the longest palindrome found - return text[longest_start:longest_start + longest_length] + return text[longest_start : longest_start + longest_length] def is_palindrome(text: str) -> bool: """ Checks if the input string is a palindrome. - + Parameters: text: str, string to check - + Returns: bool: True if the string is a palindrome, False otherwise - + Examples: >>> is_palindrome("racecar") True From 0f1f62c4fbaac4726a17654aaf64c13484bd5096 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Wed, 1 Jan 2025 15:02:13 +0000 Subject: [PATCH 031/139] files update --- solutions/phone_letter_combinations.py | 13 +++++++++++++ solutions/tests/test_phone_letter_combinations | 0 2 files changed, 13 insertions(+) create mode 100644 solutions/phone_letter_combinations.py create mode 100644 solutions/tests/test_phone_letter_combinations diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py new file mode 100644 index 000000000..f3b7fa65a --- /dev/null +++ b/solutions/phone_letter_combinations.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for all the possible letter combinations for a given number + +Module contents: + - phone_letter_combinations: Creates a new list with possible + letter combinations + +Created on 2024-12-30 +Author: Hiba Daffallah +""" +def phone_letter_combinations() diff --git a/solutions/tests/test_phone_letter_combinations b/solutions/tests/test_phone_letter_combinations new file mode 100644 index 000000000..e69de29bb From 20aa67f32eed92b85bc42f7202c553dedcbcf862 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Wed, 1 Jan 2025 18:37:28 +0000 Subject: [PATCH 032/139] update --- solutions/phone_letter_combinations.py | 59 ++++++++++++++++++- solutions/tests/__init__.py | 1 - .../tests/test_phone_letter_combinations | 55 +++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) delete mode 100644 solutions/tests/__init__.py diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py index f3b7fa65a..da4d2780c 100644 --- a/solutions/phone_letter_combinations.py +++ b/solutions/phone_letter_combinations.py @@ -4,10 +4,63 @@ A module for all the possible letter combinations for a given number Module contents: - - phone_letter_combinations: Creates a new list with possible - letter combinations + phone_letter_combinations: Creates a new list with possible + letter combinations in phone keyboard for the numbers given + for simplification I made it maximum of 2 digits Created on 2024-12-30 Author: Hiba Daffallah """ -def phone_letter_combinations() + + +def phone_letter_combinations(digits: str) -> list[str]: + """ + phone_letter_combinations function creates a new list with possible + letter combinations in phone keyboard for the numbers given + for simplification I made it maximum of 2 digits + + Parameters: + digits: string of numbers it should be from 2 to 9 + + Returns: + possible_combinations: list of characters + + Raises: + AssertionError if the input was not a number + + Example: + >>> phone_letter_combinations("23") + ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf'] + >>> phone_letter_combinations("") + [] + >>> phone_letter_combinations("2") + ['a', 'b', 'c'] + >>> phone_letter_combinations("1") + Input must only contain digits from 2 to 9. + """ + if not all(char in "23456789" for char in digits): + raise AssertionError("Input must only contain digits from 2 to 9.") + if not digits: + return [] + digit_to_letters = { + "2": "abc", + "3": "def", + "4": "ghi", + "5": "jkl", + "6": "mno", + "7": "pqrs", + "8": "tuv", + "9": "wxyz", + } + + def possibility(i, temp): + if i == len(digits): + combination.append(temp[:]) + return + for letter in digit_to_letters[digits[i]]: + possibility(i + 1, temp + letter) + + combination = [] + possibility(0, "") + + return combination diff --git a/solutions/tests/__init__.py b/solutions/tests/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/solutions/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/solutions/tests/test_phone_letter_combinations b/solutions/tests/test_phone_letter_combinations index e69de29bb..135d54965 100644 --- a/solutions/tests/test_phone_letter_combinations +++ b/solutions/tests/test_phone_letter_combinations @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for phone_letter_combinations function. + +Created on 2024-12-30 +Author: Hiba Daffallah +""" + +import unittest + +from ..phone_letter_combinations import phone_letter_combinations + + +class TestPhoneLetterCombinations(unittest.TestCase): + """Test phone_letter_combinations function""" + + def test_numbers_within_range(self): + """It should return all the possible letter combinations for 2,3""" + self.assertEqual( + phone_letter_combinations("23"), + ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"], + ) + + def test_empty(self): + """It should return empty list""" + self.assertEqual(phone_letter_combinations(""), []) + + def test_single_number(self): + """It should return all the letters for 2""" + self.assertEqual(phone_letter_combinations("2"), ["a", "b", "c"]) + + def test_numbers_out_of_range(self): + """It should return a message""" + self.assertEqual( + phone_letter_combinations("1"), + "Input must only contain digits from 2 to 9.", + ) + + def test_numbers_contains_one_out_of_range(self): + """It should return a message""" + self.assertEqual( + phone_letter_combinations("12"), + "Input must only contain digits from 2 to 9.", + ) + + # Defensive tests + def test_none_input(self): + """It should raise AssertionError for non-integer input""" + with self.assertRaises(AssertionError): + phone_letter_combinations("a") + + +if __name__ == "__main__": + unittest.main() From dfefd6b1c369b243953fd14450dca1fd4a005f59 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Thu, 2 Jan 2025 00:59:20 +0000 Subject: [PATCH 033/139] challenge/reverse_string.py completed --- solutions/reverse_string.py | 34 +++++++++++ solutions/tests/test_reverse_string.py | 78 ++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 solutions/reverse_string.py create mode 100644 solutions/tests/test_reverse_string.py diff --git a/solutions/reverse_string.py b/solutions/reverse_string.py new file mode 100644 index 000000000..0bac9fc51 --- /dev/null +++ b/solutions/reverse_string.py @@ -0,0 +1,34 @@ +def reverse_string(string: str): + """This function takes a string and returns the reverse form of the string + + Parameters: + string (str): The input to be reversed + + Returns: + str: The reversed version of the input string + + Raises: + AssertionError: If the input is not a string + + Examples: + >>> reverse_string('hello') + 'olleh' + + >>> reverse_string('Python programming') + 'gnimmargorp nohtyP' + + >>> reverse_string('12345') + '54321' + + >>> reverse_string('Madam') + 'madaM' + + >>> reverse_string('racecar') + 'racecar' + """ + # Check if input is a string + assert isinstance(string, str), 'Input must be a string' + + return string[::-1] + +print(reverse_string('Evan Cole')) \ No newline at end of file diff --git a/solutions/tests/test_reverse_string.py b/solutions/tests/test_reverse_string.py new file mode 100644 index 000000000..2bf8b296e --- /dev/null +++ b/solutions/tests/test_reverse_string.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# -- coding: utf-8 -- + + +import unittest + +from ..reverse_string import reverse_string + + +class TestReverseString(unittest.TestCase): + "Test the reverse_string function" + + def test_empty_string(self): + """It should return an empty string for an empty string""" + self.assertEqual(reverse_string(""), "") + + def test_single_character(self): + """It should return the same character for a single character""" + self.assertEqual(reverse_string("a"), "a") + + def test_two_characters(self): + """It should reverse two characters""" + self.assertEqual(reverse_string("ab"), "ba") + + def test_palindrome(self): + """It should return the same string for a palindrome""" + self.assertEqual(reverse_string("racecar"), "racecar") + + def test_spaces_only(self): + """It should return the same string for spaces only""" + self.assertEqual(reverse_string(" "), " ") + + def test_string_with_spaces(self): + """It should reverse a string containing spaces""" + self.assertEqual(reverse_string("hello world"), "dlrow olleh") + + def test_numeric_string(self): + """It should reverse a numeric string""" + self.assertEqual(reverse_string("12345"), "54321") + + def test_mixed_case(self): + """It should reverse a string with mixed case""" + self.assertEqual(reverse_string("Python"), "nohtyP") + + def test_special_characters(self): + """It should reverse a string with special characters""" + self.assertEqual(reverse_string("!@#$%"), "%$#@!") + + def test_alphanumeric_string(self): + """It should reverse an alphanumeric string""" + self.assertEqual(reverse_string("abc123"), "321cba") + + def test_unicode_characters(self): + """It should reverse a string with Unicode characters""" + self.assertEqual( + reverse_string("\u3053\u3093\u306b\u3061\u306f"), + "\u306f\u3061\u306b\u3093\u3053", + ) + + def test_leading_and_trailing_spaces(self): + """It should reverse a string with leading and trailing spaces""" + self.assertEqual(reverse_string(" hello "), " olleh ") + + def test_string_with_numbers_and_spaces(self): + """It should reverse a string containing numbers and spaces""" + self.assertEqual(reverse_string("12 34 56"), "65 43 21") + + def test_long_string(self): + """It should reverse a very long string""" + long_string = "a" * 1000 + self.assertEqual(reverse_string(long_string), "a" * 1000) + + # assertion_tests + + def test_assertion_error_on_non_string(self): + """It should raise an AssertionError for non-string inputs""" + with self.assertRaises(AssertionError): + reverse_string(12345) \ No newline at end of file From c1650e9f3701173bd5c3f9b43272b70c4513803a Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Thu, 2 Jan 2025 01:14:41 +0000 Subject: [PATCH 034/139] fixing ci check --- solutions/reverse_string.py | 23 ++++++++++++----------- solutions/tests/test_reverse_string.py | 2 +- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/solutions/reverse_string.py b/solutions/reverse_string.py index 0bac9fc51..a56bd0a13 100644 --- a/solutions/reverse_string.py +++ b/solutions/reverse_string.py @@ -1,34 +1,35 @@ def reverse_string(string: str): """This function takes a string and returns the reverse form of the string - + Parameters: string (str): The input to be reversed - + Returns: str: The reversed version of the input string - + Raises: AssertionError: If the input is not a string - + Examples: >>> reverse_string('hello') 'olleh' - + >>> reverse_string('Python programming') 'gnimmargorp nohtyP' - + >>> reverse_string('12345') '54321' - + >>> reverse_string('Madam') 'madaM' - + >>> reverse_string('racecar') 'racecar' """ # Check if input is a string - assert isinstance(string, str), 'Input must be a string' - + assert isinstance(string, str), "Input must be a string" + return string[::-1] -print(reverse_string('Evan Cole')) \ No newline at end of file + +print(reverse_string("Evan Cole")) diff --git a/solutions/tests/test_reverse_string.py b/solutions/tests/test_reverse_string.py index 2bf8b296e..45c380393 100644 --- a/solutions/tests/test_reverse_string.py +++ b/solutions/tests/test_reverse_string.py @@ -75,4 +75,4 @@ def test_long_string(self): def test_assertion_error_on_non_string(self): """It should raise an AssertionError for non-string inputs""" with self.assertRaises(AssertionError): - reverse_string(12345) \ No newline at end of file + reverse_string(12345) From 6c4e4c3eeb3be0683af5ca520ad9b7233c21274e Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 14:40:27 +0000 Subject: [PATCH 035/139] modification --- .vscode/settings.json | 4 ++-- solutions/tests/test_phone_letter_combinations | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bbda5188d..252022b48 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -119,8 +119,8 @@ "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" } } } diff --git a/solutions/tests/test_phone_letter_combinations b/solutions/tests/test_phone_letter_combinations index 135d54965..e2234fbab 100644 --- a/solutions/tests/test_phone_letter_combinations +++ b/solutions/tests/test_phone_letter_combinations @@ -9,7 +9,7 @@ Author: Hiba Daffallah import unittest -from ..phone_letter_combinations import phone_letter_combinations +from solutions.phone_letter_combinations import phone_letter_combinations class TestPhoneLetterCombinations(unittest.TestCase): From dc20f259319999cba9b3b76f5f77e488dcea9d34 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 17:29:32 +0000 Subject: [PATCH 036/139] solutions solved --- solutions/longest_substring.py | 58 +++++++++++++++++++++++ solutions/tests/test_longest_substring.py | 53 +++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 solutions/longest_substring.py create mode 100644 solutions/tests/test_longest_substring.py diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py new file mode 100644 index 000000000..3728a7af6 --- /dev/null +++ b/solutions/longest_substring.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for generating lists of Fibonacci numbers + +Module contents: + longest_substring: generates the longest substring without + repetition for a given string. + +Created on 2025-01-01 +@author: Hiba Daffallah +""" + + +def longest_substring(input_string: str) -> str: + """ + Generates a string containing the longest substring without repitition + from the input_string. + + Parameters: + input_string: str + + Returns : + substring: the longest substring + + Raises: + AssertionError: if the argument is not a string + + >>> longest_substring('') + '' + >>> longest_substring('bbbbbb') + 'b' + >>> longest_substring('abcdef') + 'abcdef' + >>> longest_substring('pwwkew') + 'wke' + >>> longest_substring('celelocceli') + 'eloc' + """ + assert isinstance(input_string, str) + + n = len(input_string) + if n == 0: + return "" + + sub = set() + longest_sub = "" + left = 0 + for right in range(n): + while input_string[right] in sub: + sub.remove(input_string[left]) + left += 1 + sub.add(input_string[right]) + current_len = right - left + 1 + if current_len > len(longest_sub): + longest_sub = input_string[left : right + 1] + + return longest_sub diff --git a/solutions/tests/test_longest_substring.py b/solutions/tests/test_longest_substring.py new file mode 100644 index 000000000..230e4cbb6 --- /dev/null +++ b/solutions/tests/test_longest_substring.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on 2024-01-01 + +@author: Hiba Daffallah +""" + +import unittest + +from ..longest_substring import longest_substring + + +class TestLongestSubstring(unittest.TestCase): + """Test the longest_substring function""" + + def test_empty_string(self): + """Checks what will happen if the input is an empty + string""" + self.assertEqual(longest_substring(""), "") + + def test_one_char_repeated(self): + """Checks what will happen if the input is a repeated + character""" + self.assertEqual(longest_substring("bbbbbb"), "b") + + def test_no_repitition(self): + """Checks what will happen if the input didn't have + repeated characters""" + self.assertEqual(longest_substring("abcdef"), "abcdef") + + def test_repeated_substring(self): + """Checks what will happen if the input conatins a + repeated substring""" + self.assertEqual(longest_substring("pwwkew"), "wke") + + def test_multiple_substring(self): + """Checks what will happen if the input contains multiple + substrings""" + self.assertEqual(longest_substring("celelocceli"), "eloc") + + def test_input_numbers(self): + """Checks what will happen if the input contains numbers""" + self.assertEqual(longest_substring("991215888"), "2158") + + def test_input_conatins_numbers(self): + """Checks what will happen if the input contains numbers""" + self.assertEqual(longest_substring("9cort9kl9m"), "cort9kl") + + def test_input_non_string(self): + """Checks what will happen if the input is not a string""" + with self.assertRaises(AssertionError): + longest_substring(["abc"]) From b52a37159b820cee4c86f33b3fc872d6ea9a16e8 Mon Sep 17 00:00:00 2001 From: Hiba Daffallah Date: Thu, 2 Jan 2025 17:40:42 +0000 Subject: [PATCH 037/139] Update longest_substring.py --- solutions/longest_substring.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py index 3728a7af6..f505258df 100644 --- a/solutions/longest_substring.py +++ b/solutions/longest_substring.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -A module for generating lists of Fibonacci numbers +A module for generating the longest substring Module contents: longest_substring: generates the longest substring without From 8a24d380258909bee5c3c847dcccbce8900985ed Mon Sep 17 00:00:00 2001 From: terryekoe Date: Thu, 2 Jan 2025 17:45:27 +0000 Subject: [PATCH 038/139] Documented temperature conversion from Celsius to Fahrenheit --- solutions/celsius_to_fahrenheit.py | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 solutions/celsius_to_fahrenheit.py diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py new file mode 100644 index 000000000..cec82a30e --- /dev/null +++ b/solutions/celsius_to_fahrenheit.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for converting temperatures between Celsius and Fahrenheit. + +Module contents: + - celsius_to_fahrenheit: converts a temperature from Celsius to Fahrenheit. + +Created on 30 12 2024 +@author: Terry Aziaba +""" + +def celsius_to_fahrenheit(celsius: float) -> float: + """Converts a temperature from Celsius to Fahrenheit. + + Parameters: + celsius: float, the temperature in Celsius. + + Returns -> float: + The temperature in Fahrenheit. + + Raises: + AssertionError: if the argument is not a float or int. + + Examples: + >>> celsius_to_fahrenheit(0) + 32.0 + + >>> celsius_to_fahrenheit(100) + 212.0 + + >>> celsius_to_fahrenheit(-40) + -40.0 + """ + # This line ensures the input (temperature) is a number (int or float) + assert isinstance(celsius, (int, float)), "Input temperature must be a number." + + # Conversion + fahrenheit = (celsius * 9 / 5) + 32 + + return fahrenheit From 3d4332651644b09765ad8fb5ad1a37db0171ccb1 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 21:48:20 +0000 Subject: [PATCH 039/139] tests problem resolved --- ...binations => test_phone_letter_combinations.py} | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) rename solutions/tests/{test_phone_letter_combinations => test_phone_letter_combinations.py} (76%) diff --git a/solutions/tests/test_phone_letter_combinations b/solutions/tests/test_phone_letter_combinations.py similarity index 76% rename from solutions/tests/test_phone_letter_combinations rename to solutions/tests/test_phone_letter_combinations.py index e2234fbab..1ceae0a75 100644 --- a/solutions/tests/test_phone_letter_combinations +++ b/solutions/tests/test_phone_letter_combinations.py @@ -32,17 +32,19 @@ def test_single_number(self): def test_numbers_out_of_range(self): """It should return a message""" + with self.assertRaises(AssertionError) as context: + phone_letter_combinations("1") self.assertEqual( - phone_letter_combinations("1"), - "Input must only contain digits from 2 to 9.", + str(context.exception), "Input must only contain digits from 2 to 9." ) def test_numbers_contains_one_out_of_range(self): """It should return a message""" - self.assertEqual( - phone_letter_combinations("12"), - "Input must only contain digits from 2 to 9.", - ) + with self.assertRaises(AssertionError) as context: + phone_letter_combinations("12") + self.assertEqual( + str(context.exception), "Input must only contain digits from 2 to 9." + ) # Defensive tests def test_none_input(self): From 3328380f25b1d975bdf09731d5f4534f01e40dc1 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 22:04:26 +0000 Subject: [PATCH 040/139] tests updated --- solutions/tests/test_phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index 1ceae0a75..ff87878ed 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -38,7 +38,7 @@ def test_numbers_out_of_range(self): str(context.exception), "Input must only contain digits from 2 to 9." ) - def test_numbers_contains_one_out_of_range(self): + def test_contains_numbers_out_of_range(self): """It should return a message""" with self.assertRaises(AssertionError) as context: phone_letter_combinations("12") From bdc540178835161aaf7689736c3e3ad14ed7607c Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 22:08:21 +0000 Subject: [PATCH 041/139] solving the tests issue --- solutions/tests/test_phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index ff87878ed..3f9a61611 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -9,7 +9,7 @@ import unittest -from solutions.phone_letter_combinations import phone_letter_combinations +from ..phone_letter_combinations import phone_letter_combinations class TestPhoneLetterCombinations(unittest.TestCase): From b11c9011b76d20f456238bd24d3c7f38684d352f Mon Sep 17 00:00:00 2001 From: yoolmalaak Date: Fri, 3 Jan 2025 00:11:19 +0200 Subject: [PATCH 042/139] updated --- CWA Calaculator/CWA_Calculator.py | 109 ++++++++++++++++++ GPA Calculator/GPA_Calculator.py | 139 +++++++++++++++++++++++ GPA Calculator/test_gpa_calculator.py | 0 collaboration/README.md | 152 ++++++++++++++++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 CWA Calaculator/CWA_Calculator.py create mode 100644 GPA Calculator/GPA_Calculator.py create mode 100644 GPA Calculator/test_gpa_calculator.py diff --git a/CWA Calaculator/CWA_Calculator.py b/CWA Calaculator/CWA_Calculator.py new file mode 100644 index 000000000..f62b69d0a --- /dev/null +++ b/CWA Calaculator/CWA_Calculator.py @@ -0,0 +1,109 @@ +class Student: + + + def __init__(self, name, index_number,reference_number, email, age, gender, program_of_study, year_of_study, university_name, num_of_courses): + self.name = name + self.age = age + self.index_number = index_number + self.reference_number = reference_number + self.email = email + self.gender = gender + self.program_of_study = program_of_study + self.year_of_study = year_of_study + self.university_name = university_name + self.num_of_courses = num_of_courses + self.courses = [] + self.CWA = 0 + +def get_grade(score): + + + if 70 <= score <= 100: + grade = "A" + elif 60 <= score < 70: + grade = "B" + elif 50 <= score < 60: + grade = "C" + elif 40 <= score < 50: + grade = "D" + elif 0 <= score < 40: + grade = "F" + else: + return "Invalid score" + return grade + + +def calculate_cwa(courses): + + grade_points = 0 + credits_obtained = 0 + for course in courses: + grade_points += course['score'] * course['credit_hours'] + credits_obtained += course['credit_hours'] + + if grade_points == 0: + return 0 + + return grade_points/credits_obtained + + + +def collect_student_data(): + + student_data = {} + student_data['name'] = input("Enter the name of the student: ") + student_data['age'] = input("Enter the age of the student: ") + student_data['index_number'] = input("Enter the index number: ") + student_data['reference_number'] = input("Enter the reference number: ") + student_data['email'] = input("Enter the student email") + student_data['gender'] = input("Enter the gender of the student: ") + student_data['program_of_study'] = input("Enter the program of study: ") + student_data['year_of_study'] = input("Enter the year of study: ") + student_data['university_name']= input("Enter the University name") + + num_of_courses = int(input("Enter the number of courses: ")) + courses = [] + + for _ in range(num_of_courses): + course_name = input("Enter the course name: ") + credit_hours = int(input(f"Enter the credit hours for {course_name}: ")) + score = float(input(f"Enter the score for {course_name}: ")) + grade = get_grade(score) + + + courses.append({ + 'name': course_name, + 'credit_hours': credit_hours, + 'score': score, + 'grade': grade, + }) + + student_data['courses'] = courses + student_data['CWA'] = calculate_cwa(courses) + + return student_data + +student = collect_student_data(): + + +print("\nStudent Details:") +print(f"Name: {student['name']}") +print(f"Age: {student['age']}") +print(f"index number: {student['index_number']}") +print(f"reference number: {student['reference_number']}") +print(f"email: {student['email']}") +print(f"Gender: {student['gender']}") +print(f"Program of Study: {student['program_of_study']}") +print(f"year of study: {student['year_of_study']}") +print(f"university name:{student['university_name']}") + +print(f"CWA: {student['CWA']:.2f}") + + +print("\nCourse Details:") +for course in student['courses']: + print(f"Course Name: {course['name']}") + print(f"Credit Hours: {course['credit_hours']}") + print(f"Score: {course['score']}") + print(f"Grade: {course['grade']}") + print("-" * 30) \ No newline at end of file diff --git a/GPA Calculator/GPA_Calculator.py b/GPA Calculator/GPA_Calculator.py new file mode 100644 index 000000000..bad2c5117 --- /dev/null +++ b/GPA Calculator/GPA_Calculator.py @@ -0,0 +1,139 @@ +class Student: + def __init__(self, name, index_number,reference_number, email, age, gender, program_of_study, year_of_study, university_name, num_of_courses): + self.name = name + self.age = age + self.index_number = index_number + self.reference_number = reference_number + self.email = email + self.gender = gender + self.program_of_study = program_of_study + self.year_of_study = year_of_study + self.university_name = university_name + self.num_of_courses = num_of_courses + self.courses = [] + self.GPA = 0 + +def get_grade(score): + if 90 <= score <= 100: + grade = "A" + elif 85 <= score < 90: + grade = "A-" + elif 80 <= score < 85: + grade = "B+" + elif 75 <= score < 80: + grade = "B" + elif 70 <= score < 75: + grade = "B-" + elif 65 <= score < 70: + grade = "C+" + elif 60 <= score < 65: + grade = "C" + elif 55 <= score < 60: + grade = "C-" + elif 45 <= score < 55: + grade = "D" + elif 40 <= score < 45: + grade = "F" + else: + return "Invalid score" + return grade + +def get_grade_point(grade): + if grade == "A": + return 4.0 + elif grade == "A-": + return 3.75 + elif grade == "B+": + return 3.5 + elif grade == "B": + return 3.0 + elif grade == "B-": + return 2.75 + elif grade == "C+": + return 2.5 + elif grade == "C": + return 2.0 + elif grade == "C-": + return 1.75 + elif grade == "D": + return 1.0 + elif grade == "F": + return 0.0 + else: + return "Grade point error" + +def calculate_gpa(courses): + total_grade_points = 0 + total_credit_hours = 0 + for course in courses: + grade = get_grade(course['score']) + grade_point = get_grade_point(grade) + total_grade_points += grade_point * course['credit_hours'] + total_credit_hours += course['credit_hours'] + + if total_credit_hours == 0: + return 0 + return total_grade_points / total_credit_hours + +def collect_student_data(): + student_data = {} + student_data['name'] = input("Enter the name of the student: ") + student_data['age'] = input("Enter the age of the student: ") + student_data['index_number'] = input("Enter the index number: ") + student_data['reference_number'] = input("Enter the reference number: ") + student_data['email'] = input("Enter the student email") + student_data['gender'] = input("Enter the gender of the student: ") + student_data['program_of_study'] = input("Enter the program of study: ") + student_data['year_of_study'] = input("Enter the year of study: ") + student_data['university_name']= input("Enter the University name") + + num_of_courses = int(input("Enter the number of courses: ")) + courses = [] + + for _ in range(num_of_courses): + course_name = input("Enter the course name: ") + credit_hours = int(input(f"Enter the credit hours for {course_name}: ")) + score = float(input(f"Enter the score for {course_name}: ")) + grade = get_grade(score) + grade_point = get_grade_point(grade) + + courses.append({ + 'name': course_name, + 'credit_hours': credit_hours, + 'score': score, + 'grade': grade, + 'grade_point': grade_point + }) + + student_data['courses'] = courses + student_data['GPA'] = calculate_gpa(courses) + + return student_data + + + +student = collect_student_data() + + +print("\nStudent Details:") +print(f"Name: {student['name']}") +print(f"Age: {student['age']}") +print(f"index number: {student['index_number']}") +print(f"reference number: {student['reference_number']}") +print(f"email: {student['email']}") +print(f"Gender: {student['gender']}") +print(f"Program of Study: {student['program_of_study']}") +print(f"year of study: {student['year_of_study']}") +print(f"university name:{student['university_name']}") + +print(f"GPA: {student['GPA']:.2f}") + + +print("\nCourse Details:") +for course in student['courses']: + print(f"Course Name: {course['name']}") + print(f"Credit Hours: {course['credit_hours']}") + print(f"Score: {course['score']}") + print(f"Grade: {course['grade']}") + print(f"Grade Point: {course['grade_point']:.2f}") + print("-" * 30) diff --git a/GPA Calculator/test_gpa_calculator.py b/GPA Calculator/test_gpa_calculator.py new file mode 100644 index 000000000..e69de29bb diff --git a/collaboration/README.md b/collaboration/README.md index 20889b951..cbd6a9e75 100644 --- a/collaboration/README.md +++ b/collaboration/README.md @@ -2,4 +2,156 @@ +## Group norms for ET6-Foundation-group-09's project + +**These group norms will serve as the guidelines and directives, everyone is expected to comply with, +yet no repercussions will follow if they are disregarded.** + +## Communication + +### Primary communication channel + +Slack + +WhatsAPP + +GitHub + +Zoom Meeting + +Google meet + +#### Response Time + +Everyone is expected to response to the messages on all the communication channels within 24 hours. + +#### Language of communication + +The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. + +#### Official Meeting platforms + +Zoom Meeting + +Google Meet + +The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. + +The time will be discussed and agreed by all the participants on slack and WhatsAPP. + +All the meetings are expected to last for one hour. + +The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. + +All the participants who missed the meeting are advised to watch the recording before sharing their opinions. + +## Group Organization + +**The team organization will ensure effective communication among the group members, making informed decisions +and ensuring that everyone is working on the same goal.** + +### Organizational Structure + +### Project lead + +### Responsibilities + +Oversees the project, ensuring timely completion and making sure no member is left behind. + +The project lead has no absolute authority over the group members. + +Coordinates the resolution of key issues and pull requests + +### Head of the project Communication + +### Key Responsibilities + +Discussion management on Github and WhatsAPP + +Schedule and control the group meeting + +### Deputy Head of the project Communication + +Assist the Head of communication in implementing communication plan + +Provides supports to group members, helping in resolving issues and answering questions. + +### Technical lead + +Assist in code review and conflict resolution + +### Collaboration Norms + +### collaboration Tools + +Github + +Git + +Visual Code Studio (VS Code) + +### Task Assignment + +Each team member will assign him/her self to the task using Github issues + +Everyone is expected to work individually and push it to the branch upon completion + +### Code Review + +Team members will review and provide feedback on each others's code within 48 hours + +we anticipate everyone bear in mind that we are reviewing codes not individuals. + +### Branching and Merging + +we will use feature branches and pull request to manage different version of codes + +## Conflict Resolution + +### Open Communication + +All the members are expected to communicate their concerns and challenges + +### Constructive Feedback + +We encourage the culture of constructive feedback and respectful criticism + +Remember we are reviewing codes not people + +### Conflict resolution process + +All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding + +## Respect and Inclusion + +### Equality + +All the group members have equal rights and their opinion must be respected. + +We equal participation from all the group members. + +### Respectful Communication + +Group members are expected to communicate respectful and professionally by avoiding offensive language. + +### Decision Making + +All the team members will have their voices in decision making. + +### Diversity + +We endeavor to create an inclusive environment that fosters diversity. + + +## Groups Norms List + +Communication Norms + +Organization norms + +Collaboration Norms + +Conflict Resolution Norms + +Respect and Inclusion Norms From e351d94f0f2f7eb3b2546f42df9d0e05324a4ad8 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 22:11:36 +0000 Subject: [PATCH 043/139] .. --- solutions/tests/test_phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index 3f9a61611..ff87878ed 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -9,7 +9,7 @@ import unittest -from ..phone_letter_combinations import phone_letter_combinations +from solutions.phone_letter_combinations import phone_letter_combinations class TestPhoneLetterCombinations(unittest.TestCase): From 8fd8a70798169f63ab0801c36a927d5ee27d9dc5 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:18:21 +0000 Subject: [PATCH 044/139] Rectified CI py_formart error --- solutions/celsius_to_fahrenheit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index cec82a30e..110b099d2 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -12,7 +12,7 @@ def celsius_to_fahrenheit(celsius: float) -> float: """Converts a temperature from Celsius to Fahrenheit. - + Parameters: celsius: float, the temperature in Celsius. @@ -38,4 +38,4 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit + return fahrenheit \ No newline at end of file From feb9cff6953bf0516131d3728836bac73d4c3505 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:20:25 +0000 Subject: [PATCH 045/139] Rectified CI py_formart error; new line mising --- solutions/celsius_to_fahrenheit.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index 110b099d2..0f3589f6a 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -10,9 +10,10 @@ @author: Terry Aziaba """ + def celsius_to_fahrenheit(celsius: float) -> float: """Converts a temperature from Celsius to Fahrenheit. - + Parameters: celsius: float, the temperature in Celsius. @@ -21,7 +22,7 @@ def celsius_to_fahrenheit(celsius: float) -> float: Raises: AssertionError: if the argument is not a float or int. - + Examples: >>> celsius_to_fahrenheit(0) 32.0 @@ -38,4 +39,5 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit \ No newline at end of file + + return fahrenheit From da556a65fb6d396170e113b01dc02d374ba82dbb Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:35:13 +0000 Subject: [PATCH 046/139] New line error --- solutions/celsius_to_fahrenheit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index 0f3589f6a..e2835b72f 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -39,5 +39,4 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit From d8f05c509bca139f19aaf525095c6da584221c67 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 3 Jan 2025 14:37:05 +0000 Subject: [PATCH 047/139] solving tests issue --- solutions/tests/test_phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index ff87878ed..d135620cd 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -50,7 +50,7 @@ def test_contains_numbers_out_of_range(self): def test_none_input(self): """It should raise AssertionError for non-integer input""" with self.assertRaises(AssertionError): - phone_letter_combinations("a") + phone_letter_combinations("b") if __name__ == "__main__": From 4600342f259cff306a407e158542d865cd14bd03 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 3 Jan 2025 14:39:24 +0000 Subject: [PATCH 048/139] attempt solving unittest problem --- ...hone_letter_combinations.py => test_phone_letter_combinations} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename solutions/tests/{test_phone_letter_combinations.py => test_phone_letter_combinations} (100%) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations similarity index 100% rename from solutions/tests/test_phone_letter_combinations.py rename to solutions/tests/test_phone_letter_combinations From e119dd8cc453bc486561304fff3853b6200b8995 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 15:51:11 +0000 Subject: [PATCH 049/139] Group constraints: External and Involuntary constraints --- collaboration/constraints.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/collaboration/constraints.md b/collaboration/constraints.md index 24079505c..d13724e21 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -2,7 +2,9 @@ # Constraints -Some boundaries around our project. +In any collaborative project, understanding and addressing constraints is essential for success. +This group faces a mix of internal involuntary, internal voluntary, and external constraints +that impact their ability to work effectively. ## External @@ -15,6 +17,16 @@ Some boundaries around our project. - ... --> +External constraints pose significant hurdles for the group, many of which are tied to +technology and infrastructure. The most prominent issue, identified by 75% of group members, +is technology limitations, such as difficulties with Git, GitHub, and communication tools. +This suggests that technical barriers are impeding the group’s workflow. +Moreover, time zone differences and internet connectivity each affect 50% +of the group, making it challenging to collaborate in real time. Other constraints, +like project deadlines, inconsistent power supply, and limited access to personal computers, +are less widespread but still impact 25% of members. These challenges reflect a diverse +set of external pressures that complicate the group’s ability to work efficiently. + ## Internal: Involuntary +The group is grappling with individual limitations that are beyond their immediate control. +Skill levels stand out as the most significant internal involuntary constraint, with 62.5% of +members identifying it as a challenge. This suggests that some members may feel under qualified +or lack confidence in certain areas, which can hinder progress. +Time is another critical factor—37.5% of members struggle with the amount of time available to +dedicate to the project, while others face conflicting work schedules that make coordination difficult. +Additionally, the inability to respond quickly to messages further exacerbates communication delays. +However, only 12.5% of the group cited their preferred number of working hours as a constraint, +indicating that most members are willing to invest the necessary effort if other challenges are addressed. + ## Internal: Voluntary -External constraints pose significant hurdles for the group, many of which are tied to -technology and infrastructure. The most prominent issue, identified by 75% of group members, -is technology limitations, such as difficulties with Git, GitHub, and communication tools. -This suggests that technical barriers are impeding the group’s workflow. -Moreover, time zone differences and internet connectivity each affect 50% -of the group, making it challenging to collaborate in real time. Other constraints, -like project deadlines, inconsistent power supply, and limited access to personal computers, -are less widespread but still impact 25% of members. These challenges reflect a diverse -set of external pressures that complicate the group’s ability to work efficiently. +- Primary Constraint: Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited + external constraint, affecting 75% of respondents. +- Time zone differences and internet connectivity are also notable external constraints, each affecting 50% of respondents. +- Other Concerns: Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. ## Internal: Involuntary @@ -35,15 +29,12 @@ set of external pressures that complicate the group’s ability to work efficien - amount of time available to work on the project --> -The group is grappling with individual limitations that are beyond their immediate control. -Skill levels stand out as the most significant internal involuntary constraint, with 62.5% of -members identifying it as a challenge. This suggests that some members may feel under qualified -or lack confidence in certain areas, which can hinder progress. -Time is another critical factor—37.5% of members struggle with the amount of time available to -dedicate to the project, while others face conflicting work schedules that make coordination difficult. -Additionally, the inability to respond quickly to messages further exacerbates communication delays. -However, only 12.5% of the group cited their preferred number of working hours as a constraint, -indicating that most members are willing to invest the necessary effort if other challenges are addressed. +Primary Constraint: The individual skill levels of group members were cited by 62.5% of respondents, making it the most significant internal constraint. +Other notable constraints (each at 37.5%) include: + The amount of time available to work on the project. + Individual work schedules. + Inability to respond quickly to messages. +Least Concern: The number of hours members want to spend working (12.5%). ## Internal: Voluntary From b871e6b8fe1570957fdef7cc72c2d2f3c216fee1 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 10:57:51 +0000 Subject: [PATCH 063/139] added interternal:voluntary constraints --- collaboration/constraints.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/collaboration/constraints.md b/collaboration/constraints.md index d13724e21..e12c89022 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -54,3 +54,9 @@ indicating that most members are willing to invest the necessary effort if other - the number of hours you want to spend working - only using the colors black and white --> +- **Primary Constraint**: + - Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited external constraint, affecting 75% of respondents. +- **Time Zone Differences and Connectivity**: + - Time zone differences and internet connectivity are notable external constraints, each affecting 50% of respondents. +- **Other Concerns**: + - Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. From 3b18f70efe78503894cc6cec6d566967fc939c2c Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 11:05:06 +0000 Subject: [PATCH 064/139] added interternal:voluntary constraints --- collaboration/constraints.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/collaboration/constraints.md b/collaboration/constraints.md index e12c89022..4bd4cc885 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -54,7 +54,8 @@ indicating that most members are willing to invest the necessary effort if other - the number of hours you want to spend working - only using the colors black and white --> -- **Primary Constraint**: + +- **Primary Constraint**: - Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited external constraint, affecting 75% of respondents. - **Time Zone Differences and Connectivity**: - Time zone differences and internet connectivity are notable external constraints, each affecting 50% of respondents. From 9212799500579b9d456aaa1a5c6403f704a8b769 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 11:06:47 +0000 Subject: [PATCH 065/139] added interternal:voluntary constraints --- collaboration/constraints.md | 1 - 1 file changed, 1 deletion(-) diff --git a/collaboration/constraints.md b/collaboration/constraints.md index 4bd4cc885..fb9f5c8e0 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -46,7 +46,6 @@ However, only 12.5% of the group cited their preferred number of working hours a indicating that most members are willing to invest the necessary effort if other challenges are addressed. ## Internal: Voluntary - -- Primary Constraint: Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited +- **Primary Constraint:** Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited external constraint, affecting 75% of respondents. - Time zone differences and internet connectivity are also notable external constraints, each affecting 50% of respondents. -- Other Concerns: Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. +- **Other Concerns:** Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. ## Internal: Involuntary @@ -29,12 +29,12 @@ A survey was conducted within the group to know the constraint of each member of - amount of time available to work on the project --> -Primary Constraint: The individual skill levels of group members were cited by 62.5% of respondents, making it the most significant internal constraint. -Other notable constraints (each at 37.5%) include: - The amount of time available to work on the project. - Individual work schedules. - Inability to respond quickly to messages. -Least Concern: The number of hours members want to spend working (12.5%). +- **Primary Constraint:** The individual skill levels of group members were cited by 62.5% of respondents, making it the most significant internal constraint. +- **Other notable constraints (each at 37.5%) include:** + - The amount of time available to work on the project. + - Individual work schedules. + - Inability to respond quickly to messages. +- **Least Concern:** The number of hours members want to spend working (12.5%). ## Internal: Voluntary -- **Primary Constraint:** Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited +- **Primary Constraint:** + - Technology limitations (e.g., Git, GitHub, and communication tools) were the most frequently cited external constraint, affecting 75% of respondents. - Time zone differences and internet connectivity are also notable external constraints, each affecting 50% of respondents. -- **Other Concerns:** Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. +- **Other Concerns:** + - Project deadlines, inconsistent power supply, and access to a personal computer were mentioned by 25% of respondents each. ## Internal: Involuntary @@ -29,12 +31,14 @@ A survey was conducted within the group to know the constraint of each member of - amount of time available to work on the project --> -- **Primary Constraint:** The individual skill levels of group members were cited by 62.5% of respondents, making it the most significant internal constraint. +- **Primary Constraint:** + - The individual skill levels of group members were cited by 62.5% of respondents, making it the most significant internal constraint. - **Other notable constraints (each at 37.5%) include:** - The amount of time available to work on the project. - Individual work schedules. - Inability to respond quickly to messages. -- **Least Concern:** The number of hours members want to spend working (12.5%). +- **Least Concern:** + - The number of hours members want to spend working (12.5%). ## Internal: Voluntary + +## Group norms for ET6-Foundation-group-09's project + +**These group norms will serve as the guidelines and directives, everyone is expected to comply with, +yet no repercussions will follow if they are disregarded.** + +## Communication + +### Primary communication channel + +Slack + +WhatsAPP + +GitHub + +Zoom Meeting + +Google meet + +#### Response Time + +Everyone is expected to response to the messages on all the communication channels within 24 hours. + +#### Language of communication + +The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. + +#### Official Meeting platforms + +Zoom Meeting + +Google Meet + +The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. + +The time will be discussed and agreed by all the participants on slack and WhatsAPP. + +All the meetings are expected to last for one hour. + +The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. + +All the participants who missed the meeting are advised to watch the recording before sharing their opinions. + +## Group Organization + +**The team organization will ensure effective communication among the group members, making informed decisions +and ensuring that everyone is working on the same goal.** + +### Organizational Structure + +### Project lead + +### Responsibilities + +Oversees the project, ensuring timely completion and making sure no member is left behind. + +The project lead has no absolute authority over the group members. + +Coordinates the resolution of key issues and pull requests + +### Head of the project Communication + +### Key Responsibilities + +Discussion management on Github and WhatsAPP + +Schedule and control the group meeting + +### Deputy Head of the project Communication + +Assist the Head of communication in implementing communication plan + +Provides supports to group members, helping in resolving issues and answering questions. + +### Technical lead + +Assist in code review and conflict resolution + +## Collaboration Norms + +### collaboration Tools + +Github + +Git + +Visual Code Studio (VS Code) + +### Task Assignment + +Each team member will assign him/her self to the task using Github issues + +Everyone is expected to work individually and push it to the branch upon completion + +### Code Review + +Team members will review and provide feedback on each others's code within 48 hours + +we anticipate everyone bear in mind that we are reviewing codes not individuals. + +### Branching and Merging + +we will use feature branches and pull request to manage different version of codes + +## Conflict Resolution + +### Open Communication + +All the members are expected to communicate their concerns and challenges + +### Constructive Feedback + +We encourage the culture of constructive feedback and respectful criticism + +Remember we are reviewing codes not people + +### Conflict resolution process + +All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding + +## Respect and Inclusion + +### Equality + +All the group members have equal rights and their opinion must be respected. + +We equal participation from all the group members. + +### Respectful Communication + +Group members are expected to communicate respectful and professionally by avoiding offensive language. + +### Decision Making + +All the team members will have their voices in decision making. + +### Diversity + +We endeavor to create an inclusive environment that fosters diversity. + + + +## Groups Norms List + +### Communication Norms + +### Organization norms + +### Collaboration_Norms + +### Conflict Resolution Norms + +### Respect and Inclusion Norms From 9600b89b8b9cf7e1a8ad479b0336fc0ab7e38234 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Sat, 4 Jan 2025 12:59:47 +0000 Subject: [PATCH 074/139] Renamed 'Group_Norms Readme.md' to 'readme.md' to comply with ls-lint rules --- collaboration/Group_Norms Readme.md | 157 ---------------------------- 1 file changed, 157 deletions(-) delete mode 100644 collaboration/Group_Norms Readme.md diff --git a/collaboration/Group_Norms Readme.md b/collaboration/Group_Norms Readme.md deleted file mode 100644 index 2f5dbd9ee..000000000 --- a/collaboration/Group_Norms Readme.md +++ /dev/null @@ -1,157 +0,0 @@ -# Collaboration - - - -## Group norms for ET6-Foundation-group-09's project - -**These group norms will serve as the guidelines and directives, everyone is expected to comply with, -yet no repercussions will follow if they are disregarded.** - -## Communication - -### Primary communication channel - -Slack - -WhatsAPP - -GitHub - -Zoom Meeting - -Google meet - -#### Response Time - -Everyone is expected to response to the messages on all the communication channels within 24 hours. - -#### Language of communication - -The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. - -#### Official Meeting platforms - -Zoom Meeting - -Google Meet - -The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. - -The time will be discussed and agreed by all the participants on slack and WhatsAPP. - -All the meetings are expected to last for one hour. - -The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. - -All the participants who missed the meeting are advised to watch the recording before sharing their opinions. - -## Group Organization - -**The team organization will ensure effective communication among the group members, making informed decisions -and ensuring that everyone is working on the same goal.** - -### Organizational Structure - -### Project lead - -### Responsibilities - -Oversees the project, ensuring timely completion and making sure no member is left behind. - -The project lead has no absolute authority over the group members. - -Coordinates the resolution of key issues and pull requests - -### Head of the project Communication - -### Key Responsibilities - -Discussion management on Github and WhatsAPP - -Schedule and control the group meeting - -### Deputy Head of the project Communication - -Assist the Head of communication in implementing communication plan - -Provides supports to group members, helping in resolving issues and answering questions. - -### Technical lead - -Assist in code review and conflict resolution - -## Collaboration Norms - -### collaboration Tools - -Github - -Git - -Visual Code Studio (VS Code) - -### Task Assignment - -Each team member will assign him/her self to the task using Github issues - -Everyone is expected to work individually and push it to the branch upon completion - -### Code Review - -Team members will review and provide feedback on each others's code within 48 hours - -we anticipate everyone bear in mind that we are reviewing codes not individuals. - -### Branching and Merging - -we will use feature branches and pull request to manage different version of codes - -## Conflict Resolution - -### Open Communication - -All the members are expected to communicate their concerns and challenges - -### Constructive Feedback - -We encourage the culture of constructive feedback and respectful criticism - -Remember we are reviewing codes not people - -### Conflict resolution process - -All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding - -## Respect and Inclusion - -### Equality - -All the group members have equal rights and their opinion must be respected. - -We equal participation from all the group members. - -### Respectful Communication - -Group members are expected to communicate respectful and professionally by avoiding offensive language. - -### Decision Making - -All the team members will have their voices in decision making. - -### Diversity - -We endeavor to create an inclusive environment that fosters diversity. - - - -## Groups Norms List - -### Communication Norms - -### Organization norms - -### Collaboration_Norms - -### Conflict Resolution Norms - -### Respect and Inclusion Norms From a6581c8945cd711d506175ebc1e4d9a82ae6c1bb Mon Sep 17 00:00:00 2001 From: terryekoe Date: Thu, 2 Jan 2025 17:45:27 +0000 Subject: [PATCH 075/139] Documented temperature conversion from Celsius to Fahrenheit --- solutions/celsius_to_fahrenheit.py | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 solutions/celsius_to_fahrenheit.py diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py new file mode 100644 index 000000000..cec82a30e --- /dev/null +++ b/solutions/celsius_to_fahrenheit.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for converting temperatures between Celsius and Fahrenheit. + +Module contents: + - celsius_to_fahrenheit: converts a temperature from Celsius to Fahrenheit. + +Created on 30 12 2024 +@author: Terry Aziaba +""" + +def celsius_to_fahrenheit(celsius: float) -> float: + """Converts a temperature from Celsius to Fahrenheit. + + Parameters: + celsius: float, the temperature in Celsius. + + Returns -> float: + The temperature in Fahrenheit. + + Raises: + AssertionError: if the argument is not a float or int. + + Examples: + >>> celsius_to_fahrenheit(0) + 32.0 + + >>> celsius_to_fahrenheit(100) + 212.0 + + >>> celsius_to_fahrenheit(-40) + -40.0 + """ + # This line ensures the input (temperature) is a number (int or float) + assert isinstance(celsius, (int, float)), "Input temperature must be a number." + + # Conversion + fahrenheit = (celsius * 9 / 5) + 32 + + return fahrenheit From 1f4cc83ba9676dc7551ba277968cec65818cfa33 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:18:21 +0000 Subject: [PATCH 076/139] Rectified CI py_formart error --- solutions/celsius_to_fahrenheit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index cec82a30e..110b099d2 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -12,7 +12,7 @@ def celsius_to_fahrenheit(celsius: float) -> float: """Converts a temperature from Celsius to Fahrenheit. - + Parameters: celsius: float, the temperature in Celsius. @@ -38,4 +38,4 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit + return fahrenheit \ No newline at end of file From 2489a76bff4454ec404895ea3da46221fabeb76d Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:20:25 +0000 Subject: [PATCH 077/139] Rectified CI py_formart error; new line mising --- solutions/celsius_to_fahrenheit.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index 110b099d2..0f3589f6a 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -10,9 +10,10 @@ @author: Terry Aziaba """ + def celsius_to_fahrenheit(celsius: float) -> float: """Converts a temperature from Celsius to Fahrenheit. - + Parameters: celsius: float, the temperature in Celsius. @@ -21,7 +22,7 @@ def celsius_to_fahrenheit(celsius: float) -> float: Raises: AssertionError: if the argument is not a float or int. - + Examples: >>> celsius_to_fahrenheit(0) 32.0 @@ -38,4 +39,5 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit \ No newline at end of file + + return fahrenheit From 1f0450b70bdccdec382c824dbd31dd2a70be036f Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 12:35:13 +0000 Subject: [PATCH 078/139] New line error --- solutions/celsius_to_fahrenheit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index 0f3589f6a..e2835b72f 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -39,5 +39,4 @@ def celsius_to_fahrenheit(celsius: float) -> float: # Conversion fahrenheit = (celsius * 9 / 5) + 32 - return fahrenheit From 968252bf338693bc6831163bea31bdfe36c81834 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 15:55:03 +0000 Subject: [PATCH 079/139] Unit test and test cases for temperature conversion from celsius to fahrenheit --- solutions/tests/test_celsius_to_fahrenheit.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 solutions/tests/test_celsius_to_fahrenheit.py diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py new file mode 100644 index 000000000..565ef54df --- /dev/null +++ b/solutions/tests/test_celsius_to_fahrenheit.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on 30 12 2024 +@author: Terry Aziaba +""" +import unittest +from ..celsius_to_fahrenheit import celsius_to_fahrenheit + + +class TestCelsiusToFahrenheit(unittest.TestCase): + """Unit tests for the celsius_to_fahrenheit function.""" + + def test_freezing_point(self): + """Test the freezing point of water.""" + self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) + + def test_boiling_point(self): + """Test the boiling point of water.""" + self.assertAlmostEqual(celsius_to_fahrenheit(100), 212.0) + + def test_negative_temperature(self): + """Test a negative temperature.""" + self.assertAlmostEqual(celsius_to_fahrenheit(-40), -40.0) + + def test_fractional_input(self): + """Test a fractional Celsius value.""" + self.assertAlmostEqual(celsius_to_fahrenheit(37.5), 99.5) + + def test_large_positive_value(self): + """Test a very large positive Celsius value.""" + self.assertAlmostEqual(celsius_to_fahrenheit(1000), 1832.0) + + def test_large_negative_value(self): + """Test a very large negative Celsius value.""" + self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) + + def test_zero_input(self): + """Test zero as input.""" + self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) + + def test_small_fractional_input(self): + """Test a small fractional input.""" + self.assertAlmostEqual(celsius_to_fahrenheit(0.5), 32.9) + + def test_assertion_error_non_numeric(self): + """Test if an assertion error is raised for non-numeric input.""" + with self.assertRaises(AssertionError): + celsius_to_fahrenheit("not a number") + + def test_assertion_error_none(self): + """Test if an assertion error is raised for None input.""" + with self.assertRaises(AssertionError): + celsius_to_fahrenheit(None) From 9588af5ba7e16b1f45433cd5d7ed74a4ab151ac2 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 16:24:30 +0000 Subject: [PATCH 080/139] Corrected pyformart error --- solutions/tests/test_celsius_to_fahrenheit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py index 565ef54df..7af79b284 100644 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ b/solutions/tests/test_celsius_to_fahrenheit.py @@ -5,6 +5,7 @@ @author: Terry Aziaba """ import unittest + from ..celsius_to_fahrenheit import celsius_to_fahrenheit @@ -32,7 +33,7 @@ def test_large_positive_value(self): self.assertAlmostEqual(celsius_to_fahrenheit(1000), 1832.0) def test_large_negative_value(self): - """Test a very large negative Celsius value.""" + """Test a very large negative Celsius value""" self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) def test_zero_input(self): From 5cc125fb26edc86ead6379364a84c2fdee4bb19e Mon Sep 17 00:00:00 2001 From: terryekoe Date: Fri, 3 Jan 2025 16:41:56 +0000 Subject: [PATCH 081/139] Corrected CI check failure --- solutions/tests/test_celsius_to_fahrenheit.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py index 7af79b284..77564bf69 100644 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ b/solutions/tests/test_celsius_to_fahrenheit.py @@ -1,9 +1,14 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ +Test module for conversion from celsius to fahrenheit. + +This module contains unittest test cases for the celsius_to_fahrenheit + Created on 30 12 2024 @author: Terry Aziaba """ + import unittest from ..celsius_to_fahrenheit import celsius_to_fahrenheit From 1610ff1d89c52e608b301d9b06bc9a3514579bca Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 14:19:17 +0000 Subject: [PATCH 082/139] finf_two_sum_indices --- solutions/find_two_sum_indices.py | 0 solutions/tests/test_find_two_sum_indices.py | 40 ++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 solutions/find_two_sum_indices.py create mode 100644 solutions/tests/test_find_two_sum_indices.py diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py new file mode 100644 index 000000000..e69de29bb diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py new file mode 100644 index 000000000..ad2b17842 --- /dev/null +++ b/solutions/tests/test_find_two_sum_indices.py @@ -0,0 +1,40 @@ +def find_two_sum_indices(nums: list[int], target: int) -> list[int]: + """ + Find two indices in the list such that their values add up to the target. + + Parameters: + nums (list[int]): The list of integers. + target (int): The target sum. + + Returns: + list[int]: The indices of the two numbers that add up to the target. + + Raises: + AssertionError: If no solution is found. + AssertionError: If the input is not a list of integers. + AssertionError: If the target is not an integer. + + Examples: + >>> find_two_sum_indices([2, 7, 11, 15], 9) + [0, 1] + + >>> find_two_sum_indices([3, 2, 4], 6) + [1, 2] + + >>> find_two_sum_indices([3, 3], 6) + [0, 1] + + """ + if not isinstance(nums, list) or not all(isinstance(i, int) for i in nums): + raise TypeError("Input must be a list of integers.") + if not isinstance(target, int): + raise TypeError("Target must be an integer.") + + num_map = {} + for i, num in enumerate(nums): + complement = target - num + if complement in num_map: + return [num_map[complement], i] + num_map[num] = i + + raise ValueError("No two sum solution.") From 0bc721c44d0cdc13df4dabb9e2d2a3b40ac2c81b Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 22:53:39 +0000 Subject: [PATCH 083/139] find_two_sum_indices_completed --- solutions/find_two_sum_indices.py | 53 +++++++ solutions/tests/test_find_two_sum_indices.py | 154 ++++++++++++++----- 2 files changed, 167 insertions(+), 40 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index e69de29bb..0aa91a7a4 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +A module for providing the indices of two numbers in a list that add up to a target sum. + +Module contents: Takes a list of numbers (integers or floats) and a target sum as input and returns the indices of the two numbers that add up to the target sum. + +Created on 2025-01-04 + +@author: Jeffery Offei Darko +""" + +def find_two_sum_indices(nums: list[float], target: float) -> list[int]: + """ + Find two indices in the list such that their values add up to the target. + + Parameters: + nums (list[float]): The list of numbers (integers or floats). + target (float): The target sum. + + Returns: + list[int]: The indices of the two numbers that add up to the target. + + Raises: + AssertionError: If the input is not valid or no solution is found. + + Examples: + >>> find_two_sum_indices([2, 7, 11, 15], 9) + [0, 1] + + >>> find_two_sum_indices([3, 2.5, 4], 6.5) + [1, 2] + + >>> find_two_sum_indices([3.0, 3], 6.0) + [0, 1] + """ + # Debugging input validation + assert isinstance(nums, list), "Input must be a list." + assert all(isinstance(num, (int, float)) for num in nums), "List must contain numbers (integers or floats)." + assert isinstance(target, (int, float)), "Target must be a number (integer or float)." + assert len(nums) > 1, "List must contain at least two numbers." + + # Debugging main logic + num_map = {} + for i, num in enumerate(nums): + complement = target - num + if complement in num_map: + return [num_map[complement], i] + num_map[num] = i + + # Debugging output if no solution + assert False, "No two numbers add up to the target sum." diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index ad2b17842..65b24b7a5 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -1,40 +1,114 @@ -def find_two_sum_indices(nums: list[int], target: int) -> list[int]: - """ - Find two indices in the list such that their values add up to the target. - - Parameters: - nums (list[int]): The list of integers. - target (int): The target sum. - - Returns: - list[int]: The indices of the two numbers that add up to the target. - - Raises: - AssertionError: If no solution is found. - AssertionError: If the input is not a list of integers. - AssertionError: If the target is not an integer. - - Examples: - >>> find_two_sum_indices([2, 7, 11, 15], 9) - [0, 1] - - >>> find_two_sum_indices([3, 2, 4], 6) - [1, 2] - - >>> find_two_sum_indices([3, 3], 6) - [0, 1] - - """ - if not isinstance(nums, list) or not all(isinstance(i, int) for i in nums): - raise TypeError("Input must be a list of integers.") - if not isinstance(target, int): - raise TypeError("Target must be an integer.") - - num_map = {} - for i, num in enumerate(nums): - complement = target - num - if complement in num_map: - return [num_map[complement], i] - num_map[num] = i - - raise ValueError("No two sum solution.") +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for find_two_sum_indices function. + +Created on 2025-01-05 + +Author: Jeffery Offei Darko +""" + +import unittest +from solutions.find_two_sum_indices import find_two_sum_indices + + +class TestFindTwoSumIndices(unittest.TestCase): + + # Basic test cases + def test_basic_case_1(self): + """Test basic case with a simple target sum.""" + self.assertEqual(find_two_sum_indices([2, 7, 11, 15], 9), [0, 1]) + + def test_basic_case_2(self): + """Test basic case with a different array and target.""" + self.assertEqual(find_two_sum_indices([3, 2, 4], 6), [1, 2]) + + def test_basic_case_3(self): + """Test basic case with duplicate values.""" + self.assertEqual(find_two_sum_indices([3, 3], 6), [0, 1]) + + # Edge cases with integers + def test_with_negative_numbers(self): + """Test case with negative numbers.""" + self.assertEqual(find_two_sum_indices([-3, 4, 3, 90], 0), [0, 2]) + + def test_with_zeroes(self): + """Test case where all numbers are zero.""" + self.assertEqual(find_two_sum_indices([0, 0, 0], 0), [0, 1]) + + def test_with_large_numbers(self): + """Test case with large integers.""" + self.assertEqual(find_two_sum_indices([1000000, 2500000, 1500000], 3500000), [0, 1]) + + # Cases where no solution exists + def test_no_solution(self): + """Test case where no solution exists.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1, 2, 3], 7) + + def test_empty_list(self): + """Test case with an empty list.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([], 5) + + def test_single_element(self): + """Test case with a single element.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1], 1) + + def test_repeated_elements(self): + """Test case with repeated elements where no solution exists.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1, 1, 1, 1], 3) + + # Tests with floats + def test_with_floats_basic(self): + """Test with floats that add up to the target.""" + self.assertEqual(find_two_sum_indices([2.5, 7.1, 11.3], 9.6), [0, 1]) + + def test_with_floats_and_integers(self): + """Test with a mix of floats and integers.""" + self.assertEqual(find_two_sum_indices([1, 2.5, 4.5], 7), [1, 2]) + + def test_with_floats_no_solution(self): + """Test with floats where no solution exists.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1.2, 3.4, 5.6], 10) + + def test_with_float_target(self): + """Test with a float target.""" + self.assertEqual(find_two_sum_indices([2, 3.5, 5.5], 9), [1, 2]) + + def test_with_float_and_negative(self): + """Test with floats and negative numbers.""" + self.assertEqual(find_two_sum_indices([-1.5, 3.0, 2.5], 1.0), [0, 2]) + + # Invalid input tests + def test_invalid_input_not_list(self): + """Test with an invalid input that is not a list.""" + with self.assertRaises(AssertionError): + find_two_sum_indices("123", 5) + + def test_invalid_input_with_non_number_elements(self): + """Test with invalid input containing non-number elements.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1, "two", 3], 5) + + def test_invalid_target_not_number(self): + """Test with an invalid target that is not a number.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1, 2, 3], "five") + + def test_invalid_input_none(self): + """Test with an invalid input of None.""" + with self.assertRaises(AssertionError): + find_two_sum_indices(None, 5) + + def test_invalid_target_none(self): + """Test with an invalid target of None.""" + with self.assertRaises(AssertionError): + find_two_sum_indices([1, 2, 3], None) + + +if __name__ == "__main__": + unittest.main() From 5e73c5525e516fb553902f4bd5897c19ae881bd1 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:00:23 +0000 Subject: [PATCH 084/139] find_two_sum_indices_completed --- solutions/find_two_sum_indices.py | 17 +++++++++++------ solutions/tests/test_find_two_sum_indices.py | 5 +++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index 0aa91a7a4..377629b91 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -11,6 +11,7 @@ @author: Jeffery Offei Darko """ + def find_two_sum_indices(nums: list[float], target: float) -> list[int]: """ Find two indices in the list such that their values add up to the target. @@ -28,19 +29,23 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: Examples: >>> find_two_sum_indices([2, 7, 11, 15], 9) [0, 1] - + >>> find_two_sum_indices([3, 2.5, 4], 6.5) [1, 2] - + >>> find_two_sum_indices([3.0, 3], 6.0) [0, 1] """ # Debugging input validation assert isinstance(nums, list), "Input must be a list." - assert all(isinstance(num, (int, float)) for num in nums), "List must contain numbers (integers or floats)." - assert isinstance(target, (int, float)), "Target must be a number (integer or float)." + assert all( + isinstance(num, (int, float)) for num in nums + ), "List must contain numbers (integers or floats)." + assert isinstance( + target, (int, float) + ), "Target must be a number (integer or float)." assert len(nums) > 1, "List must contain at least two numbers." - + # Debugging main logic num_map = {} for i, num in enumerate(nums): @@ -48,6 +53,6 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: if complement in num_map: return [num_map[complement], i] num_map[num] = i - + # Debugging output if no solution assert False, "No two numbers add up to the target sum." diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index 65b24b7a5..adbdb3565 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -13,7 +13,6 @@ class TestFindTwoSumIndices(unittest.TestCase): - # Basic test cases def test_basic_case_1(self): """Test basic case with a simple target sum.""" @@ -38,7 +37,9 @@ def test_with_zeroes(self): def test_with_large_numbers(self): """Test case with large integers.""" - self.assertEqual(find_two_sum_indices([1000000, 2500000, 1500000], 3500000), [0, 1]) + self.assertEqual( + find_two_sum_indices([1000000, 2500000, 1500000], 3500000), [0, 1] + ) # Cases where no solution exists def test_no_solution(self): From 53398070b0b89b9c96328ad32981c0d24dfa0470 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sat, 4 Jan 2025 23:39:07 +0000 Subject: [PATCH 085/139] find_two_sum_indices_completed --- solutions/celsius_to_fahrenheit.py | 42 ------------- solutions/tests/test_celsius_to_fahrenheit.py | 60 ------------------- 2 files changed, 102 deletions(-) delete mode 100644 solutions/celsius_to_fahrenheit.py delete mode 100644 solutions/tests/test_celsius_to_fahrenheit.py diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py deleted file mode 100644 index e2835b72f..000000000 --- a/solutions/celsius_to_fahrenheit.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -A module for converting temperatures between Celsius and Fahrenheit. - -Module contents: - - celsius_to_fahrenheit: converts a temperature from Celsius to Fahrenheit. - -Created on 30 12 2024 -@author: Terry Aziaba -""" - - -def celsius_to_fahrenheit(celsius: float) -> float: - """Converts a temperature from Celsius to Fahrenheit. - - Parameters: - celsius: float, the temperature in Celsius. - - Returns -> float: - The temperature in Fahrenheit. - - Raises: - AssertionError: if the argument is not a float or int. - - Examples: - >>> celsius_to_fahrenheit(0) - 32.0 - - >>> celsius_to_fahrenheit(100) - 212.0 - - >>> celsius_to_fahrenheit(-40) - -40.0 - """ - # This line ensures the input (temperature) is a number (int or float) - assert isinstance(celsius, (int, float)), "Input temperature must be a number." - - # Conversion - fahrenheit = (celsius * 9 / 5) + 32 - - return fahrenheit diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py deleted file mode 100644 index 77564bf69..000000000 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Test module for conversion from celsius to fahrenheit. - -This module contains unittest test cases for the celsius_to_fahrenheit - -Created on 30 12 2024 -@author: Terry Aziaba -""" - -import unittest - -from ..celsius_to_fahrenheit import celsius_to_fahrenheit - - -class TestCelsiusToFahrenheit(unittest.TestCase): - """Unit tests for the celsius_to_fahrenheit function.""" - - def test_freezing_point(self): - """Test the freezing point of water.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) - - def test_boiling_point(self): - """Test the boiling point of water.""" - self.assertAlmostEqual(celsius_to_fahrenheit(100), 212.0) - - def test_negative_temperature(self): - """Test a negative temperature.""" - self.assertAlmostEqual(celsius_to_fahrenheit(-40), -40.0) - - def test_fractional_input(self): - """Test a fractional Celsius value.""" - self.assertAlmostEqual(celsius_to_fahrenheit(37.5), 99.5) - - def test_large_positive_value(self): - """Test a very large positive Celsius value.""" - self.assertAlmostEqual(celsius_to_fahrenheit(1000), 1832.0) - - def test_large_negative_value(self): - """Test a very large negative Celsius value""" - self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) - - def test_zero_input(self): - """Test zero as input.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) - - def test_small_fractional_input(self): - """Test a small fractional input.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0.5), 32.9) - - def test_assertion_error_non_numeric(self): - """Test if an assertion error is raised for non-numeric input.""" - with self.assertRaises(AssertionError): - celsius_to_fahrenheit("not a number") - - def test_assertion_error_none(self): - """Test if an assertion error is raised for None input.""" - with self.assertRaises(AssertionError): - celsius_to_fahrenheit(None) From edec28a3a18da9f7646b996e9d6c0a900cef32af Mon Sep 17 00:00:00 2001 From: Hiba Daffallah Date: Sun, 5 Jan 2025 13:35:51 +0000 Subject: [PATCH 086/139] descriptive comments added --- solutions/longest_substring.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py index f505258df..14407f791 100644 --- a/solutions/longest_substring.py +++ b/solutions/longest_substring.py @@ -37,22 +37,35 @@ def longest_substring(input_string: str) -> str: >>> longest_substring('celelocceli') 'eloc' """ + # Ensure the input is a string assert isinstance(input_string, str) n = len(input_string) + # If the string is empty, return an empty string as the result if n == 0: return "" - + # Initialize a set to keep track of unique characters in the current substring sub = set() + # Initialize the longest substring variable longest_sub = "" + # Initialize the left pointer of the sliding window left = 0 for right in range(n): + + # If the character at the right pointer is already in the set, + # slide the left pointer to remove characters until the duplicate is removed while input_string[right] in sub: sub.remove(input_string[left]) left += 1 + + # Add the current character at the right pointer to the set sub.add(input_string[right]) current_len = right - left + 1 + + # If the current substring is longer than the previously recorded longest substring, + # update the longest substring if current_len > len(longest_sub): longest_sub = input_string[left : right + 1] + # Return the longest substring found return longest_sub From 553b96e2ab33d533886c7646a1f6300c70cf1b80 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:36:47 +0000 Subject: [PATCH 087/139] making changes on float target test --- solutions/tests/test_find_two_sum_indices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index adbdb3565..15491df9d 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -78,7 +78,7 @@ def test_with_floats_no_solution(self): def test_with_float_target(self): """Test with a float target.""" - self.assertEqual(find_two_sum_indices([2, 3.5, 5.5], 9), [1, 2]) + self.assertEqual(find_two_sum_indices([2, 3.5, 5], 8.5), [1, 2]) def test_with_float_and_negative(self): """Test with floats and negative numbers.""" From 36eb011a03e6f49b16b493376bd3bb816b7673cd Mon Sep 17 00:00:00 2001 From: terryekoe Date: Sun, 5 Jan 2025 23:02:19 +0000 Subject: [PATCH 088/139] A function that converts a number from (0-9) to it's word representation --- solutions/number_to_word.py | 58 +++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 solutions/number_to_word.py diff --git a/solutions/number_to_word.py b/solutions/number_to_word.py new file mode 100644 index 000000000..231fa6d8e --- /dev/null +++ b/solutions/number_to_word.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for converting single-digit number into its word representation. + +Module contents: + - number_to_word: converts a number to it's word equivalent. + +Created on 03 01 2024 +@author: Terry Aziaba +""" + + +def number_to_word(number: int) -> str: + """ + Converts a single-digit number into its word representation. + + Parameters: + number (int): A single-digit number (0–9). + + Returns: + str: The word representation of the number. + + Raises: + ValueError: If the number is not a single digit. + + Examples: + >>> number_to_word(0) + 'zero' + + >>> number_to_word(7) + 'seven' + + >>> number_to_word(10) + Traceback (most recent call last): + ... + ValueError: Number must be a single digit (0–9). + """ + # A dictionary mapping digits to their word representation + digit_to_word = { + 0: "zero", + 1: "one", + 2: "two", + 3: "three", + 4: "four", + 5: "five", + 6: "six", + 7: "seven", + 8: "eight", + 9: "nine", + } + + # Checks if the input is a valid single-digit number + if number not in digit_to_word: + raise ValueError("Number must be a single digit (0–9).") + + # Returns the word representation + return digit_to_word[number] From c0ac6eb024ee614c360a31524007699e59b43c0f Mon Sep 17 00:00:00 2001 From: terryekoe Date: Sun, 5 Jan 2025 23:03:16 +0000 Subject: [PATCH 089/139] A function that converts a number from (0-9) to it's word representation --- solutions/number_to_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/number_to_word.py b/solutions/number_to_word.py index 231fa6d8e..260e97a3e 100644 --- a/solutions/number_to_word.py +++ b/solutions/number_to_word.py @@ -4,7 +4,7 @@ A module for converting single-digit number into its word representation. Module contents: - - number_to_word: converts a number to it's word equivalent. + - number_to_word: converts a number ranging from (0-9) to it's word equivalent. Created on 03 01 2024 @author: Terry Aziaba From 5b300d3ec221d80a0431716f75f6df876089bdd2 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Mon, 6 Jan 2025 01:04:13 +0000 Subject: [PATCH 090/139] solving ruff --- solutions/longest_substring.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py index 14407f791..86e7bfa84 100644 --- a/solutions/longest_substring.py +++ b/solutions/longest_substring.py @@ -7,7 +7,7 @@ longest_substring: generates the longest substring without repetition for a given string. -Created on 2025-01-01 +Created on 2025-01-05 @author: Hiba Daffallah """ @@ -41,7 +41,7 @@ def longest_substring(input_string: str) -> str: assert isinstance(input_string, str) n = len(input_string) - # If the string is empty, return an empty string as the result + # If the string is empty, return an empty string as the result if n == 0: return "" # Initialize a set to keep track of unique characters in the current substring @@ -51,18 +51,17 @@ def longest_substring(input_string: str) -> str: # Initialize the left pointer of the sliding window left = 0 for right in range(n): - # If the character at the right pointer is already in the set, # slide the left pointer to remove characters until the duplicate is removed while input_string[right] in sub: sub.remove(input_string[left]) left += 1 - - # Add the current character at the right pointer to the set + + # Add the current character at the right pointer to the set sub.add(input_string[right]) current_len = right - left + 1 - - # If the current substring is longer than the previously recorded longest substring, + + # If the current substring is longer than the previously recorded longest substring, # update the longest substring if current_len > len(longest_sub): longest_sub = input_string[left : right + 1] From e0839d949468c73a798d39782613d14e156c6bbe Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Mon, 6 Jan 2025 01:14:52 +0000 Subject: [PATCH 091/139] making changes as suggested --- solutions/tests/test_find_two_sum_indices.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index 15491df9d..b3867504f 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -14,15 +14,15 @@ class TestFindTwoSumIndices(unittest.TestCase): # Basic test cases - def test_basic_case_1(self): + def test_with_simple_target_sum(self): """Test basic case with a simple target sum.""" self.assertEqual(find_two_sum_indices([2, 7, 11, 15], 9), [0, 1]) - def test_basic_case_2(self): + def test_with_different_array_and_target(self): """Test basic case with a different array and target.""" self.assertEqual(find_two_sum_indices([3, 2, 4], 6), [1, 2]) - def test_basic_case_3(self): + def test_with_duplicates(self): """Test basic case with duplicate values.""" self.assertEqual(find_two_sum_indices([3, 3], 6), [0, 1]) From 82711ab12783074165be2cea33e920d4d1002a18 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 08:00:46 +0000 Subject: [PATCH 092/139] Unit test cases for number to word function --- solutions/tests/test_number_to_word.py | 54 ++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 solutions/tests/test_number_to_word.py diff --git a/solutions/tests/test_number_to_word.py b/solutions/tests/test_number_to_word.py new file mode 100644 index 000000000..a30ecda2f --- /dev/null +++ b/solutions/tests/test_number_to_word.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for conversion from number to word. + +This module contains unittest test and edge cases for the number_to_word + +Created on 03 01 2025 +@author: Terry Aziaba +""" + +import unittest + +from solutions.number_to_word import number_to_word + + +class TestNumberToWord(unittest.TestCase): + """Unit tests for the number_to_word function.""" + + def test_valid_single_digits(self): + """Test valid single-digit inputs.""" + self.assertEqual(number_to_word(0), "zero") + self.assertEqual(number_to_word(1), "one") + self.assertEqual(number_to_word(2), "two") + self.assertEqual(number_to_word(3), "three") + self.assertEqual(number_to_word(4), "four") + self.assertEqual(number_to_word(5), "five") + self.assertEqual(number_to_word(6), "six") + self.assertEqual(number_to_word(7), "seven") + self.assertEqual(number_to_word(8), "eight") + self.assertEqual(number_to_word(9), "nine") + + def test_invalid_numbers(self): + """Test invalid numbers that are not single digits.""" + with self.assertRaises(ValueError): + number_to_word(10) # Two-digit number + with self.assertRaises(ValueError): + number_to_word(-1) # Negative number + with self.assertRaises(ValueError): + number_to_word(100) # Larger number + + def test_non_integer_inputs(self): + """Test inputs that are not integers.""" + with self.assertRaises(ValueError): + number_to_word(3.5) # Float input + with self.assertRaises(ValueError): + number_to_word("three") # String input + with self.assertRaises(ValueError): + number_to_word(None) # NoneType input + + def test_edge_cases(self): + """Test edge cases like boundary values.""" + self.assertEqual(number_to_word(0), "zero") # Lower boundary + self.assertEqual(number_to_word(9), "nine") # Upper boundary From 84b004f9aa02718d7522c7c328039a3900f91dda Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 08:56:42 +0000 Subject: [PATCH 093/139] Added infinity positive and negative cases --- solutions/tests/test_celsius_to_fahrenheit.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py index 77564bf69..804ece60d 100644 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ b/solutions/tests/test_celsius_to_fahrenheit.py @@ -41,6 +41,21 @@ def test_large_negative_value(self): """Test a very large negative Celsius value""" self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) + def test_infinity_positive(self): + """Test positive infinity.""" + result = celsius_to_fahrenheit(float("inf")) + self.assertEqual(result, float("inf")) + + def test_infinity_negative(self): + """Test negative infinity.""" + result = celsius_to_fahrenheit(float("-inf")) + self.assertEqual(result, float("-inf")) + + def test_nan_value(self): + """Test if NaN is handled correctly.""" + with self.assertRaises(AssertionError): + celsius_to_fahrenheit(float("nan")) + def test_zero_input(self): """Test zero as input.""" self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) From d64d7f516ab3c303a253faf1aa07ab8a4a5c1956 Mon Sep 17 00:00:00 2001 From: Terry Aziaba <125621206+terryekoe@users.noreply.github.com> Date: Mon, 6 Jan 2025 09:00:48 +0000 Subject: [PATCH 094/139] Delete solutions/celsius_to_fahrenheit.py Accidentally push to another branch --- solutions/celsius_to_fahrenheit.py | 42 ------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 solutions/celsius_to_fahrenheit.py diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py deleted file mode 100644 index e2835b72f..000000000 --- a/solutions/celsius_to_fahrenheit.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -A module for converting temperatures between Celsius and Fahrenheit. - -Module contents: - - celsius_to_fahrenheit: converts a temperature from Celsius to Fahrenheit. - -Created on 30 12 2024 -@author: Terry Aziaba -""" - - -def celsius_to_fahrenheit(celsius: float) -> float: - """Converts a temperature from Celsius to Fahrenheit. - - Parameters: - celsius: float, the temperature in Celsius. - - Returns -> float: - The temperature in Fahrenheit. - - Raises: - AssertionError: if the argument is not a float or int. - - Examples: - >>> celsius_to_fahrenheit(0) - 32.0 - - >>> celsius_to_fahrenheit(100) - 212.0 - - >>> celsius_to_fahrenheit(-40) - -40.0 - """ - # This line ensures the input (temperature) is a number (int or float) - assert isinstance(celsius, (int, float)), "Input temperature must be a number." - - # Conversion - fahrenheit = (celsius * 9 / 5) + 32 - - return fahrenheit From a40312e12fc2ac5f871552c7f163c4e5a927760e Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:03:53 +0000 Subject: [PATCH 095/139] Added infinity positive and negative cases --- solutions/tests/test_celsius_to_fahrenheit.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py index 77564bf69..804ece60d 100644 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ b/solutions/tests/test_celsius_to_fahrenheit.py @@ -41,6 +41,21 @@ def test_large_negative_value(self): """Test a very large negative Celsius value""" self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) + def test_infinity_positive(self): + """Test positive infinity.""" + result = celsius_to_fahrenheit(float("inf")) + self.assertEqual(result, float("inf")) + + def test_infinity_negative(self): + """Test negative infinity.""" + result = celsius_to_fahrenheit(float("-inf")) + self.assertEqual(result, float("-inf")) + + def test_nan_value(self): + """Test if NaN is handled correctly.""" + with self.assertRaises(AssertionError): + celsius_to_fahrenheit(float("nan")) + def test_zero_input(self): """Test zero as input.""" self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) From a63bda87f48102cd4c193015945ef746b5a96d30 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:32:29 +0000 Subject: [PATCH 096/139] Made changes for NaN values to pass unit test --- solutions/celsius_to_fahrenheit.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/solutions/celsius_to_fahrenheit.py b/solutions/celsius_to_fahrenheit.py index e2835b72f..298b8b365 100644 --- a/solutions/celsius_to_fahrenheit.py +++ b/solutions/celsius_to_fahrenheit.py @@ -10,6 +10,8 @@ @author: Terry Aziaba """ +import math + def celsius_to_fahrenheit(celsius: float) -> float: """Converts a temperature from Celsius to Fahrenheit. @@ -35,6 +37,7 @@ def celsius_to_fahrenheit(celsius: float) -> float: """ # This line ensures the input (temperature) is a number (int or float) assert isinstance(celsius, (int, float)), "Input temperature must be a number." + assert not math.isnan(celsius), "Input temperature must not be NaN." # Conversion fahrenheit = (celsius * 9 / 5) + 32 From 08b6bab88829d408508c9a26db04b1428c516573 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:40:37 +0000 Subject: [PATCH 097/139] Fix path error in the test file --- solutions/tests/test_number_to_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_number_to_word.py b/solutions/tests/test_number_to_word.py index a30ecda2f..f2476b1f6 100644 --- a/solutions/tests/test_number_to_word.py +++ b/solutions/tests/test_number_to_word.py @@ -11,7 +11,7 @@ import unittest -from solutions.number_to_word import number_to_word +from ..number_to_word import number_to_word class TestNumberToWord(unittest.TestCase): From b3bdd9de2dbfa9242f678480b43bbc115669f171 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:46:48 +0000 Subject: [PATCH 098/139] Removed function that is not supposed to be in directory --- solutions/tests/test_celsius_to_fahrenheit.py | 75 ------------------- 1 file changed, 75 deletions(-) delete mode 100644 solutions/tests/test_celsius_to_fahrenheit.py diff --git a/solutions/tests/test_celsius_to_fahrenheit.py b/solutions/tests/test_celsius_to_fahrenheit.py deleted file mode 100644 index 804ece60d..000000000 --- a/solutions/tests/test_celsius_to_fahrenheit.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Test module for conversion from celsius to fahrenheit. - -This module contains unittest test cases for the celsius_to_fahrenheit - -Created on 30 12 2024 -@author: Terry Aziaba -""" - -import unittest - -from ..celsius_to_fahrenheit import celsius_to_fahrenheit - - -class TestCelsiusToFahrenheit(unittest.TestCase): - """Unit tests for the celsius_to_fahrenheit function.""" - - def test_freezing_point(self): - """Test the freezing point of water.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) - - def test_boiling_point(self): - """Test the boiling point of water.""" - self.assertAlmostEqual(celsius_to_fahrenheit(100), 212.0) - - def test_negative_temperature(self): - """Test a negative temperature.""" - self.assertAlmostEqual(celsius_to_fahrenheit(-40), -40.0) - - def test_fractional_input(self): - """Test a fractional Celsius value.""" - self.assertAlmostEqual(celsius_to_fahrenheit(37.5), 99.5) - - def test_large_positive_value(self): - """Test a very large positive Celsius value.""" - self.assertAlmostEqual(celsius_to_fahrenheit(1000), 1832.0) - - def test_large_negative_value(self): - """Test a very large negative Celsius value""" - self.assertAlmostEqual(celsius_to_fahrenheit(-273.15), -459.67) - - def test_infinity_positive(self): - """Test positive infinity.""" - result = celsius_to_fahrenheit(float("inf")) - self.assertEqual(result, float("inf")) - - def test_infinity_negative(self): - """Test negative infinity.""" - result = celsius_to_fahrenheit(float("-inf")) - self.assertEqual(result, float("-inf")) - - def test_nan_value(self): - """Test if NaN is handled correctly.""" - with self.assertRaises(AssertionError): - celsius_to_fahrenheit(float("nan")) - - def test_zero_input(self): - """Test zero as input.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0), 32.0) - - def test_small_fractional_input(self): - """Test a small fractional input.""" - self.assertAlmostEqual(celsius_to_fahrenheit(0.5), 32.9) - - def test_assertion_error_non_numeric(self): - """Test if an assertion error is raised for non-numeric input.""" - with self.assertRaises(AssertionError): - celsius_to_fahrenheit("not a number") - - def test_assertion_error_none(self): - """Test if an assertion error is raised for None input.""" - with self.assertRaises(AssertionError): - celsius_to_fahrenheit(None) From 204747171a37fe1ef20a12181d88a5b925490e33 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:52:13 +0000 Subject: [PATCH 099/139] Fix python test error --- solutions/tests/test_number_to_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_number_to_word.py b/solutions/tests/test_number_to_word.py index f2476b1f6..ae881ba25 100644 --- a/solutions/tests/test_number_to_word.py +++ b/solutions/tests/test_number_to_word.py @@ -3,7 +3,7 @@ """ Test module for conversion from number to word. -This module contains unittest test and edge cases for the number_to_word +This module contains unittest test and edge cases for the number_to_word. Created on 03 01 2025 @author: Terry Aziaba From c71eed0d66f4c6817a6c1eaeb52bcd7c74d56367 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:19:00 +0000 Subject: [PATCH 100/139] added edge case examples --- solutions/tests/test_find_two_sum_indices.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index b3867504f..bf67edf7e 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -109,7 +109,20 @@ def test_invalid_target_none(self): """Test with an invalid target of None.""" with self.assertRaises(AssertionError): find_two_sum_indices([1, 2, 3], None) - - + + #adding edge cases + def test_with_precision(self): + """Test edge case with float precision.""" + self.assertEqual(find_two_sum_indices([1.0000001, 2.9999999], 4), [0, 1]) + + def test_with_nan(self): + """Test with NaN input or target.""" + with self.assertRaises(ValueError): + find_two_sum_indices([float("nan"), 2.5], float("nan")) + + def test_with_zero_target(self): + "Test when the target is zero." + self.assertEqual(find_two_sum_indices([-1, 1, 2], 0), [0, 1]) + if __name__ == "__main__": unittest.main() From 321cff719862517105a038df2b0b08b970af3547 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:19:09 +0000 Subject: [PATCH 101/139] added edge case examples --- solutions/find_two_sum_indices.py | 23 ++++++++++++-------- solutions/tests/test_find_two_sum_indices.py | 18 ++++++++------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index 377629b91..f6232093b 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -36,23 +36,28 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: >>> find_two_sum_indices([3.0, 3], 6.0) [0, 1] """ - # Debugging input validation + import math + + # Validate inputs assert isinstance(nums, list), "Input must be a list." assert all( isinstance(num, (int, float)) for num in nums - ), "List must contain numbers (integers or floats)." - assert isinstance( - target, (int, float) - ), "Target must be a number (integer or float)." + ), "List must contain numbers." + assert isinstance(target, (int, float)), "Target must be a number." assert len(nums) > 1, "List must contain at least two numbers." + assert not any( + math.isnan(x) for x in nums + ), "Input list must not contain NaN values." + assert not math.isnan(target), "Target must not be NaN." - # Debugging main logic + # Main logic with floating-point precision handling + epsilon = 1e-7 num_map = {} for i, num in enumerate(nums): complement = target - num - if complement in num_map: - return [num_map[complement], i] + for seen_num, seen_index in num_map.items(): + if abs(seen_num - complement) < epsilon: + return [seen_index, i] num_map[num] = i - # Debugging output if no solution assert False, "No two numbers add up to the target sum." diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index bf67edf7e..7daf56ead 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -10,6 +10,7 @@ import unittest from solutions.find_two_sum_indices import find_two_sum_indices +import math class TestFindTwoSumIndices(unittest.TestCase): @@ -109,20 +110,21 @@ def test_invalid_target_none(self): """Test with an invalid target of None.""" with self.assertRaises(AssertionError): find_two_sum_indices([1, 2, 3], None) - - #adding edge cases + + # Edge cases for precision and NaN def test_with_precision(self): """Test edge case with float precision.""" - self.assertEqual(find_two_sum_indices([1.0000001, 2.9999999], 4), [0, 1]) - + self.assertEqual(find_two_sum_indices([1.0000001, 2.9999999], 4.0), [0, 1]) + def test_with_nan(self): """Test with NaN input or target.""" - with self.assertRaises(ValueError): + with self.assertRaises(AssertionError): find_two_sum_indices([float("nan"), 2.5], float("nan")) - + def test_with_zero_target(self): - "Test when the target is zero." + """Test when the target is zero.""" self.assertEqual(find_two_sum_indices([-1, 1, 2], 0), [0, 1]) - + + if __name__ == "__main__": unittest.main() From dc04c1734139e62df877ee9912f1544b3b7bf190 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:22:28 +0000 Subject: [PATCH 102/139] fixing CI checks --- solutions/find_two_sum_indices.py | 2 +- solutions/tests/test_find_two_sum_indices.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index f6232093b..165396cc9 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -60,4 +60,4 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: return [seen_index, i] num_map[num] = i - assert False, "No two numbers add up to the target sum." + assert False, "No two numbers add up to the target sum." \ No newline at end of file diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index 7daf56ead..bc2bcd257 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -10,11 +10,9 @@ import unittest from solutions.find_two_sum_indices import find_two_sum_indices -import math - class TestFindTwoSumIndices(unittest.TestCase): - # Basic test cases + # Basic tests def test_with_simple_target_sum(self): """Test basic case with a simple target sum.""" self.assertEqual(find_two_sum_indices([2, 7, 11, 15], 9), [0, 1]) From b3afa997437f833fbbaedd3a8c3a124b408e2231 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Tue, 7 Jan 2025 00:23:26 +0000 Subject: [PATCH 103/139] fixing CI checks --- solutions/find_two_sum_indices.py | 2 +- solutions/tests/test_find_two_sum_indices.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index 165396cc9..f6232093b 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -60,4 +60,4 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: return [seen_index, i] num_map[num] = i - assert False, "No two numbers add up to the target sum." \ No newline at end of file + assert False, "No two numbers add up to the target sum." diff --git a/solutions/tests/test_find_two_sum_indices.py b/solutions/tests/test_find_two_sum_indices.py index bc2bcd257..ff1fccf14 100644 --- a/solutions/tests/test_find_two_sum_indices.py +++ b/solutions/tests/test_find_two_sum_indices.py @@ -11,6 +11,7 @@ import unittest from solutions.find_two_sum_indices import find_two_sum_indices + class TestFindTwoSumIndices(unittest.TestCase): # Basic tests def test_with_simple_target_sum(self): From 6351a19b3729f5ff9218b0f7ac00cec927421880 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Tue, 7 Jan 2025 13:45:17 +0000 Subject: [PATCH 104/139] added test for multiple numbers --- solutions/phone_letter_combinations.py | 10 +- .../tests/test_phone_letter_combinations.py | 92 +++++++++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 solutions/tests/test_phone_letter_combinations.py diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py index da4d2780c..099de1c34 100644 --- a/solutions/phone_letter_combinations.py +++ b/solutions/phone_letter_combinations.py @@ -8,7 +8,7 @@ letter combinations in phone keyboard for the numbers given for simplification I made it maximum of 2 digits -Created on 2024-12-30 +Created on 2024-01-07 Author: Hiba Daffallah """ @@ -17,7 +17,7 @@ def phone_letter_combinations(digits: str) -> list[str]: """ phone_letter_combinations function creates a new list with possible letter combinations in phone keyboard for the numbers given - for simplification I made it maximum of 2 digits + Parameters: digits: string of numbers it should be from 2 to 9 @@ -33,8 +33,10 @@ def phone_letter_combinations(digits: str) -> list[str]: ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf'] >>> phone_letter_combinations("") [] - >>> phone_letter_combinations("2") - ['a', 'b', 'c'] + >>> phone_letter_combinations("234") + ['adg', 'adh', 'adi', 'aeg', 'aeh', 'aei', 'afg', 'afh', + 'afi', 'bdg', 'bdh', 'bdi', 'beg', 'beh', 'bei', 'bfg', + 'bfh', 'bfi', 'cdg', 'cdh', 'cdi', 'ceg', 'ceh', 'cei', 'cfg', 'cfh', 'cfi'] >>> phone_letter_combinations("1") Input must only contain digits from 2 to 9. """ diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py new file mode 100644 index 000000000..ecd93f1df --- /dev/null +++ b/solutions/tests/test_phone_letter_combinations.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for phone_letter_combinations function. + +Created on 2025-01-07 +Author: Hiba Daffallah +""" + +import unittest + +from solutions.phone_letter_combinations import phone_letter_combinations + + +class TestPhoneLetterCombinations(unittest.TestCase): + """Test phone_letter_combinations function""" + + def test_numbers_within_range(self): + """It should return all the possible letter combinations for 2,3""" + self.assertEqual( + phone_letter_combinations("23"), + ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"], + ) + + def test_empty(self): + """It should return empty list""" + self.assertEqual(phone_letter_combinations(""), []) + + def test_single_number(self): + """It should return all the letters for 2""" + self.assertEqual(phone_letter_combinations("2"), ["a", "b", "c"]) + + def test_numbers_out_of_range(self): + """It should return a message""" + with self.assertRaises(AssertionError) as context: + phone_letter_combinations("1") + self.assertEqual( + str(context.exception), "Input must only contain digits from 2 to 9." + ) + + def test_contains_numbers_out_of_range(self): + """It should return a message""" + with self.assertRaises(AssertionError) as context: + phone_letter_combinations("12") + self.assertEqual( + str(context.exception), "Input must only contain digits from 2 to 9." + ) + + def test_contains_multiple_numbers(self): + "Tests if it can handle multiple numbers" + self.assertEqual( + phone_letter_combinations("234"), + [ + "adg", + "adh", + "adi", + "aeg", + "aeh", + "aei", + "afg", + "afh", + "afi", + "bdg", + "bdh", + "bdi", + "beg", + "beh", + "bei", + "bfg", + "bfh", + "bfi", + "cdg", + "cdh", + "cdi", + "ceg", + "ceh", + "cei", + "cfg", + "cfh", + "cfi", + ], + ) + + # Defensive tests + def test_none_input(self): + """It should raise AssertionError for non-integer input""" + with self.assertRaises(AssertionError): + phone_letter_combinations("b") + + +if __name__ == "__main__": + unittest.main() From 292077b53fbf3dcefa7a3917aa4b42bbdcf54588 Mon Sep 17 00:00:00 2001 From: terryekoe Date: Tue, 7 Jan 2025 15:01:13 +0000 Subject: [PATCH 105/139] Single assertion for each test --- solutions/tests/test_number_to_word.py | 74 ++++++++++++++++++++------ 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/solutions/tests/test_number_to_word.py b/solutions/tests/test_number_to_word.py index ae881ba25..803e38bc1 100644 --- a/solutions/tests/test_number_to_word.py +++ b/solutions/tests/test_number_to_word.py @@ -17,38 +17,80 @@ class TestNumberToWord(unittest.TestCase): """Unit tests for the number_to_word function.""" - def test_valid_single_digits(self): - """Test valid single-digit inputs.""" + def test_zero(self): + """Test the input 0.""" self.assertEqual(number_to_word(0), "zero") + + def test_one(self): + """Test the input 1.""" self.assertEqual(number_to_word(1), "one") + + def test_two(self): + """Test the input 2.""" self.assertEqual(number_to_word(2), "two") + + def test_three(self): + """Test the input 3.""" self.assertEqual(number_to_word(3), "three") + + def test_four(self): + """Test the input 4.""" self.assertEqual(number_to_word(4), "four") + + def test_five(self): + """Test the input 5.""" self.assertEqual(number_to_word(5), "five") + + def test_six(self): + """Test the input 6.""" self.assertEqual(number_to_word(6), "six") + + def test_seven(self): + """Test the input 7.""" self.assertEqual(number_to_word(7), "seven") + + def test_eight(self): + """Test the input 8.""" self.assertEqual(number_to_word(8), "eight") + + def test_nine(self): + """Test the input 9.""" self.assertEqual(number_to_word(9), "nine") - def test_invalid_numbers(self): - """Test invalid numbers that are not single digits.""" + def test_invalid_input_ten(self): + """Test the input 10 (two-digit number).""" with self.assertRaises(ValueError): - number_to_word(10) # Two-digit number + number_to_word(10) + + def test_invalid_input_negative(self): + """Test the input -1 (negative number).""" with self.assertRaises(ValueError): - number_to_word(-1) # Negative number + number_to_word(-1) + + def test_invalid_input_large_number(self): + """Test the input 100 (large number).""" with self.assertRaises(ValueError): - number_to_word(100) # Larger number + number_to_word(100) - def test_non_integer_inputs(self): - """Test inputs that are not integers.""" + def test_invalid_input_float(self): + """Test the input 3.5 (float).""" with self.assertRaises(ValueError): - number_to_word(3.5) # Float input + number_to_word(3.5) + + def test_invalid_input_string(self): + """Test the input "three" (string).""" with self.assertRaises(ValueError): - number_to_word("three") # String input + number_to_word("three") + + def test_invalid_input_none(self): + """Test the input None.""" with self.assertRaises(ValueError): - number_to_word(None) # NoneType input + number_to_word(None) + + def test_edge_case_zero(self): + """Test the lower boundary input 0.""" + self.assertEqual(number_to_word(0), "zero") - def test_edge_cases(self): - """Test edge cases like boundary values.""" - self.assertEqual(number_to_word(0), "zero") # Lower boundary - self.assertEqual(number_to_word(9), "nine") # Upper boundary + def test_edge_case_nine(self): + """Test the upper boundary input 9.""" + self.assertEqual(number_to_word(9), "nine") From 53a46a3f8c0a97a2b300d322852b7831277e169c Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Wed, 8 Jan 2025 00:46:54 +0000 Subject: [PATCH 106/139] my first challenge --- solutions/add_numbers.py | 48 +++++++++++++++++++++++++++++ solutions/tests/test_add_numbers.py | 36 ++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 solutions/add_numbers.py create mode 100644 solutions/tests/test_add_numbers.py diff --git a/solutions/add_numbers.py b/solutions/add_numbers.py new file mode 100644 index 000000000..f449519c8 --- /dev/null +++ b/solutions/add_numbers.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# -- coding: utf-8 -- + +""" +A module that takes two numbers and return their sum. + +Module contents: Takes two numbers and return their sum. + +Created on 2025-01-08 + +@author: Martha Yelademe Nyekanga +""" + + +def add_numbers(num1:int, num2:int) -> int: + """This function takes two numbers and returns their sum. + + Parameters: + num1 (int): The first number for the function + num2 (int): The second number for the function + + Returns: + int: The sum of the two numbers + + Raises: + TypeError: If the input is not a number + + Examples: + >>> add_numbers(2, 3) + 5 + + >>> add_numbers(-2, 3) + 1 + + >>> add_numbers(0, 0) + 0 + + >>> add_numbers(2, -3) + -1 + """ + + assert isinstance(num1, int), "Input must be a number." + assert isinstance(num2, int), "Input must be a number." + + #return the sum of the two numbers + return num1 + num2 + +print(add_numbers(0,0)) \ No newline at end of file diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py new file mode 100644 index 000000000..b67a03f68 --- /dev/null +++ b/solutions/tests/test_add_numbers.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# -- coding: utf-8 -- +""" +Test module for adding two numbers. + +Created on 2025-01-07 + +Author: Martha Yelademe Nyekanga +""" + +import unittest +from ..add_numbers import add_numbers + +class TestAddNumbers(unittest.TestCase): + """This class contains tests for the add_numbers function.""" + + def test_add_two_positive_numbers(self): + """Test adding two positive numbers.""" + self.assertEqual(add_numbers(2, 3), 5) + + def test_add_positive_and_negative_numbers(self): + """Test adding a positive and a negative number.""" + self.assertEqual(add_numbers(-2, 3), 1) + + def test_add_zeros(self): + """Test adding two zeros.""" + self.assertEqual(add_numbers(0, 0), 0) + + def test_add_two_negative_numbers(self): + """Test adding two negative numbers.""" + self.assertEqual(add_numbers(-2, -3), -5) + + def test_add_numbers_string(self): + """Test adding a string and a number.""" + with self.assertRaises(AssertionError): + add_numbers("2",3) \ No newline at end of file From 7768a3f48c0377d1e607ef428e1d15faaad27767 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 9 Jan 2025 01:46:08 +0000 Subject: [PATCH 107/139] get rid of duplicate --- .../tests/test_phone_letter_combinations | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 solutions/tests/test_phone_letter_combinations diff --git a/solutions/tests/test_phone_letter_combinations b/solutions/tests/test_phone_letter_combinations deleted file mode 100644 index d135620cd..000000000 --- a/solutions/tests/test_phone_letter_combinations +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Test module for phone_letter_combinations function. - -Created on 2024-12-30 -Author: Hiba Daffallah -""" - -import unittest - -from solutions.phone_letter_combinations import phone_letter_combinations - - -class TestPhoneLetterCombinations(unittest.TestCase): - """Test phone_letter_combinations function""" - - def test_numbers_within_range(self): - """It should return all the possible letter combinations for 2,3""" - self.assertEqual( - phone_letter_combinations("23"), - ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"], - ) - - def test_empty(self): - """It should return empty list""" - self.assertEqual(phone_letter_combinations(""), []) - - def test_single_number(self): - """It should return all the letters for 2""" - self.assertEqual(phone_letter_combinations("2"), ["a", "b", "c"]) - - def test_numbers_out_of_range(self): - """It should return a message""" - with self.assertRaises(AssertionError) as context: - phone_letter_combinations("1") - self.assertEqual( - str(context.exception), "Input must only contain digits from 2 to 9." - ) - - def test_contains_numbers_out_of_range(self): - """It should return a message""" - with self.assertRaises(AssertionError) as context: - phone_letter_combinations("12") - self.assertEqual( - str(context.exception), "Input must only contain digits from 2 to 9." - ) - - # Defensive tests - def test_none_input(self): - """It should raise AssertionError for non-integer input""" - with self.assertRaises(AssertionError): - phone_letter_combinations("b") - - -if __name__ == "__main__": - unittest.main() From ea9bd7a6d3b823e2b8c47672e01d249c233c35cb Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 9 Jan 2025 13:29:38 +0000 Subject: [PATCH 108/139] final modifications --- solutions/phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py index 099de1c34..3730d54b2 100644 --- a/solutions/phone_letter_combinations.py +++ b/solutions/phone_letter_combinations.py @@ -8,7 +8,7 @@ letter combinations in phone keyboard for the numbers given for simplification I made it maximum of 2 digits -Created on 2024-01-07 +Created on 2025-01-07 Author: Hiba Daffallah """ From db1a57b03aa2c09b5f95593d9335957c5d088188 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 13:12:55 +0000 Subject: [PATCH 109/139] solving ruff formating --- solutions/phone_letter_combinations.py | 2 +- solutions/tests/test_phone_letter_combinations.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py index 3730d54b2..9f6a72baf 100644 --- a/solutions/phone_letter_combinations.py +++ b/solutions/phone_letter_combinations.py @@ -8,7 +8,7 @@ letter combinations in phone keyboard for the numbers given for simplification I made it maximum of 2 digits -Created on 2025-01-07 +Created on 2025-01-01 Author: Hiba Daffallah """ diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index ecd93f1df..7fbd9af2f 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -3,7 +3,7 @@ """ Test module for phone_letter_combinations function. -Created on 2025-01-07 +Created on 2025-01-01 Author: Hiba Daffallah """ From 92ba8b47fb37a4b69786e8613b63c39eb8fe9036 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 13:22:03 +0000 Subject: [PATCH 110/139] solving formatting issue --- solutions/phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/phone_letter_combinations.py b/solutions/phone_letter_combinations.py index 9f6a72baf..3730d54b2 100644 --- a/solutions/phone_letter_combinations.py +++ b/solutions/phone_letter_combinations.py @@ -8,7 +8,7 @@ letter combinations in phone keyboard for the numbers given for simplification I made it maximum of 2 digits -Created on 2025-01-01 +Created on 2025-01-07 Author: Hiba Daffallah """ From 0e97e4fda21891cb441b320bc0adaf6312b6c58c Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 13:32:37 +0000 Subject: [PATCH 111/139] solve formatting error --- solutions/tests/test_phone_letter_combinations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/tests/test_phone_letter_combinations.py b/solutions/tests/test_phone_letter_combinations.py index 7fbd9af2f..ecd93f1df 100644 --- a/solutions/tests/test_phone_letter_combinations.py +++ b/solutions/tests/test_phone_letter_combinations.py @@ -3,7 +3,7 @@ """ Test module for phone_letter_combinations function. -Created on 2025-01-01 +Created on 2025-01-07 Author: Hiba Daffallah """ From 669ba0d6d7d59e2a918d7f82b456d613d9e909d6 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Fri, 10 Jan 2025 13:37:05 +0000 Subject: [PATCH 112/139] ruff updated! --- solutions/number_to_word.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/number_to_word.py b/solutions/number_to_word.py index 260e97a3e..b23a3171c 100644 --- a/solutions/number_to_word.py +++ b/solutions/number_to_word.py @@ -6,7 +6,7 @@ Module contents: - number_to_word: converts a number ranging from (0-9) to it's word equivalent. -Created on 03 01 2024 +Created on 04 01 2024 @author: Terry Aziaba """ From 2afde11e4dfcc86abc548fe28c4fa9b0398144b6 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 13:54:03 +0000 Subject: [PATCH 113/139] .. --- .github/workflows/ci-checks.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 3b95f5dfe..2fbdcb8b4 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -22,10 +22,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Python - Check Formatting + - name: Python - debugging Formatting uses: astral-sh/ruff-action@v1 with: - args: "format --check" + args: "format --diff" py_linting: runs-on: ubuntu-latest @@ -68,4 +68,3 @@ jobs: if: steps.check_tests.outputs.has_tests == 'true' run: echo "PYTHONPATH=$GITHUB_WORKSPACE" >> $GITHUB_ENV shell: bash - From e6d59548b9403307a83113802aaf7fd26cb3a9af Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 14:28:20 +0000 Subject: [PATCH 114/139] formatting error resolved --- .github/workflows/ci-checks.yml | 4 ++-- solutions/find_two_sum_indices.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 2fbdcb8b4..74de21293 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -22,10 +22,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Python - debugging Formatting + - name: Python - Check Formatting uses: astral-sh/ruff-action@v1 with: - args: "format --diff" + args: "format --check" py_linting: runs-on: ubuntu-latest diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index f6232093b..81529f8ac 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -40,14 +40,14 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: # Validate inputs assert isinstance(nums, list), "Input must be a list." - assert all( - isinstance(num, (int, float)) for num in nums - ), "List must contain numbers." + assert all(isinstance(num, (int, float)) for num in nums), ( + "List must contain numbers." + ) assert isinstance(target, (int, float)), "Target must be a number." assert len(nums) > 1, "List must contain at least two numbers." - assert not any( - math.isnan(x) for x in nums - ), "Input list must not contain NaN values." + assert not any(math.isnan(x) for x in nums), ( + "Input list must not contain NaN values." + ) assert not math.isnan(target), "Target must not be NaN." # Main logic with floating-point precision handling From 8173e2b8ce9606038fbe90a135ce45656077f48a Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 14:34:41 +0000 Subject: [PATCH 115/139] ruff reformatted --- solutions/find_two_sum_indices.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index f6232093b..81529f8ac 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -40,14 +40,14 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: # Validate inputs assert isinstance(nums, list), "Input must be a list." - assert all( - isinstance(num, (int, float)) for num in nums - ), "List must contain numbers." + assert all(isinstance(num, (int, float)) for num in nums), ( + "List must contain numbers." + ) assert isinstance(target, (int, float)), "Target must be a number." assert len(nums) > 1, "List must contain at least two numbers." - assert not any( - math.isnan(x) for x in nums - ), "Input list must not contain NaN values." + assert not any(math.isnan(x) for x in nums), ( + "Input list must not contain NaN values." + ) assert not math.isnan(target), "Target must not be NaN." # Main logic with floating-point precision handling From a780c3a6211c4330d08ab68feb1111a11b985db2 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 14:49:37 +0000 Subject: [PATCH 116/139] ruff issue solved --- solutions/add_numbers.py | 25 +++++++++++++------------ solutions/find_two_sum_indices.py | 12 ++++++------ solutions/tests/test_add_numbers.py | 3 ++- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/solutions/add_numbers.py b/solutions/add_numbers.py index f449519c8..26c9e2b38 100644 --- a/solutions/add_numbers.py +++ b/solutions/add_numbers.py @@ -12,37 +12,38 @@ """ -def add_numbers(num1:int, num2:int) -> int: +def add_numbers(num1: int, num2: int) -> int: """This function takes two numbers and returns their sum. - + Parameters: num1 (int): The first number for the function num2 (int): The second number for the function - + Returns: int: The sum of the two numbers - + Raises: TypeError: If the input is not a number - + Examples: >>> add_numbers(2, 3) 5 - + >>> add_numbers(-2, 3) 1 - + >>> add_numbers(0, 0) 0 - + >>> add_numbers(2, -3) -1 """ - + assert isinstance(num1, int), "Input must be a number." assert isinstance(num2, int), "Input must be a number." - - #return the sum of the two numbers + + # return the sum of the two numbers return num1 + num2 -print(add_numbers(0,0)) \ No newline at end of file + +print(add_numbers(0, 0)) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index f6232093b..81529f8ac 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -40,14 +40,14 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: # Validate inputs assert isinstance(nums, list), "Input must be a list." - assert all( - isinstance(num, (int, float)) for num in nums - ), "List must contain numbers." + assert all(isinstance(num, (int, float)) for num in nums), ( + "List must contain numbers." + ) assert isinstance(target, (int, float)), "Target must be a number." assert len(nums) > 1, "List must contain at least two numbers." - assert not any( - math.isnan(x) for x in nums - ), "Input list must not contain NaN values." + assert not any(math.isnan(x) for x in nums), ( + "Input list must not contain NaN values." + ) assert not math.isnan(target), "Target must not be NaN." # Main logic with floating-point precision handling diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py index b67a03f68..ac0a2f59b 100644 --- a/solutions/tests/test_add_numbers.py +++ b/solutions/tests/test_add_numbers.py @@ -11,6 +11,7 @@ import unittest from ..add_numbers import add_numbers + class TestAddNumbers(unittest.TestCase): """This class contains tests for the add_numbers function.""" @@ -33,4 +34,4 @@ def test_add_two_negative_numbers(self): def test_add_numbers_string(self): """Test adding a string and a number.""" with self.assertRaises(AssertionError): - add_numbers("2",3) \ No newline at end of file + add_numbers("2", 3) From ba48b9a5fcf3a16074e15dca86d8aa92c21d0f26 Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Fri, 10 Jan 2025 16:32:55 +0000 Subject: [PATCH 117/139] add numbers.py --- solutions/add_numbers.py | 12 ++++++------ solutions/tests/test_add_numbers.py | 4 ++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/solutions/add_numbers.py b/solutions/add_numbers.py index f449519c8..5a7e07e83 100644 --- a/solutions/add_numbers.py +++ b/solutions/add_numbers.py @@ -12,12 +12,12 @@ """ -def add_numbers(num1:int, num2:int) -> int: +def add_numbers(first_number:int, second_number:int) -> int: """This function takes two numbers and returns their sum. Parameters: - num1 (int): The first number for the function - num2 (int): The second number for the function + first_number (int): The first number for the function + second_number (int): The second number for the function Returns: int: The sum of the two numbers @@ -39,10 +39,10 @@ def add_numbers(num1:int, num2:int) -> int: -1 """ - assert isinstance(num1, int), "Input must be a number." - assert isinstance(num2, int), "Input must be a number." + assert isinstance(first_number, int), "Input must be a number." + assert isinstance(second_number, int), "Input must be a number." #return the sum of the two numbers - return num1 + num2 + return first_number + second_number print(add_numbers(0,0)) \ No newline at end of file diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py index b67a03f68..fcbd4ab47 100644 --- a/solutions/tests/test_add_numbers.py +++ b/solutions/tests/test_add_numbers.py @@ -30,6 +30,10 @@ def test_add_two_negative_numbers(self): """Test adding two negative numbers.""" self.assertEqual(add_numbers(-2, -3), -5) + def test_add_two_float_numbers(self): + """"Test adding two float numbers.""" + self.assertEqual(add_numbers(2.5, 1.3), 3.8) + def test_add_numbers_string(self): """Test adding a string and a number.""" with self.assertRaises(AssertionError): From ca9050c3c75dbe23c1ca9b3b9a35eee57096c3ae Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Fri, 10 Jan 2025 21:32:08 +0000 Subject: [PATCH 118/139] changes made --- solutions/tests/test_add_numbers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py index fcbd4ab47..01ee42ec6 100644 --- a/solutions/tests/test_add_numbers.py +++ b/solutions/tests/test_add_numbers.py @@ -32,7 +32,8 @@ def test_add_two_negative_numbers(self): def test_add_two_float_numbers(self): """"Test adding two float numbers.""" - self.assertEqual(add_numbers(2.5, 1.3), 3.8) + with self.assertRaises(AssertionError): + add_numbers(2.5, 1.3) def test_add_numbers_string(self): """Test adding a string and a number.""" From df8e4f10e6504107abbbd67a34968204f81aacc3 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Fri, 10 Jan 2025 22:41:14 +0000 Subject: [PATCH 119/139] ruff reformatted --- solutions/find_two_sum_indices.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/solutions/find_two_sum_indices.py b/solutions/find_two_sum_indices.py index f6232093b..81529f8ac 100644 --- a/solutions/find_two_sum_indices.py +++ b/solutions/find_two_sum_indices.py @@ -40,14 +40,14 @@ def find_two_sum_indices(nums: list[float], target: float) -> list[int]: # Validate inputs assert isinstance(nums, list), "Input must be a list." - assert all( - isinstance(num, (int, float)) for num in nums - ), "List must contain numbers." + assert all(isinstance(num, (int, float)) for num in nums), ( + "List must contain numbers." + ) assert isinstance(target, (int, float)), "Target must be a number." assert len(nums) > 1, "List must contain at least two numbers." - assert not any( - math.isnan(x) for x in nums - ), "Input list must not contain NaN values." + assert not any(math.isnan(x) for x in nums), ( + "Input list must not contain NaN values." + ) assert not math.isnan(target), "Target must not be NaN." # Main logic with floating-point precision handling From d031ca3b48517e113c55c3dec14f11a8ce4d70c9 Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Sat, 11 Jan 2025 12:17:59 +0000 Subject: [PATCH 120/139] 2nd challenge --- solutions/even_numbers.py | 45 +++++++++++++++ solutions/tests/test_add_numbers.py | 2 +- solutions/tests/test_even_numbers.py | 82 ++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 solutions/even_numbers.py create mode 100644 solutions/tests/test_even_numbers.py diff --git a/solutions/even_numbers.py b/solutions/even_numbers.py new file mode 100644 index 000000000..a7c232e54 --- /dev/null +++ b/solutions/even_numbers.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# -- coding: utf-8 -- + +""" +A module that checks if a number is even. + +Module contents: Checks if a given number is even and returns True or False. + +Created on 2025-01-11 + +@author: Martha Yelademe Nyekanga +""" + +def is_even(number: int) -> bool: + """This function checks if a given number is even. + + Parameters: + number (int): The number to check + + Returns: + bool: True if the number is even, False otherwise + + Raises: + AssertionError: If the input is not an integer + + Examples: + >>> is_even(2) + True + + >>> is_even(3) + False + + >>> is_even(0) + True + + >>> is_even(-4) + True + """ + assert isinstance(number, int) and not isinstance(number, bool), "the input number must be an integer and not a boolean" + # Return True if the number is even, False otherwise + return number % 2 == 0 + +# Example: +if __name__ == "__main__": + print(is_even(0)) diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py index 1cecf524b..14475a1ba 100644 --- a/solutions/tests/test_add_numbers.py +++ b/solutions/tests/test_add_numbers.py @@ -3,7 +3,7 @@ """ Test module for adding two numbers. -Created on 2025-01-07 +Created on 2025-01-10 Author: Martha Yelademe Nyekanga """ diff --git a/solutions/tests/test_even_numbers.py b/solutions/tests/test_even_numbers.py new file mode 100644 index 000000000..7fb74b1e3 --- /dev/null +++ b/solutions/tests/test_even_numbers.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# -- coding: utf-8 -- +""" +Test module to check is a number is even + +Created on 2025-01-11 + +Author:Martha Yelademe Nyekanga +""" + + +import unittest +from ..even_numbers import is_even + +class TestIsEven(unittest.TestCase): + + # Test case for a positive even number + def test_positive_even(self): + self.assertTrue(is_even(2)) + + # Test case for a positive odd number + def test_positive_odd(self): + self.assertFalse(is_even(3)) + + # Test case for zero (edge case) + def test_zero(self): + self.assertTrue(is_even(0)) + + # Test case for a negative even number + def test_negative_even(self): + self.assertTrue(is_even(-4)) + + # Test case for a negative odd number + def test_negative_odd(self): + self.assertFalse(is_even(-7)) + + # Test case for a large positive even number + def test_large_even(self): + self.assertTrue(is_even(1000000)) + + # Test case for a large positive odd number + def test_large_odd(self): + self.assertFalse(is_even(1000001)) + + # Test case for a small positive even number + def test_small_even(self): + self.assertTrue(is_even(2)) + + # Test case for a small positive odd number + def test_small_odd(self): + self.assertFalse(is_even(1)) + + # Test case to check if a float raises a TypeError + def test_type_error_with_float(self): + with self.assertRaises(AssertionError): + is_even(4.5) + + # Test case to check if a string raises a TypeError + def test_type_error_with_string(self): + with self.assertRaises(AssertionError): + is_even("10") + + # Test case to check if a list raises a TypeError + def test_type_error_with_list(self): + with self.assertRaises(AssertionError): + is_even([2]) + + # Test case to check if a dictionary raises a TypeError + def test_type_error_with_dict(self): + with self.assertRaises(AssertionError): + is_even({"number": 4}) + + # Test case to check if None raises a TypeError + def test_type_error_with_none(self): + with self.assertRaises(AssertionError): + is_even(None) + + # Test case to check if a boolean raises a TypeError + def test_type_error_with_bool(self): + with self.assertRaises(AssertionError): + is_even(True) + From 385cd373cbef25bcdfe55fc798dcd36069bc2c2f Mon Sep 17 00:00:00 2001 From: Martha Yelademe Nyekanga Date: Sat, 11 Jan 2025 12:34:03 +0000 Subject: [PATCH 121/139] second challenge --- solutions/even_numbers.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/solutions/even_numbers.py b/solutions/even_numbers.py index a7c232e54..1cebe5ed8 100644 --- a/solutions/even_numbers.py +++ b/solutions/even_numbers.py @@ -2,10 +2,7 @@ # -- coding: utf-8 -- """ -A module that checks if a number is even. - -Module contents: Checks if a given number is even and returns True or False. - +This module checks if a given number is even and returns True for even numbers or False otherwise. Created on 2025-01-11 @author: Martha Yelademe Nyekanga From cad5795123c328f8cc2df7c1b2636efcb7a6ea4b Mon Sep 17 00:00:00 2001 From: yoolmalaak Date: Sat, 11 Jan 2025 16:09:03 +0000 Subject: [PATCH 122/139] remove deleted files --- CWA Calaculator/CWA_Calculator.py | 109 ------------------ GPA Calculator/GPA_Calculator.py | 139 ----------------------- GPA Calculator/test_gpa_calculator.py | 0 collaboration/Group_Norms Readme.md | 157 -------------------------- 4 files changed, 405 deletions(-) delete mode 100644 CWA Calaculator/CWA_Calculator.py delete mode 100644 GPA Calculator/GPA_Calculator.py delete mode 100644 GPA Calculator/test_gpa_calculator.py delete mode 100644 collaboration/Group_Norms Readme.md diff --git a/CWA Calaculator/CWA_Calculator.py b/CWA Calaculator/CWA_Calculator.py deleted file mode 100644 index f62b69d0a..000000000 --- a/CWA Calaculator/CWA_Calculator.py +++ /dev/null @@ -1,109 +0,0 @@ -class Student: - - - def __init__(self, name, index_number,reference_number, email, age, gender, program_of_study, year_of_study, university_name, num_of_courses): - self.name = name - self.age = age - self.index_number = index_number - self.reference_number = reference_number - self.email = email - self.gender = gender - self.program_of_study = program_of_study - self.year_of_study = year_of_study - self.university_name = university_name - self.num_of_courses = num_of_courses - self.courses = [] - self.CWA = 0 - -def get_grade(score): - - - if 70 <= score <= 100: - grade = "A" - elif 60 <= score < 70: - grade = "B" - elif 50 <= score < 60: - grade = "C" - elif 40 <= score < 50: - grade = "D" - elif 0 <= score < 40: - grade = "F" - else: - return "Invalid score" - return grade - - -def calculate_cwa(courses): - - grade_points = 0 - credits_obtained = 0 - for course in courses: - grade_points += course['score'] * course['credit_hours'] - credits_obtained += course['credit_hours'] - - if grade_points == 0: - return 0 - - return grade_points/credits_obtained - - - -def collect_student_data(): - - student_data = {} - student_data['name'] = input("Enter the name of the student: ") - student_data['age'] = input("Enter the age of the student: ") - student_data['index_number'] = input("Enter the index number: ") - student_data['reference_number'] = input("Enter the reference number: ") - student_data['email'] = input("Enter the student email") - student_data['gender'] = input("Enter the gender of the student: ") - student_data['program_of_study'] = input("Enter the program of study: ") - student_data['year_of_study'] = input("Enter the year of study: ") - student_data['university_name']= input("Enter the University name") - - num_of_courses = int(input("Enter the number of courses: ")) - courses = [] - - for _ in range(num_of_courses): - course_name = input("Enter the course name: ") - credit_hours = int(input(f"Enter the credit hours for {course_name}: ")) - score = float(input(f"Enter the score for {course_name}: ")) - grade = get_grade(score) - - - courses.append({ - 'name': course_name, - 'credit_hours': credit_hours, - 'score': score, - 'grade': grade, - }) - - student_data['courses'] = courses - student_data['CWA'] = calculate_cwa(courses) - - return student_data - -student = collect_student_data(): - - -print("\nStudent Details:") -print(f"Name: {student['name']}") -print(f"Age: {student['age']}") -print(f"index number: {student['index_number']}") -print(f"reference number: {student['reference_number']}") -print(f"email: {student['email']}") -print(f"Gender: {student['gender']}") -print(f"Program of Study: {student['program_of_study']}") -print(f"year of study: {student['year_of_study']}") -print(f"university name:{student['university_name']}") - -print(f"CWA: {student['CWA']:.2f}") - - -print("\nCourse Details:") -for course in student['courses']: - print(f"Course Name: {course['name']}") - print(f"Credit Hours: {course['credit_hours']}") - print(f"Score: {course['score']}") - print(f"Grade: {course['grade']}") - print("-" * 30) \ No newline at end of file diff --git a/GPA Calculator/GPA_Calculator.py b/GPA Calculator/GPA_Calculator.py deleted file mode 100644 index bad2c5117..000000000 --- a/GPA Calculator/GPA_Calculator.py +++ /dev/null @@ -1,139 +0,0 @@ -class Student: - def __init__(self, name, index_number,reference_number, email, age, gender, program_of_study, year_of_study, university_name, num_of_courses): - self.name = name - self.age = age - self.index_number = index_number - self.reference_number = reference_number - self.email = email - self.gender = gender - self.program_of_study = program_of_study - self.year_of_study = year_of_study - self.university_name = university_name - self.num_of_courses = num_of_courses - self.courses = [] - self.GPA = 0 - -def get_grade(score): - if 90 <= score <= 100: - grade = "A" - elif 85 <= score < 90: - grade = "A-" - elif 80 <= score < 85: - grade = "B+" - elif 75 <= score < 80: - grade = "B" - elif 70 <= score < 75: - grade = "B-" - elif 65 <= score < 70: - grade = "C+" - elif 60 <= score < 65: - grade = "C" - elif 55 <= score < 60: - grade = "C-" - elif 45 <= score < 55: - grade = "D" - elif 40 <= score < 45: - grade = "F" - else: - return "Invalid score" - return grade - -def get_grade_point(grade): - if grade == "A": - return 4.0 - elif grade == "A-": - return 3.75 - elif grade == "B+": - return 3.5 - elif grade == "B": - return 3.0 - elif grade == "B-": - return 2.75 - elif grade == "C+": - return 2.5 - elif grade == "C": - return 2.0 - elif grade == "C-": - return 1.75 - elif grade == "D": - return 1.0 - elif grade == "F": - return 0.0 - else: - return "Grade point error" - -def calculate_gpa(courses): - total_grade_points = 0 - total_credit_hours = 0 - for course in courses: - grade = get_grade(course['score']) - grade_point = get_grade_point(grade) - total_grade_points += grade_point * course['credit_hours'] - total_credit_hours += course['credit_hours'] - - if total_credit_hours == 0: - return 0 - return total_grade_points / total_credit_hours - -def collect_student_data(): - student_data = {} - student_data['name'] = input("Enter the name of the student: ") - student_data['age'] = input("Enter the age of the student: ") - student_data['index_number'] = input("Enter the index number: ") - student_data['reference_number'] = input("Enter the reference number: ") - student_data['email'] = input("Enter the student email") - student_data['gender'] = input("Enter the gender of the student: ") - student_data['program_of_study'] = input("Enter the program of study: ") - student_data['year_of_study'] = input("Enter the year of study: ") - student_data['university_name']= input("Enter the University name") - - num_of_courses = int(input("Enter the number of courses: ")) - courses = [] - - for _ in range(num_of_courses): - course_name = input("Enter the course name: ") - credit_hours = int(input(f"Enter the credit hours for {course_name}: ")) - score = float(input(f"Enter the score for {course_name}: ")) - grade = get_grade(score) - grade_point = get_grade_point(grade) - - courses.append({ - 'name': course_name, - 'credit_hours': credit_hours, - 'score': score, - 'grade': grade, - 'grade_point': grade_point - }) - - student_data['courses'] = courses - student_data['GPA'] = calculate_gpa(courses) - - return student_data - - - -student = collect_student_data() - - -print("\nStudent Details:") -print(f"Name: {student['name']}") -print(f"Age: {student['age']}") -print(f"index number: {student['index_number']}") -print(f"reference number: {student['reference_number']}") -print(f"email: {student['email']}") -print(f"Gender: {student['gender']}") -print(f"Program of Study: {student['program_of_study']}") -print(f"year of study: {student['year_of_study']}") -print(f"university name:{student['university_name']}") - -print(f"GPA: {student['GPA']:.2f}") - - -print("\nCourse Details:") -for course in student['courses']: - print(f"Course Name: {course['name']}") - print(f"Credit Hours: {course['credit_hours']}") - print(f"Score: {course['score']}") - print(f"Grade: {course['grade']}") - print(f"Grade Point: {course['grade_point']:.2f}") - print("-" * 30) diff --git a/GPA Calculator/test_gpa_calculator.py b/GPA Calculator/test_gpa_calculator.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/collaboration/Group_Norms Readme.md b/collaboration/Group_Norms Readme.md deleted file mode 100644 index 2f5dbd9ee..000000000 --- a/collaboration/Group_Norms Readme.md +++ /dev/null @@ -1,157 +0,0 @@ -# Collaboration - - - -## Group norms for ET6-Foundation-group-09's project - -**These group norms will serve as the guidelines and directives, everyone is expected to comply with, -yet no repercussions will follow if they are disregarded.** - -## Communication - -### Primary communication channel - -Slack - -WhatsAPP - -GitHub - -Zoom Meeting - -Google meet - -#### Response Time - -Everyone is expected to response to the messages on all the communication channels within 24 hours. - -#### Language of communication - -The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. - -#### Official Meeting platforms - -Zoom Meeting - -Google Meet - -The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. - -The time will be discussed and agreed by all the participants on slack and WhatsAPP. - -All the meetings are expected to last for one hour. - -The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. - -All the participants who missed the meeting are advised to watch the recording before sharing their opinions. - -## Group Organization - -**The team organization will ensure effective communication among the group members, making informed decisions -and ensuring that everyone is working on the same goal.** - -### Organizational Structure - -### Project lead - -### Responsibilities - -Oversees the project, ensuring timely completion and making sure no member is left behind. - -The project lead has no absolute authority over the group members. - -Coordinates the resolution of key issues and pull requests - -### Head of the project Communication - -### Key Responsibilities - -Discussion management on Github and WhatsAPP - -Schedule and control the group meeting - -### Deputy Head of the project Communication - -Assist the Head of communication in implementing communication plan - -Provides supports to group members, helping in resolving issues and answering questions. - -### Technical lead - -Assist in code review and conflict resolution - -## Collaboration Norms - -### collaboration Tools - -Github - -Git - -Visual Code Studio (VS Code) - -### Task Assignment - -Each team member will assign him/her self to the task using Github issues - -Everyone is expected to work individually and push it to the branch upon completion - -### Code Review - -Team members will review and provide feedback on each others's code within 48 hours - -we anticipate everyone bear in mind that we are reviewing codes not individuals. - -### Branching and Merging - -we will use feature branches and pull request to manage different version of codes - -## Conflict Resolution - -### Open Communication - -All the members are expected to communicate their concerns and challenges - -### Constructive Feedback - -We encourage the culture of constructive feedback and respectful criticism - -Remember we are reviewing codes not people - -### Conflict resolution process - -All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding - -## Respect and Inclusion - -### Equality - -All the group members have equal rights and their opinion must be respected. - -We equal participation from all the group members. - -### Respectful Communication - -Group members are expected to communicate respectful and professionally by avoiding offensive language. - -### Decision Making - -All the team members will have their voices in decision making. - -### Diversity - -We endeavor to create an inclusive environment that fosters diversity. - - - -## Groups Norms List - -### Communication Norms - -### Organization norms - -### Collaboration_Norms - -### Conflict Resolution Norms - -### Respect and Inclusion Norms From 5c2ef141655f065beaff1572e27f5a8411496e6b Mon Sep 17 00:00:00 2001 From: yoolmalaak Date: Sat, 11 Jan 2025 16:35:10 +0000 Subject: [PATCH 123/139] challenge/weather --- solutions/__init__.py | 0 solutions/tests/__init__.py | 0 solutions/tests/test_weather_conditions.py | 62 ++++++++++++++++++++++ solutions/weather_conditions.py | 52 ++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 solutions/__init__.py create mode 100644 solutions/tests/__init__.py create mode 100644 solutions/tests/test_weather_conditions.py create mode 100644 solutions/weather_conditions.py diff --git a/solutions/__init__.py b/solutions/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/solutions/tests/__init__.py b/solutions/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/solutions/tests/test_weather_conditions.py b/solutions/tests/test_weather_conditions.py new file mode 100644 index 000000000..09b3cab67 --- /dev/null +++ b/solutions/tests/test_weather_conditions.py @@ -0,0 +1,62 @@ +""" Test module for input temperature +This unittest contains test +and edge cases for the weather condition + +Created on Sat Jan 10 2025 + +@author: Yool Malaak +""" + + +import unittest + +from ..weather_conditions import get_weather_condition + + +class TestGetWeatherCondition(unittest.TestCase): + """ + Unit tests for the `get_weather_condition` function, which determines + weather conditions based on temperature in Celsius. + """ + + def test_extremely_hot(self): + """ + Test for temperatures in the 'Extremely Hot' range (45-50°C). + """ + self.assertEqual(get_weather_condition(45), "Extremely Hot") + self.assertEqual(get_weather_condition(50), "Extremely Hot") + + def test_hot(self): + """ + Test for temperatures in the 'Hot' range (31-44°C). + """ + self.assertEqual(get_weather_condition(40), "Hot") + self.assertEqual(get_weather_condition(31), "Hot") + + def test_sunny(self): + """ + Test for temperatures in the 'Sunny' range (20-30°C). + """ + self.assertEqual(get_weather_condition(25), "Sunny") + self.assertEqual(get_weather_condition(20), "Sunny") + + def test_cloudy(self): + """ + Test for temperatures in the 'Cloudy' range (10-19°C). + """ + self.assertEqual(get_weather_condition(15), "Cloudy") + self.assertEqual(get_weather_condition(10), "Cloudy") + + def test_rainy(self): + """ + Test for temperatures in the 'Rainy' range (0-9°C). + """ + self.assertEqual(get_weather_condition(5), "Rainy") + self.assertEqual(get_weather_condition(0), "Rainy") + + def test_freezing(self): + """ + Test for temperatures in the 'Freezing' range (below 0°C). + """ + self.assertEqual(get_weather_condition(-5), "Freezing") + self.assertEqual(get_weather_condition(-10), "Freezing") diff --git a/solutions/weather_conditions.py b/solutions/weather_conditions.py new file mode 100644 index 000000000..31d4d5cb1 --- /dev/null +++ b/solutions/weather_conditions.py @@ -0,0 +1,52 @@ +""" +The function takes in temperature in degree celsius and +return weather condition based on temperature + +Created on Fri Jan 10 2025 + +@author: Yool Malaak +""" + +def get_weather_condition(temperature): + """ + A module for getting the weather condition + Module: takes temperature as input and returns weather condition + + parameters: + temperature (float): The temperature in degrees Celsius. + + Returns: + str: The weather condition: + - 'Extremely Hot': 45 <= Temperature <= 50 + - 'Hot': 31 <= Temperature <= 44 + - 'Sunny': 20 <= Temperature <= 30 + - 'Cloudy': 10 <= Temperature <= 19 + - 'Rainy': 0 <= Temperature <= 9 + - 'Freezing': Temperature < 0 + + Examples: + >>> get_weather_condition(47) + 'Extremely Hot' + >>> get_weather_condition(40) + 'Hot' + >>> get_weather_condition(25) + 'Sunny' + >>> get_weather_condition(15) + 'Cloudy' + >>> get_weather_condition(5) + 'Rainy' + >>> get_weather_condition(-5) + 'Freezing' + """ + if 45 <= temperature <= 50: + return "Extremely Hot" + elif 31 <= temperature <= 44: + return "Hot" + elif 20 <= temperature <= 30: + return "Sunny" + elif 10 <= temperature <= 19: + return "Cloudy" + elif 0 <= temperature <= 9: + return "Rainy" + else: + return "Freezing" From 6d9809b7ebae150e96dc7de46f8123b3befb0479 Mon Sep 17 00:00:00 2001 From: yoolmalaak Date: Sat, 11 Jan 2025 16:39:03 +0000 Subject: [PATCH 124/139] --- solutions/tests/test_weather_conditions.py | 7 +++---- solutions/weather_conditions.py | 1 + 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/solutions/tests/test_weather_conditions.py b/solutions/tests/test_weather_conditions.py index 09b3cab67..870f60066 100644 --- a/solutions/tests/test_weather_conditions.py +++ b/solutions/tests/test_weather_conditions.py @@ -1,13 +1,12 @@ -""" Test module for input temperature -This unittest contains test -and edge cases for the weather condition +"""Test module for input temperature +This unittest contains test +and edge cases for the weather condition Created on Sat Jan 10 2025 @author: Yool Malaak """ - import unittest from ..weather_conditions import get_weather_condition diff --git a/solutions/weather_conditions.py b/solutions/weather_conditions.py index 31d4d5cb1..f7f594d76 100644 --- a/solutions/weather_conditions.py +++ b/solutions/weather_conditions.py @@ -7,6 +7,7 @@ @author: Yool Malaak """ + def get_weather_condition(temperature): """ A module for getting the weather condition From 9b8b0973d29598af2d6603ad1a9f0d1025c4e4b6 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Sat, 11 Jan 2025 17:14:00 +0000 Subject: [PATCH 125/139] ruff --- solutions/add_numbers.py | 42 ++++++++++++++-------------- solutions/even_numbers.py | 20 +++++++------ solutions/tests/test_add_numbers.py | 4 +-- solutions/tests/test_even_numbers.py | 6 ++-- 4 files changed, 37 insertions(+), 35 deletions(-) diff --git a/solutions/add_numbers.py b/solutions/add_numbers.py index 9de2f17e1..e8e742581 100644 --- a/solutions/add_numbers.py +++ b/solutions/add_numbers.py @@ -11,39 +11,39 @@ @author: Martha Yelademe Nyekanga """ -def add_numbers(first_number:int, second_number:int) -> int: +def add_numbers(first_number: int, second_number: int) -> int: """This function takes two numbers and returns their sum. - Parameters: + Parameters: - first_number (int): The first number for the function - second_number (int): The second number for the function - - Returns: - int: The sum of the two numbers + first_number (int): The first number for the function + second_number (int): The second number for the function - Raises: - TypeError: If the input is not a number + Returns: + int: The sum of the two numbers - Examples: - >>> add_numbers(2, 3) - 5 + Raises: + TypeError: If the input is not a number - >>> add_numbers(-2, 3) - 1 + Examples: + >>> add_numbers(2, 3) + 5 - >>> add_numbers(0, 0) - 0 + >>> add_numbers(-2, 3) + 1 - >>> add_numbers(2, -3) - -1 + >>> add_numbers(0, 0) + 0 + + >>> add_numbers(2, -3) + -1 """ - assert isinstance(first_number, int), "Input must be a number." assert isinstance(second_number, int), "Input must be a number." - - #return the sum of the two numbers + + # return the sum of the two numbers return first_number + second_number + print(add_numbers(0, 0)) diff --git a/solutions/even_numbers.py b/solutions/even_numbers.py index 1cebe5ed8..b2e75379e 100644 --- a/solutions/even_numbers.py +++ b/solutions/even_numbers.py @@ -8,35 +8,39 @@ @author: Martha Yelademe Nyekanga """ + def is_even(number: int) -> bool: """This function checks if a given number is even. - + Parameters: number (int): The number to check - + Returns: bool: True if the number is even, False otherwise - + Raises: AssertionError: If the input is not an integer - + Examples: >>> is_even(2) True - + >>> is_even(3) False - + >>> is_even(0) True - + >>> is_even(-4) True """ - assert isinstance(number, int) and not isinstance(number, bool), "the input number must be an integer and not a boolean" + assert isinstance(number, int) and not isinstance(number, bool), ( + "the input number must be an integer and not a boolean" + ) # Return True if the number is even, False otherwise return number % 2 == 0 + # Example: if __name__ == "__main__": print(is_even(0)) diff --git a/solutions/tests/test_add_numbers.py b/solutions/tests/test_add_numbers.py index 14475a1ba..cb6dd8e53 100644 --- a/solutions/tests/test_add_numbers.py +++ b/solutions/tests/test_add_numbers.py @@ -32,10 +32,10 @@ def test_add_two_negative_numbers(self): self.assertEqual(add_numbers(-2, -3), -5) def test_add_two_float_numbers(self): - """"Test adding two float numbers.""" + """ "Test adding two float numbers.""" with self.assertRaises(AssertionError): add_numbers(2.5, 1.3) - + def test_add_numbers_string(self): """Test adding a string and a number.""" with self.assertRaises(AssertionError): diff --git a/solutions/tests/test_even_numbers.py b/solutions/tests/test_even_numbers.py index 7fb74b1e3..1c0ce00d7 100644 --- a/solutions/tests/test_even_numbers.py +++ b/solutions/tests/test_even_numbers.py @@ -8,12 +8,11 @@ Author:Martha Yelademe Nyekanga """ - import unittest -from ..even_numbers import is_even +from ..even_numbers import is_even + class TestIsEven(unittest.TestCase): - # Test case for a positive even number def test_positive_even(self): self.assertTrue(is_even(2)) @@ -79,4 +78,3 @@ def test_type_error_with_none(self): def test_type_error_with_bool(self): with self.assertRaises(AssertionError): is_even(True) - From 014797e996540e0907535ba9b7442175f0a7b562 Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Sat, 11 Jan 2025 19:25:25 +0000 Subject: [PATCH 126/139] group retrospective final version! --- collaboration/retrospective.md | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/collaboration/retrospective.md b/collaboration/retrospective.md index 74e18813b..ea06f954a 100644 --- a/collaboration/retrospective.md +++ b/collaboration/retrospective.md @@ -4,20 +4,44 @@ ## Stop Doing +- Skipping regular informal check-ins between scheduled meetings. Introducing occasional touch points could help identify and address potential blockers earlier. +- Assuming that everyone was fully comfortable with the tools and workflows. +- While most team members adapted well, a little extra guidance or troubleshooting sessions could have eased the learning curve for some. + ## Continue Doing +- Regular Friday meetings to track progress and provide updates. These were effective in aligning team members and ensuring transparency. +- Using GitHub pull requests for code reviews and collaboration. The process of reviewing changes within 48 hours worked well. +- Maintaining an inclusive and open communication culture where team members feel free to ask for help, as outlined in the "Asking for Help" section. + ## Start Doing +- Implementing a clearer method for prioritizing tasks to ensure everyone knows the critical priorities for the week. +- Holding occasional training or Q&A sessions to address gaps in technical skills, especially in Git and Python. +- Creating a shared calendar or reminder system to avoid any potential conflicts in availability for meetings or task deadlines. + ## Lessons Learned -______________________________________________________________________ +- **Time Zone Challenges**: The group realized that time zone differences, while manageable, required better planning for synchronous communication. +- **Skill Gaps**: Variations in team members' proficiency with tools highlighted the need for tailored support to help everyone contribute effectively. +- **Flexibility and Adaptability**: The team showed great adaptability in overcoming technology limitations and communication barriers. +However, this can be improved further by having contingency plans for unexpected constraints. ## Strategy vs. Board ### What parts of your plan went as expected? + The team successfully conducted weekly meetings, reviewed pull requests on time, and collaborated effectively on Slack. + ### What parts of your plan did not work out? +The reliance on Slack or GitHub only for resolving complex issues sometimes caused delays. More face-to-face virtual calls could have streamlined problem-solving. + ### Did you need to add things that weren't in your strategy? +- Introduce a weekly summary of constraints and priorities to keep everyone updated. +- Create clearer guidelines for documenting issues and resolutions in GitHub. + ### Or remove extra steps? + +- Reduce redundant follow-ups in Slack by consolidating updates during meetings. From 673d99fec59cfb953ff676c920fe2f60ff4a9f2c Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Sat, 11 Jan 2025 20:32:46 +0000 Subject: [PATCH 127/139] added longest substring challenge again --- solutions/longest_substring.py | 70 +++++++++++++++++++++++ solutions/tests/test_longest_substring.py | 53 +++++++++++++++++ 2 files changed, 123 insertions(+) create mode 100644 solutions/longest_substring.py create mode 100644 solutions/tests/test_longest_substring.py diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py new file mode 100644 index 000000000..86e7bfa84 --- /dev/null +++ b/solutions/longest_substring.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for generating the longest substring + +Module contents: + longest_substring: generates the longest substring without + repetition for a given string. + +Created on 2025-01-05 +@author: Hiba Daffallah +""" + + +def longest_substring(input_string: str) -> str: + """ + Generates a string containing the longest substring without repitition + from the input_string. + + Parameters: + input_string: str + + Returns : + substring: the longest substring + + Raises: + AssertionError: if the argument is not a string + + >>> longest_substring('') + '' + >>> longest_substring('bbbbbb') + 'b' + >>> longest_substring('abcdef') + 'abcdef' + >>> longest_substring('pwwkew') + 'wke' + >>> longest_substring('celelocceli') + 'eloc' + """ + # Ensure the input is a string + assert isinstance(input_string, str) + + n = len(input_string) + # If the string is empty, return an empty string as the result + if n == 0: + return "" + # Initialize a set to keep track of unique characters in the current substring + sub = set() + # Initialize the longest substring variable + longest_sub = "" + # Initialize the left pointer of the sliding window + left = 0 + for right in range(n): + # If the character at the right pointer is already in the set, + # slide the left pointer to remove characters until the duplicate is removed + while input_string[right] in sub: + sub.remove(input_string[left]) + left += 1 + + # Add the current character at the right pointer to the set + sub.add(input_string[right]) + current_len = right - left + 1 + + # If the current substring is longer than the previously recorded longest substring, + # update the longest substring + if current_len > len(longest_sub): + longest_sub = input_string[left : right + 1] + + # Return the longest substring found + return longest_sub diff --git a/solutions/tests/test_longest_substring.py b/solutions/tests/test_longest_substring.py new file mode 100644 index 000000000..230e4cbb6 --- /dev/null +++ b/solutions/tests/test_longest_substring.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on 2024-01-01 + +@author: Hiba Daffallah +""" + +import unittest + +from ..longest_substring import longest_substring + + +class TestLongestSubstring(unittest.TestCase): + """Test the longest_substring function""" + + def test_empty_string(self): + """Checks what will happen if the input is an empty + string""" + self.assertEqual(longest_substring(""), "") + + def test_one_char_repeated(self): + """Checks what will happen if the input is a repeated + character""" + self.assertEqual(longest_substring("bbbbbb"), "b") + + def test_no_repitition(self): + """Checks what will happen if the input didn't have + repeated characters""" + self.assertEqual(longest_substring("abcdef"), "abcdef") + + def test_repeated_substring(self): + """Checks what will happen if the input conatins a + repeated substring""" + self.assertEqual(longest_substring("pwwkew"), "wke") + + def test_multiple_substring(self): + """Checks what will happen if the input contains multiple + substrings""" + self.assertEqual(longest_substring("celelocceli"), "eloc") + + def test_input_numbers(self): + """Checks what will happen if the input contains numbers""" + self.assertEqual(longest_substring("991215888"), "2158") + + def test_input_conatins_numbers(self): + """Checks what will happen if the input contains numbers""" + self.assertEqual(longest_substring("9cort9kl9m"), "cort9kl") + + def test_input_non_string(self): + """Checks what will happen if the input is not a string""" + with self.assertRaises(AssertionError): + longest_substring(["abc"]) From 3593d4e7d0c36863040cf512993029a6c80dafe4 Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sun, 12 Jan 2025 00:10:14 +0000 Subject: [PATCH 128/139] made some changes to continue doing sub-section --- collaboration/retrospective.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collaboration/retrospective.md b/collaboration/retrospective.md index ea06f954a..8fad88606 100644 --- a/collaboration/retrospective.md +++ b/collaboration/retrospective.md @@ -12,7 +12,7 @@ - Regular Friday meetings to track progress and provide updates. These were effective in aligning team members and ensuring transparency. - Using GitHub pull requests for code reviews and collaboration. The process of reviewing changes within 48 hours worked well. -- Maintaining an inclusive and open communication culture where team members feel free to ask for help, as outlined in the "Asking for Help" section. +- Maintaining an inclusive and open communication culture where team members feel free to ask for help.. ## Start Doing From 7bc34f22504f9ed564ed33a6e1ef2c321c762b1d Mon Sep 17 00:00:00 2001 From: JEFFDARKO <139300293+JEFFDARKO@users.noreply.github.com> Date: Sun, 12 Jan 2025 00:11:48 +0000 Subject: [PATCH 129/139] made some changes to continue doing sub-section --- collaboration/retrospective.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/collaboration/retrospective.md b/collaboration/retrospective.md index 8fad88606..8ce7762ea 100644 --- a/collaboration/retrospective.md +++ b/collaboration/retrospective.md @@ -12,7 +12,7 @@ - Regular Friday meetings to track progress and provide updates. These were effective in aligning team members and ensuring transparency. - Using GitHub pull requests for code reviews and collaboration. The process of reviewing changes within 48 hours worked well. -- Maintaining an inclusive and open communication culture where team members feel free to ask for help.. +- Maintaining an inclusive and open communication culture where team members feel free to ask for help. ## Start Doing From 13cf0f568a72514fc9bc324d15236e0538009ad3 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Sun, 12 Jan 2025 00:28:36 +0000 Subject: [PATCH 130/139] collaboration file final update --- collaboration/communication.md | 2 - collaboration/groupnorms.md | 157 --------------------------------- 2 files changed, 159 deletions(-) delete mode 100644 collaboration/groupnorms.md diff --git a/collaboration/communication.md b/collaboration/communication.md index 6d82423b8..cc1936106 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -17,7 +17,6 @@ ______________________________________________________________________ | --- | :-: | ----------------------- | |Every Friday, 9 EST| Google Meet| Activity Updates| | | | | -| | | | ## Communication Channels @@ -46,7 +45,6 @@ ______________________________________________________________________ | Rina | | 7-15 | | 7-15 | 7-15 | 9-15 | 9-15 | | Terry | 9-11 | 9-11 | 9-11 | 6-9 | 9-11 | 9-12 | 9-11 | | Yool | 9-12 | 9-12 | 10-13 | 8-12 | 9-12 | 10-13 | 10-13 | -|Shagun | | | | | | | | ## Asking for Help diff --git a/collaboration/groupnorms.md b/collaboration/groupnorms.md deleted file mode 100644 index 2f5dbd9ee..000000000 --- a/collaboration/groupnorms.md +++ /dev/null @@ -1,157 +0,0 @@ -# Collaboration - - - -## Group norms for ET6-Foundation-group-09's project - -**These group norms will serve as the guidelines and directives, everyone is expected to comply with, -yet no repercussions will follow if they are disregarded.** - -## Communication - -### Primary communication channel - -Slack - -WhatsAPP - -GitHub - -Zoom Meeting - -Google meet - -#### Response Time - -Everyone is expected to response to the messages on all the communication channels within 24 hours. - -#### Language of communication - -The official language of communication is English, and we strongly recommend using clear, concise language, avoid using jargon. - -#### Official Meeting platforms - -Zoom Meeting - -Google Meet - -The group meeting will be conducted on the official platforms at least once in the week which can be adjusted based on group demands. - -The time will be discussed and agreed by all the participants on slack and WhatsAPP. - -All the meetings are expected to last for one hour. - -The recording will be made available after the meeting and uploaded to the group channels, it will be helpful to the participants who missed the meeting. - -All the participants who missed the meeting are advised to watch the recording before sharing their opinions. - -## Group Organization - -**The team organization will ensure effective communication among the group members, making informed decisions -and ensuring that everyone is working on the same goal.** - -### Organizational Structure - -### Project lead - -### Responsibilities - -Oversees the project, ensuring timely completion and making sure no member is left behind. - -The project lead has no absolute authority over the group members. - -Coordinates the resolution of key issues and pull requests - -### Head of the project Communication - -### Key Responsibilities - -Discussion management on Github and WhatsAPP - -Schedule and control the group meeting - -### Deputy Head of the project Communication - -Assist the Head of communication in implementing communication plan - -Provides supports to group members, helping in resolving issues and answering questions. - -### Technical lead - -Assist in code review and conflict resolution - -## Collaboration Norms - -### collaboration Tools - -Github - -Git - -Visual Code Studio (VS Code) - -### Task Assignment - -Each team member will assign him/her self to the task using Github issues - -Everyone is expected to work individually and push it to the branch upon completion - -### Code Review - -Team members will review and provide feedback on each others's code within 48 hours - -we anticipate everyone bear in mind that we are reviewing codes not individuals. - -### Branching and Merging - -we will use feature branches and pull request to manage different version of codes - -## Conflict Resolution - -### Open Communication - -All the members are expected to communicate their concerns and challenges - -### Constructive Feedback - -We encourage the culture of constructive feedback and respectful criticism - -Remember we are reviewing codes not people - -### Conflict resolution process - -All sorts of conflict and misunderstanding shall be resolved through open discussion and mutual understanding - -## Respect and Inclusion - -### Equality - -All the group members have equal rights and their opinion must be respected. - -We equal participation from all the group members. - -### Respectful Communication - -Group members are expected to communicate respectful and professionally by avoiding offensive language. - -### Decision Making - -All the team members will have their voices in decision making. - -### Diversity - -We endeavor to create an inclusive environment that fosters diversity. - - - -## Groups Norms List - -### Communication Norms - -### Organization norms - -### Collaboration_Norms - -### Conflict Resolution Norms - -### Respect and Inclusion Norms From 1c3657f32d4580e876b1f1dae10f4b3f35191ea4 Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 12:43:48 +0000 Subject: [PATCH 131/139] Add calculate_grade module and its tests to solutions --- solutions/calculate_grade.py | 55 ++++++++++++++++++ solutions/test_calculate_grade.py | 94 +++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 solutions/calculate_grade.py create mode 100644 solutions/test_calculate_grade.py diff --git a/solutions/calculate_grade.py b/solutions/calculate_grade.py new file mode 100644 index 000000000..55805815e --- /dev/null +++ b/solutions/calculate_grade.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for converting numeric scores to letter grades. + +Module contents: + - calculate_grade: converts a numeric score (0-100) to a letter grade (A-F). + +Created on 2025-01-08 +@author: AI Developer +""" + + +def calculate_grade(score: float) -> str: + """ + Convert a numeric score to a letter grade based on standard grading scale. + + Parameters: + score: float, the numeric score to convert (must be between 0 and 100) + + Returns: + str: the corresponding letter grade (A, B, C, D, or F) + + Raises: + AssertionError: if the input is not a valid numeric score + ValueError: if the score is not between 0 and 100 + + Examples: + >>> calculate_grade(95) + 'A' + >>> calculate_grade(83) + 'B' + >>> calculate_grade(76) + 'C' + >>> calculate_grade(65) + 'D' + >>> calculate_grade(50) + 'F' + """ + # Input validation + assert isinstance(score, (int, float)), "Score must be a number" + if not 0 <= score <= 100: + raise ValueError("Score must be between 0 and 100") + + # Grade boundaries + if score >= 90: + return "A" + elif score >= 80: + return "B" + elif score >= 70: + return "C" + elif score >= 60: + return "D" + else: + return "F" diff --git a/solutions/test_calculate_grade.py b/solutions/test_calculate_grade.py new file mode 100644 index 000000000..3cee10997 --- /dev/null +++ b/solutions/test_calculate_grade.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for calculate_grade function. + +Created on 2025-01-08 +@author: AI Developer +""" + +import unittest +from calculate_grade import calculate_grade + + +class TestCalculateGrade(unittest.TestCase): + """Test suite for the calculate_grade function.""" + + # Test valid grades at boundaries + def test_perfect_score(self): + """Test perfect score of 100.""" + self.assertEqual(calculate_grade(100), "A") + + def test_minimum_a(self): + """Test minimum A grade.""" + self.assertEqual(calculate_grade(90), "A") + + def test_maximum_b(self): + """Test maximum B grade.""" + self.assertEqual(calculate_grade(89.9), "B") + + def test_minimum_b(self): + """Test minimum B grade.""" + self.assertEqual(calculate_grade(80), "B") + + def test_maximum_c(self): + """Test maximum C grade.""" + self.assertEqual(calculate_grade(79.9), "C") + + def test_minimum_c(self): + """Test minimum C grade.""" + self.assertEqual(calculate_grade(70), "C") + + def test_maximum_d(self): + """Test maximum D grade.""" + self.assertEqual(calculate_grade(69.9), "D") + + def test_minimum_d(self): + """Test minimum D grade.""" + self.assertEqual(calculate_grade(60), "D") + + def test_maximum_f(self): + """Test maximum F grade.""" + self.assertEqual(calculate_grade(59.9), "F") + + def test_zero_score(self): + """Test score of zero.""" + self.assertEqual(calculate_grade(0), "F") + + # Test invalid inputs + def test_negative_score(self): + """Test that negative scores raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(-1) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_score_above_100(self): + """Test that scores above 100 raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(101) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_string_input(self): + """Test that string input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade("90") + self.assertEqual(str(context.exception), "Score must be a number") + + def test_none_input(self): + """Test that None input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade(None) + self.assertEqual(str(context.exception), "Score must be a number") + + # Test edge cases + def test_float_score(self): + """Test that float scores are handled correctly.""" + self.assertEqual(calculate_grade(89.99), "B") + + def test_zero_decimal(self): + """Test score with zero decimal.""" + self.assertEqual(calculate_grade(90.0), "A") + + +if __name__ == "__main__": + unittest.main() From 4a741246298a62a5dde1e3ca86df8a01c8b67f6b Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 18:00:30 +0000 Subject: [PATCH 132/139] Update calculate_grade.py --- solutions/calculate_grade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/calculate_grade.py b/solutions/calculate_grade.py index 55805815e..02756a2ae 100644 --- a/solutions/calculate_grade.py +++ b/solutions/calculate_grade.py @@ -7,7 +7,7 @@ - calculate_grade: converts a numeric score (0-100) to a letter grade (A-F). Created on 2025-01-08 -@author: AI Developer +@author: Karina """ From 9199bc354a9202be4bdf090ceb6bf43a2de250e9 Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 18:01:24 +0000 Subject: [PATCH 133/139] Update test_calculate_grade.py --- solutions/test_calculate_grade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/test_calculate_grade.py b/solutions/test_calculate_grade.py index 3cee10997..85f5a2fa1 100644 --- a/solutions/test_calculate_grade.py +++ b/solutions/test_calculate_grade.py @@ -4,7 +4,7 @@ Test module for calculate_grade function. Created on 2025-01-08 -@author: AI Developer +@author: Karina """ import unittest From b0a68767d937c1ceaf7395140cadeb02de7a3411 Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:04:28 +0000 Subject: [PATCH 134/139] Delete solutions/test_calculate_grade.py --- solutions/test_calculate_grade.py | 94 ------------------------------- 1 file changed, 94 deletions(-) delete mode 100644 solutions/test_calculate_grade.py diff --git a/solutions/test_calculate_grade.py b/solutions/test_calculate_grade.py deleted file mode 100644 index 85f5a2fa1..000000000 --- a/solutions/test_calculate_grade.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Test module for calculate_grade function. - -Created on 2025-01-08 -@author: Karina -""" - -import unittest -from calculate_grade import calculate_grade - - -class TestCalculateGrade(unittest.TestCase): - """Test suite for the calculate_grade function.""" - - # Test valid grades at boundaries - def test_perfect_score(self): - """Test perfect score of 100.""" - self.assertEqual(calculate_grade(100), "A") - - def test_minimum_a(self): - """Test minimum A grade.""" - self.assertEqual(calculate_grade(90), "A") - - def test_maximum_b(self): - """Test maximum B grade.""" - self.assertEqual(calculate_grade(89.9), "B") - - def test_minimum_b(self): - """Test minimum B grade.""" - self.assertEqual(calculate_grade(80), "B") - - def test_maximum_c(self): - """Test maximum C grade.""" - self.assertEqual(calculate_grade(79.9), "C") - - def test_minimum_c(self): - """Test minimum C grade.""" - self.assertEqual(calculate_grade(70), "C") - - def test_maximum_d(self): - """Test maximum D grade.""" - self.assertEqual(calculate_grade(69.9), "D") - - def test_minimum_d(self): - """Test minimum D grade.""" - self.assertEqual(calculate_grade(60), "D") - - def test_maximum_f(self): - """Test maximum F grade.""" - self.assertEqual(calculate_grade(59.9), "F") - - def test_zero_score(self): - """Test score of zero.""" - self.assertEqual(calculate_grade(0), "F") - - # Test invalid inputs - def test_negative_score(self): - """Test that negative scores raise ValueError.""" - with self.assertRaises(ValueError) as context: - calculate_grade(-1) - self.assertEqual(str(context.exception), "Score must be between 0 and 100") - - def test_score_above_100(self): - """Test that scores above 100 raise ValueError.""" - with self.assertRaises(ValueError) as context: - calculate_grade(101) - self.assertEqual(str(context.exception), "Score must be between 0 and 100") - - def test_string_input(self): - """Test that string input raises AssertionError.""" - with self.assertRaises(AssertionError) as context: - calculate_grade("90") - self.assertEqual(str(context.exception), "Score must be a number") - - def test_none_input(self): - """Test that None input raises AssertionError.""" - with self.assertRaises(AssertionError) as context: - calculate_grade(None) - self.assertEqual(str(context.exception), "Score must be a number") - - # Test edge cases - def test_float_score(self): - """Test that float scores are handled correctly.""" - self.assertEqual(calculate_grade(89.99), "B") - - def test_zero_decimal(self): - """Test score with zero decimal.""" - self.assertEqual(calculate_grade(90.0), "A") - - -if __name__ == "__main__": - unittest.main() From 51123231c12e4d51ec4429bc63f880ceb56d1b4d Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:04:56 +0000 Subject: [PATCH 135/139] Add files via upload --- solutions/tests/test_calculate_grade.py | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 solutions/tests/test_calculate_grade.py diff --git a/solutions/tests/test_calculate_grade.py b/solutions/tests/test_calculate_grade.py new file mode 100644 index 000000000..85f5a2fa1 --- /dev/null +++ b/solutions/tests/test_calculate_grade.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for calculate_grade function. + +Created on 2025-01-08 +@author: Karina +""" + +import unittest +from calculate_grade import calculate_grade + + +class TestCalculateGrade(unittest.TestCase): + """Test suite for the calculate_grade function.""" + + # Test valid grades at boundaries + def test_perfect_score(self): + """Test perfect score of 100.""" + self.assertEqual(calculate_grade(100), "A") + + def test_minimum_a(self): + """Test minimum A grade.""" + self.assertEqual(calculate_grade(90), "A") + + def test_maximum_b(self): + """Test maximum B grade.""" + self.assertEqual(calculate_grade(89.9), "B") + + def test_minimum_b(self): + """Test minimum B grade.""" + self.assertEqual(calculate_grade(80), "B") + + def test_maximum_c(self): + """Test maximum C grade.""" + self.assertEqual(calculate_grade(79.9), "C") + + def test_minimum_c(self): + """Test minimum C grade.""" + self.assertEqual(calculate_grade(70), "C") + + def test_maximum_d(self): + """Test maximum D grade.""" + self.assertEqual(calculate_grade(69.9), "D") + + def test_minimum_d(self): + """Test minimum D grade.""" + self.assertEqual(calculate_grade(60), "D") + + def test_maximum_f(self): + """Test maximum F grade.""" + self.assertEqual(calculate_grade(59.9), "F") + + def test_zero_score(self): + """Test score of zero.""" + self.assertEqual(calculate_grade(0), "F") + + # Test invalid inputs + def test_negative_score(self): + """Test that negative scores raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(-1) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_score_above_100(self): + """Test that scores above 100 raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(101) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_string_input(self): + """Test that string input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade("90") + self.assertEqual(str(context.exception), "Score must be a number") + + def test_none_input(self): + """Test that None input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade(None) + self.assertEqual(str(context.exception), "Score must be a number") + + # Test edge cases + def test_float_score(self): + """Test that float scores are handled correctly.""" + self.assertEqual(calculate_grade(89.99), "B") + + def test_zero_decimal(self): + """Test score with zero decimal.""" + self.assertEqual(calculate_grade(90.0), "A") + + +if __name__ == "__main__": + unittest.main() From 2c2221a27f9740198a24221ba03b5c664255ee2a Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:08:38 +0000 Subject: [PATCH 136/139] Update test_calculate_grade.py --- solutions/tests/test_calculate_grade.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/solutions/tests/test_calculate_grade.py b/solutions/tests/test_calculate_grade.py index 85f5a2fa1..8db777f0a 100644 --- a/solutions/tests/test_calculate_grade.py +++ b/solutions/tests/test_calculate_grade.py @@ -85,9 +85,11 @@ def test_float_score(self): """Test that float scores are handled correctly.""" self.assertEqual(calculate_grade(89.99), "B") - def test_zero_decimal(self): - """Test score with zero decimal.""" - self.assertEqual(calculate_grade(90.0), "A") + def test_dict_input(self): + """Test that dict input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade({"score": 90}) + self.assertEqual(str(context.exception), "Score must be a number") if __name__ == "__main__": From 56f60347d61e450bb3f9fcd61f37075c01b2b638 Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:10:27 +0000 Subject: [PATCH 137/139] Update test_calculate_grade.py --- solutions/tests/test_calculate_grade.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/solutions/tests/test_calculate_grade.py b/solutions/tests/test_calculate_grade.py index 8db777f0a..3344060a7 100644 --- a/solutions/tests/test_calculate_grade.py +++ b/solutions/tests/test_calculate_grade.py @@ -85,12 +85,9 @@ def test_float_score(self): """Test that float scores are handled correctly.""" self.assertEqual(calculate_grade(89.99), "B") - def test_dict_input(self): - """Test that dict input raises AssertionError.""" - with self.assertRaises(AssertionError) as context: - calculate_grade({"score": 90}) - self.assertEqual(str(context.exception), "Score must be a number") - + def test_zero_decimal(self): + """Test score with zero decimal.""" + self.assertEqual(calculate_grade(90.0), "A") if __name__ == "__main__": unittest.main() From f2a8621406f1d6ec5e8b1dccee2eb6e5de10998a Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:22:59 +0000 Subject: [PATCH 138/139] Delete solutions/tests/test_calculate_grade.py --- solutions/tests/test_calculate_grade.py | 93 ------------------------- 1 file changed, 93 deletions(-) delete mode 100644 solutions/tests/test_calculate_grade.py diff --git a/solutions/tests/test_calculate_grade.py b/solutions/tests/test_calculate_grade.py deleted file mode 100644 index 3344060a7..000000000 --- a/solutions/tests/test_calculate_grade.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -Test module for calculate_grade function. - -Created on 2025-01-08 -@author: Karina -""" - -import unittest -from calculate_grade import calculate_grade - - -class TestCalculateGrade(unittest.TestCase): - """Test suite for the calculate_grade function.""" - - # Test valid grades at boundaries - def test_perfect_score(self): - """Test perfect score of 100.""" - self.assertEqual(calculate_grade(100), "A") - - def test_minimum_a(self): - """Test minimum A grade.""" - self.assertEqual(calculate_grade(90), "A") - - def test_maximum_b(self): - """Test maximum B grade.""" - self.assertEqual(calculate_grade(89.9), "B") - - def test_minimum_b(self): - """Test minimum B grade.""" - self.assertEqual(calculate_grade(80), "B") - - def test_maximum_c(self): - """Test maximum C grade.""" - self.assertEqual(calculate_grade(79.9), "C") - - def test_minimum_c(self): - """Test minimum C grade.""" - self.assertEqual(calculate_grade(70), "C") - - def test_maximum_d(self): - """Test maximum D grade.""" - self.assertEqual(calculate_grade(69.9), "D") - - def test_minimum_d(self): - """Test minimum D grade.""" - self.assertEqual(calculate_grade(60), "D") - - def test_maximum_f(self): - """Test maximum F grade.""" - self.assertEqual(calculate_grade(59.9), "F") - - def test_zero_score(self): - """Test score of zero.""" - self.assertEqual(calculate_grade(0), "F") - - # Test invalid inputs - def test_negative_score(self): - """Test that negative scores raise ValueError.""" - with self.assertRaises(ValueError) as context: - calculate_grade(-1) - self.assertEqual(str(context.exception), "Score must be between 0 and 100") - - def test_score_above_100(self): - """Test that scores above 100 raise ValueError.""" - with self.assertRaises(ValueError) as context: - calculate_grade(101) - self.assertEqual(str(context.exception), "Score must be between 0 and 100") - - def test_string_input(self): - """Test that string input raises AssertionError.""" - with self.assertRaises(AssertionError) as context: - calculate_grade("90") - self.assertEqual(str(context.exception), "Score must be a number") - - def test_none_input(self): - """Test that None input raises AssertionError.""" - with self.assertRaises(AssertionError) as context: - calculate_grade(None) - self.assertEqual(str(context.exception), "Score must be a number") - - # Test edge cases - def test_float_score(self): - """Test that float scores are handled correctly.""" - self.assertEqual(calculate_grade(89.99), "B") - - def test_zero_decimal(self): - """Test score with zero decimal.""" - self.assertEqual(calculate_grade(90.0), "A") - -if __name__ == "__main__": - unittest.main() From b032e8651718c7a96219217a6e95c724c7669682 Mon Sep 17 00:00:00 2001 From: rina1z <80955094055a@gmail.com> Date: Sun, 12 Jan 2025 21:23:21 +0000 Subject: [PATCH 139/139] Add files via upload --- solutions/tests/test_calculate_grade.py | 94 +++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 solutions/tests/test_calculate_grade.py diff --git a/solutions/tests/test_calculate_grade.py b/solutions/tests/test_calculate_grade.py new file mode 100644 index 000000000..85f5a2fa1 --- /dev/null +++ b/solutions/tests/test_calculate_grade.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for calculate_grade function. + +Created on 2025-01-08 +@author: Karina +""" + +import unittest +from calculate_grade import calculate_grade + + +class TestCalculateGrade(unittest.TestCase): + """Test suite for the calculate_grade function.""" + + # Test valid grades at boundaries + def test_perfect_score(self): + """Test perfect score of 100.""" + self.assertEqual(calculate_grade(100), "A") + + def test_minimum_a(self): + """Test minimum A grade.""" + self.assertEqual(calculate_grade(90), "A") + + def test_maximum_b(self): + """Test maximum B grade.""" + self.assertEqual(calculate_grade(89.9), "B") + + def test_minimum_b(self): + """Test minimum B grade.""" + self.assertEqual(calculate_grade(80), "B") + + def test_maximum_c(self): + """Test maximum C grade.""" + self.assertEqual(calculate_grade(79.9), "C") + + def test_minimum_c(self): + """Test minimum C grade.""" + self.assertEqual(calculate_grade(70), "C") + + def test_maximum_d(self): + """Test maximum D grade.""" + self.assertEqual(calculate_grade(69.9), "D") + + def test_minimum_d(self): + """Test minimum D grade.""" + self.assertEqual(calculate_grade(60), "D") + + def test_maximum_f(self): + """Test maximum F grade.""" + self.assertEqual(calculate_grade(59.9), "F") + + def test_zero_score(self): + """Test score of zero.""" + self.assertEqual(calculate_grade(0), "F") + + # Test invalid inputs + def test_negative_score(self): + """Test that negative scores raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(-1) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_score_above_100(self): + """Test that scores above 100 raise ValueError.""" + with self.assertRaises(ValueError) as context: + calculate_grade(101) + self.assertEqual(str(context.exception), "Score must be between 0 and 100") + + def test_string_input(self): + """Test that string input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade("90") + self.assertEqual(str(context.exception), "Score must be a number") + + def test_none_input(self): + """Test that None input raises AssertionError.""" + with self.assertRaises(AssertionError) as context: + calculate_grade(None) + self.assertEqual(str(context.exception), "Score must be a number") + + # Test edge cases + def test_float_score(self): + """Test that float scores are handled correctly.""" + self.assertEqual(calculate_grade(89.99), "B") + + def test_zero_decimal(self): + """Test score with zero decimal.""" + self.assertEqual(calculate_grade(90.0), "A") + + +if __name__ == "__main__": + unittest.main()