From 658d50ab0fc29495a2eb3d1eb3770f408eef1564 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Mon, 26 Jun 2023 22:10:45 -0700 Subject: [PATCH 1/2] python/largest-series-product: download exercise --- .../.exercism/config.json | 33 +++++ .../.exercism/metadata.json | 1 + python/largest-series-product/HELP.md | 129 ++++++++++++++++++ python/largest-series-product/README.md | 81 +++++++++++ .../largest_series_product.py | 2 + .../largest_series_product_test.py | 77 +++++++++++ 6 files changed, 323 insertions(+) create mode 100644 python/largest-series-product/.exercism/config.json create mode 100644 python/largest-series-product/.exercism/metadata.json create mode 100644 python/largest-series-product/HELP.md create mode 100644 python/largest-series-product/README.md create mode 100644 python/largest-series-product/largest_series_product.py create mode 100644 python/largest-series-product/largest_series_product_test.py diff --git a/python/largest-series-product/.exercism/config.json b/python/largest-series-product/.exercism/config.json new file mode 100644 index 00000000..138f3592 --- /dev/null +++ b/python/largest-series-product/.exercism/config.json @@ -0,0 +1,33 @@ +{ + "authors": [ + "sjakobi" + ], + "contributors": [ + "alexpjohnson", + "behrtam", + "cmccandless", + "Dog", + "fortrieb", + "iandexter", + "ikhadykin", + "kytrinyx", + "N-Parsons", + "petertseng", + "pheanex", + "tqa236" + ], + "files": { + "solution": [ + "largest_series_product.py" + ], + "test": [ + "largest_series_product_test.py" + ], + "example": [ + ".meta/example.py" + ] + }, + "blurb": "Given a string of digits, calculate the largest product for a contiguous substring of digits of length n.", + "source": "A variation on Problem 8 at Project Euler", + "source_url": "https://projecteuler.net/problem=8" +} diff --git a/python/largest-series-product/.exercism/metadata.json b/python/largest-series-product/.exercism/metadata.json new file mode 100644 index 00000000..49d43365 --- /dev/null +++ b/python/largest-series-product/.exercism/metadata.json @@ -0,0 +1 @@ +{"track":"python","exercise":"largest-series-product","id":"15a5c99e56cc4f0ca11bedfc66b21e4a","url":"https://exercism.org/tracks/python/exercises/largest-series-product","handle":"vpayno","is_requester":true,"auto_approve":false} \ No newline at end of file diff --git a/python/largest-series-product/HELP.md b/python/largest-series-product/HELP.md new file mode 100644 index 00000000..68aafe9a --- /dev/null +++ b/python/largest-series-product/HELP.md @@ -0,0 +1,129 @@ +# Help + +## Running the tests + +We use [pytest][pytest: Getting Started Guide] as our website test runner. +You will need to install `pytest` on your development machine if you want to run tests for the Python track locally. +You should also install the following `pytest` plugins: + +- [pytest-cache][pytest-cache] +- [pytest-subtests][pytest-subtests] + +Extended information can be found in our website [Python testing guide][Python track tests page]. + + +### Running Tests + +To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_). +Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded. + +Linux/MacOS +```bash +$ cd {path/to/exercise-folder-location} +``` + +Windows +```powershell +PS C:\Users\foobar> cd {path\to\exercise-folder-location} +``` + +
+ +Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file: + +Linux/MacOS +```bash +$ python3 -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + +Windows +```powershell +PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py} +==================== 7 passed in 0.08s ==================== +``` + + +### Common options +- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_) +- `-v` : enable verbose output. +- `-x` : stop running tests on first failure. +- `--ff` : run failures from previous test before running other test cases. + +For additional options, use `python3 -m pytest -h` or `py -m pytest -h`. + + +### Fixing warnings + +If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax: + +```bash +PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html +``` + +To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file. +We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini]. + +You can also create your own `pytest.ini` file with the following content: + +```ini +[pytest] +markers = + task: A concept exercise task. +``` + +Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings. +More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers]. + +Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats]. + + +### Extending your IDE or Code Editor + +Many IDEs and code editors have built-in support for using `pytest` and other code quality tools. +Some community-sourced options can be found on our [Python track tools page][Python track tools page]. + +[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html +[Python track tools page]: https://exercism.org/docs/tracks/python/tools +[Python track tests page]: https://exercism.org/docs/tracks/python/tests +[pytest-cache]:http://pythonhosted.org/pytest-cache/ +[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests +[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini +[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats +[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks +[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers + +## Submitting your solution + +You can submit your solution using the `exercism submit largest_series_product.py` command. +This command will upload your solution to the Exercism website and print the solution page's URL. + +It's possible to submit an incomplete solution which allows you to: + +- See how others have completed the exercise +- Request help from a mentor + +## Need to get help? + +If you'd like help solving the exercise, check the following pages: + +- The [Python track's documentation](https://exercism.org/docs/tracks/python) +- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5) +- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs) + +Should those resources not suffice, you could submit your (incomplete) solution to request mentoring. + +Below are some resources for getting help if you run into trouble: + +- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources. +- [The Exercism Community on Discord](https://exercism.org/r/discord) +- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community. +- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners. +- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done. +- [Python Community Forums](https://discuss.python.org/) +- [Free Code Camp Community Forums](https://forum.freecodecamp.org/) +- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help) +- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually. + +Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already. + If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question. \ No newline at end of file diff --git a/python/largest-series-product/README.md b/python/largest-series-product/README.md new file mode 100644 index 00000000..adb38ad0 --- /dev/null +++ b/python/largest-series-product/README.md @@ -0,0 +1,81 @@ +# Largest Series Product + +Welcome to Largest Series Product on Exercism's Python Track. +If you need help running the tests or submitting your code, check out `HELP.md`. + +## Introduction + +You work for a government agency that has intercepted a series of encrypted communication signals from a group of bank robbers. +The signals contain a long sequence of digits. +Your team needs to use various digital signal processing techniques to analyze the signals and identify any patterns that may indicate the planning of a heist. + +## Instructions + +Your task is to look for patterns in the long sequence of digits in the encrypted signal. + +The technique you're going to use here is called the largest series product. + +Let's define a few terms, first. + +- **input**: the sequence of digits that you need to analyze +- **series**: a sequence of adjacent digits (those that are next to each other) that is contained within the input +- **span**: how many digits long each series is +- **product**: what you get when you multiply numbers together + +Let's work through an example, with the input `"63915"`. + +- To form a series, take adjacent digits in the original input. +- If you are working with a span of `3`, there will be three possible series: + - `"639"` + - `"391"` + - `"915"` +- Then we need to calculate the product of each series: + - The product of the series `"639"` is 162 (`6 × 3 × 9 = 162`) + - The product of the series `"391"` is 27 (`3 × 9 × 1 = 27`) + - The product of the series `"915"` is 45 (`9 × 1 × 5 = 45`) +- 162 is bigger than both 27 and 45, so the largest series product of `"63915"` is from the series `"639"`. + So the answer is **162**. + +## Exception messages + +Sometimes it is necessary to [raise an exception](https://docs.python.org/3/tutorial/errors.html#raising-exceptions). When you do this, you should always include a **meaningful error message** to indicate what the source of the error is. This makes your code more readable and helps significantly with debugging. For situations where you know that the error source will be a certain type, you can choose to raise one of the [built in error types](https://docs.python.org/3/library/exceptions.html#base-classes), but should still include a meaningful message. + +This particular exercise requires that you use the [raise statement](https://docs.python.org/3/reference/simple_stmts.html#the-raise-statement) to "throw" a `ValueError` when your `largest_product()` function receives invalid input. The tests will only pass if you both `raise` the `exception` and include a message with it. Feel free to reuse your code from the `series` exercise! + +To raise a `ValueError` with a message, write the message as an argument to the `exception` type: + +```python +# span of numbers is longer than number series +raise ValueError("span must be smaller than string length") + +# span of number is negative +raise ValueError("span must not be negative") + +# series includes non-number input +raise ValueError("digits input must only contain digits") +``` + +## Source + +### Created by + +- @sjakobi + +### Contributed to by + +- @alexpjohnson +- @behrtam +- @cmccandless +- @Dog +- @fortrieb +- @iandexter +- @ikhadykin +- @kytrinyx +- @N-Parsons +- @petertseng +- @pheanex +- @tqa236 + +### Based on + +A variation on Problem 8 at Project Euler - https://projecteuler.net/problem=8 \ No newline at end of file diff --git a/python/largest-series-product/largest_series_product.py b/python/largest-series-product/largest_series_product.py new file mode 100644 index 00000000..ca1b0e8d --- /dev/null +++ b/python/largest-series-product/largest_series_product.py @@ -0,0 +1,2 @@ +def largest_product(series, size): + pass diff --git a/python/largest-series-product/largest_series_product_test.py b/python/largest-series-product/largest_series_product_test.py new file mode 100644 index 00000000..ba8ae10d --- /dev/null +++ b/python/largest-series-product/largest_series_product_test.py @@ -0,0 +1,77 @@ +import unittest + +from largest_series_product import ( + largest_product, +) + +# Tests adapted from `problem-specifications//canonical-data.json` + + +class LargestSeriesProductTest(unittest.TestCase): + def test_finds_the_largest_product_if_span_equals_length(self): + self.assertEqual(largest_product("29", 2), 18) + + def test_can_find_the_largest_product_of_2_with_numbers_in_order(self): + self.assertEqual(largest_product("0123456789", 2), 72) + + def test_can_find_the_largest_product_of_2(self): + self.assertEqual(largest_product("576802143", 2), 48) + + def test_can_find_the_largest_product_of_3_with_numbers_in_order(self): + self.assertEqual(largest_product("0123456789", 3), 504) + + def test_can_find_the_largest_product_of_3(self): + self.assertEqual(largest_product("1027839564", 3), 270) + + def test_can_find_the_largest_product_of_5_with_numbers_in_order(self): + self.assertEqual(largest_product("0123456789", 5), 15120) + + def test_can_get_the_largest_product_of_a_big_number(self): + self.assertEqual( + largest_product("73167176531330624919225119674426574742355349194934", 6), + 23520, + ) + + def test_reports_zero_if_the_only_digits_are_zero(self): + self.assertEqual(largest_product("0000", 2), 0) + + def test_reports_zero_if_all_spans_include_zero(self): + self.assertEqual(largest_product("99099", 3), 0) + + def test_rejects_span_longer_than_string_length(self): + with self.assertRaises(ValueError) as err: + largest_product("123", 4) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], "span must be smaller than string length" + ) + + def test_rejects_empty_string_and_nonzero_span(self): + with self.assertRaises(ValueError) as err: + largest_product("", 1) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual( + err.exception.args[0], "span must be smaller than string length" + ) + + def test_rejects_invalid_character_in_digits(self): + with self.assertRaises(ValueError) as err: + largest_product("1234a5", 2) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "digits input must only contain digits") + + def test_rejects_negative_span(self): + with self.assertRaises(ValueError) as err: + largest_product("12345", -1) + self.assertEqual(type(err.exception), ValueError) + self.assertEqual(err.exception.args[0], "span must not be negative") + + # Additional tests for this track + def test_euler_big_number(self): + self.assertEqual( + largest_product( + "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450", + 13, + ), + 23514624000, + ) From c2cdc614d845bc022bd3bc42ee60e1db8c334667 Mon Sep 17 00:00:00 2001 From: Victor Payno Date: Tue, 27 Jun 2023 21:35:14 -0700 Subject: [PATCH 2/2] python/largest-series-product: 1st iteration --- python/README.md | 1 + python/largest-series-product | 1 + .../largest_series_product.py | 2 - python/largest_series_product/.coverage | Bin 0 -> 53247 bytes python/largest_series_product/.coverage.xml | 46 ++++ python/largest_series_product/.coveragerc | 2 + .../.exercism/config.json | 0 .../.exercism/metadata.json | 0 .../HELP.md | 0 .../README.md | 7 +- python/largest_series_product/__init__.py | 0 .../largest_series_product.py | 48 +++++ .../largest_series_product.py,cover | 48 +++++ .../largest_series_product_test.py | 2 +- .../run-tests-python.txt | 196 ++++++++++++++++++ 15 files changed, 349 insertions(+), 4 deletions(-) create mode 120000 python/largest-series-product delete mode 100644 python/largest-series-product/largest_series_product.py create mode 100644 python/largest_series_product/.coverage create mode 100644 python/largest_series_product/.coverage.xml create mode 100644 python/largest_series_product/.coveragerc rename python/{largest-series-product => largest_series_product}/.exercism/config.json (100%) rename python/{largest-series-product => largest_series_product}/.exercism/metadata.json (100%) rename python/{largest-series-product => largest_series_product}/HELP.md (100%) rename python/{largest-series-product => largest_series_product}/README.md (96%) create mode 100644 python/largest_series_product/__init__.py create mode 100644 python/largest_series_product/largest_series_product.py create mode 100644 python/largest_series_product/largest_series_product.py,cover rename python/{largest-series-product => largest_series_product}/largest_series_product_test.py (99%) create mode 100644 python/largest_series_product/run-tests-python.txt diff --git a/python/README.md b/python/README.md index b9cfeb63..af9a8ee8 100644 --- a/python/README.md +++ b/python/README.md @@ -32,3 +32,4 @@ - [ellens-alien-game](./ellens-alien-game/README.md) - [word-count](./word-count/README.md) - [sum-of-multiples](./sum-of-multiples/README.md) +- [largest-series-product](./largest-series-product/README.md) diff --git a/python/largest-series-product b/python/largest-series-product new file mode 120000 index 00000000..09670323 --- /dev/null +++ b/python/largest-series-product @@ -0,0 +1 @@ +largest_series_product \ No newline at end of file diff --git a/python/largest-series-product/largest_series_product.py b/python/largest-series-product/largest_series_product.py deleted file mode 100644 index ca1b0e8d..00000000 --- a/python/largest-series-product/largest_series_product.py +++ /dev/null @@ -1,2 +0,0 @@ -def largest_product(series, size): - pass diff --git a/python/largest_series_product/.coverage b/python/largest_series_product/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..a95ba3455891cd3a8cd1b1e7767f6af691dc074a GIT binary patch literal 53247 zcmeI4Uu+{s9mjWL$CFK*olBj>=lt^~X%ah$oeTGXph$2)9;#LxS56>=gl}W7lcl!T zx4XVvgb;FD=_F7e`T!~d!4p!Ekg5vt01~|Pp)VlO2UH;>q#_|I@lYP9ghf&K&FpL( z-^EoWL{2T=k-h%z?ELx7XMQu|@ml+Z8&A5SW7R#sX@}NT?UJVJ+NUf_(=>zLlk|=Q zBaw_x=upO|Du*oJ+JYvPG0Aw^baQ2CtgoCjc-l-kl99+E+Bva2!H?x z{C^YZ-bk}-E~h{9jnLk2IH7M>9X~owe&(sYYd80-o7X=5o7wrXzG4&By)6&^Zq>Q3O)#6m}LwA6`&Wtm^7id&;xp>se*w0*Z}`^VPP z&hfTPplS=9yI~YTg*fg(OQf(0DtpoLox0;Yt*R45RutS?alH8KH^*5vlhN-vvQ4&M zrPstjYbc`Ml*j8-P}TEm!uoyRZdDJRVB4}!TUhnT&bwjMTHkB#gr3!KTe6w0zztom zWjS}9YA1AR=QeO#K#K#xJKGv6>y~KHtth9e>kOTK=5unYr&zLjJW*vn@J@azqt}-msj*@`j#j?ECJUbNaI1-hu9nk&7OUa&=nn?T&NW`P)`M z=eBG{%iFd@Bgg~RCQ{jtWps_a(zzSlZqWCwiroo4d0wH;uk6wx{oK?T%jWa?z1z}J z1fI&i8wRJs7;u`?=pn8nt`GMcF-iuVM2w(qjUL1_;dsak6@+RTV=e5N)V>cO2h7aLVdxG%Y-AMG#X!OI(E?U6`q7b6mP(H)u9# z+pbSTmgeAS1+YZInoWuAeXkQr{}rdwJ;mD7w>K)Fe;%`^R7IJbhWF>aAaH3}70Xue z@i^AnIJ5&X3k4h2zUMU@yA`bsl;iP$>U0B3+VJ42^vQl1!Lcag;Le7$DPCN}G=Gx@ zT|B->G@Ev-rq(O53`eEX+%E>Fs3)34D5JGOgEF8YdS97wq3WubvEuT}ZDJxyZQ8YH zxQk9XQ{vH~^FVRYYV=t>_9O5*pK}>E@ z5AH`4;#BIp&UjI5@OAz#ja~>K00JNY0w4eaAOHd&00JNY0w4eaA3g#JeMDzs|3AXt z)cD(UKmY*{009sH0T2KI5C8!X009sH0TB3L5=f6E7J2*^k6o@O=CkTg03R)XqEq>Jvnx!Mpe>!N>W0H2-$Kj#Z+G)^J7@Q!i1di`IL8a|`wN5o05>3xb5cmIe z{ymLe2p|9gAOHd&00JNY0w4eaAOHd&00I|Hpq}jBF#h-Ze?0&1qB|D#fdB}A00@8p z2!H?xfB*=900@Ah5C8!X009sH0T2KI5C8!X0D*@>K-~Yw{{Nw%N2MSD0w4ea zAOHd&00JNY0w4eaAaG#>#Qpzu^QRjBC;vPDEB_P!J^u}VmH(2z!e8P);@{=Z^XK^2 zxzAmGi+_oKj_>hL@T+{2FZ0Ws^OX5-^B?Bl%s-odFn?#hX8zjzITeNg0w4eaAOHd& z00JNY0w4eaAOHgY1p&4`Y8bkHrN`E!C|qHWN>M7XRVm5^wi3mZ*|HRyC1y#nwaM~P z%obacqPWQxr6?5Hf)wk^Y+j1Bbv7r(YJugXSXpJ4BeBM^QY^2qSt;_%Y(|QuJe!tc zafxN5SXg9_NHN!AQ&QyS*riA;FfK*5$4n_^vurXFIhK}Uy2mD@$V{{GNX#-rim4tO zlY&n%7Ksc?NzvnMR0?*&l2RlYOGuGOrbb8@dLpHZ2;)TD|6e!nY5X<%1>kM|7yd{7 zI{z8}75@qU4(uQgFRfH&dLmY{<4R5S45j$g zSgbNksUA-$#ZE?*O0uL + + + + + /home/vpayno/git_vpayno/exercism-workspace/python/largest_series_product + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/python/largest_series_product/.coveragerc b/python/largest_series_product/.coveragerc new file mode 100644 index 00000000..883531db --- /dev/null +++ b/python/largest_series_product/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = __init__.py, *_test.py diff --git a/python/largest-series-product/.exercism/config.json b/python/largest_series_product/.exercism/config.json similarity index 100% rename from python/largest-series-product/.exercism/config.json rename to python/largest_series_product/.exercism/config.json diff --git a/python/largest-series-product/.exercism/metadata.json b/python/largest_series_product/.exercism/metadata.json similarity index 100% rename from python/largest-series-product/.exercism/metadata.json rename to python/largest_series_product/.exercism/metadata.json diff --git a/python/largest-series-product/HELP.md b/python/largest_series_product/HELP.md similarity index 100% rename from python/largest-series-product/HELP.md rename to python/largest_series_product/HELP.md diff --git a/python/largest-series-product/README.md b/python/largest_series_product/README.md similarity index 96% rename from python/largest-series-product/README.md rename to python/largest_series_product/README.md index adb38ad0..0906b52e 100644 --- a/python/largest-series-product/README.md +++ b/python/largest_series_product/README.md @@ -78,4 +78,9 @@ raise ValueError("digits input must only contain digits") ### Based on -A variation on Problem 8 at Project Euler - https://projecteuler.net/problem=8 \ No newline at end of file +A variation on Problem 8 at Project Euler - https://projecteuler.net/problem=8 + +### My Solution + +- [my solution](./largest_series_product.py) +- [run-tests](./run-tests-python.txt) diff --git a/python/largest_series_product/__init__.py b/python/largest_series_product/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/python/largest_series_product/largest_series_product.py b/python/largest_series_product/largest_series_product.py new file mode 100644 index 00000000..440b7d5d --- /dev/null +++ b/python/largest_series_product/largest_series_product.py @@ -0,0 +1,48 @@ +""" Largest Series Product Python Exercism""" + +import re +from typing import List + + +def largest_product(series: str, size: int) -> int: + """Returns the largest product for a contiguous substring of digits of size n. + + :param series: str - sequence of positive integers + :param size: int - length of sequence substring + :return: int - the largest product of the substrings in the sequence + """ + + if not series: + # this is catching a different test, test for this doesn't exist + raise ValueError("span must be smaller than string length") + + if size <= 0: + raise ValueError("span must not be negative") + + if len(series) < size: + raise ValueError("span must be smaller than string length") + + if not re.match(r"^[0-9]+$", series): + raise ValueError("digits input must only contain digits") + + result: int = 0 + words: List[str] = [] + word: str = "" + digits: str = series + + for _ in range(len(series)): + if len(digits) < size: + break + + words.append(digits[0:size]) + digits = digits[1:] + + for word in words.copy(): + product = 1 + for n in list(word): + product *= int(n) + + if result < product: + result = product + + return result diff --git a/python/largest_series_product/largest_series_product.py,cover b/python/largest_series_product/largest_series_product.py,cover new file mode 100644 index 00000000..d3c2695e --- /dev/null +++ b/python/largest_series_product/largest_series_product.py,cover @@ -0,0 +1,48 @@ +> """ Largest Series Product Python Exercism""" + +> import re +> from typing import List + + +> def largest_product(series: str, size: int) -> int: +> """Returns the largest product for a contiguous substring of digits of size n. + +> :param series: str - sequence of positive integers +> :param size: int - length of sequence substring +> :return: int - the largest product of the substrings in the sequence +> """ + +> if not series: + # this is catching a different test, test for this doesn't exist +> raise ValueError("span must be smaller than string length") + +> if size <= 0: +> raise ValueError("span must not be negative") + +> if len(series) < size: +> raise ValueError("span must be smaller than string length") + +> if not re.match(r"^[0-9]+$", series): +> raise ValueError("digits input must only contain digits") + +> result: int = 0 +> words: List[str] = [] +> word: str = "" +> digits: str = series + +> for _ in range(len(series)): +> if len(digits) < size: +> break + +> words.append(digits[0:size]) +> digits = digits[1:] + +> for word in words.copy(): +> product = 1 +> for n in list(word): +> product *= int(n) + +> if result < product: +> result = product + +> return result diff --git a/python/largest-series-product/largest_series_product_test.py b/python/largest_series_product/largest_series_product_test.py similarity index 99% rename from python/largest-series-product/largest_series_product_test.py rename to python/largest_series_product/largest_series_product_test.py index ba8ae10d..9d8ccfaf 100644 --- a/python/largest-series-product/largest_series_product_test.py +++ b/python/largest_series_product/largest_series_product_test.py @@ -1,6 +1,6 @@ import unittest -from largest_series_product import ( +from .largest_series_product import ( largest_product, ) diff --git a/python/largest_series_product/run-tests-python.txt b/python/largest_series_product/run-tests-python.txt new file mode 100644 index 00000000..4f69f2a9 --- /dev/null +++ b/python/largest_series_product/run-tests-python.txt @@ -0,0 +1,196 @@ +Running automated test file(s): + + +=============================================================================== + +Running: pylint --ignore-patterns (__init__|.*_test).py . + +real 0m0.443s +user 0m0.367s +sys 0m0.075s + +=============================================================================== + +Running: ruff check --ignore E501 ./__init__.py ./largest_series_product.py ./largest_series_product_test.py + +real 0m0.065s +user 0m0.029s +sys 0m0.037s + +=============================================================================== + +Running: pyright --stats . +Found 3 source files +pyright 1.1.316 +0 errors, 0 warnings, 0 informations +Completed in 0.781sec + +Analysis stats +Total files parsed and bound: 35 +Total files checked: 3 + +Timing stats +Find Source Files: 0sec +Read Source Files: 0.01sec +Tokenize: 0.06sec +Parse: 0.09sec +Resolve Imports: 0.04sec +Bind: 0.1sec +Check: 0.14sec +Detect Cycles: 0sec + +real 0m1.655s +user 0m1.670s +sys 0m0.192s + +=============================================================================== + +Running: bandit --verbose --recursive . +[main] INFO profile include tests: None +[main] INFO profile exclude tests: None +[main] INFO cli include tests: None +[main] INFO cli exclude tests: None +[main] INFO running on Python 3.11.3 +Run started:2023-06-28 04:33:05.423523 +Files in scope (3): + ./__init__.py (score: {SEVERITY: 0, CONFIDENCE: 0}) + ./largest_series_product.py (score: {SEVERITY: 0, CONFIDENCE: 0}) + ./largest_series_product_test.py (score: {SEVERITY: 0, CONFIDENCE: 0}) +Files excluded (15): + ./.coverage + ./.coverage.xml + ./.coveragerc + ./.exercism/config.json + ./.exercism/metadata.json + ./.mypy_cache/.gitignore + ./.mypy_cache/3.11/@plugins_snapshot.json + ./.mypy_cache/CACHEDIR.TAG + ./HELP.md + ./README.md + ./__pycache__/__init__.cpython-311.pyc + ./__pycache__/largest_series_product.cpython-311.pyc + ./__pycache__/largest_series_product_test.cpython-311-pytest-7.3.1.pyc + ./largest_series_product.py,cover + ./run-tests-python.txt + +Test results: + No issues identified. + +Code scanned: + Total lines of code: 91 + Total lines skipped (#nosec): 0 + Total potential issues skipped due to specifically being disabled (e.g., #nosec BXXX): 0 + +Run metrics: + Total issues (by severity): + Undefined: 0 + Low: 0 + Medium: 0 + High: 0 + Total issues (by confidence): + Undefined: 0 + Low: 0 + Medium: 0 + High: 0 +Files skipped (0): + +real 0m0.250s +user 0m0.183s +sys 0m0.065s + +=============================================================================== + +Running: refurb . +./largest_series_product_test.py:15:42 [FURB156]: Replace `0123456789` with `string.digits` +./largest_series_product_test.py:21:42 [FURB156]: Replace `0123456789` with `string.digits` +./largest_series_product_test.py:27:42 [FURB156]: Replace `0123456789` with `string.digits` + +Run `refurb --explain ERR` to further explain an error. Use `--quiet` to silence this message + +real 0m1.372s +user 0m1.308s +sys 0m0.064s + +=============================================================================== + +==> .coveragerc <== +[run] +omit = __init__.py, *_test.py + +Running: pytest --verbose --cov=. --cov-branch --cov-report=term-missing --cov-report=xml:.coverage.xml -p no:randomly +============================= test session starts ============================== +platform linux -- Python 3.11.3, pytest-7.3.1, pluggy-1.0.0 -- /home/vpayno/.pyenv/versions/3.11.3/bin/python +cachedir: .pytest_cache +rootdir: /home/vpayno/git_vpayno/exercism-workspace/python +configfile: pytest.ini +plugins: anyio-3.6.2, libtmux-0.21.1, pylama-8.4.1, cov-4.0.0, datafiles-3.0.0, docker-1.0.1, subprocess-1.5.0, typeguard-2.13.3 +collecting ... collected 14 items + +largest_series_product_test.py::LargestSeriesProductTest::test_can_find_the_largest_product_of_2 PASSED [ 7%] +largest_series_product_test.py::LargestSeriesProductTest::test_can_find_the_largest_product_of_2_with_numbers_in_order PASSED [ 14%] +largest_series_product_test.py::LargestSeriesProductTest::test_can_find_the_largest_product_of_3 PASSED [ 21%] +largest_series_product_test.py::LargestSeriesProductTest::test_can_find_the_largest_product_of_3_with_numbers_in_order PASSED [ 28%] +largest_series_product_test.py::LargestSeriesProductTest::test_can_find_the_largest_product_of_5_with_numbers_in_order PASSED [ 35%] +largest_series_product_test.py::LargestSeriesProductTest::test_can_get_the_largest_product_of_a_big_number PASSED [ 42%] +largest_series_product_test.py::LargestSeriesProductTest::test_euler_big_number PASSED [ 50%] +largest_series_product_test.py::LargestSeriesProductTest::test_finds_the_largest_product_if_span_equals_length PASSED [ 57%] +largest_series_product_test.py::LargestSeriesProductTest::test_rejects_empty_string_and_nonzero_span PASSED [ 64%] +largest_series_product_test.py::LargestSeriesProductTest::test_rejects_invalid_character_in_digits PASSED [ 71%] +largest_series_product_test.py::LargestSeriesProductTest::test_rejects_negative_span PASSED [ 78%] +largest_series_product_test.py::LargestSeriesProductTest::test_rejects_span_longer_than_string_length PASSED [ 85%] +largest_series_product_test.py::LargestSeriesProductTest::test_reports_zero_if_all_spans_include_zero PASSED [ 92%] +largest_series_product_test.py::LargestSeriesProductTest::test_reports_zero_if_the_only_digits_are_zero PASSED [100%] + +---------- coverage: platform linux, python 3.11.3-final-0 ----------- +Name Stmts Miss Branch BrPart Cover Missing +----------------------------------------------------------------------- +largest_series_product.py 27 0 18 1 98% 33->40 +----------------------------------------------------------------------- +TOTAL 27 0 18 1 98% +Coverage XML written to file .coverage.xml + + +============================== 14 passed in 0.06s ============================== + +real 0m0.996s +user 0m0.868s +sys 0m0.126s + +=============================================================================== + +Running: coverage report --show-missing +Name Stmts Miss Branch BrPart Cover Missing +----------------------------------------------------------------------- +largest_series_product.py 27 0 18 1 98% 33->40 +----------------------------------------------------------------------- +TOTAL 27 0 18 1 98% + +real 0m0.148s +user 0m0.102s +sys 0m0.046s + +=============================================================================== + +coverage annotate +The annotate command will be removed in a future version. +Get in touch if you still use it: ned@nedbatchelder.com + +real 0m0.157s +user 0m0.110s +sys 0m0.048s + +tail -n 10000 ./*,cover | grep -E -C 3 '^> def |^! ' + +> def largest_product(series: str, size: int) -> int: +> """Returns the largest product for a contiguous substring of digits of size n. + +=============================================================================== + +Running: misspell ./__init__.py ./largest_series_product.py ./largest_series_product_test.py + +real 0m0.024s +user 0m0.024s +sys 0m0.013s + +=============================================================================== +