goodmap 0.4.0__py3-none-any.whl → 0.4.2__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.
- goodmap/core.py +3 -0
- goodmap/core_api.py +49 -13
- goodmap/data_models/location.py +28 -6
- goodmap/data_validator.py +1 -1
- goodmap/db.py +97 -4
- goodmap/goodmap.py +27 -5
- goodmap/templates/map.html +5 -2
- {goodmap-0.4.0.dist-info → goodmap-0.4.2.dist-info}/METADATA +16 -2
- goodmap-0.4.2.dist-info/RECORD +14 -0
- goodmap-0.4.0.dist-info/RECORD +0 -14
- {goodmap-0.4.0.dist-info → goodmap-0.4.2.dist-info}/LICENSE.md +0 -0
- {goodmap-0.4.0.dist-info → goodmap-0.4.2.dist-info}/WHEEL +0 -0
goodmap/core.py
CHANGED
goodmap/core_api.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import importlib.metadata
|
|
2
|
+
import uuid
|
|
2
3
|
|
|
4
|
+
import deprecation
|
|
3
5
|
from flask import Blueprint, jsonify, make_response, request
|
|
4
6
|
from flask_babel import gettext
|
|
5
7
|
from flask_restx import Api, Resource, fields
|
|
6
8
|
from platzky.config import LanguagesMapping
|
|
7
9
|
|
|
8
|
-
from goodmap.
|
|
9
|
-
|
|
10
|
-
from .core import get_queried_data
|
|
11
|
-
from .formatter import prepare_pin
|
|
10
|
+
from goodmap.core import get_queried_data
|
|
11
|
+
from goodmap.formatter import prepare_pin
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
def make_tuple_translation(keys_to_translate):
|
|
@@ -16,7 +16,7 @@ def make_tuple_translation(keys_to_translate):
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def core_pages(
|
|
19
|
-
database, languages: LanguagesMapping, notifier_function, csrf_generator
|
|
19
|
+
database, languages: LanguagesMapping, notifier_function, csrf_generator, location_model
|
|
20
20
|
) -> Blueprint:
|
|
21
21
|
core_api_blueprint = Blueprint("api", __name__, url_prefix="/api")
|
|
22
22
|
core_api = Api(core_api_blueprint, doc="/doc", version="0.1")
|
|
@@ -29,26 +29,28 @@ def core_pages(
|
|
|
29
29
|
},
|
|
30
30
|
)
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# TODO get this from Location pydantic model
|
|
33
|
+
suggested_location_model = core_api.model(
|
|
33
34
|
"LocationSuggestion",
|
|
34
35
|
{
|
|
35
|
-
"name": fields.String(required=
|
|
36
|
-
"
|
|
36
|
+
"name": fields.String(required=False, description="Organization name"),
|
|
37
|
+
"position": fields.String(required=True, description="Location of the suggestion"),
|
|
37
38
|
"photo": fields.String(required=False, description="Photo of the location"),
|
|
38
39
|
},
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
@core_api.route("/suggest-new-point")
|
|
42
43
|
class NewLocation(Resource):
|
|
43
|
-
@core_api.expect(
|
|
44
|
+
@core_api.expect(suggested_location_model)
|
|
44
45
|
def post(self):
|
|
45
46
|
"""Suggest new location"""
|
|
46
47
|
try:
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
suggested_location = request.get_json()
|
|
49
|
+
suggested_location.update({"uuid": str(uuid.uuid4())})
|
|
50
|
+
location = location_model.model_validate(suggested_location)
|
|
49
51
|
message = (
|
|
50
|
-
f"A new location has been suggested: '{location.
|
|
51
|
-
f"at position: {location.
|
|
52
|
+
f"A new location has been suggested under uuid: '{location.uuid}' "
|
|
53
|
+
f"at position: {location.position}"
|
|
52
54
|
)
|
|
53
55
|
notifier_function(message)
|
|
54
56
|
except ValueError as e:
|
|
@@ -75,6 +77,12 @@ def core_pages(
|
|
|
75
77
|
|
|
76
78
|
@core_api.route("/data")
|
|
77
79
|
class Data(Resource):
|
|
80
|
+
@deprecation.deprecated(
|
|
81
|
+
deprecated_in="0.4.1",
|
|
82
|
+
removed_in="0.5.0",
|
|
83
|
+
current_version=importlib.metadata.version("goodmap"),
|
|
84
|
+
details="Use /locations or /location/<point_id> instead",
|
|
85
|
+
)
|
|
78
86
|
def get(self):
|
|
79
87
|
"""
|
|
80
88
|
Shows all data filtered by query parameters
|
|
@@ -90,6 +98,34 @@ def core_pages(
|
|
|
90
98
|
formatted_data = [prepare_pin(x, visible_data, meta_data) for x in queried_data]
|
|
91
99
|
return jsonify(formatted_data)
|
|
92
100
|
|
|
101
|
+
@core_api.route("/locations")
|
|
102
|
+
class GetLocations(Resource):
|
|
103
|
+
def get(self):
|
|
104
|
+
"""
|
|
105
|
+
Shows list of locations with uuid and position
|
|
106
|
+
"""
|
|
107
|
+
query_params = request.args.to_dict(flat=False)
|
|
108
|
+
all_locations = database.get_locations(query_params)
|
|
109
|
+
return jsonify([x.basic_info() for x in all_locations])
|
|
110
|
+
|
|
111
|
+
@core_api.route("/location/<location_id>")
|
|
112
|
+
class GetLocation(Resource):
|
|
113
|
+
def get(self, location_id):
|
|
114
|
+
"""
|
|
115
|
+
Shows a single location with all data
|
|
116
|
+
"""
|
|
117
|
+
location = database.get_location(location_id)
|
|
118
|
+
|
|
119
|
+
# TODO getting visible_data and meta_data should be taken from db methods
|
|
120
|
+
# e.g. db.get_visible_data() and db.get_meta_data()
|
|
121
|
+
# visible_data and meta_data should be models
|
|
122
|
+
all_data = database.get_data()
|
|
123
|
+
visible_data = all_data["visible_data"]
|
|
124
|
+
meta_data = all_data["meta_data"]
|
|
125
|
+
|
|
126
|
+
formatted_data = prepare_pin(location.model_dump(), visible_data, meta_data)
|
|
127
|
+
return jsonify(formatted_data)
|
|
128
|
+
|
|
93
129
|
@core_api.route("/version")
|
|
94
130
|
class Version(Resource):
|
|
95
131
|
def get(self):
|
goodmap/data_models/location.py
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import Any, Type
|
|
2
2
|
|
|
3
|
+
from pydantic import BaseModel, Field, create_model, field_validator
|
|
3
4
|
|
|
4
|
-
class Location(BaseModel):
|
|
5
|
-
name: str
|
|
6
|
-
coordinates: tuple[float, float]
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
class LocationBase(BaseModel, extra="allow"):
|
|
7
|
+
position: tuple[float, float]
|
|
8
|
+
uuid: str
|
|
9
|
+
|
|
10
|
+
@field_validator("position")
|
|
9
11
|
@classmethod
|
|
10
|
-
def
|
|
12
|
+
def position_must_be_valid(cls, v):
|
|
11
13
|
if v[0] < -90 or v[0] > 90:
|
|
12
14
|
raise ValueError("latitude must be in range -90 to 90")
|
|
13
15
|
if v[1] < -180 or v[1] > 180:
|
|
14
16
|
raise ValueError("longitude must be in range -180 to 180")
|
|
15
17
|
return v
|
|
18
|
+
|
|
19
|
+
def basic_info(self):
|
|
20
|
+
return {"uuid": self.uuid, "position": self.position}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def create_location_model(obligatory_fields: list[tuple[str, Type[Any]]]) -> Type[BaseModel]:
|
|
24
|
+
fields = {
|
|
25
|
+
field_name: (field_type, Field(...)) for (field_name, field_type) in obligatory_fields
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return create_model(
|
|
29
|
+
"Location",
|
|
30
|
+
__config__=None,
|
|
31
|
+
__doc__=None,
|
|
32
|
+
__module__="Location",
|
|
33
|
+
__validators__=None,
|
|
34
|
+
__base__=LocationBase,
|
|
35
|
+
__cls_kwargs__=None,
|
|
36
|
+
**fields,
|
|
37
|
+
)
|
goodmap/data_validator.py
CHANGED
|
@@ -76,7 +76,7 @@ def report_data_violations_from_json(json_database):
|
|
|
76
76
|
map_data = json_database["map"]
|
|
77
77
|
datapoints = map_data["data"]
|
|
78
78
|
categories = map_data["categories"]
|
|
79
|
-
obligatory_fields = map_data["
|
|
79
|
+
obligatory_fields = map_data["location_obligatory_fields"]
|
|
80
80
|
|
|
81
81
|
data_violations = []
|
|
82
82
|
|
goodmap/db.py
CHANGED
|
@@ -1,12 +1,37 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from functools import partial
|
|
3
|
+
|
|
4
|
+
from goodmap.core import get_queried_data
|
|
2
5
|
|
|
3
6
|
# TODO file is temporary solution to be compatible with old, static code,
|
|
4
7
|
# it should be replaced with dynamic solution
|
|
5
8
|
|
|
6
9
|
|
|
10
|
+
# ------------------------------------------------
|
|
11
|
+
# get_location_obligatory_fields
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def json_db_get_location_obligatory_fields(db):
|
|
15
|
+
return db.data["location_obligatory_fields"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def json_file_db_get_location_obligatory_fields(db):
|
|
19
|
+
with open(db.data_file_path, "r") as file:
|
|
20
|
+
return json.load(file)["map"]["location_obligatory_fields"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def google_json_db_get_location_obligatory_fields(db):
|
|
24
|
+
return json.loads(db.blob.download_as_text(client=None))["map"]["location_obligatory_fields"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_location_obligatory_fields(db):
|
|
28
|
+
return globals()[f"{db.module_name}_get_location_obligatory_fields"](db)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# ------------------------------------------------
|
|
32
|
+
# get_data
|
|
7
33
|
def google_json_db_get_data(self):
|
|
8
|
-
|
|
9
|
-
return json.loads(raw_data)["map"]
|
|
34
|
+
return json.loads(self.blob.download_as_text(client=None))["map"]
|
|
10
35
|
|
|
11
36
|
|
|
12
37
|
def json_file_db_get_data(self):
|
|
@@ -19,5 +44,73 @@ def json_db_get_data(self):
|
|
|
19
44
|
|
|
20
45
|
|
|
21
46
|
def get_data(db):
|
|
22
|
-
|
|
23
|
-
|
|
47
|
+
return globals()[f"{db.module_name}_get_data"]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ------------------------------------------------
|
|
51
|
+
# get_location
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_location_from_raw_data(raw_data, uuid, location_model):
|
|
55
|
+
point = next((point for point in raw_data["data"] if point["uuid"] == uuid), None)
|
|
56
|
+
return location_model.model_validate(point) if point else None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def google_json_db_get_location(self, uuid, location_model):
|
|
60
|
+
return get_location_from_raw_data(
|
|
61
|
+
json.loads(self.blob.download_as_text(client=None))["map"], uuid, location_model
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def json_file_db_get_location(self, uuid, location_model):
|
|
66
|
+
with open(self.data_file_path, "r") as file:
|
|
67
|
+
point = get_location_from_raw_data(json.load(file)["map"], uuid, location_model)
|
|
68
|
+
return point
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def json_db_get_location(self, uuid, location_model):
|
|
72
|
+
return get_location_from_raw_data(self.data, uuid, location_model)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def get_location(db, location_model):
|
|
76
|
+
return partial(globals()[f"{db.module_name}_get_location"], location_model=location_model)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# ------------------------------------------------
|
|
80
|
+
# get_locations
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_locations_list_from_raw_data(map_data, query, location_model):
|
|
84
|
+
filtered_locations = get_queried_data(map_data["data"], map_data["categories"], query)
|
|
85
|
+
return [location_model.model_validate(point) for point in filtered_locations]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def google_json_db_get_locations(self, query, location_model):
|
|
89
|
+
return get_locations_list_from_raw_data(
|
|
90
|
+
json.loads(self.blob.download_as_text(client=None))["map"], query, location_model
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def json_file_db_get_locations(self, query, location_model):
|
|
95
|
+
with open(self.data_file_path, "r") as file:
|
|
96
|
+
return get_locations_list_from_raw_data(json.load(file)["map"], query, location_model)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def json_db_get_locations(self, query, location_model):
|
|
100
|
+
return get_locations_list_from_raw_data(self.data, query, location_model)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def get_locations(db, location_model):
|
|
104
|
+
return partial(globals()[f"{db.module_name}_get_locations"], location_model=location_model)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# TODO extension function should be replaced with simple extend which would take a db plugin
|
|
108
|
+
# it could look like that:
|
|
109
|
+
# `db.extend(goodmap_db_plugin)` in plugin all those functions would be organized
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def extend_db_with_goodmap_queries(db, location_model):
|
|
113
|
+
db.extend("get_data", get_data(db))
|
|
114
|
+
db.extend("get_locations", get_locations(db, location_model))
|
|
115
|
+
db.extend("get_location", get_location(db, location_model))
|
|
116
|
+
return db
|
goodmap/goodmap.py
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
from flask import Blueprint, render_template
|
|
2
4
|
from flask_wtf.csrf import CSRFProtect, generate_csrf
|
|
3
5
|
from platzky import platzky
|
|
4
6
|
from platzky.config import Config, languages_dict
|
|
5
7
|
|
|
6
|
-
from .core_api import core_pages
|
|
7
|
-
from .
|
|
8
|
+
from goodmap.core_api import core_pages
|
|
9
|
+
from goodmap.data_models.location import create_location_model
|
|
10
|
+
from goodmap.db import extend_db_with_goodmap_queries, get_location_obligatory_fields
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
def create_app(config_path: str) -> platzky.Engine:
|
|
@@ -12,19 +15,38 @@ def create_app(config_path: str) -> platzky.Engine:
|
|
|
12
15
|
return create_app_from_config(config)
|
|
13
16
|
|
|
14
17
|
|
|
18
|
+
# TODO Checking if there is a feature flag secition should be part of configs logic not client app
|
|
19
|
+
def is_feature_enabled(config: Config, feature: str) -> bool:
|
|
20
|
+
return config.feature_flags.get(feature, False) if config.feature_flags else False
|
|
21
|
+
|
|
22
|
+
|
|
15
23
|
def create_app_from_config(config: Config) -> platzky.Engine:
|
|
24
|
+
directory = os.path.dirname(os.path.realpath(__file__))
|
|
25
|
+
|
|
26
|
+
locale_dir = os.path.join(directory, "locale")
|
|
27
|
+
config.translation_directories.append(locale_dir)
|
|
16
28
|
app = platzky.create_app_from_config(config)
|
|
17
29
|
|
|
18
|
-
|
|
30
|
+
if is_feature_enabled(config, "USE_LAZY_LOADING"):
|
|
31
|
+
location_obligatory_fields = get_location_obligatory_fields(app.db)
|
|
32
|
+
else:
|
|
33
|
+
location_obligatory_fields = []
|
|
34
|
+
|
|
35
|
+
location_model = create_location_model(location_obligatory_fields)
|
|
36
|
+
|
|
37
|
+
app.db = extend_db_with_goodmap_queries(app.db, location_model)
|
|
38
|
+
|
|
19
39
|
CSRFProtect(app)
|
|
20
40
|
|
|
21
|
-
cp = core_pages(
|
|
41
|
+
cp = core_pages(
|
|
42
|
+
app.db, languages_dict(config.languages), app.notify, generate_csrf, location_model
|
|
43
|
+
)
|
|
22
44
|
app.register_blueprint(cp)
|
|
23
45
|
goodmap = Blueprint("goodmap", __name__, url_prefix="/", template_folder="templates")
|
|
24
46
|
|
|
25
47
|
@goodmap.route("/")
|
|
26
48
|
def index():
|
|
27
|
-
return render_template("map.html")
|
|
49
|
+
return render_template("map.html", feature_flags=config.feature_flags)
|
|
28
50
|
|
|
29
51
|
app.register_blueprint(goodmap)
|
|
30
52
|
return app
|
goodmap/templates/map.html
CHANGED
|
@@ -35,12 +35,11 @@
|
|
|
35
35
|
</style>
|
|
36
36
|
|
|
37
37
|
<div id="loadingPopup" class="loading-popup">
|
|
38
|
-
|
|
38
|
+
{{ gettext('Loading') }}...
|
|
39
39
|
</div>
|
|
40
40
|
|
|
41
41
|
<div id="map" class="map h-100 w-100"></div>
|
|
42
42
|
|
|
43
|
-
|
|
44
43
|
<script type="text/javascript">
|
|
45
44
|
|
|
46
45
|
(function() {
|
|
@@ -113,6 +112,10 @@ function hideLoading() {
|
|
|
113
112
|
window.APP_LANG = "{{ current_language }}";
|
|
114
113
|
window.SECONDARY_COLOR = "{{ secondary_color }}";
|
|
115
114
|
window.PRIMARY_COLOR = "{{ primary_color }}";
|
|
115
|
+
|
|
116
|
+
window.SHOW_SUGGEST_NEW_POINT_BUTTON = {{ feature_flags.SHOW_SUGGEST_NEW_POINT_BUTTON | default(false) | tojson }};
|
|
117
|
+
window.SHOW_SEARCH_BAR = {{ feature_flags.SHOW_SEARCH_BAR | default(false) | tojson }};
|
|
118
|
+
window.USE_LAZY_LOADING = {{ feature_flags.USE_LAZY_LOADING | default(false) | tojson }};
|
|
116
119
|
</script>
|
|
117
120
|
<script src="/static/map.js"></script>
|
|
118
121
|
{% endblock %}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: goodmap
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Map engine to serve all the people :)
|
|
5
5
|
Author: Krzysztof Kolodzinski
|
|
6
6
|
Author-email: krzysztof.kolodzinski@problematy.pl
|
|
@@ -16,6 +16,7 @@ Requires-Dist: Flask-Babel (>=4.0.0,<5.0.0)
|
|
|
16
16
|
Requires-Dist: Flask-WTF (>=1.2.1,<2.0.0)
|
|
17
17
|
Requires-Dist: PyYAML (>=6.0,<7.0)
|
|
18
18
|
Requires-Dist: aiohttp (>=3.8.4,<4.0.0)
|
|
19
|
+
Requires-Dist: deprecation (>=2.1.0,<3.0.0)
|
|
19
20
|
Requires-Dist: flask-restx (>=1.3.0,<2.0.0)
|
|
20
21
|
Requires-Dist: google-cloud-storage (>=2.7.0,<3.0.0)
|
|
21
22
|
Requires-Dist: gql (>=3.4.0,<4.0.0)
|
|
@@ -34,6 +35,19 @@ Map engine to serve all the people ;)
|
|
|
34
35
|
|
|
35
36
|
## Setup
|
|
36
37
|
|
|
38
|
+
#### 0. Clone the repo
|
|
39
|
+
```
|
|
40
|
+
git clone --recursive
|
|
41
|
+
```
|
|
42
|
+
Remember, everytime you want to pull the newest changes, run:
|
|
43
|
+
```
|
|
44
|
+
git pull
|
|
45
|
+
git submodule update
|
|
46
|
+
```
|
|
47
|
+
because `goodmap` contains a submodule.
|
|
48
|
+
|
|
49
|
+
#TODO remove all submodule connected instructions after removing platzky submodule (see #157)
|
|
50
|
+
|
|
37
51
|
#### 1. Use python 3.10
|
|
38
52
|
If you have a different version of Python on your system, install python 3.10 alongside. For that, you can use [`pyenv`](https://github.com/pyenv/pyenv). Follow the [documentation](https://github.com/pyenv/pyenv?tab=readme-ov-file#installation). Useful commands: `pyenv help <command>`, `pyenv install`, `pyenv shell`, `pyenv versions`.
|
|
39
53
|
|
|
@@ -96,7 +110,7 @@ TODO: `obligatory_fields` is a new subsection, start using it in the actual appl
|
|
|
96
110
|
```
|
|
97
111
|
- `meta-data` - some special data like
|
|
98
112
|
```
|
|
99
|
-
"
|
|
113
|
+
"uuid"
|
|
100
114
|
```
|
|
101
115
|
|
|
102
116
|
You can define the fields in all these subsections. Besides these types of fields, there is no restriction on the number of fields a datapoint can have.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
goodmap/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
+
goodmap/core.py,sha256=hOTHrDRzbqkfSeKAoD01lzSoY4W8JwupXlJTwTzcvAU,586
|
|
3
|
+
goodmap/core_api.py,sha256=R7c6NywWYyudIOzekbY_Xa2izszIFv-5YFEe5BrkJFw,6476
|
|
4
|
+
goodmap/data_models/location.py,sha256=ESR4Z_zINIjldJKhlXImMaQrdtUPJBQc6SatpPPJyNQ,1054
|
|
5
|
+
goodmap/data_validator.py,sha256=e_PCc2CTgiEBK6inF_HDX5mb5R8poh3KkcbhyrLrFVA,4086
|
|
6
|
+
goodmap/db.py,sha256=AJHUP3n29BRjgt6GoGnPtxLNg5TL-KSJhtSZtsZKmGM,3665
|
|
7
|
+
goodmap/formatter.py,sha256=VlUHcK1HtM_IEU0VE3S5TOkZLVheMdakvUeW2tCKdq0,783
|
|
8
|
+
goodmap/goodmap.py,sha256=cPTTyGqajuza3RDlfFuCl8idxy7TFo6LPuANP8hmg7U,1806
|
|
9
|
+
goodmap/templates/admin.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
+
goodmap/templates/map.html,sha256=eU_h61l404g8e3_wszUokDrOC92bQ1nFl8yGMKRXFww,3820
|
|
11
|
+
goodmap-0.4.2.dist-info/LICENSE.md,sha256=nkCQOR7uheLRvHRfXmwx9LhBnMcPeBU9d4ebLojDiQU,1067
|
|
12
|
+
goodmap-0.4.2.dist-info/METADATA,sha256=rSIeCJEqtI6SKaeD8TgBJ6HempDKjy8tJRafe3XystA,4525
|
|
13
|
+
goodmap-0.4.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
14
|
+
goodmap-0.4.2.dist-info/RECORD,,
|
goodmap-0.4.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
goodmap/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
-
goodmap/core.py,sha256=rU0RIoDR3trdaFH2F2DrO73P_SuYSPbbHZuYzPZiUj8,551
|
|
3
|
-
goodmap/core_api.py,sha256=yhZT_w9ImIH6j2gU7U9QsBWNId5VzX3NntEHZUrPGfg,4957
|
|
4
|
-
goodmap/data_models/location.py,sha256=mqECJ2K1RCcUX4wJJJUqQY2uX2eBuJlVOME5D9HtYV8,455
|
|
5
|
-
goodmap/data_validator.py,sha256=sEyQEQcdDKSFYwendQxSFoOVL61JsVSYRnZVYNxAw3g,4077
|
|
6
|
-
goodmap/db.py,sha256=tcjjh5vMzmOwB3p1MU5Mj6rim5WIsWllBts577qVhj0,543
|
|
7
|
-
goodmap/formatter.py,sha256=VlUHcK1HtM_IEU0VE3S5TOkZLVheMdakvUeW2tCKdq0,783
|
|
8
|
-
goodmap/goodmap.py,sha256=CQ1B6cD3qgSM7pZjPBr6D2xZIJaZ-Yg9F6oyYLxuYNA,907
|
|
9
|
-
goodmap/templates/admin.html,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
goodmap/templates/map.html,sha256=l5sn8jmFoh3mdV-PAIy8fHxxB7JU3SA-kMLOKvWVGnM,3511
|
|
11
|
-
goodmap-0.4.0.dist-info/LICENSE.md,sha256=nkCQOR7uheLRvHRfXmwx9LhBnMcPeBU9d4ebLojDiQU,1067
|
|
12
|
-
goodmap-0.4.0.dist-info/METADATA,sha256=O72F5pISxOSZGqXTzWWdlB3Yhdq20pWitVXtFYlKNPg,4192
|
|
13
|
-
goodmap-0.4.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
14
|
-
goodmap-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|