From 6ca52e5248fe4f98b667681492aac54dd8697eee Mon Sep 17 00:00:00 2001 From: MahdiaAhmadi Date: Sun, 22 Dec 2024 23:13:07 +0000 Subject: [PATCH 01/84] 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 02/84] 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 03/84] 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 04/84] 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 05/84] 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 06/84] 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 07/84] 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 08/84] 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 09/84] 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 10/84] 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 11/84] 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 12/84] 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 13/84] 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 14/84] 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 15/84] 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 16/84] 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 17/84] 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 18/84] 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 19/84] 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 20/84] 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 21/84] 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 22/84] 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 23/84] 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 24/84] 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 25/84] 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 26/84] 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 27/84] 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 28/84] 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 29/84] 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 30/84] 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 31/84] 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 32/84] 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 6c4e4c3eeb3be0683af5ca520ad9b7233c21274e Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 14:40:27 +0000 Subject: [PATCH 33/84] 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 34/84] 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 35/84] 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 36/84] 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 37/84] 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 38/84] 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 39/84] 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 e351d94f0f2f7eb3b2546f42df9d0e05324a4ad8 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Thu, 2 Jan 2025 22:11:36 +0000 Subject: [PATCH 40/84] .. --- 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 41/84] 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 42/84] 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 43/84] 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 44/84] 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 45/84] 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 46/84] 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 52/84] 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 53/84] 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 54/84] 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 62/84] 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 63/84] 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 64/84] 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 65/84] 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 66/84] 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 67/84] 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 68/84] 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 69/84] 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 70/84] 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 71/84] 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 72/84] 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 73/84] 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 74/84] 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 75/84] 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 5b300d3ec221d80a0431716f75f6df876089bdd2 Mon Sep 17 00:00:00 2001 From: Hiba-Daffallah Date: Mon, 6 Jan 2025 01:04:13 +0000 Subject: [PATCH 76/84] 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 77/84] 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 a40312e12fc2ac5f871552c7f163c4e5a927760e Mon Sep 17 00:00:00 2001 From: terryekoe Date: Mon, 6 Jan 2025 09:03:53 +0000 Subject: [PATCH 78/84] 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 79/84] 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 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 80/84] 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 81/84] 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 82/84] 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 83/84] 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 84/84] 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()