Skip to content

Commit fc369ed

Browse files
authored
Merge pull request snychka#4 from pluralsight-projects/module1
Module1
2 parents 85d2ade + bfb8b55 commit fc369ed

File tree

13 files changed

+1041
-29
lines changed

13 files changed

+1041
-29
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ instance/
6868

6969
# Virtualenv
7070
venv/
71+
venv36/
72+
venv37/
73+
venv38/
7174
.venv/
7275

7376
# Datasets

conftest.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import ast
2+
import json
3+
4+
import parso
5+
import pytest
6+
7+
from collections import OrderedDict
8+
from types import GeneratorType as generator
9+
from itertools import chain
10+
from pathlib import Path
11+
12+
from objectpath import Tree
13+
from mongoquery import Query
14+
15+
from tests.nodes import convert_node, flatten
16+
from tests.template import Template
17+
18+
19+
class Parser:
20+
def __init__(self, file_name, nodes):
21+
22+
sensor = Path.cwd() / "sensor"
23+
# ext = sensor / "extensions"
24+
25+
self.data = {
26+
"success": True,
27+
"full_path": "",
28+
"message": "",
29+
"start_pos": 0,
30+
"nodes": nodes,
31+
}
32+
33+
if file_name is not None:
34+
path = lambda root, fn: root / "{}.py".format(fn)
35+
# if file_name == "menu" or file_name == "stats":
36+
# full_path = path(ext, file_name)
37+
if file_name == "sensor":
38+
full_path = path(Path.cwd(), file_name)
39+
else:
40+
full_path = path(sensor, file_name)
41+
42+
grammar = parso.load_grammar()
43+
module = grammar.parse(path=full_path)
44+
self.data["success"] = len(grammar.iter_errors(module)) == 0
45+
46+
if self.data["success"]:
47+
self.data["message"] = "Syntax: valid"
48+
if file_name is not None:
49+
self.data["nodes"] = convert_node(ast.parse(full_path.read_text()))
50+
self.data["code"] = full_path.read_text()
51+
52+
else:
53+
self.data["message"] = grammar.iter_errors(module)[0].message
54+
self.data["start_pos"] = grammar.iter_errors(module)[0].start_pos[0]
55+
56+
@property
57+
def nodes(self):
58+
return self.data["nodes"]
59+
60+
n = nodes
61+
62+
@property
63+
def success(self):
64+
return self.data["success"]
65+
66+
@property
67+
def code(self):
68+
return self.data["code"]
69+
70+
def query(self, pattern):
71+
nodes = Template(pattern).process(self.code)
72+
if isinstance(nodes, list) and len(nodes) == 1:
73+
nodes = nodes[0]
74+
75+
return Parser(None, nodes)
76+
77+
def query_raw(self, pattern):
78+
nodes = Template(pattern).process(self.code, True)
79+
if isinstance(nodes, list) and len(nodes) == 1:
80+
nodes = [flatten(convert_node(node)) for node in nodes[0].body]
81+
return Parser(None, nodes)
82+
83+
def last_line(self):
84+
return flatten(self.nodes["body"][-1])
85+
86+
@property
87+
def message(self):
88+
return "{} on or around line {} in `{}`.".format(
89+
self.data["message"], self.data["start_pos"], self.data["full_path"]
90+
)
91+
92+
def match(self, template):
93+
return Parser(None, list(filter(Query(template).match, self.nodes)))
94+
95+
def execute(self, expr):
96+
result = Tree(self.nodes).execute(expr)
97+
if isinstance(result, (generator, chain, map)):
98+
process = list(result)
99+
return (
100+
Parser(None, process[0]) if len(process) == 1 else Parser(None, process)
101+
)
102+
else:
103+
return Parser(None, result)
104+
105+
ex = execute
106+
107+
def exists(self):
108+
return bool(self.nodes)
109+
110+
def calls(self):
111+
nodes = self.execute("$.body[@.type is 'Expr' and @.value.type is 'Call']").n
112+
node_list = [nodes] if isinstance(nodes, dict) else nodes
113+
114+
return Parser(None, [flatten(node) for node in node_list])
115+
116+
def assign_(self):
117+
return Parser(None, [flatten(self.execute("$.body[@.type is 'Assign']").n)])
118+
119+
def assigns(self):
120+
return Parser(
121+
None,
122+
[flatten(node) for node in self.execute("$.body[@.type is 'Assign']").n],
123+
)
124+
125+
def globals(self, name):
126+
return name in self.execute("$.body[@.type is 'Global'].names").n
127+
128+
def defines(self, name):
129+
return self.execute(
130+
"$.body[@.type is 'FunctionDef' and @.name is '{}'].(name, args, body, decorator_list)".format(
131+
name
132+
)
133+
)
134+
135+
def class_(self, name):
136+
return self.execute(
137+
"$.body[@.type is 'ClassDef' and @.name is '{}'].(name, args, body)".format(
138+
name
139+
)
140+
)
141+
142+
def decorators(self):
143+
return Parser(None, [flatten(self.execute("$.decorator_list").n)])
144+
145+
def returns(self, name):
146+
return name == self.execute("$.body[@.type is 'Return'].value.id").n
147+
148+
def returns_call(self):
149+
return Parser(None, [flatten(self.execute("$.body[@.type is 'Return']").n)])
150+
151+
def method(self, name):
152+
return self.execute(
153+
"$..body[@.type is 'FunctionDef' and @.name is '{}']".format(name)
154+
)
155+
156+
def has_arg(self, name, pos=0):
157+
nodes = self.execute("$.args.args.arg").n
158+
return nodes[pos] if isinstance(nodes, list) else nodes
159+
160+
def imports(self, name):
161+
return name in self.execute("$.body[@.type is 'Import'].names..name").n
162+
163+
def for_(self):
164+
for_body = self.execute("$.body[@.type is 'For'].body").n
165+
iterators = self.execute("$.body[@.type is 'For'].(target, iter)").n
166+
return Parser(None, [flatten(for_body), flatten(iterators)])
167+
168+
def from_imports(self, mod, alias):
169+
nodes = self.execute(
170+
"$.body[@.type is 'ImportFrom' and @.module is '{}'].names..name".format(
171+
mod
172+
)
173+
).n
174+
return alias in (nodes if isinstance(nodes, list) else [nodes])
175+
176+
177+
@pytest.fixture
178+
def parse():
179+
def _parse(file_name):
180+
return Parser(file_name, {})
181+
182+
return _parse

datasets/SENSOR_ROOM1.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
id,date,time,temperature,humidity,energy_usage,particulate,room
1+
id,date,time,temperature,humidity,energy_usage,particulate,area
22
1,5/7/2020,0:01,60,0.8,0xffe,6.2E+00,1
33
2,5/7/2020,0:01,60,0.8,0xff3,6.3E+00,1
44
3,5/7/2020,0:04,60,0.8,0xfef,6.5E+00,1

datasets/SENSOR_ROOM2.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
id,date,time,temperature,humidity,energy_usage,particulate,room
1+
id,date,time,temperature,humidity,energy_usage,particulate,area
22
1,5/7/2020,0:01,50,0.8,0xffc,8.1E+00,2
33
2,5/7/2020,0:02,50,0.53,0xffb,8.1E+00,2
44
3,5/7/2020,0:02,50,0.82,0xff3,8.5E+00,2

pytest.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[pytest]
2-
addopts = --tb=short -p no:warnings
2+
addopts = -rN --tb=short -p no:warnings

requirements.txt

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
docutils==0.16
2-
Markdown==3.1.1
3-
parso==0.6.0
4-
pytest==5.3.5
2+
Markdown==3.2.1
3+
mongoquery==1.3.6
4+
objectpath==0.6.1
5+
parso==0.6.2
6+
pytest==5.4.1
57
pytest-json-report==1.2.1
6-
pytest-metadata==1.8.0
7-
pytest-sugar==0.9.2
8-
python-dateutil==2.7.5
9-
py==1.7.0
10-
pyparsing==2.3.0
11-
more-itertools==4.3.0
8+
PyYAML==5.3.1
9+
typer==0.1.1

sensor/load_data.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Module 1: Load data from files
2+
import os
3+
import glob
4+
import csv
5+
6+
def load_sensor_data():
7+
sensor_data = []

sensor/load_info.py

Lines changed: 0 additions & 1 deletion
This file was deleted.
File renamed without changes.

tasks.md

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,56 @@
22

33
- [Module 01 - The Sensor Class](#module-01---the-sensor-class)
44
- [Status](#status)
5-
- [Module 1: System Setup](#module-1-system-setup)
6-
- [Module 2: Load Data From Files](#module-2-load-data-from-files)
7-
- [Module 3: Create a Class HomeData](#module-3-create-a-class-homedata)
8-
- [Module 4: Analyze Temperature Data](#module-4-analyze-temperature-data)
9-
- [Module 5: Analyze Humidity Data](#module-5-analyze-humidity-data)
10-
- [Module 6: Analyze Air Quality Data](#module-6-analyze-air-quality-data)
11-
- [Module 7: Analyze Energy Consumption Data](#module-7-analyze-energy-consumption-data)
5+
- [Module 1: Load Sensor Data From Files](#module-1-load-sensor-data-from-files)
6+
- [Task 1: Import os, glob, and csv](#task-1-import-os-glob-and-csv)
7+
- [Task 2: Create a Function to parse the data](#task-2-create-a-function-to-parse-the-data)
8+
- [Module 2: Create a Class HomeData](#module-2-create-a-class-homedata)
9+
- [Module 3: Analyze Temperature Data](#module-3-analyze-temperature-data)
10+
- [Module 4: Analyze Humidity Data](#module-4-analyze-humidity-data)
11+
- [Module 5: Analyze Air Quality Data](#module-5-analyze-air-quality-data)
12+
- [Module 6: Analyze Energy Consumption Data](#module-6-analyze-energy-consumption-data)
1213

1314
## Status
1415

1516
Draft.
1617

17-
## Module 1: System Setup
18+
## Module 1: Load Sensor Data From Files
1819

19-
## Module 2: Load Data From Files
20+
### Task 1: Import os, glob, and csv
21+
22+
[//]:# (@pytest.mark.test_load_data_function_module1)
23+
24+
```python
25+
import os
26+
import glob
27+
import csv
28+
```
29+
30+
The dataset for this project is stored in several CSV files found in the `dataset` folder. It represents the data collected from a device with multiple sensors. The records include measurements of temperature, humidity, energy consumption, and particle count in the air over a given area. The data is collected over a period of 24 hours.
31+
32+
To start, open the file called `load_data.py` in the `sensor` folder - the rest of the tasks in this module happen in this same file.
33+
34+
At the top of the file create three import statements for `os`, `glob`, and `csv`. These libraries will allow us to work with a collection of files.
35+
36+
### Task 2: Create a Function to parse the data
37+
38+
[//]:# (@pytest.mark.test_load_data_load_sensor_func_module1)
2039

2140
```python
22-
from sensor_file import Sensor
41+
def load_sensor_data():
42+
# create a list to store data
43+
sensor_data = []
2344
```
2445

25-
## Module 3: Create a Class HomeData
46+
Create a method called `load_sensor_data` that takes no arguments.
47+
In the body of the `load_sensor_data` function, create variable called `sensor_data` and set it as an empty `list`.
48+
49+
## Module 2: Create a Class HomeData
2650

27-
## Module 4: Analyze Temperature Data
51+
## Module 3: Analyze Temperature Data
2852

29-
## Module 5: Analyze Humidity Data
53+
## Module 4: Analyze Humidity Data
3054

31-
## Module 6: Analyze Air Quality Data
55+
## Module 5: Analyze Air Quality Data
3256

33-
## Module 7: Analyze Energy Consumption Data
57+
## Module 6: Analyze Energy Consumption Data

0 commit comments

Comments
 (0)