diff --git a/Pipfile b/Pipfile index c2ea6b3..1f4d3cc 100644 --- a/Pipfile +++ b/Pipfile @@ -6,10 +6,10 @@ name = "pypi" [packages] examplepackagefb1258 = {file = ".", editable = true} build = "*" -pytest = "*" coverage = "*" pytest-cov = "*" twine = "*" +pytest = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index ce96b39..e110676 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -136,73 +136,102 @@ "toml" ], "hashes": [ - "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94", - "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92", - "sha256:104bf640f408f4e115b85110047c7f27377e1a8b7ba86f7db4fa47aa49dc9a8e", - "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82", - "sha256:1586ad158523f4133499a4f322b230e2cfef9cc724820dbd58595a5a236186f4", - "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68", - "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90", - "sha256:1c8fbce80b2b8bf135d105aa8f5b36eae0c57d702a1cc3ebdea2a6f03f6cdde5", - "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656", - "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa", - "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db", - "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608", - "sha256:39abcacd1ed54e2c33c54bdc488b310e8ef6705833f7148b6eb9a547199d375d", - "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39", - "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c", - "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265", - "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072", - "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd", - "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe", - "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d", - "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573", - "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d", - "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816", - "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2", - "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf", - "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd", - "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a", - "sha256:70f0925c4e2bfc965369f417e7cc72538fd1ba91639cf1e4ef4b1a6b50439b3b", - "sha256:7789e700f33f2b133adae582c9f437523cd5db8de845774988a58c360fc88253", - "sha256:7b6c96d69928a3a6767fab8dc1ce8a02cf0156836ccb1e820c7f45a423570d98", - "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5", - "sha256:7f18d47641282664276977c604b5a261e51fefc2980f5271d547d706b06a837f", - "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce", - "sha256:8c938c6ae59be67ac19a7204e079efc94b38222cd7d0269f96e45e18cddeaa59", - "sha256:8e336b56301774ace6be0017ff85c3566c556d938359b61b840796a0202f805c", - "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7", - "sha256:a2454b12a3f12cc4698f3508912e6225ec63682e2ca5a96f80a2b93cef9e63f3", - "sha256:a538a23119d1e2e2ce077e902d02ea3d8e0641786ef6e0faf11ce82324743944", - "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705", - "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4", - "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4", - "sha256:b0fac2088ec4aaeb5468b814bd3ff5e5978364bfbce5e567c44c9e2854469f6c", - "sha256:b3e212a894d8ae07fde2ca8b43d666a6d49bbbddb10da0f6a74ca7bd31f20054", - "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07", - "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0", - "sha256:b8c36093aca722db73633cf2359026ed7782a239eb1c6db2abcff876012dc4cf", - "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8", - "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135", - "sha256:c075d167a6ec99b798c1fdf6e391a1d5a2d054caffe9593ba0f97e3df2c04f0e", - "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463", - "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c", - "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57", - "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322", - "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166", - "sha256:d013c07061751ae81861cae6ec3a4fe04e84781b11fd4b6b4201590234b25c7b", - "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b", - "sha256:d9710521f07f526de30ccdead67e6b236fe996d214e1a7fba8b36e2ba2cd8261", - "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f", - "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba", - "sha256:f2a1e18a85bd066c7c556d85277a7adf4651f259b2579113844835ba1a74aafd", - "sha256:f32b165bf6dfea0846a9c9c38b7e1d68f313956d60a15cde5d1709fddcaf3bee", - "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a", - "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b" + "sha256:037b2d064c2f8cc8716fe4d39cb705779af3fbf1ba318dc96a1af858888c7bb5", + "sha256:05791e528a18f7072bf5998ba772fe29db4da1234c45c2087866b5ba4dea710e", + "sha256:0d7f0616c557cbc3d1c2090334eddcbb70e1ae3a40b07222d62b3aa47f608fab", + "sha256:0efa742f431529699712b92ecdf22de8ff198df41e43aeaaadf69973eb93f17a", + "sha256:10ad04ac3a122048688387828b4537bc9cf60c0bf4869c1e9989c46e45690b82", + "sha256:167bd504ac1ca2af7ff3b81d245dfea0292c5032ebef9d66cc08a7d28c1b8050", + "sha256:16ce17ceb5d211f320b62df002fa7016b7442ea0fd260c11cec8ce7730954893", + "sha256:214b622259dd0cf435f10241f1333d32caa64dbc27f8790ab693428a141723de", + "sha256:24d6f3128f1b2d20d84b24f4074475457faedc3d4613a7e66b5e769939c7d969", + "sha256:258d9967520cca899695d4eb7ea38be03f06951d6ca2f21fb48b1235f791e601", + "sha256:269bfe913b7d5be12ab13a95f3a76da23cf147be7fa043933320ba5625f0a8de", + "sha256:2727d47fce3ee2bac648528e41455d1b0c46395a087a229deac75e9f88ba5a05", + "sha256:314c24e700d7027ae3ab0d95fbf8d53544fca1f20345fd30cd219b737c6e58d3", + "sha256:3d4ba9a449e9364a936a27322b20d32d8b166553bfe63059bd21527e681e2fad", + "sha256:3d4ed4de17e692ba6415b0587bc7f12bc80915031fc9db46a23ce70fc88c9841", + "sha256:3d58ecaa865c5b9fa56e35efc51d1014d4c0d22838815b9fce57a27dd9576847", + "sha256:4036cc9c7983a2b1f2556d574d2eb2154ac6ed55114761685657e38782b23f52", + "sha256:424538266794db2861db4922b05d729ade0940ee69dcf0591ce8f69784db0e11", + "sha256:4b7589765348d78fb4e5fb6ea35d07564e387da2fc5efff62e0222971f155f68", + "sha256:4c1eeb3fb8eb9e0190bebafd0462936f75717687117339f708f395fe455acc73", + "sha256:4d3ffa07a08657306cd2215b0da53761c4d73cb54d9143b9303a6481ec0cd415", + "sha256:5693e57a065760dcbeb292d60cc4d0231a6d4b6b6f6a3191561e1d5e8820b745", + "sha256:587c38849b853b157706407e9ebdca8fd12f45869edb56defbef2daa5fb0812b", + "sha256:596763d2f9a0ee7eec6e643e29660def2eef297e1de0d334c78c08706f1cb785", + "sha256:59a6e5a265f7cfc05f76e3bb53eca2e0dfe90f05e07e849930fecd6abb8f40b4", + "sha256:5a03eaf7ec24078ad64a07f02e30060aaf22b91dedf31a6b24d0d98d2bba7f48", + "sha256:5ef83b107f50db3f9ae40f69e34b3bd9337456c5a7fe3461c7abf8b75dd666a2", + "sha256:630d0bd7a293ad2fc8b4b94e5758c8b2536fdf36c05f1681270203e463cbfa9b", + "sha256:695340f698a5f56f795b2836abe6fb576e7c53d48cd155ad2f80fd24bc63a040", + "sha256:6fbcee1a8f056af07ecd344482f711f563a9eb1c2cad192e87df00338ec3cdb0", + "sha256:7161edd3426c8d19bdccde7d49e6f27f748f3c31cc350c5de7c633fea445d866", + "sha256:73feb83bb41c32811973b8565f3705caf01d928d972b72042b44e97c71fd70d1", + "sha256:765c0bc8fe46f48e341ef737c91c715bd2a53a12792592296a095f0c237e09cf", + "sha256:7ab934dd13b1c5e94b692b1e01bd87e4488cb746e3a50f798cb9464fd128374b", + "sha256:7db53b5cdd2917b6eaadd0b1251cf4e7d96f4a8d24e174bdbdf2f65b5ea7994d", + "sha256:80027673e9d0bd6aef86134b0771845e2da85755cf686e7c7c59566cf5a89115", + "sha256:81b335f03ba67309a95210caf3eb43bd6fe75a4e22ba653ef97b4696c56c7ec2", + "sha256:865965bf955d92790f1facd64fe7ff73551bd2c1e7e6b26443934e9701ba30b9", + "sha256:8badf70446042553a773547a61fecaa734b55dc738cacf20c56ab04b77425e43", + "sha256:8c934bd088eed6174210942761e38ee81d28c46de0132ebb1801dbe36a390dcc", + "sha256:9516add7256b6713ec08359b7b05aeff8850c98d357784c7205b2e60aa2513fa", + "sha256:9c49e77811cf9d024b95faf86c3f059b11c0c9be0b0d61bc598f453703bd6fd1", + "sha256:9cbabd8f4d0d3dc571d77ae5bdbfa6afe5061e679a9d74b6797c48d143307088", + "sha256:9ed43fa22c6436f7957df036331f8fe4efa7af132054e1844918866cd228af6c", + "sha256:a09c1211959903a479e389685b7feb8a17f59ec5a4ef9afde7650bd5eabc2777", + "sha256:a1839d08406e4cba2953dcc0ffb312252f14d7c4c96919f70167611f4dee2623", + "sha256:a386c1061bf98e7ea4758e4313c0ab5ecf57af341ef0f43a0bf26c2477b5c268", + "sha256:a3b6a5f8b2524fd6c1066bc85bfd97e78709bb5e37b5b94911a6506b65f47186", + "sha256:a3d0e2087dba64c86a6b254f43e12d264b636a39e88c5cc0a01a7c71bcfdab7e", + "sha256:a61e37a403a778e2cda2a6a39abcc895f1d984071942a41074b5c7ee31642007", + "sha256:aef1747ede4bd8ca9cfc04cc3011516500c6891f1b33a94add3253f6f876b7b7", + "sha256:b56efee146c98dbf2cf5cffc61b9829d1e94442df4d7398b26892a53992d3547", + "sha256:b5c2705afa83f49bd91962a4094b6b082f94aef7626365ab3f8f4bd159c5acf3", + "sha256:b679e171f1c104a5668550ada700e3c4937110dbdd153b7ef9055c4f1a1ee3cc", + "sha256:b971bdefdd75096163dd4261c74be813c4508477e39ff7b92191dea19f24cd37", + "sha256:bab7ec4bb501743edc63609320aaec8cd9188b396354f482f4de4d40a9d10721", + "sha256:bc1fbea96343b53f65d5351d8fd3b34fd415a2670d7c300b06d3e14a5af4f552", + "sha256:c6f31f281012235ad08f9a560976cc2fc9c95c17604ff3ab20120fe480169bca", + "sha256:c770885b28fb399aaf2a65bbd1c12bf6f307ffd112d6a76c5231a94276f0c497", + "sha256:c79cae102bb3b1801e2ef1511fb50e91ec83a1ce466b2c7c25010d884336de46", + "sha256:c9f08ea03114a637dab06cedb2e914da9dc67fa52c6015c018ff43fdde25b9c2", + "sha256:ca61691ba8c5b6797deb221a0d09d7470364733ea9c69425a640f1f01b7c5bf0", + "sha256:cacb29f420cfeb9283b803263c3b9a068924474ff19ca126ba9103e1278dfa44", + "sha256:cc3f49e65ea6e0d5d9bd60368684fe52a704d46f9e7fc413918f18d046ec40e1", + "sha256:cdbcd376716d6b7fbfeedd687a6c4be019c5a5671b35f804ba76a4c0a778cba4", + "sha256:ce37f215223af94ef0f75ac68ea096f9f8e8c8ec7d6e8c346ee45c0d363f0479", + "sha256:ce9f3bde4e9b031eaf1eb61df95c1401427029ea1bfddb8621c1161dcb0fa02e", + "sha256:cee6291bb4fed184f1c2b663606a115c743df98a537c969c3c64b49989da96c2", + "sha256:cf9e6ff4ca908ca15c157c409d608da77a56a09877b97c889b98fb2c32b6465e", + "sha256:d06f4fc7acf3cabd6d74941d53329e06bab00a8fe10e4df2714f0b134bfc64ef", + "sha256:d66c0104aec3b75e5fd897e7940188ea1892ca1d0235316bf89286d6a22568c0", + "sha256:d91ebeac603812a09cf6a886ba6e464f3bbb367411904ae3790dfe28311b15ad", + "sha256:d9a03ec6cb9f40a5c360f138b88266fd8f58408d71e89f536b4f91d85721d075", + "sha256:dadbcce51a10c07b7c72b0ce4a25e4b6dcb0c0372846afb8e5b6307a121eb99f", + "sha256:dba82204769d78c3fd31b35c3d5f46e06511936c5019c39f98320e05b08f794d", + "sha256:dbbf012be5f32533a490709ad597ad8a8ff80c582a95adc8d62af664e532f9ca", + "sha256:df01d6c4c81e15a7c88337b795bb7595a8596e92310266b5072c7e301168efbd", + "sha256:e0eb0a2dcc62478eb5b4cbb80b97bdee852d7e280b90e81f11b407d0b81c4287", + "sha256:e24045453384e0ae2a587d562df2a04d852672eb63051d16096d3f08aa4c7c2f", + "sha256:e44a86a47bbdf83b0a3ea4d7df5410d6b1a0de984fbd805fa5101f3624b9abe0", + "sha256:e4dc07e95495923d6fd4d6c27bf70769425b71c89053083843fd78f378558996", + "sha256:e89641f5175d65e2dbb44db15fe4ea48fade5d5bbb9868fdc2b4fce22f4a469d", + "sha256:e9570ad567f880ef675673992222746a124b9595506826b210fbe0ce3f0499cd", + "sha256:eb53f1e8adeeb2e78962bade0c08bfdc461853c7969706ed901821e009b35e31", + "sha256:eb92e47c92fcbcdc692f428da67db33337fa213756f7adb6a011f7b5a7a20740", + "sha256:ef55537ff511b5e0a43edb4c50a7bf7ba1c3eea20b4f49b1490f1e8e0e42c591", + "sha256:f39ae2f63f37472c17b4990f794035c9890418b1b8cca75c01193f3c8d3e01be", + "sha256:f413ce6e07e0d0dc9c433228727b619871532674b45165abafe201f200cc215f", + "sha256:f91f927a3215b8907e214af77200250bb6aae36eca3f760f89780d13e495388d", + "sha256:f9ea02ef40bb83823b2b04964459d281688fe173e20643870bb5d2edf68bc836", + "sha256:fcc0a4aa589de34bc56e1a80a740ee0f8c47611bdfb28cd1849de60660f3799d", + "sha256:fcc15fc462707b0680cff6242c48625da7f9a16a28a41bb8fd7a4280920e676c" ], "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==7.7.0" + "markers": "python_version >= '3.10'", + "version": "==7.11.0" }, "docutils": { "hashes": [ @@ -212,10 +241,6 @@ "markers": "python_version >= '3.9'", "version": "==0.21.2" }, - "examplepackagefb1258": { - "editable": true, - "file": "." - }, "id": { "hashes": [ "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d", @@ -234,11 +259,11 @@ }, "iniconfig": { "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", + "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12" ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" + "markers": "python_version >= '3.10'", + "version": "==2.3.0" }, "jaraco.classes": { "hashes": [ @@ -328,27 +353,27 @@ }, "packaging": { "hashes": [ - "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", - "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f" + "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", + "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f" ], "markers": "python_version >= '3.8'", - "version": "==24.2" + "version": "==25.0" }, "pluggy": { "hashes": [ - "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", - "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669" + "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", + "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746" ], - "markers": "python_version >= '3.8'", - "version": "==1.5.0" + "markers": "python_version >= '3.9'", + "version": "==1.6.0" }, "pygments": { "hashes": [ - "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", - "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c" + "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" ], "markers": "python_version >= '3.8'", - "version": "==2.19.1" + "version": "==2.19.2" }, "pyproject-hooks": { "hashes": [ @@ -360,21 +385,21 @@ }, "pytest": { "hashes": [ - "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", - "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845" + "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", + "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==8.3.5" + "markers": "python_version >= '3.9'", + "version": "==8.4.2" }, "pytest-cov": { "hashes": [ - "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", - "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0" + "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", + "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==6.0.0" + "version": "==7.0.0" }, "readme-renderer": { "hashes": [ diff --git a/README.md b/README.md index 2e37c74..06fa9be 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,154 @@ -![Python build & test](https://github.com/nyu-software-engineering/python-package-example/actions/workflows/build.yaml/badge.svg) +# πŸ₯  PyFortuneCookie -# Python Package Example +A fun Python package that generates your **daily fortune cookie** β€” complete with a lucky number and color! +Perfect for learning how to build and run Python packages. -This package was created by generally following the [Packaging Python Projects](https://packaging.python.org/en/latest/tutorials/packaging-projects/) with the addition of some [pipenv setup](https://packaging.python.org/en/latest/tutorials/managing-dependencies/) to manage virtual environments. +--- -## How this package was created +## πŸ“¦ Installation -1. [Install pipenv](https://packaging.python.org/en/latest/tutorials/managing-dependencies/#managing-dependencies), [build](https://packaging.python.org/en/latest/tutorials/packaging-projects/#generating-distribution-archives), and [twine](https://packaging.python.org/en/latest/key_projects/#twine) if not already installed. -2. create directory structure for the package like that below, where `examplepackagefb1258` is replaced with your package's name. This name must be uniquely yours when uploaded to [PyPI](https://pypi.org/). Better to avoid hyphens or underline characters (`-` or `_`) in the package name, as these can create problems when importing. The parent directory name (the repository name) - `python-package-example` in this case - is not relevant to the package name. +Clone or download this repository, then install it locally (in editable mode): +```bash +pipenv install +pipenv run pip install -e . +```` + +If you don’t have **pipenv**, install it first: + +```bash +pip install pipenv ``` -python-package-example/ - |____README.md - |____LICENSE - |____pyproject.toml - |____tests - |____src - |____examplepackagefb1258 - |______init__.py - |______main__.py - |____wisdom.py + +--- +πŸ’» Run Locally (for teammates) + +If you want to run this project on your own machine (e.g., to test or modify it): + +# 1️⃣ Clone the repository +```bash +git clone https://github.com/your-username/pyfortunecookie.git +cd pyfortunecookie ``` -3. Make `__init__.py` an empty file. -4. Enter the text of a [copyright license of your choosing](https://choosealicense.com/) into `LICENSE`. -5. Add settings in `pyproject.toml` suitable for a `setuptools`-based build and add metadata fields to this file - see the example in this repository. -6. Put your own custom module code into `src`/`examplepackagefb1258`/`wisdom.py` or whatever filename(s) you choose for the module(s) that live within your package. -7. Optionally add a `__main__.py` file to the package directory, if you want to be able to run the package as a script from the command line, e.g. `python -m examplepackagefb1258`. -8. Build the project by running `python -m build` from the same directory where the `pyproject.toml` file is located. -9. Verify that the built `.tar` archive has the files you expect your package to have (including any important non-code files) by running the command: `tar --list -f dist/examplepackagefb1258-0.0.7.tar.gz`, where `examplepackagefb1258-0.0.7` is replaced with your own package name and version. -10. Create an account on [TestPyPI](https://test.pypi.org/) where one can upload to a test repository instead of the production PyPI repo. -11. Create a [new API token](https://test.pypi.org/manage/account/#api-tokens) on TestPyPI with the "Scope" set to β€œEntire account”. Save a copy of the token somewhere safe. -12. [Upload your package](examplepackagefb1258) to the TestPyPI repository using twine, e.g. `twine upload -r testpypi dist/*` -13. twine will output the URL of your package on the PyPI website - load that URL in your web browser to see your packaged published - make sure the `README.md` file looks nice on the web site. +# 2️⃣ Install pipenv and dependencies +```bash +pip install pipenv +pipenv install +``` +# 3️⃣ Enter the virtual environment +```bash +pipenv shell +``` +# 4️⃣ Run the tests (optional, to verify everything works) +```bash +pipenv run pytest +```bash +# 5️⃣ Run the package +```bash +python3 -m pyfortunecookie +``` -Every time you change the code in your package, you will need to rebuild and reupload it to PyPI. You will need to build from a clean slate and update the version number to achieve this: +πŸ’‘ You can exit the environment anytime with: -1. delete the autogenerated `dist` directory -2. delete the autogenerated `src/*.egg-info` directory -3. update the version number in `pyproject.toml` and anywhere else it is mentioned (do a find/replace) -4. build the package again with `python -m build` -5. upload the package again with `twine upload -r testpypi dist/*` +``` +exit +``` +--- + +## πŸš€ Usage -Repeat as many times as necessary until the package works as expected. +You can run PyFortuneCookie either from the **command line** or directly as a **Python module**. -If updating version numbers is tedious, you may consider using [bumpver](https://pypi.org/project/bumpver/#configuration-setup) - a tool that can automate some parts of updating version numbers. +### ▢️ Option 1: Run as command-line tool + +```bash +pipenv run pyfortunecookie +``` -**Once complete, upload to the real PyPI** instead of the TestPyPI repository. +### ▢️ Option 2: Run as a Python module -## How to install and use this package +```bash +pipenv run python -m pyfortunecookie +``` -Try [installing and using your package](https://packaging.python.org/en/latest/tutorials/packaging-projects/#installing-your-newly-uploaded-package) in a separate Python project: +### ▢️ Option 3: Import and use functions in your code -1. Create a `pipenv`-managed virtual environment and install the latest version of your package installed: `pipenv install -i https://test.pypi.org/simple/ examplepackagefb1258==0.0.7`. (Note that if you've previously created a `pipenv` virtual environment in the same directory, you may have to delete the old one first. Find out where it is located with the `pipenv --venv` command.) -1. Activate the virtual environment: `pipenv shell`. -1. Create a Python program file that imports your package and uses it, e.g. `from examplepackagefb1258 import wisdom` and then `print(wisdom.get())` (replace `wisdom` and `get()` with any module name and function that exists in your package) . -1. Run the program: `python3 my_program_filename.py`. -1. Exit the virtual environment: `exit`. +```python +from pyfortunecookie.core import get_fortune, get_lucky_number, get_color -Try running the package directly: +print(get_fortune()) +print(get_lucky_number()) +print(get_color()) +``` -1. Create and activate up the `pipenv` virtual environment as before. -2. Run the package directly from the command line: `python3 -m examplepackagefb1258`. This should run the code in the `__main__.py` file. -3. Exit the virtual environment. +--- -## How to run unit tests +## 🌟 Example Output -Simple example unit tests are included within the `tests` directory. To run these tests... +When you run the command: -1. Install `pytest` into the virtual environment, e.g. `pipenv install pytest` -1. Run the tests from the main project directory: `python3 -m pytest`. -1. Tests should never fail. Any failed tests indicate that the production code is behaving differently from the behavior the tests expect. +```bash +pipenv run pyfortunecookie +``` -## How to calculate code coverage +You might see something like this: -To calculate the "code coverage" of the unit tests, use the `coverage` package. +``` +πŸ₯  Welcome to PyFortune Cookie! -1. Install `coverage` and `pytest-cov` into the virtual environment, e.g. `pipenv install coverage pytest-cov` -1. Run the tests with a coverage report included at the bottom, e.g. `python3 -m pytest --cov=.` +Today's fortune: Your curiosity will lead to something amazing today ✨ +Your lucky number: 37 +Your lucky color: Lavender +``` + +Each time you run it, you’ll get a new random fortune, number, and color! + +--- + +## 🧠 Features + +| Function | Description | +| -------------------- | -------------------------------- | +| `get_fortune()` | Returns a random fortune message | +| `get_lucky_number()` | Generates a random lucky number | +| `get_color()` | Returns a random lucky color | + +--- + +## πŸ§ͺ Run Tests + +Make sure everything works properly with: + +```bash +pipenv run pytest +``` + +All tests are located inside the `tests/` directory. + +--- + +## πŸ›  Project Structure + +``` +pyfortunecookie/ +β”œβ”€β”€ src/ +β”‚ └── pyfortunecookie/ +β”‚ β”œβ”€β”€ __init__.py +β”‚ β”œβ”€β”€ __main__.py +β”‚ └── core.py +β”œβ”€β”€ tests/ +β”‚ └── test_core.py +β”œβ”€β”€ Pipfile +β”œβ”€β”€ pyproject.toml +└── README.md +``` -## Pro tip +--- -While working on the package code, and verifying it behaves as expected, it can be helpful to install the package in "_editable_" mode so that changes to the package are immediately updated in the virtual environment. +## πŸ‘©β€πŸ’» Author -- To do this, run `pipenv install -e .` from the main project directory. +Created by **Sina Liu** (NYU SWE Fall 2025) +-- a practice for SWE Project 3! 🌈 -## Continuous integration -This project has a continuous integration workflow that builds and runs unit tests automatically with every _push_ of the code to GitHub. diff --git a/pyproject.toml b/pyproject.toml index 96d77a6..1e7903d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,15 +3,15 @@ requires = ["setuptools>=61.0", "wheel"] build-backend = "setuptools.build_meta" [project] -name = "examplepackagefb1258" -description = "An example of a package developed with pipenv, built with build using setuptools, uploaded to PyPI using twine, and distributed via pip." -version = "0.1.2" +name = "pyfortunecookie" +description = "A fun fortune cookie generator with lucky number and color" +version = "0.1.0" authors = [ - { name="Foo Barstein", email="foo.barstein@onepotcooking.com" }, + { name="SinaL0123", email="sl9608@nyu.edu" }, ] license = { file = "LICENSE" } readme = "README.md" -keywords = ["python", "package", "build", "tutorial"] +keywords = ["fortune", "fun", "demo"] requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", @@ -24,9 +24,9 @@ classifiers = [ dev = ["pytest"] [project.urls] -"Homepage" = "https://github.com/nyu-software-engineering/python-package-example" -"Repository" = "https://github.com/nyu-software-engineering/python-package-example.git" -"Bug Tracker" = "https://github.com/nyu-software-engineering/python-package-example/issues" +"Homepage" = "https://github.com/your-username/python-package-practice" +"Repository" = "https://github.com/your-username/python-package-practice.git" +"Bug Tracker" = "https://github.com/your-username/python-package-practice/issues" [project.scripts] -examplepackagefb1258 = "examplepackagefb1258.__main__:main" +pyfortunecookie = "pyfortunecookie.__main__:main" diff --git a/src/examplepackagefb1258/__main__.py b/src/examplepackagefb1258/__main__.py deleted file mode 100644 index fbf5044..0000000 --- a/src/examplepackagefb1258/__main__.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -In Python packages, this file called __main__.py is run when the package is run -directly from command line, as opposed to importing it into another program. -""" - -import examplepackagefb1258.wisdom as wisdom - - -def main(): - """ - Get some wise text and print it out. - """ - line = wisdom.get() # get a line of text - print(line) # print it out - - -if __name__ == "__main__": - # run the main function - main() diff --git a/src/examplepackagefb1258/wisdom.py b/src/examplepackagefb1258/wisdom.py deleted file mode 100644 index f8aced9..0000000 --- a/src/examplepackagefb1258/wisdom.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -This module provides a function to retrieve a pseudo-random line from Lewis Carroll's poem "The Jabberwocky". -Read more about Jabberwocky here: https://en.wikipedia.org/wiki/Jabberwocky -""" - -import random - - -def get(): - """ - Returns a pseudo-random line from Lewis Carroll's "The Jabberwocky". Empty lines will not be returned. - """ - - text = """Twas brillig, and the slithy toves -Did gyre and gimble in the wabe; -All mimsy were the borogoves, -And the mome raths outgrabe. - -"Beware the Jabberwock, my son! -The jaws that bite, the claws that catch! -Beware the Jubjub bird, and shun -The frumious Bandersnatch!" - -He took his vorpal sword in hand: -Long time the manxome foe he soughtβ€” -So rested he by the Tumtum tree, -And stood awhile in thought. - -And as in uffish thought he stood, -The Jabberwock, with eyes of flame, -Came whiffling through the tulgey wood, -And burbled as it came! - -One, two! One, two! And through and through -The vorpal blade went snicker-snack! -He left it dead, and with its head -He went galumphing back. - -"And hast thou slain the Jabberwock? -Come to my arms, my beamish boy! -O frabjous day! Callooh! Callay!" -He chortled in his joy. - -'Twas brillig, and the slithy toves -Did gyre and gimble in the wabe; -All mimsy were the borogoves, -And the mome raths outgrabe.""" - - lines = text.split("\n") - lines = [line for line in lines if line.strip() != ""] # remove empty lines - random_line = random.choice(lines) - return random_line diff --git a/src/examplepackagefb1258/__init__.py b/src/pyfortunecookie/__init__.py similarity index 78% rename from src/examplepackagefb1258/__init__.py rename to src/pyfortunecookie/__init__.py index f187532..73417de 100644 --- a/src/examplepackagefb1258/__init__.py +++ b/src/pyfortunecookie/__init__.py @@ -8,3 +8,6 @@ For more information, see the official documentation: https://docs.python.org/3/reference/import.html#regular-packages """ +from .core import get_fortune, get_lucky_number, get_color + +__all__ = ["get_fortune", "get_lucky_number", "get_color"] diff --git a/src/pyfortunecookie/__main__.py b/src/pyfortunecookie/__main__.py new file mode 100644 index 0000000..466d7e0 --- /dev/null +++ b/src/pyfortunecookie/__main__.py @@ -0,0 +1,15 @@ +""" +In Python packages, this file called __main__.py is run when the package is run +directly from command line, as opposed to importing it into another program. +""" + +from pyfortunecookie.core import get_fortune, get_lucky_number, get_color + +def main(): + print("πŸ₯  Welcome to PyFortune Cookie!\n") + print(f"Today's fortune: {get_fortune()}") + print(f"Your lucky number: {get_lucky_number()}") + print(f"Your lucky color: {get_color()}") + +if __name__ == "__main__": + main() diff --git a/src/pyfortunecookie/core.py b/src/pyfortunecookie/core.py new file mode 100644 index 0000000..4d60367 --- /dev/null +++ b/src/pyfortunecookie/core.py @@ -0,0 +1,37 @@ +import random + +_FORTUNES = [ + "Today is a good day to start small.", + "A pleasant surprise is waiting for you.", + "Your code will compile on the first try.", + "Help others and luck will help you.", + "Take a short walk; ideas will follow.", + "A cup of coffee will solve half your problems. β˜•", + "You will soon discover a hidden strength. πŸ’ͺ", + "Your curiosity is your superpower. πŸ”" +] + +_PALETTES = { + "soft": ["peach", "mint", "lavender", "sky", "lemon"], + "bold": ["crimson", "indigo", "emerald", "amber", "teal"], + "mono": ["black", "white", "gray"] +} + +def get_fortune(rng: random.Random | None = None) -> str: + """Return a random fortune sentence.""" + rng = rng or random + return rng.choice(_FORTUNES) + +def get_lucky_number(seed: int | None = None, min_value: int = 1, max_value: int = 99) -> int: + """Return a lucky number (optionally deterministic if seed provided).""" + if min_value > max_value: + raise ValueError("min_value must be <= max_value") + rng = random.Random(seed) if seed is not None else random + return rng.randint(min_value, max_value) + +def get_color(palette: str = "soft", rng: random.Random | None = None) -> str: + """Return a lucky color from the selected palette.""" + if palette not in _PALETTES: + raise ValueError(f"Unknown palette '{palette}'. Valid: {', '.join(_PALETTES)}") + rng = rng or random + return rng.choice(_PALETTES[palette]) diff --git a/tests/test_core.py b/tests/test_core.py new file mode 100644 index 0000000..f13d8c2 --- /dev/null +++ b/tests/test_core.py @@ -0,0 +1,24 @@ +import pytest +from pyfortunecookie import get_fortune, get_lucky_number, get_color + +def test_get_fortune_returns_string(): + result = get_fortune() + assert isinstance(result, str) + assert len(result) > 0 + +def test_get_lucky_number_range_and_seed(): + x = get_lucky_number(seed=42, min_value=10, max_value=20) + assert 10 <= x <= 20 + assert x == get_lucky_number(seed=42, min_value=10, max_value=20) + +def test_get_lucky_number_invalid_range(): + with pytest.raises(ValueError): + get_lucky_number(min_value=5, max_value=4) + +def test_get_color_valid_palettes(): + assert get_color("soft") in {"peach","mint","lavender","sky","lemon"} + assert get_color("bold") in {"crimson","indigo","emerald","amber","teal"} + +def test_get_color_invalid_palette(): + with pytest.raises(ValueError): + get_color("rainbow") diff --git a/tests/test_wisdom.py b/tests/test_wisdom.py deleted file mode 100644 index 5c3cffd..0000000 --- a/tests/test_wisdom.py +++ /dev/null @@ -1,96 +0,0 @@ -import pytest -from examplepackagefb1258 import wisdom - - -class Tests: - # - # Fixtures - these are functions that can do any optional setup or teardown before or after a test function is run. - # - - @pytest.fixture - def example_fixture(self): - """ - An example of a pytest fixture - a function that can be used for setup and teardown before and after test functions are run. - """ - - # place any setup you want to do before any test function that uses this fixture is run - - yield # at th=e yield point, the test function will run and do its business - - # place with any teardown you want to do after any test function that uses this fixture has completed - - # - # Test functions - # - - def test_sanity_check(self, example_fixture): - """ - Test debugging... making sure that we can run a simple test that always passes. - Note the use of the example_fixture in the parameter list - any setup and teardown in that fixture will be run before and after this test function executes - From the main project directory, run the `python3 -m pytest` command to run all tests. - """ - expected = True # the value we expect to be present - actual = True # the value we see in reality - assert actual == expected, "Expected True to be equal to True!" - - def test_get(self): - """ - Verify get() function and make sure it returns a non-empty string. - Note that for example purposes, we have not used the example_fixture in this test functino. - """ - # since get returns a random string, run it a bunch of times and verify the output - for i in range(100): - actual = wisdom.get() - assert isinstance( - actual, str - ), f"Expected get() to return a string. Instead, it returned {actual}" - assert ( - len(actual) > 0 - ), f"Expected get() not to be empty. Instead, it returned a string with {len(actual)} characters" - - def test_content(self): - """ - Make sure that the text returned by the get() function is actually from the correct poem. - """ - # the full text of the actual Jabberwocky poem by Lewis Carroll - full_text = """Twas brillig, and the slithy toves -Did gyre and gimble in the wabe; -All mimsy were the borogoves, -And the mome raths outgrabe. - -"Beware the Jabberwock, my son! -The jaws that bite, the claws that catch! -Beware the Jubjub bird, and shun -The frumious Bandersnatch!" - -He took his vorpal sword in hand: -Long time the manxome foe he soughtβ€” -So rested he by the Tumtum tree, -And stood awhile in thought. - -And as in uffish thought he stood, -The Jabberwock, with eyes of flame, -Came whiffling through the tulgey wood, -And burbled as it came! - -One, two! One, two! And through and through -The vorpal blade went snicker-snack! -He left it dead, and with its head -He went galumphing back. - -"And hast thou slain the Jabberwock? -Come to my arms, my beamish boy! -O frabjous day! Callooh! Callay!" -He chortled in his joy. - -'Twas brillig, and the slithy toves -Did gyre and gimble in the wabe; -All mimsy were the borogoves, -And the mome raths outgrabe.""" - - # since get returns a random string, run it a bunch of times and verify the output - for i in range(100): - actual = wisdom.get() - assert ( - actual in full_text - ), f"Expected the text returned by get() to be from the Jabberwocky poem by Lewis Carroll. Instead, it returned '{actual}'."