polarsteps-data-parser 0.1.0__py3-none-any.whl → 0.1.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.
@@ -1,74 +1,74 @@
1
- import time
2
- from pathlib import Path
3
-
4
- import click
5
- from dotenv import load_dotenv
6
-
7
- from polarsteps_data_parser.retrieve_step_comments import StepCommentsEnricher
8
- from polarsteps_data_parser.model import Trip, Location
9
- from polarsteps_data_parser.pdf_generator import PDFGenerator
10
- from polarsteps_data_parser.utils import load_json_from_file
11
-
12
-
13
- @click.command()
14
- @click.argument(
15
- "input-folder",
16
- type=click.Path(exists=True, dir_okay=True, file_okay=False, readable=True),
17
- )
18
- @click.option(
19
- "--output",
20
- default="Trip report.pdf",
21
- show_default=True,
22
- help="Output PDF file name",
23
- )
24
- @click.option(
25
- "--enrich-with-comments",
26
- is_flag=True,
27
- show_default=True,
28
- default=False,
29
- help="Whether to enrich the trip with comments or not.",
30
- )
31
- def cli(input_folder: str, output: str, enrich_with_comments: str) -> None:
32
- """Parse the data from a Polarsteps trip export.
33
-
34
- INPUT_FOLDER should contain the Polarsteps data export of one (!) trip. Make sure the folder contains
35
- a `trip.json` and `locations.json`.
36
- """
37
- load_dotenv()
38
-
39
- input_folder = Path(input_folder)
40
- trip_data_path = input_folder / "trip.json"
41
- location_data_path = input_folder / "locations.json"
42
-
43
- if not trip_data_path.exists() or not location_data_path.exists():
44
- log("Error: Cannot find Polarsteps trip in folder!")
45
- log("Please make sure the input folder contains a `trip.json` and a `locations.json` file. ")
46
- return
47
-
48
- log("✅ Found Polarsteps trip", color="green", bold=True)
49
- trip_data = load_json_from_file(trip_data_path)
50
- location_data = load_json_from_file(location_data_path)
51
-
52
- log("🔄 Starting to parse trip...", color="cyan")
53
- trip = Trip.from_json(trip_data)
54
-
55
- if enrich_with_comments is True:
56
- StepCommentsEnricher(input_folder).enrich(trip)
57
-
58
- [Location.from_json(data) for data in location_data["locations"]] # TODO! use location data
59
-
60
- log("🔄 Generating PDF...", color="cyan")
61
- pdf_generator = PDFGenerator(output)
62
- pdf_generator.generate_pdf(trip)
63
- log(f"✅ Generated report: {click.format_filename(output)}", color="green", bold=True)
64
-
65
-
66
- def log(message: str, color: str = "white", bold: bool = False) -> None:
67
- """Helper function to format messages."""
68
- click.echo(click.style(f"[{time.strftime('%H:%M:%S')}] {message}", fg=color, bold=bold))
69
-
70
-
71
- if __name__ == "__main__":
72
- load_dotenv()
73
-
74
- cli()
1
+ import time
2
+ from pathlib import Path
3
+
4
+ import click
5
+ from dotenv import load_dotenv
6
+
7
+ from polarsteps_data_parser.retrieve_step_comments import StepCommentsEnricher
8
+ from polarsteps_data_parser.model import Trip, Location
9
+ from polarsteps_data_parser.pdf_generator import PDFGenerator
10
+ from polarsteps_data_parser.utils import load_json_from_file
11
+
12
+
13
+ @click.command()
14
+ @click.argument(
15
+ "input-folder",
16
+ type=click.Path(exists=True, dir_okay=True, file_okay=False, readable=True),
17
+ )
18
+ @click.option(
19
+ "--output",
20
+ default="Trip report.pdf",
21
+ show_default=True,
22
+ help="Output PDF file name",
23
+ )
24
+ @click.option(
25
+ "--enrich-with-comments",
26
+ is_flag=True,
27
+ show_default=True,
28
+ default=False,
29
+ help="Whether to enrich the trip with comments or not.",
30
+ )
31
+ def cli(input_folder: str, output: str, enrich_with_comments: str) -> None:
32
+ """Parse the data from a Polarsteps trip export.
33
+
34
+ INPUT_FOLDER should contain the Polarsteps data export of one (!) trip. Make sure the folder contains
35
+ a `trip.json` and `locations.json`.
36
+ """
37
+ load_dotenv()
38
+
39
+ input_folder = Path(input_folder)
40
+ trip_data_path = input_folder / "trip.json"
41
+ location_data_path = input_folder / "locations.json"
42
+
43
+ if not trip_data_path.exists() or not location_data_path.exists():
44
+ log("Error: Cannot find Polarsteps trip in folder!")
45
+ log("Please make sure the input folder contains a `trip.json` and a `locations.json` file. ")
46
+ return
47
+
48
+ log("✅ Found Polarsteps trip", color="green", bold=True)
49
+ trip_data = load_json_from_file(trip_data_path)
50
+ location_data = load_json_from_file(location_data_path)
51
+
52
+ log("🔄 Starting to parse trip...", color="cyan")
53
+ trip = Trip.from_json(trip_data)
54
+
55
+ if enrich_with_comments is True:
56
+ StepCommentsEnricher(input_folder).enrich(trip)
57
+
58
+ [Location.from_json(data) for data in location_data["locations"]] # TODO! use location data
59
+
60
+ log("🔄 Generating PDF...", color="cyan")
61
+ pdf_generator = PDFGenerator(output)
62
+ pdf_generator.generate_pdf(trip)
63
+ log(f"✅ Generated report: {click.format_filename(output)}", color="green", bold=True)
64
+
65
+
66
+ def log(message: str, color: str = "white", bold: bool = False) -> None:
67
+ """Helper function to format messages."""
68
+ click.echo(click.style(f"[{time.strftime('%H:%M:%S')}] {message}", fg=color, bold=bold))
69
+
70
+
71
+ if __name__ == "__main__":
72
+ load_dotenv()
73
+
74
+ cli()
@@ -1,147 +1,147 @@
1
- from dataclasses import dataclass
2
- from datetime import datetime, date
3
- from pathlib import Path
4
- from typing import Self
5
-
6
- from polarsteps_data_parser.utils import parse_date, find_folder_by_id, list_files_in_folder
7
-
8
-
9
- @dataclass
10
- class Location:
11
- """Location as tracked by the travel tracker."""
12
-
13
- lat: float
14
- lon: float
15
- time: datetime
16
-
17
- @classmethod
18
- def from_json(cls, data: dict) -> Self:
19
- """Parse object from JSON data."""
20
- return Location(lat=data["lat"], lon=data["lon"], time=parse_date(data["time"]))
21
-
22
-
23
- @dataclass
24
- class StepLocation:
25
- """Location as provided by a step."""
26
-
27
- lat: float
28
- lon: float
29
- name: str
30
- country: str
31
-
32
- @classmethod
33
- def from_json(cls, data: dict) -> Self:
34
- """Parse object from JSON data."""
35
- return StepLocation(
36
- lat=data["lat"],
37
- lon=data["lon"],
38
- name=data["name"],
39
- country=data["detail"],
40
- )
41
-
42
-
43
- @dataclass
44
- class Follower:
45
- """Follower (can leave comments)."""
46
-
47
- user_id: str
48
- username: str
49
- first_name: str
50
- last_name: str
51
-
52
- @classmethod
53
- def from_json(cls, data: dict) -> Self:
54
- """Parse object from JSON data."""
55
- return Follower(
56
- user_id=data["id"],
57
- username=data["username"],
58
- first_name=data["first_name"],
59
- last_name=data["last_name"],
60
- )
61
-
62
- @property
63
- def name(self) -> str:
64
- """Name of the follower."""
65
- return f"{self.first_name} {self.last_name}"
66
-
67
-
68
- @dataclass
69
- class StepComment:
70
- """Comment connected to a step."""
71
-
72
- comment_id: str
73
- text: str
74
- date: datetime
75
- follower: Follower
76
-
77
- @classmethod
78
- def from_json(cls, data: dict) -> Self:
79
- """Parse object from JSON data."""
80
- return StepComment(
81
- comment_id=data["id"],
82
- text=data["text"],
83
- date=parse_date(data["creation_time"]),
84
- follower=Follower.from_json(data["user"]),
85
- )
86
-
87
-
88
- @dataclass
89
- class Step:
90
- """Polarsteps Step object."""
91
-
92
- step_id: str
93
- name: str
94
- description: str
95
- location: StepLocation
96
- date: date
97
- photos: list[Path]
98
- videos: list[Path]
99
- comments: list[StepComment]
100
-
101
- @classmethod
102
- def from_json(cls, data: dict) -> Self:
103
- """Parse object from JSON data."""
104
- s = Step(
105
- step_id=data["id"],
106
- name=data["name"] or data["display_name"],
107
- description=data["description"],
108
- location=StepLocation.from_json(data["location"]),
109
- date=parse_date(data["start_time"]),
110
- photos=[],
111
- videos=[],
112
- comments=[],
113
- )
114
- s.load_media()
115
- return s
116
-
117
- def load_media(self) -> None:
118
- """Load photos and videos for the step."""
119
- step_dir = find_folder_by_id(self.step_id)
120
- if step_dir is None:
121
- self.photos = []
122
- self.videos = []
123
- else:
124
- self.photos = list_files_in_folder(step_dir / "photos", dir_has_to_exist=False)
125
- self.videos = list_files_in_folder(step_dir / "videos", dir_has_to_exist=False)
126
-
127
-
128
- @dataclass
129
- class Trip:
130
- """Polarsteps trip object."""
131
-
132
- name: str
133
- start_date: datetime
134
- end_date: datetime
135
- cover_photo_path: str
136
- steps: list[Step]
137
-
138
- @classmethod
139
- def from_json(cls, data: dict) -> Self:
140
- """Parse object from JSON data."""
141
- return Trip(
142
- name=data["name"],
143
- start_date=parse_date(data.get("start_date")),
144
- end_date=parse_date(data.get("end_date")),
145
- cover_photo_path=data["cover_photo_path"],
146
- steps=[Step.from_json(step) for step in data.get("all_steps")],
147
- )
1
+ from dataclasses import dataclass
2
+ from datetime import datetime, date
3
+ from pathlib import Path
4
+ from typing import Self
5
+
6
+ from polarsteps_data_parser.utils import parse_date, find_folder_by_id, list_files_in_folder
7
+
8
+
9
+ @dataclass
10
+ class Location:
11
+ """Location as tracked by the travel tracker."""
12
+
13
+ lat: float
14
+ lon: float
15
+ time: datetime
16
+
17
+ @classmethod
18
+ def from_json(cls, data: dict) -> Self:
19
+ """Parse object from JSON data."""
20
+ return Location(lat=data["lat"], lon=data["lon"], time=parse_date(data["time"]))
21
+
22
+
23
+ @dataclass
24
+ class StepLocation:
25
+ """Location as provided by a step."""
26
+
27
+ lat: float
28
+ lon: float
29
+ name: str
30
+ country: str
31
+
32
+ @classmethod
33
+ def from_json(cls, data: dict) -> Self:
34
+ """Parse object from JSON data."""
35
+ return StepLocation(
36
+ lat=data["lat"],
37
+ lon=data["lon"],
38
+ name=data["name"],
39
+ country=data["detail"],
40
+ )
41
+
42
+
43
+ @dataclass
44
+ class Follower:
45
+ """Follower (can leave comments)."""
46
+
47
+ user_id: str
48
+ username: str
49
+ first_name: str
50
+ last_name: str
51
+
52
+ @classmethod
53
+ def from_json(cls, data: dict) -> Self:
54
+ """Parse object from JSON data."""
55
+ return Follower(
56
+ user_id=data["id"],
57
+ username=data["username"],
58
+ first_name=data["first_name"],
59
+ last_name=data["last_name"],
60
+ )
61
+
62
+ @property
63
+ def name(self) -> str:
64
+ """Name of the follower."""
65
+ return f"{self.first_name} {self.last_name}"
66
+
67
+
68
+ @dataclass
69
+ class StepComment:
70
+ """Comment connected to a step."""
71
+
72
+ comment_id: str
73
+ text: str
74
+ date: datetime
75
+ follower: Follower
76
+
77
+ @classmethod
78
+ def from_json(cls, data: dict) -> Self:
79
+ """Parse object from JSON data."""
80
+ return StepComment(
81
+ comment_id=data["id"],
82
+ text=data["text"],
83
+ date=parse_date(data["creation_time"]),
84
+ follower=Follower.from_json(data["user"]),
85
+ )
86
+
87
+
88
+ @dataclass
89
+ class Step:
90
+ """Polarsteps Step object."""
91
+
92
+ step_id: str
93
+ name: str
94
+ description: str
95
+ location: StepLocation
96
+ date: date
97
+ photos: list[Path]
98
+ videos: list[Path]
99
+ comments: list[StepComment]
100
+
101
+ @classmethod
102
+ def from_json(cls, data: dict) -> Self:
103
+ """Parse object from JSON data."""
104
+ s = Step(
105
+ step_id=data["id"],
106
+ name=data["name"] or data["display_name"],
107
+ description=data["description"],
108
+ location=StepLocation.from_json(data["location"]),
109
+ date=parse_date(data["start_time"]),
110
+ photos=[],
111
+ videos=[],
112
+ comments=[],
113
+ )
114
+ s.load_media()
115
+ return s
116
+
117
+ def load_media(self) -> None:
118
+ """Load photos and videos for the step."""
119
+ step_dir = find_folder_by_id(self.step_id)
120
+ if step_dir is None:
121
+ self.photos = []
122
+ self.videos = []
123
+ else:
124
+ self.photos = list_files_in_folder(step_dir / "photos", dir_has_to_exist=False)
125
+ self.videos = list_files_in_folder(step_dir / "videos", dir_has_to_exist=False)
126
+
127
+
128
+ @dataclass
129
+ class Trip:
130
+ """Polarsteps trip object."""
131
+
132
+ name: str
133
+ start_date: datetime
134
+ end_date: datetime
135
+ cover_photo_path: str
136
+ steps: list[Step]
137
+
138
+ @classmethod
139
+ def from_json(cls, data: dict) -> Self:
140
+ """Parse object from JSON data."""
141
+ return Trip(
142
+ name=data["name"],
143
+ start_date=parse_date(data.get("start_date")),
144
+ end_date=parse_date(data.get("end_date")),
145
+ cover_photo_path=data["cover_photo_path"],
146
+ steps=[Step.from_json(step) for step in data.get("all_steps")],
147
+ )