bdcdata 0.0.1__py3-none-any.whl

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.
bdcdata/__init__.py ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Feb 10 2025.
5
+
6
+ @author: npappin-wsu
7
+ @license: MIT
8
+
9
+ Updated on Feb 11 2025.
10
+ """
11
+
12
+ import logging
13
+ import os
14
+ from dotenv import load_dotenv # type: ignore
15
+
16
+ load_dotenv()
17
+
18
+ apiKey = os.getenv("BDC_API_KEY")
19
+ username = os.getenv("BDC_USERNAME")
20
+
21
+ # print(apiKey)
22
+
23
+ # Configure logging
24
+ logging.basicConfig(
25
+ filename="bdc.log", filemode="w", format="%(asctime)s - %(levelname)s - %(message)s"
26
+ )
27
+ logger = logging.getLogger(__name__)
28
+ logger.addHandler(logging.StreamHandler())
29
+ logger.setLevel(logging.DEBUG)
30
+
31
+ # print(logger)
32
+
33
+ from .helpers import get_session
34
+
35
+ session = get_session(apiKey, username)
36
+
37
+ from .helpers import get_metadata, bdcCache
38
+
39
+ metadata = get_metadata()
40
+
41
+ from .bdc import *
bdcdata/bdc.py ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Feb 10 2025.
5
+
6
+ @author: npappin-wsu
7
+ @license: MIT
8
+
9
+ Updated on Feb 11 2025.
10
+ """
11
+
12
+ from . import logger, session, metadata, bdcCache
13
+ import pandas as pd
14
+ import json, zipfile, io
15
+ from pprint import pprint
16
+
17
+ # from . import config
18
+
19
+
20
+ class availability:
21
+
22
+ def state(
23
+ states: int | str | list = "53",
24
+ technology: int | str | list = "50",
25
+ release: str | list = "2024-06-30",
26
+ cache=False,
27
+ ) -> pd.DataFrame:
28
+ logger.info("Collecting availability...")
29
+ logger.debug(f"State: {states}")
30
+ logger.debug(f"Technology: {technology}")
31
+ logger.debug(f"Release: {release}")
32
+ # TODO: Handle no data here
33
+
34
+ if type(states) is not list:
35
+ states = [states]
36
+ if type(technology) is not list:
37
+ technology = [technology]
38
+ if type(release) is not list:
39
+ release = [release]
40
+ # TODO: Add normalization code here
41
+
42
+ # Retrieve availability data
43
+ availability = dict()
44
+ for r in release:
45
+ response = session.get(
46
+ f"https://broadbandmap.fcc.gov/api/public/map/downloads/listAvailabilityData/{r}"
47
+ )
48
+ if response.status_code != 200:
49
+ logger.error(f"Failed to retrieve availability data for {r}.")
50
+ raise Exception(f"Failed to retrieve availability data for {r}.")
51
+ # TODO: adding dtype hints here I think would be helpful.
52
+ availability[r] = pd.DataFrame.from_dict(response.json()["data"])
53
+ df = pd.DataFrame()
54
+ for r in release:
55
+ rlocal = availability[r]
56
+ items = rlocal[
57
+ (rlocal.category == "State")
58
+ & (rlocal.state_fips.isin(states))
59
+ & (rlocal.technology_code.isin(technology))
60
+ ].to_dict("records")
61
+ for item in items:
62
+ logger.debug(
63
+ f"State: {item['state_name']}, Technology: {item['technology_code']}, Release: {r}"
64
+ )
65
+ # FUCK I DONT LIKE THIS
66
+ if cache and bdcCache.check(item["file_name"]):
67
+ data = bdcCache.get(item["file_name"])
68
+ logger.debug("Cache hit!")
69
+ pass
70
+ else:
71
+ response = session.get(
72
+ f"https://broadbandmap.fcc.gov/api/public/map/downloads/downloadFile/availability/{item['file_id']}"
73
+ )
74
+ if response.status_code == 200 and cache:
75
+ bdcCache.save(item["file_name"], response.content)
76
+ data = response.content
77
+ if response.status_code != 200:
78
+ logger.error(
79
+ f"Failed to retrieve availability data for {item['state_name']} and {item['technology_code']} in {r}."
80
+ )
81
+ raise Exception(
82
+ f"Failed to retrieve availability data for {item['state_name']} and {item['technology_code']} in {r}."
83
+ )
84
+ else:
85
+ zip = zipfile.ZipFile(io.BytesIO(data))
86
+ localdf = pd.read_csv(
87
+ zip.open(zip.filelist[0].filename)
88
+ ) # , dtype=columnHints)
89
+ df = pd.concat([df, localdf], ignore_index=True)
90
+ logger.debug(f"State: {states}, Technology: {technology}, Release: {release}")
91
+ return df
92
+
93
+
94
+ def echo(message):
95
+ logger.info(message)
96
+ print(message)
97
+ pass
98
+
99
+
100
+ def main():
101
+ logger.info("Starting the application...")
102
+ # Your code here
103
+
104
+
105
+ if __name__ == "__main__":
106
+ main()
bdcdata/helpers.py ADDED
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Feb 10 2025.
5
+
6
+ @author: npappin-wsu
7
+ @license: MIT
8
+
9
+ Updated on Feb 11 2025.
10
+ """
11
+
12
+ from . import logger
13
+ import json, pathlib
14
+
15
+ from requests_ratelimiter import LimiterSession # type: ignore
16
+
17
+
18
+ def get_session(apiKey, username, cache=False):
19
+ session = LimiterSession(max_retries=3, per_minute=10)
20
+ session.headers.update({"User-Agent": "python-bdc"})
21
+ session.headers.update({"hash_value": apiKey})
22
+ session.headers.update({"username": username})
23
+ logger.debug(session.headers)
24
+ logger.info("Session created.")
25
+ return session
26
+
27
+
28
+ def get_metadata():
29
+ from . import session
30
+
31
+ logger.info("Collecting metadata...")
32
+ r = session.get("https://broadbandmap.fcc.gov/api/public/map/listAsOfDates")
33
+ logger.debug(r.json())
34
+ parsed = json.loads(r.text)
35
+ logger.debug(parsed)
36
+ logger.debug(parsed["data"])
37
+ logger.info("Metadata collected.")
38
+ types = set([item["data_type"] for item in parsed["data"]])
39
+ metadata = {}
40
+ for t in types:
41
+ if t not in metadata.keys():
42
+ metadata[t] = list()
43
+ for item in parsed["data"]:
44
+ if item["data_type"] == t:
45
+ logger.debug(f"Data type: {t}")
46
+ logger.debug(item)
47
+ metadata[t].append(item["as_of_date"])
48
+ return metadata
49
+
50
+ class bdcCache:
51
+ def check(filename):
52
+ if pathlib.Path('cache', f'{filename}.zip').exists():
53
+ return True
54
+ else:
55
+ return False
56
+
57
+ def save(filename, data):
58
+ if not pathlib.Path('cache').exists():
59
+ pathlib.Path('cache').mkdir(parents=True, exist_ok=True)
60
+ with open(pathlib.Path('cache', f'{filename}.zip'), 'wb')as f:
61
+ f.write(data)
62
+ pass
63
+
64
+ def get(filename):
65
+ with open(pathlib.Path('cache', f'{filename}.zip'), 'rb') as f:
66
+ return f.read()
67
+
68
+
69
+ def isEmpty() -> bool:
70
+ pass
@@ -0,0 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: bdcdata
3
+ Version: 0.0.1
4
+ Summary: A tool to work with BDC data from the FCC.
5
+ Project-URL: Homepage, https://github.com/npappin-wsu/bdc
6
+ Project-URL: Issues, https://github.com/npappin-wsu/bdc/issues
7
+ Author-email: "W. Nick Pappin" <nick.pappin@wsu.edu>
8
+ Maintainer-email: "W. Nick Pappin" <npappin@gmail.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE.txt
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Requires-Python: >=3.6
15
+ Requires-Dist: pandas>=2
16
+ Requires-Dist: python-dotenv
17
+ Requires-Dist: requests-ratelimiter
18
+ Description-Content-Type: text/markdown
19
+
20
+ # BDC
21
+
22
+ This is a python module that will allow users to work with BDC data from the FCC through Python and Pandas.
23
+
24
+ ## Authentication
25
+
26
+ TODO: Write something here.
@@ -0,0 +1,7 @@
1
+ bdcdata/__init__.py,sha256=E449upcky-fr91wgOe6zZmZvfh4XPs3NM8ktCF_oTKM,744
2
+ bdcdata/bdc.py,sha256=x1HTy43arIFSgl5ibpQwMfCR-Pfnpw_SsokCKYkt2t8,3720
3
+ bdcdata/helpers.py,sha256=QMwQAW7iAyOtF-CfxlCFm6ci2PZ9HgpS3u_NBlgfxDc,1930
4
+ bdcdata-0.0.1.dist-info/METADATA,sha256=qmvDq5CRankRGiqk4kd-R5KLUBaZhp_V_wM-2lOAxDY,843
5
+ bdcdata-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ bdcdata-0.0.1.dist-info/licenses/LICENSE.txt,sha256=XRRBPm03M10yh16ZEzUI1fWz-1rbmawyBrQpykU15Q8,1071
7
+ bdcdata-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025, W. Nick Pappin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.