uk_bin_collection 0.76.1__tar.gz → 0.78.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/PKG-INFO +1 -1
  2. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/pyproject.toml +1 -1
  3. uk_bin_collection-0.78.0/uk_bin_collection/tests/council_feature_input_parity.py +128 -0
  4. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/features/validate_council_outputs.feature +10 -0
  5. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/input.json +15 -2
  6. uk_bin_collection-0.78.0/uk_bin_collection/uk_bin_collection/councils/BracknellForestCouncil.py +246 -0
  7. uk_bin_collection-0.78.0/uk_bin_collection/uk_bin_collection/councils/FarehamBoroughCouncil.py +69 -0
  8. uk_bin_collection-0.76.1/uk_bin_collection/tests/council_feature_input_parity.py +0 -91
  9. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/LICENSE +0 -0
  10. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/README.md +0 -0
  11. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/README.rst +0 -0
  12. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/features/environment.py +0 -0
  13. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/output.schema +0 -0
  14. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/step_defs/step_helpers/file_handler.py +0 -0
  15. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/step_defs/test_validate_council.py +0 -0
  16. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/test_collect_data.py +0 -0
  17. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/tests/test_common_functions.py +0 -0
  18. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/collect_data.py +0 -0
  19. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/common.py +0 -0
  20. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/AdurAndWorthingCouncils.py +0 -0
  21. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ArunCouncil.py +0 -0
  22. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/AylesburyValeCouncil.py +0 -0
  23. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BCPCouncil.py +0 -0
  24. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BarnetCouncil.py +0 -0
  25. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BarnsleyMBCouncil.py +0 -0
  26. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BasingstokeCouncil.py +0 -0
  27. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BathAndNorthEastSomersetCouncil.py +0 -0
  28. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BedfordBoroughCouncil.py +0 -0
  29. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BedfordshireCouncil.py +0 -0
  30. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BexleyCouncil.py +0 -0
  31. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BirminghamCityCouncil.py +0 -0
  32. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BlackburnCouncil.py +0 -0
  33. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BoltonCouncil.py +0 -0
  34. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BradfordMDC.py +0 -0
  35. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BrightonandHoveCityCouncil.py +0 -0
  36. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BristolCityCouncil.py +0 -0
  37. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BromleyBoroughCouncil.py +0 -0
  38. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BroxtoweBoroughCouncil.py +0 -0
  39. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BuckinghamshireCouncil.py +0 -0
  40. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/BuryCouncil.py +0 -0
  41. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CalderdaleCouncil.py +0 -0
  42. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CannockChaseDistrictCouncil.py +0 -0
  43. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CardiffCouncil.py +0 -0
  44. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CastlepointDistrictCouncil.py +0 -0
  45. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CharnwoodBoroughCouncil.py +0 -0
  46. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ChelmsfordCityCouncil.py +0 -0
  47. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CheshireEastCouncil.py +0 -0
  48. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CheshireWestAndChesterCouncil.py +0 -0
  49. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ChorleyCouncil.py +0 -0
  50. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ConwyCountyBorough.py +0 -0
  51. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CrawleyBoroughCouncil.py +0 -0
  52. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/CroydonCouncil.py +0 -0
  53. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/DerbyshireDalesDistrictCouncil.py +0 -0
  54. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/DoncasterCouncil.py +0 -0
  55. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/DorsetCouncil.py +0 -0
  56. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/DoverDistrictCouncil.py +0 -0
  57. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/DurhamCouncil.py +0 -0
  58. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastCambridgeshireCouncil.py +0 -0
  59. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastDevonDC.py +0 -0
  60. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastLindseyDistrictCouncil.py +0 -0
  61. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastRidingCouncil.py +0 -0
  62. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastSuffolkCouncil.py +0 -0
  63. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EastleighBoroughCouncil.py +0 -0
  64. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/EnvironmentFirst.py +0 -0
  65. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ErewashBoroughCouncil.py +0 -0
  66. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/FenlandDistrictCouncil.py +0 -0
  67. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ForestOfDeanDistrictCouncil.py +0 -0
  68. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/GatesheadCouncil.py +0 -0
  69. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/GedlingBoroughCouncil.py +0 -0
  70. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/GlasgowCityCouncil.py +0 -0
  71. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/GuildfordCouncil.py +0 -0
  72. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HaltonBoroughCouncil.py +0 -0
  73. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HaringeyCouncil.py +0 -0
  74. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HarrogateBoroughCouncil.py +0 -0
  75. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HighPeakCouncil.py +0 -0
  76. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HullCityCouncil.py +0 -0
  77. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/HuntingdonDistrictCouncil.py +0 -0
  78. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/KingstonUponThamesCouncil.py +0 -0
  79. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/KirkleesCouncil.py +0 -0
  80. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/KnowsleyMBCouncil.py +0 -0
  81. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LancasterCityCouncil.py +0 -0
  82. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LeedsCityCouncil.py +0 -0
  83. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LisburnCastlereaghCityCouncil.py +0 -0
  84. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LiverpoolCityCouncil.py +0 -0
  85. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LondonBoroughHounslow.py +0 -0
  86. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/LondonBoroughRedbridge.py +0 -0
  87. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MaldonDistrictCouncil.py +0 -0
  88. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MalvernHillsDC.py +0 -0
  89. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ManchesterCityCouncil.py +0 -0
  90. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MansfieldDistrictCouncil.py +0 -0
  91. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MertonCouncil.py +0 -0
  92. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MidAndEastAntrimBoroughCouncil.py +0 -0
  93. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MidSussexDistrictCouncil.py +0 -0
  94. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MiltonKeynesCityCouncil.py +0 -0
  95. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/MoleValleyDistrictCouncil.py +0 -0
  96. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NeathPortTalbotCouncil.py +0 -0
  97. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NewarkAndSherwoodDC.py +0 -0
  98. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NewcastleCityCouncil.py +0 -0
  99. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NewhamCouncil.py +0 -0
  100. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NewportCityCouncil.py +0 -0
  101. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthEastDerbyshireDistrictCouncil.py +0 -0
  102. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthEastLincs.py +0 -0
  103. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthKestevenDistrictCouncil.py +0 -0
  104. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthLanarkshireCouncil.py +0 -0
  105. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthLincolnshireCouncil.py +0 -0
  106. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthNorfolkDistrictCouncil.py +0 -0
  107. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthNorthamptonshireCouncil.py +0 -0
  108. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthSomersetCouncil.py +0 -0
  109. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthTynesideCouncil.py +0 -0
  110. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthWestLeicestershire.py +0 -0
  111. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthYorkshire.py +0 -0
  112. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NorthumberlandCouncil.py +0 -0
  113. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/NottinghamCityCouncil.py +0 -0
  114. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/OldhamCouncil.py +0 -0
  115. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/PortsmouthCityCouncil.py +0 -0
  116. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/PrestonCityCouncil.py +0 -0
  117. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ReadingBoroughCouncil.py +0 -0
  118. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ReigateAndBansteadBoroughCouncil.py +0 -0
  119. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RenfrewshireCouncil.py +0 -0
  120. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RhonddaCynonTaffCouncil.py +0 -0
  121. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RochdaleCouncil.py +0 -0
  122. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RochfordCouncil.py +0 -0
  123. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RugbyBoroughCouncil.py +0 -0
  124. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RushcliffeBoroughCouncil.py +0 -0
  125. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/RushmoorCouncil.py +0 -0
  126. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SalfordCityCouncil.py +0 -0
  127. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SevenoaksDistrictCouncil.py +0 -0
  128. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SheffieldCityCouncil.py +0 -0
  129. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ShropshireCouncil.py +0 -0
  130. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SolihullCouncil.py +0 -0
  131. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SomersetCouncil.py +0 -0
  132. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthAyrshireCouncil.py +0 -0
  133. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthCambridgeshireCouncil.py +0 -0
  134. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthGloucestershireCouncil.py +0 -0
  135. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthLanarkshireCouncil.py +0 -0
  136. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthNorfolkCouncil.py +0 -0
  137. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthOxfordshireCouncil.py +0 -0
  138. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SouthTynesideCouncil.py +0 -0
  139. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StAlbansCityAndDistrictCouncil.py +0 -0
  140. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StHelensBC.py +0 -0
  141. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StaffordshireMoorlandsDistrictCouncil.py +0 -0
  142. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StockportBoroughCouncil.py +0 -0
  143. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StokeOnTrentCityCouncil.py +0 -0
  144. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/StratfordUponAvonCouncil.py +0 -0
  145. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SunderlandCityCouncil.py +0 -0
  146. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/SwaleBoroughCouncil.py +0 -0
  147. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TamesideMBCouncil.py +0 -0
  148. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TandridgeDistrictCouncil.py +0 -0
  149. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TelfordAndWrekinCouncil.py +0 -0
  150. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TestValleyBoroughCouncil.py +0 -0
  151. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TonbridgeAndMallingBC.py +0 -0
  152. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TorbayCouncil.py +0 -0
  153. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/TorridgeDistrictCouncil.py +0 -0
  154. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ValeofGlamorganCouncil.py +0 -0
  155. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/ValeofWhiteHorseCouncil.py +0 -0
  156. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WakefieldCityCouncil.py +0 -0
  157. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WarwickDistrictCouncil.py +0 -0
  158. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WaverleyBoroughCouncil.py +0 -0
  159. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WealdenDistrictCouncil.py +0 -0
  160. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WelhatCouncil.py +0 -0
  161. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WestBerkshireCouncil.py +0 -0
  162. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WestLindseyDistrictCouncil.py +0 -0
  163. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WestLothianCouncil.py +0 -0
  164. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WestNorthamptonshireCouncil.py +0 -0
  165. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WestSuffolkCouncil.py +0 -0
  166. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WiganBoroughCouncil.py +0 -0
  167. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WiltshireCouncil.py +0 -0
  168. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WindsorAndMaidenheadCouncil.py +0 -0
  169. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WokingBoroughCouncil.py +0 -0
  170. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/WyreCouncil.py +0 -0
  171. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/YorkCouncil.py +0 -0
  172. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/councils/council_class_template/councilclasstemplate.py +0 -0
  173. {uk_bin_collection-0.76.1 → uk_bin_collection-0.78.0}/uk_bin_collection/uk_bin_collection/get_bin_data.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uk_bin_collection
3
- Version: 0.76.1
3
+ Version: 0.78.0
4
4
  Summary: Python Lib to collect UK Bin Data
5
5
  Author: Robert Bradley
6
6
  Author-email: robbrad182@gmail.com
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "uk_bin_collection"
3
- version = "0.76.1"
3
+ version = "0.78.0"
4
4
  description = "Python Lib to collect UK Bin Data"
5
5
  readme = "README.md"
6
6
  authors = ["Robert Bradley <robbrad182@gmail.com>"]
@@ -0,0 +1,128 @@
1
+ import json
2
+ import re
3
+ import requests
4
+ import sys
5
+ from tabulate import tabulate
6
+
7
+ def get_councils_from_files(repo, branch):
8
+ url = f"https://api.github.com/repos/{repo}/contents/uk_bin_collection/uk_bin_collection/councils?ref={branch}"
9
+ print(f"Fetching councils from files at URL: {url}")
10
+ response = requests.get(url)
11
+
12
+ # Debugging lines to check the response content and type
13
+ print(f"Response Status Code (Files): {response.status_code}")
14
+
15
+ if response.status_code == 200:
16
+ try:
17
+ data = response.json()
18
+ #print(f"Parsed JSON Data (Files): {data}")
19
+ # Ensure 'data' is a list before proceeding
20
+ if isinstance(data, list):
21
+ return [item['name'].replace('.py', '') for item in data if item['name'].endswith('.py')]
22
+ else:
23
+ print("Expected a list from the JSON response but got something else.")
24
+ raise ValueError("Expected a list from the JSON response but got something else.")
25
+ except json.JSONDecodeError as e:
26
+ print(f"JSON decoding error: {e}")
27
+ raise
28
+ else:
29
+ print(f"Failed to fetch councils from files: {response.content}")
30
+ return []
31
+
32
+ def get_councils_from_json(repo, branch):
33
+ url = f"https://raw.githubusercontent.com/{repo}/{branch}/uk_bin_collection/tests/input.json"
34
+ print(f"Fetching councils from JSON at URL: {url}")
35
+ response = requests.get(url)
36
+
37
+ # Debugging lines to check the response content and type
38
+ print(f"Response Status Code (JSON): {response.status_code}")
39
+
40
+ if response.status_code == 200:
41
+ try:
42
+ data = json.loads(response.text)
43
+ #print(f"Parsed JSON Data: {data}")
44
+ return list(data.keys())
45
+ except json.JSONDecodeError as e:
46
+ print(f"JSON decoding error: {e}")
47
+ raise
48
+ else:
49
+ print(f"Failed to fetch councils from JSON: {response.content}")
50
+ return []
51
+
52
+ def get_councils_from_features(repo, branch):
53
+ url = f"https://raw.githubusercontent.com/{repo}/{branch}/uk_bin_collection/tests/features/validate_council_outputs.feature"
54
+ print(f"Fetching councils from features at URL: {url}")
55
+ response = requests.get(url)
56
+
57
+ # Debugging lines to check the response content and type
58
+ print(f"Response Status Code (Features): {response.status_code}")
59
+
60
+ if response.status_code == 200:
61
+ content = response.text
62
+ #print(f"Fetched Features Content: {content[:500]}...") # Print only the first 500 characters for brevity
63
+ return re.findall(r'Examples:\s+(\w+)', content)
64
+ else:
65
+ print(f"Failed to fetch councils from features: {response.content}")
66
+ return []
67
+
68
+ def compare_councils(councils1, councils2, councils3):
69
+ set1 = set(councils1)
70
+ set2 = set(councils2)
71
+ set3 = set(councils3)
72
+ all_councils = set1 | set2 | set3
73
+ all_council_data = {}
74
+ discrepancies_found = False
75
+ for council in all_councils:
76
+ in_files = council in set1
77
+ in_json = council in set2
78
+ in_features = council in set3
79
+ discrepancies_count = [in_files, in_json, in_features].count(False)
80
+ all_council_data[council] = {
81
+ 'in_files': in_files,
82
+ 'in_json': in_json,
83
+ 'in_features': in_features,
84
+ 'discrepancies_count': discrepancies_count
85
+ }
86
+ if discrepancies_count > 0:
87
+ discrepancies_found = True
88
+ return all_council_data, discrepancies_found
89
+
90
+ def main(repo="robbrad/UKBinCollectionData", branch="master"):
91
+ # Execute and print the comparison
92
+ print(f"Starting comparison for repo: {repo}, branch: {branch}")
93
+ file_councils = get_councils_from_files(repo, branch)
94
+ json_councils = get_councils_from_json(repo, branch)
95
+ feature_councils = get_councils_from_features(repo, branch)
96
+
97
+ #print(f"Councils from files: {file_councils}")
98
+ #print(f"Councils from JSON: {json_councils}")
99
+ #print(f"Councils from features: {feature_councils}")
100
+
101
+ all_councils_data, discrepancies_found = compare_councils(file_councils, json_councils, feature_councils)
102
+
103
+ # Create a list of lists for tabulate, sort by discrepancies count and then by name
104
+ table_data = []
105
+ headers = ["Council Name", "In Files", "In JSON", "In Features", "Discrepancies"]
106
+ for council, presence in sorted(all_councils_data.items(), key=lambda x: (x[1]['discrepancies_count'], x[0])):
107
+ row = [
108
+ council,
109
+ "✔" if presence['in_files'] else "✘",
110
+ "✔" if presence['in_json'] else "✘",
111
+ "✔" if presence['in_features'] else "✘",
112
+ presence['discrepancies_count']
113
+ ]
114
+ table_data.append(row)
115
+
116
+ # Print the table using tabulate
117
+ print(tabulate(table_data, headers=headers, tablefmt='grid'))
118
+
119
+ if discrepancies_found:
120
+ print("Discrepancies found! Failing the workflow.")
121
+ sys.exit(1)
122
+ else:
123
+ print("No discrepancies found. Workflow successful.")
124
+
125
+ if __name__ == "__main__":
126
+ repo = sys.argv[1] if len(sys.argv) > 1 else "robbrad/UKBinCollectionData"
127
+ branch = sys.argv[2] if len(sys.argv) > 2 else "master"
128
+ main(repo, branch)
@@ -76,6 +76,11 @@ Feature: Test each council output matches expected results
76
76
  | council |
77
77
  | BoltonCouncil |
78
78
 
79
+ @BracknellForestCouncil
80
+ Examples: BracknellForestCouncil
81
+ | council |
82
+ | BracknellForestCouncil |
83
+
79
84
  @BradfordMDC
80
85
  Examples: BradfordMDC
81
86
  | council |
@@ -236,6 +241,11 @@ Feature: Test each council output matches expected results
236
241
  | council |
237
242
  | ErewashBoroughCouncil |
238
243
 
244
+ @FarehamBoroughCouncil
245
+ Examples: FarehamBoroughCouncil
246
+ | council |
247
+ | FarehamBoroughCouncil |
248
+
239
249
  @FenlandDistrictCouncil
240
250
  Examples: FenlandDistrictCouncil
241
251
  | council |
@@ -101,6 +101,13 @@
101
101
  "wiki_name": "Bolton Council",
102
102
  "wiki_note": "To get the UPRN, you will need to use [FindMyAddress](https://www.findmyaddress.co.uk/search). Previously required single field that was UPRN and full address, now requires UPRN and postcode as separate fields."
103
103
  },
104
+ "BracknellForestCouncil": {
105
+ "paon": "57",
106
+ "postcode": "GU47 9BS",
107
+ "skip_get_url": true,
108
+ "url": "https://selfservice.mybfc.bracknell-forest.gov.uk/w/webpage/waste-collection-days",
109
+ "wiki_name": "Bracknell Forest Council"
110
+ },
104
111
  "BradfordMDC": {
105
112
  "custom_component_show_url_field": false,
106
113
  "skip_get_url": true,
@@ -209,8 +216,8 @@
209
216
  "CheshireWestAndChesterCouncil": {
210
217
  "house_number": "Hill View House",
211
218
  "postcode": "CH3 9ER",
212
- "uprn": "100012346655",
213
219
  "skip_get_url": true,
220
+ "uprn": "100012346655",
214
221
  "url": "https://www.cheshirewestandchester.gov.uk/residents/waste-and-recycling/your-bin-collection/collection-day",
215
222
  "web_driver": "http://selenium:4444",
216
223
  "wiki_name": "Cheshire West and Chester Council"
@@ -335,6 +342,12 @@
335
342
  "url": "https://map.erewash.gov.uk/isharelive.web/myerewash.aspx",
336
343
  "wiki_name": "Erewash Borough Council"
337
344
  },
345
+ "FarehamBoroughCouncil": {
346
+ "postcode": "PO14 4NR",
347
+ "skip_get_url": true,
348
+ "url": "https://www.fareham.gov.uk/internetlookups/search_data.aspx?type=JSON&list=DomesticBinCollections&Road=&Postcode=PO14%204NR",
349
+ "wiki_name": "Fareham Borough Council"
350
+ },
338
351
  "FenlandDistrictCouncil": {
339
352
  "skip_get_url": true,
340
353
  "uprn": "200002981143",
@@ -1027,8 +1040,8 @@
1027
1040
  },
1028
1041
  "WestSuffolkCouncil": {
1029
1042
  "postcode": "IP28 6DR",
1030
- "uprn": "10009739960",
1031
1043
  "skip_get_url": true,
1044
+ "uprn": "10009739960",
1032
1045
  "url": "https://maps.westsuffolk.gov.uk/MyWestSuffolk.aspx",
1033
1046
  "wiki_name": "West Suffolk Council"
1034
1047
  },
@@ -0,0 +1,246 @@
1
+ import time
2
+
3
+ from bs4 import BeautifulSoup
4
+
5
+ from uk_bin_collection.uk_bin_collection.common import *
6
+ from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
7
+
8
+
9
+ def get_headers(base_url: str, method: str) -> dict[str, str]:
10
+ """
11
+ Gets request headers
12
+ :rtype: dict[str, str]
13
+ :param base_url: Base URL to use
14
+ :param method: Method to use
15
+ :return: Request headers
16
+ """
17
+ headers = {
18
+ "Accept-Encoding": "gzip, deflate, br",
19
+ "Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
20
+ "Cache-Control": "max-age=0",
21
+ "Connection": "keep-alive",
22
+ "Host": "selfservice.mybfc.bracknell-forest.gov.uk",
23
+ "Origin": base_url,
24
+ "sec-ch-ua": '"Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"',
25
+ "sec-ch-ua-mobile": "?0",
26
+ "sec-ch-ua-platform": "Windows",
27
+ "Sec-Fetch-Dest": "document",
28
+ "Sec-Fetch-User": "?1",
29
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"
30
+ " Chrome/109.0.0.0 Safari/537.36",
31
+ }
32
+ if method.lower() == "post":
33
+ headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
34
+ headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8"
35
+ headers["Sec-Fetch-Mode"] = "cors"
36
+ headers["Sec-Fetch-Mode"] = "same-origin"
37
+ headers["X-Requested-With"] = "XMLHttpRequest"
38
+ else:
39
+ headers["Accept"] = (
40
+ "text/html,application/xhtml+xml,application/xml;"
41
+ "q=0.9,image/avif,image/webp,image/apng,*/*;"
42
+ "q=0.8,application/signed-exchange;v=b3;q=0.9"
43
+ )
44
+ headers["Sec-Fetch-Mode"] = "navigate"
45
+ headers["Sec-Fetch-Mode"] = "none"
46
+ return headers
47
+
48
+
49
+ def get_session_storage_global() -> object:
50
+ """
51
+ Gets session storage global object
52
+ :rtype: object
53
+ :return: Session storage global object
54
+ """
55
+ return {
56
+ "destination_stack": [
57
+ "w/webpage/waste-collection-days",
58
+ ],
59
+ "last_context_record_id": "86086077",
60
+ }
61
+
62
+
63
+ def get_csrf_token(s: requests.session, base_url: str) -> str:
64
+ """
65
+ Gets a CSRF token
66
+ :rtype: str
67
+ :param s: requests.session() to use
68
+ :param base_url: Base URL to use
69
+ :return: CSRF token
70
+ """
71
+ csrf_token = ""
72
+ response = s.get(
73
+ base_url + "/w/webpage/waste-collection-days",
74
+ headers=get_headers(base_url, "GET"),
75
+ )
76
+ if response.status_code == 200:
77
+ soup = BeautifulSoup(response.text, features="html.parser")
78
+ soup.prettify()
79
+ app_body = soup.find("div", {"class": "app-body"})
80
+ script = app_body.find("script", {"type": "text/javascript"}).string
81
+ p = re.compile("var CSRF = ('|\")(.*?)('|\");")
82
+ m = p.search(script)
83
+ csrf_token = m.groups()[1]
84
+ else:
85
+ raise ValueError(
86
+ "Code 1: Failed to get a CSRF token. Please ensure the council website is online first,"
87
+ " then open an issue on GitHub."
88
+ )
89
+ return csrf_token
90
+
91
+
92
+ def get_address_id(
93
+ s: requests.session, base_url: str, csrf_token: str, postcode: str, paon: str
94
+ ) -> str:
95
+ """
96
+ Gets the address ID
97
+ :rtype: str
98
+ :param s: requests.session() to use
99
+ :param base_url: Base URL to use
100
+ :param csrf_token: CSRF token to use
101
+ :param postcode: Postcode to use
102
+ :param paon: House number/address to find
103
+ :return: address ID
104
+ """
105
+ address_id = "0"
106
+ # Get the addresses for the postcode
107
+ form_data = {
108
+ "code_action": "find_addresses",
109
+ "code_params": '{"search":"' + postcode + '"}',
110
+ "_session_storage": json.dumps(
111
+ {
112
+ "/w/webpage/waste-collection-days": {},
113
+ "_global": get_session_storage_global(),
114
+ }
115
+ ),
116
+ "action_cell_id": "PCL0003988FEFFB1",
117
+ "action_page_id": "PAG0000570FEFFB1",
118
+ "form_check_ajax": csrf_token,
119
+ }
120
+ response = s.post(
121
+ base_url
122
+ + "/w/webpage/waste-collection-days?webpage_subpage_id=PAG0000570FEFFB1"
123
+ "&webpage_token=390170046582b0e3d7ca68ef1d6b4829ccff0b1ae9c531047219c6f9b5295738"
124
+ "&widget_action=handle_event",
125
+ headers=get_headers(base_url, "POST"),
126
+ data=form_data,
127
+ )
128
+ if response.status_code == 200:
129
+ json_response = json.loads(response.text)
130
+ addresses = json_response["response"]["addresses"]["items"]
131
+ # Find the matching address id for the paon
132
+ for address in addresses:
133
+ # Check for full matches first
134
+ if address.get("Description") == paon:
135
+ address_id = address.get("Id")
136
+ break
137
+ # Check for matching start if no full match found
138
+ if address_id == "0":
139
+ for address in addresses:
140
+ if address.get("Description").split()[0] == paon.strip():
141
+ address_id = address.get("Id")
142
+ break
143
+ # Check match was found
144
+ if address_id == "0":
145
+ raise ValueError(
146
+ "Code 2: No matching address for house number/full address found."
147
+ )
148
+ else:
149
+ raise ValueError("Code 3: No addresses found for provided postcode.")
150
+ return address_id
151
+
152
+
153
+ def get_collection_data(
154
+ s: requests.session, base_url: str, csrf_token: str, address_id: str
155
+ ) -> str:
156
+ """
157
+ Gets the collection data
158
+ :rtype: str
159
+ :param s: requests.session() to use
160
+ :param base_url: Base URL to use
161
+ :param csrf_token: CSRF token to use
162
+ :param address_id: Address id to use
163
+ :param retries: Retries count
164
+ :return: Collection data
165
+ """
166
+ collection_data = ""
167
+ if address_id != "0":
168
+ form_data = {
169
+ "code_action": "find_rounds",
170
+ "code_params": '{"addressId":"' + address_id + '"}',
171
+ "_session_storage": json.dumps(
172
+ {
173
+ "/w/webpage/waste-collection-days": {},
174
+ "_global": get_session_storage_global(),
175
+ }
176
+ ),
177
+ "action_cell_id": "PCL0003988FEFFB1",
178
+ "action_page_id": "PAG0000570FEFFB1",
179
+ "form_check_ajax": csrf_token,
180
+ }
181
+ response = s.post(
182
+ base_url
183
+ + "/w/webpage/waste-collection-days?webpage_subpage_id=PAG0000570FEFFB1"
184
+ "&webpage_token=390170046582b0e3d7ca68ef1d6b4829ccff0b1ae9c531047219c6f9b5295738"
185
+ "&widget_action=handle_event",
186
+ headers=get_headers(base_url, "POST"),
187
+ data=form_data,
188
+ )
189
+ if response.status_code == 200 and len(response.text) > 0:
190
+ json_response = json.loads(response.text)
191
+ collection_data = json_response["response"]["collections"]
192
+ else:
193
+ raise ValueError("Code 4: Failed to get bin data.")
194
+ return collection_data
195
+
196
+
197
+ class CouncilClass(AbstractGetBinDataClass):
198
+ """
199
+ Concrete classes have to implement all abstract operations of the
200
+ base class. They can also override some operations with a default
201
+ implementation.
202
+ """
203
+
204
+ def parse_data(self, page: str, **kwargs) -> dict:
205
+ requests.packages.urllib3.disable_warnings()
206
+ s = requests.session()
207
+ base_url = "https://selfservice.mybfc.bracknell-forest.gov.uk"
208
+ paon = kwargs.get("paon")
209
+ postcode = kwargs.get("postcode")
210
+ check_paon(paon)
211
+ check_postcode(postcode)
212
+
213
+ # Firstly, get a CSRF (cross-site request forgery) token
214
+ csrf_token = get_csrf_token(s, base_url)
215
+ # Next, get the address_id
216
+ address_id = get_address_id(s, base_url, csrf_token, postcode, paon)
217
+ # Finally, use the address_id to get the collection data
218
+ collection_data = get_collection_data(s, base_url, csrf_token, address_id)
219
+ if collection_data != "":
220
+ # Form a JSON wrapper
221
+ data = {"bins": []}
222
+
223
+ for c in collection_data:
224
+ collection_type = c["round"]
225
+ for c_date in c["upcomingCollections"]:
226
+ collection_date = (
227
+ re.search(r"Your (.*) is(.*)", c_date).group(2).strip()
228
+ )
229
+ dict_data = {
230
+ "type": collection_type,
231
+ "collectionDate": datetime.strptime(
232
+ collection_date, "%A %d %B %Y"
233
+ ).strftime(date_format),
234
+ }
235
+ data["bins"].append(dict_data)
236
+
237
+ if len(data["bins"]) == 0:
238
+ raise ValueError(
239
+ "Code 5: No bin data found. Please ensure the council website is showing data first,"
240
+ " then open an issue on GitHub."
241
+ )
242
+
243
+ data["bins"].sort(
244
+ key=lambda x: datetime.strptime(x.get("collectionDate"), date_format)
245
+ )
246
+ return data
@@ -0,0 +1,69 @@
1
+ import json
2
+
3
+ import requests
4
+ from uk_bin_collection.uk_bin_collection.common import *
5
+ from uk_bin_collection.uk_bin_collection.get_bin_data import AbstractGetBinDataClass
6
+
7
+ class CouncilClass(AbstractGetBinDataClass):
8
+ """
9
+ Concrete classes have to implement all abstract operations of the
10
+ base class. They can also override some operations with a default
11
+ implementation.
12
+ """
13
+
14
+ def parse_data(self, page: str, **kwargs) -> dict:
15
+ user_postcode = kwargs.get("postcode")
16
+ check_postcode(user_postcode)
17
+
18
+ headers = {
19
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
20
+ }
21
+ params = {
22
+ "type": "JSON",
23
+ "list": "DomesticBinCollections",
24
+ "Road": "",
25
+ "Postcode": user_postcode
26
+ }
27
+
28
+ response = requests.get(
29
+ "https://www.fareham.gov.uk/internetlookups/search_data.aspx",
30
+ params = params,
31
+ headers = headers
32
+ )
33
+
34
+ bin_data = response.json()["data"]
35
+ data = {"bins": []}
36
+
37
+ if "rows" in bin_data:
38
+ collection_str = bin_data["rows"][0]["DomesticBinDay"]
39
+
40
+ results = re.findall(r"(\d\d?\/\d\d?\/\d{4}) \((\w*)\)", collection_str)
41
+
42
+ if results:
43
+ for result in results:
44
+ collection_date = datetime.strptime(result[0], "%d/%m/%Y")
45
+ dict_data = {
46
+ "type": result[1],
47
+ "collectionDate": collection_date.strftime(date_format),
48
+ }
49
+ data["bins"].append(dict_data)
50
+
51
+ # Garden waste is also collected on recycling day
52
+ if (dict_data["type"] == "Recycling"):
53
+ garden_data = {
54
+ "type": "Garden",
55
+ "collectionDate": dict_data["collectionDate"],
56
+ }
57
+ data["bins"].append(garden_data)
58
+ else:
59
+ raise RuntimeError("Dates not parsed correctly.")
60
+ else:
61
+ raise ValueError("Postcode not found on website.")
62
+
63
+ data["bins"].sort(
64
+ key=lambda x: datetime.strptime(
65
+ x.get("collectionDate"), "%d/%m/%Y"
66
+ )
67
+ )
68
+
69
+ return data
@@ -1,91 +0,0 @@
1
- import json
2
- import re
3
- import requests
4
- import sys
5
- from tabulate import tabulate
6
-
7
- def get_councils_from_files(branch):
8
- url = f"https://api.github.com/repos/robbrad/UKBinCollectionData/contents/uk_bin_collection/uk_bin_collection/councils?ref={branch}"
9
- response = requests.get(url)
10
- data = response.json()
11
-
12
- # Debugging lines to check the response content and type
13
- print(f"Response Status Code: {response.status_code}")
14
- print(f"Response Content: {response.content}")
15
- print(f"Parsed JSON Data: {data}")
16
- print(f"Data Type: {type(data)}")
17
-
18
- # Ensure 'data' is a list before proceeding
19
- if isinstance(data, list):
20
- return [item['name'].replace('.py', '') for item in data if item['name'].endswith('.py')]
21
- else:
22
- raise ValueError("Expected a list from the JSON response but got something else.")
23
-
24
-
25
- def get_councils_from_json(branch):
26
- url = f"https://raw.githubusercontent.com/robbrad/UKBinCollectionData/{branch}/uk_bin_collection/tests/input.json"
27
- response = requests.get(url)
28
- data = json.loads(response.text)
29
- return list(data.keys())
30
-
31
- def get_councils_from_features(branch):
32
- url = f"https://raw.githubusercontent.com/robbrad/UKBinCollectionData/{branch}/uk_bin_collection/tests/features/validate_council_outputs.feature"
33
- response = requests.get(url)
34
- content = response.text
35
- return re.findall(r'Examples:\s+(\w+)', content)
36
-
37
- def compare_councils(councils1, councils2, councils3):
38
- set1 = set(councils1)
39
- set2 = set(councils2)
40
- set3 = set(councils3)
41
- all_councils = set1 | set2 | set3
42
- all_council_data = {}
43
- discrepancies_found = False
44
- for council in all_councils:
45
- in_files = council in set1
46
- in_json = council in set2
47
- in_features = council in set3
48
- discrepancies_count = [in_files, in_json, in_features].count(False)
49
- all_council_data[council] = {
50
- 'in_files': in_files,
51
- 'in_json': in_json,
52
- 'in_features': in_features,
53
- 'discrepancies_count': discrepancies_count
54
- }
55
- if discrepancies_count > 0:
56
- discrepancies_found = True
57
- return all_council_data, discrepancies_found
58
-
59
- def main(branch="master"):
60
- # Execute and print the comparison
61
- file_councils = get_councils_from_files(branch)
62
- json_councils = get_councils_from_json(branch)
63
- feature_councils = get_councils_from_features(branch)
64
-
65
- all_councils_data, discrepancies_found = compare_councils(file_councils, json_councils, feature_councils)
66
-
67
- # Create a list of lists for tabulate, sort by discrepancies count and then by name
68
- table_data = []
69
- headers = ["Council Name", "In Files", "In JSON", "In Features", "Discrepancies"]
70
- for council, presence in sorted(all_councils_data.items(), key=lambda x: (x[1]['discrepancies_count'], x[0])):
71
- row = [
72
- council,
73
- "✔" if presence['in_files'] else "✘",
74
- "✔" if presence['in_json'] else "✘",
75
- "✔" if presence['in_features'] else "✘",
76
- presence['discrepancies_count']
77
- ]
78
- table_data.append(row)
79
-
80
- # Print the table using tabulate
81
- print(tabulate(table_data, headers=headers, tablefmt='grid'))
82
-
83
- if discrepancies_found:
84
- print("Discrepancies found! Failing the workflow.")
85
- sys.exit(1)
86
- else:
87
- print("No discrepancies found. Workflow successful.")
88
-
89
- if __name__ == "__main__":
90
- branch = sys.argv[1] if len(sys.argv) > 1 else "master"
91
- main(branch)