panther 1.3.2__py3-none-any.whl → 1.4.0__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.
- panther/__init__.py +1 -1
- panther/cli/template.py +2 -0
- panther/configs.py +3 -1
- panther/db/queries/mongodb_queries.py +1 -13
- panther/db/queries/pantherdb_queries.py +2 -3
- panther/db/queries/queries.py +15 -1
- panther/db/utils.py +4 -4
- panther/logger.py +17 -9
- panther/main.py +1 -0
- panther/middlewares/monitoring.py +3 -3
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/METADATA +1 -1
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/RECORD +16 -16
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/LICENSE +0 -0
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/WHEEL +0 -0
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/entry_points.txt +0 -0
- {panther-1.3.2.dist-info → panther-1.4.0.dist-info}/top_level.txt +0 -0
panther/__init__.py
CHANGED
panther/cli/template.py
CHANGED
panther/configs.py
CHANGED
@@ -15,6 +15,7 @@ class JWTConfig:
|
|
15
15
|
class Config(TypedDict):
|
16
16
|
base_dir: Path
|
17
17
|
monitoring: bool
|
18
|
+
log_queries: bool
|
18
19
|
urls: dict
|
19
20
|
middlewares: list
|
20
21
|
reversed_middlewares: list
|
@@ -28,7 +29,8 @@ class Config(TypedDict):
|
|
28
29
|
|
29
30
|
config: Config = {
|
30
31
|
'base_dir': Path(),
|
31
|
-
'monitoring':
|
32
|
+
'monitoring': False,
|
33
|
+
'log_queries': False,
|
32
34
|
'secret_key': None,
|
33
35
|
'urls': {},
|
34
36
|
'middlewares': [],
|
@@ -3,7 +3,7 @@ from typing import TypeVar
|
|
3
3
|
import bson
|
4
4
|
|
5
5
|
from panther.db.connection import db # NOQA: F401
|
6
|
-
from panther.db.utils import clean_object_id_in_dicts, merge_dicts,
|
6
|
+
from panther.db.utils import clean_object_id_in_dicts, merge_dicts, log_query
|
7
7
|
|
8
8
|
# TODO: Not sure about this bounding
|
9
9
|
T = TypeVar('T', bound='BaseMongoDBQuery')
|
@@ -12,7 +12,6 @@ T = TypeVar('T', bound='BaseMongoDBQuery')
|
|
12
12
|
class BaseMongoDBQuery:
|
13
13
|
|
14
14
|
@classmethod
|
15
|
-
@query_logger
|
16
15
|
def get_one(cls: type[T], _data: dict = None, /, **kwargs) -> T:
|
17
16
|
clean_object_id_in_dicts(_data, kwargs)
|
18
17
|
_query = merge_dicts(_data, kwargs)
|
@@ -20,14 +19,12 @@ class BaseMongoDBQuery:
|
|
20
19
|
return cls(**obj) if obj else None
|
21
20
|
|
22
21
|
@classmethod
|
23
|
-
@query_logger
|
24
22
|
def count(cls, _data: dict = None, /, **kwargs) -> int:
|
25
23
|
clean_object_id_in_dicts(_data, kwargs)
|
26
24
|
_query = merge_dicts(_data, kwargs)
|
27
25
|
return eval(f'db.session.{cls.__name__}.count_documents(_query)')
|
28
26
|
|
29
27
|
@classmethod
|
30
|
-
@query_logger
|
31
28
|
def list(cls, _data: dict = None, /, **kwargs):
|
32
29
|
clean_object_id_in_dicts(_data, kwargs)
|
33
30
|
_query = merge_dicts(_data, kwargs)
|
@@ -35,32 +32,27 @@ class BaseMongoDBQuery:
|
|
35
32
|
return [cls(**obj) for obj in result]
|
36
33
|
|
37
34
|
@classmethod
|
38
|
-
@query_logger
|
39
35
|
def create(cls, _data: dict = None, **kwargs) -> bson.objectid.ObjectId:
|
40
36
|
_query = merge_dicts(_data, kwargs)
|
41
37
|
return eval(f'db.session.{cls.__name__}.insert_one(_query)').inserted_id
|
42
38
|
|
43
|
-
@query_logger
|
44
39
|
def delete(self) -> bool:
|
45
40
|
_filter = {'_id': self._id}
|
46
41
|
result = eval(f'db.session.{self.__class__.__name__}.delete_one(_filter)')
|
47
42
|
return bool(result.deleted_count)
|
48
43
|
|
49
44
|
@classmethod
|
50
|
-
@query_logger
|
51
45
|
def delete_one(cls, **kwargs) -> bool:
|
52
46
|
clean_object_id_in_dicts(kwargs)
|
53
47
|
result = eval(f'db.session.{cls.__name__}.delete_one(kwargs)')
|
54
48
|
return bool(result.deleted_count)
|
55
49
|
|
56
50
|
@classmethod
|
57
|
-
@query_logger
|
58
51
|
def delete_many(cls, **kwargs) -> int:
|
59
52
|
clean_object_id_in_dicts(kwargs)
|
60
53
|
result = eval(f'db.session.{cls.__name__}.delete_many(kwargs)')
|
61
54
|
return result.deleted_count
|
62
55
|
|
63
|
-
@query_logger
|
64
56
|
def update(self, _data: dict = None, **kwargs) -> dict:
|
65
57
|
for field, value in (_data or kwargs).items():
|
66
58
|
if hasattr(self, field):
|
@@ -70,7 +62,6 @@ class BaseMongoDBQuery:
|
|
70
62
|
return eval(f'db.session.{self.__class__.__name__}.update_one(_filter, _update)')
|
71
63
|
|
72
64
|
@classmethod
|
73
|
-
@query_logger
|
74
65
|
def update_one(cls, _filter, _data: dict = None, /, **kwargs) -> dict:
|
75
66
|
clean_object_id_in_dicts(_filter)
|
76
67
|
|
@@ -81,19 +72,16 @@ class BaseMongoDBQuery:
|
|
81
72
|
return eval(f'db.session.{cls.__name__}.update_one(_filter, _data | _update)')
|
82
73
|
|
83
74
|
@classmethod
|
84
|
-
@query_logger
|
85
75
|
def update_many(cls, _filter, **kwargs) -> dict:
|
86
76
|
_update = {'$set': kwargs}
|
87
77
|
return eval(f'db.session.{cls.__name__}.update_many(_filter, _update)')
|
88
78
|
|
89
79
|
@classmethod
|
90
|
-
@query_logger
|
91
80
|
def increment(cls, _filter, **kwargs):
|
92
81
|
_update = {'$inc': kwargs}
|
93
82
|
return eval(f'db.session.{cls.__name__}.update_many({_filter}, {_update})')
|
94
83
|
|
95
84
|
@classmethod
|
96
|
-
@query_logger
|
97
85
|
def get_or_create(cls, **kwargs) -> tuple[bool, any]:
|
98
86
|
obj = cls.get_one(**kwargs)
|
99
87
|
if obj:
|
@@ -1,9 +1,8 @@
|
|
1
|
-
import operator
|
2
|
-
from functools import reduce
|
3
1
|
from typing import Self
|
4
2
|
from pydantic import ValidationError
|
5
3
|
|
6
4
|
from panther.db.connection import db
|
5
|
+
from panther.db.utils import merge_dicts
|
7
6
|
from panther.exceptions import DBException
|
8
7
|
|
9
8
|
|
@@ -32,7 +31,7 @@ class BasePantherDBQuery:
|
|
32
31
|
@classmethod
|
33
32
|
def _merge(cls, *args) -> dict:
|
34
33
|
# TODO: Convert "id" to "_id"
|
35
|
-
return
|
34
|
+
return merge_dicts(*args)
|
36
35
|
|
37
36
|
# # # # # Find # # # # #
|
38
37
|
@classmethod
|
panther/db/queries/queries.py
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
from typing import Self
|
2
2
|
|
3
|
+
from panther.configs import config
|
4
|
+
from panther.db.utils import log_query
|
3
5
|
from panther.db.queries.mongodb_queries import BaseMongoDBQuery
|
4
6
|
from panther.db.queries.pantherdb_queries import BasePantherDBQuery
|
5
|
-
from panther.configs import config
|
6
7
|
|
7
8
|
if config['db_engine'] == 'pantherdb':
|
8
9
|
BaseQuery = BasePantherDBQuery
|
@@ -18,6 +19,7 @@ class Query(BaseQuery):
|
|
18
19
|
|
19
20
|
# # # # # Find # # # # #
|
20
21
|
@classmethod
|
22
|
+
@log_query
|
21
23
|
def find_one(cls, _data: dict = None, /, **kwargs) -> Self | None:
|
22
24
|
"""
|
23
25
|
example:
|
@@ -27,6 +29,7 @@ class Query(BaseQuery):
|
|
27
29
|
return super().find_one(_data, **kwargs)
|
28
30
|
|
29
31
|
@classmethod
|
32
|
+
@log_query
|
30
33
|
def find(cls, _data: dict = None, /, **kwargs) -> list[Self]:
|
31
34
|
"""
|
32
35
|
example:
|
@@ -37,6 +40,7 @@ class Query(BaseQuery):
|
|
37
40
|
|
38
41
|
# # # # # Insert # # # # #
|
39
42
|
@classmethod
|
43
|
+
@log_query
|
40
44
|
def insert_one(cls, _data: dict = None, /, **kwargs) -> Self:
|
41
45
|
"""
|
42
46
|
example:
|
@@ -46,10 +50,12 @@ class Query(BaseQuery):
|
|
46
50
|
return super().insert_one(_data, **kwargs)
|
47
51
|
|
48
52
|
@classmethod
|
53
|
+
@log_query
|
49
54
|
def insert_many(cls, _data: dict = None, **kwargs):
|
50
55
|
return super().insert_many(_data, **kwargs)
|
51
56
|
|
52
57
|
# # # # # Delete # # # # #
|
58
|
+
@log_query
|
53
59
|
def delete(self) -> None:
|
54
60
|
"""
|
55
61
|
example:
|
@@ -60,6 +66,7 @@ class Query(BaseQuery):
|
|
60
66
|
return super().delete()
|
61
67
|
|
62
68
|
@classmethod
|
69
|
+
@log_query
|
63
70
|
def delete_one(cls, **kwargs) -> bool:
|
64
71
|
"""
|
65
72
|
example:
|
@@ -69,6 +76,7 @@ class Query(BaseQuery):
|
|
69
76
|
return super().delete_one(**kwargs)
|
70
77
|
|
71
78
|
@classmethod
|
79
|
+
@log_query
|
72
80
|
def delete_many(cls, **kwargs) -> int:
|
73
81
|
"""
|
74
82
|
example:
|
@@ -78,6 +86,7 @@ class Query(BaseQuery):
|
|
78
86
|
return super().delete_many(**kwargs)
|
79
87
|
|
80
88
|
# # # # # Update # # # # #
|
89
|
+
@log_query
|
81
90
|
def update(self, **kwargs) -> None:
|
82
91
|
"""
|
83
92
|
example:
|
@@ -88,6 +97,7 @@ class Query(BaseQuery):
|
|
88
97
|
return super().update(**kwargs)
|
89
98
|
|
90
99
|
@classmethod
|
100
|
+
@log_query
|
91
101
|
def update_one(cls, _filter, _data: dict = None, /, **kwargs) -> bool:
|
92
102
|
"""
|
93
103
|
example:
|
@@ -98,6 +108,7 @@ class Query(BaseQuery):
|
|
98
108
|
return super().update_one(_filter, _data, **kwargs)
|
99
109
|
|
100
110
|
@classmethod
|
111
|
+
@log_query
|
101
112
|
def update_many(cls, _filter, **kwargs) -> int:
|
102
113
|
"""
|
103
114
|
example:
|
@@ -108,6 +119,7 @@ class Query(BaseQuery):
|
|
108
119
|
|
109
120
|
# # # # # Other # # # # #
|
110
121
|
@classmethod
|
122
|
+
@log_query
|
111
123
|
def first(cls, _data: dict = None, /, **kwargs) -> Self | None:
|
112
124
|
"""
|
113
125
|
It works same as find_one()
|
@@ -118,6 +130,7 @@ class Query(BaseQuery):
|
|
118
130
|
return super().first(_data, **kwargs)
|
119
131
|
|
120
132
|
@classmethod
|
133
|
+
@log_query
|
121
134
|
def last(cls, _data: dict = None, /, **kwargs) -> Self | None:
|
122
135
|
"""
|
123
136
|
example:
|
@@ -127,6 +140,7 @@ class Query(BaseQuery):
|
|
127
140
|
return super().last(_data, **kwargs)
|
128
141
|
|
129
142
|
@classmethod
|
143
|
+
@log_query
|
130
144
|
def count(cls, _data: dict = None, /, **kwargs) -> int:
|
131
145
|
"""
|
132
146
|
example:
|
panther/db/utils.py
CHANGED
@@ -4,18 +4,18 @@ from functools import reduce
|
|
4
4
|
from time import perf_counter
|
5
5
|
|
6
6
|
from panther.configs import config
|
7
|
-
from panther.logger import
|
7
|
+
from panther.logger import query_logger
|
8
8
|
|
9
9
|
|
10
|
-
def
|
10
|
+
def log_query(func):
|
11
11
|
def log(*args, **kwargs):
|
12
|
-
if config['
|
12
|
+
if config['log_queries'] is False:
|
13
13
|
return func(*args, **kwargs)
|
14
14
|
start = perf_counter()
|
15
15
|
response = func(*args, **kwargs)
|
16
16
|
end = perf_counter()
|
17
17
|
class_name = args[0].__name__ if hasattr(args[0], '__name__') else args[0].__class__.__name__
|
18
|
-
|
18
|
+
query_logger.info(f'\033[1mQuery -->\033[0m {class_name}.{func.__name__}() --> {(end - start) * 1_000:.2} ms')
|
19
19
|
return response
|
20
20
|
return log
|
21
21
|
|
panther/logger.py
CHANGED
@@ -18,6 +18,7 @@ class LogConfig(BaseModel):
|
|
18
18
|
DEFAULT_LOG_FORMAT: str = '%(levelprefix)s | %(asctime)s | %(message)s'
|
19
19
|
FILE_LOG_FORMAT: str = '%(asctime)s | %(message)s'
|
20
20
|
LOG_LEVEL: str = 'DEBUG'
|
21
|
+
MAX_FILE_SIZE: int = 1024 * 1024 * 100 # 100 MB
|
21
22
|
|
22
23
|
version = 1
|
23
24
|
disable_existing_loggers = False
|
@@ -39,15 +40,21 @@ class LogConfig(BaseModel):
|
|
39
40
|
'formatter': 'file_formatter',
|
40
41
|
'filename': LOGS_DIR / 'monitoring.log',
|
41
42
|
'class': 'logging.handlers.RotatingFileHandler',
|
42
|
-
'maxBytes':
|
43
|
+
'maxBytes': MAX_FILE_SIZE, # 100 MB,
|
44
|
+
'backupCount': 3,
|
45
|
+
},
|
46
|
+
'query_file': {
|
47
|
+
'formatter': 'file_formatter',
|
48
|
+
'filename': LOGS_DIR / 'query.log',
|
49
|
+
'class': 'logging.handlers.RotatingFileHandler',
|
50
|
+
'maxBytes': MAX_FILE_SIZE, # 100 MB,
|
43
51
|
'backupCount': 3,
|
44
52
|
},
|
45
53
|
'file': {
|
46
54
|
'formatter': 'file_formatter',
|
47
|
-
|
48
|
-
'filename': LOGS_DIR / f'{config["base_dir"].name}.log',
|
55
|
+
'filename': LOGS_DIR / f'main.log',
|
49
56
|
'class': 'logging.handlers.RotatingFileHandler',
|
50
|
-
'maxBytes':
|
57
|
+
'maxBytes': MAX_FILE_SIZE, # 100 MB,
|
51
58
|
'backupCount': 3,
|
52
59
|
},
|
53
60
|
'default': {
|
@@ -65,13 +72,14 @@ class LogConfig(BaseModel):
|
|
65
72
|
'handlers': ['monitoring_file'],
|
66
73
|
'level': LOG_LEVEL,
|
67
74
|
},
|
75
|
+
'query': {
|
76
|
+
'handlers': ['default', 'query_file'],
|
77
|
+
'level': LOG_LEVEL,
|
78
|
+
},
|
68
79
|
}
|
69
80
|
|
70
81
|
|
71
82
|
dictConfig(LogConfig().dict())
|
72
83
|
logger = logging.getLogger('panther')
|
73
|
-
|
74
|
-
|
75
|
-
"""
|
76
|
-
[debug, info, warning, error, critical]
|
77
|
-
"""
|
84
|
+
query_logger = logging.getLogger('query')
|
85
|
+
monitoring_logger = logging.getLogger('monitoring')
|
panther/main.py
CHANGED
@@ -117,6 +117,7 @@ class Panther:
|
|
117
117
|
|
118
118
|
# Put Variables In "config"
|
119
119
|
config['monitoring'] = self.settings.get('MONITORING', config['monitoring'])
|
120
|
+
config['log_queries'] = self.settings.get('LOG_QUERIES', config['log_queries'])
|
120
121
|
config['default_cache_exp'] = self.settings.get('DEFAULT_CACHE_EXP', config['default_cache_exp'])
|
121
122
|
config['secret_key'] = self._get_secret_key()
|
122
123
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
from time import perf_counter
|
2
2
|
|
3
|
-
from panther.logger import monitoring
|
4
|
-
from panther.middlewares.base import BaseMiddleware
|
5
3
|
from panther.request import Request
|
4
|
+
from panther.logger import monitoring_logger
|
5
|
+
from panther.middlewares.base import BaseMiddleware
|
6
6
|
|
7
7
|
|
8
8
|
class Middleware(BaseMiddleware):
|
@@ -21,4 +21,4 @@ class Middleware(BaseMiddleware):
|
|
21
21
|
but we should put in middlewares chain later ...
|
22
22
|
"""
|
23
23
|
response_time = (perf_counter() - self.start_time) * 1_000
|
24
|
-
|
24
|
+
monitoring_logger.info(f'{self.log} | {response_time: .3} ms | {status_code}')
|
@@ -1,12 +1,12 @@
|
|
1
|
-
panther/__init__.py,sha256=
|
1
|
+
panther/__init__.py,sha256=ViOJcmBWhbt9e0b1kOj-Y3RfqE4-sRmE9jJ0CwqE-FM,89
|
2
2
|
panther/_utils.py,sha256=Ltev6PCrTWHTWSQcWNfHMWDof1_MXODTAcDaGwflgXo,3667
|
3
3
|
panther/app.py,sha256=tojfQaU8x5pZa7m8XS4m9fR7D5sIe_-d96hD2ccBINo,5469
|
4
4
|
panther/authentications.py,sha256=FCRQL3xqN1Tla2vZsOY8-qXwPhnZBFsujJ-R7CeaW7w,2350
|
5
5
|
panther/caching.py,sha256=qCqb-IaXD1T7VU0AzJVMoXawb366ZYob9kblDUT-7sM,2452
|
6
|
-
panther/configs.py,sha256=
|
6
|
+
panther/configs.py,sha256=bRGRy772Rxjb3RunEBBvfa9LCNCmgcc2TKkfbNTK0GM,975
|
7
7
|
panther/exceptions.py,sha256=c1MeSo7_uwDuqoBcjKTFyXz17uXP5iZ3bM0Sp5Stvhw,769
|
8
|
-
panther/logger.py,sha256=
|
9
|
-
panther/main.py,sha256=
|
8
|
+
panther/logger.py,sha256=1skaZg4w55mTh4pSrCohkGp-7dg62lyEIoFAJKMP5L8,2499
|
9
|
+
panther/main.py,sha256=Aa43X3ZEonPrJ4Mj5ACEyGmJl-BbsHcPyKj3fDe2E4k,7460
|
10
10
|
panther/request.py,sha256=Ix1podGHCU5NlUCT9Emc79GOITKEw623ldpTw3oZm68,4383
|
11
11
|
panther/response.py,sha256=zzfe8vsPSnydN-_peJTizlnmnawxlNbJFU9zvXppYTk,1025
|
12
12
|
panther/routings.py,sha256=sV3xWksKYb3_95BTDOtSqouroHkB98ExoNkgWT1t7jE,4422
|
@@ -17,24 +17,24 @@ panther/cli/create_command.py,sha256=cUPMzXJnwsa2J1eGetWYUnbEL5GEEe5x-_wG3fA3rLg
|
|
17
17
|
panther/cli/main.py,sha256=TttHOr0jA2rkLxCCtpW3ES9x4dDpq5AS32dMN0VwoW0,891
|
18
18
|
panther/cli/monitor_command.py,sha256=wR6Ti8-2-LuLhfPzdXH77g7xlNQAL5flpBoVwu9qdoE,2458
|
19
19
|
panther/cli/run_command.py,sha256=SdguosH7Orlh-8x8eZK_EWrv8MPnXFKzqxruTHYdHqk,1501
|
20
|
-
panther/cli/template.py,sha256=
|
20
|
+
panther/cli/template.py,sha256=KhehW5nzovQzbW75J1lpAAQcIsqucqU4IXQXpVWBj5M,2317
|
21
21
|
panther/cli/utils.py,sha256=QKQ5_qLWtTjpLY0lZ6yt2vDlc2H0jF6HFe3F-8YNJDg,8225
|
22
22
|
panther/db/__init__.py,sha256=lOgqqRkGMzMSS1WS8D7lTChTr9ikIB5ImRPmucOhCyc,54
|
23
23
|
panther/db/connection.py,sha256=BoqTetHcWn2cmjo1ELDoFFGkGlvJw6qDuBorKSe8ru0,2097
|
24
24
|
panther/db/models.py,sha256=vnhFtVONqhCkTkFMOSz_rTDmAAxNcegPoxk1p5SljLc,1028
|
25
|
-
panther/db/utils.py,sha256=
|
25
|
+
panther/db/utils.py,sha256=6ndrZ9reaVTqnbFhX8MjOYtcrcPSY7UywAbDquY4eEg,1219
|
26
26
|
panther/db/queries/__init__.py,sha256=BMffHS9RbHE-AUAeT9C5uY3L-hpDh0WGRduDUQ9Kpuc,41
|
27
|
-
panther/db/queries/mongodb_queries.py,sha256=
|
28
|
-
panther/db/queries/pantherdb_queries.py,sha256=
|
29
|
-
panther/db/queries/queries.py,sha256=
|
27
|
+
panther/db/queries/mongodb_queries.py,sha256=qFW1tsxnyh459rFOOD-jPTZwhDFh6q6qSttA_a4ryaw,3228
|
28
|
+
panther/db/queries/pantherdb_queries.py,sha256=CEKxBcFZo4PmcleE87Jw1PrujtOB-emd20mqzHI1IKw,3834
|
29
|
+
panther/db/queries/queries.py,sha256=yG5B_qg4cNL8nDkeJtJ0RRj4EH5dEMC-2jNIk4I1eS0,4134
|
30
30
|
panther/middlewares/__init__.py,sha256=7RtHuS-MfybnJc6pcBSGhi9teXNhDsnJ3n7h_cXSkJk,66
|
31
31
|
panther/middlewares/base.py,sha256=Php29ckITeGZm6GfauFG3i61bcsb4qoU8RpPLTqsfls,240
|
32
32
|
panther/middlewares/db.py,sha256=C_PevTIaMykJl0NaaMYEfwE_oLdSLfKW2HR9UoPN1dU,508
|
33
|
-
panther/middlewares/monitoring.py,sha256=
|
33
|
+
panther/middlewares/monitoring.py,sha256=CbGNJ4Ja-m9Wq3Ytv7RFyd-Qj9Ft6cYqBZZncCAxccs,852
|
34
34
|
panther/middlewares/redis.py,sha256=_XIvPAOrVl74UoiA6-Xz8hSfWoeuM2Y1e74xeyvW0I4,1126
|
35
|
-
panther-1.
|
36
|
-
panther-1.
|
37
|
-
panther-1.
|
38
|
-
panther-1.
|
39
|
-
panther-1.
|
40
|
-
panther-1.
|
35
|
+
panther-1.4.0.dist-info/LICENSE,sha256=2aF1hL2aC0zRPjzUkSxJUzZbn2_uLoOkn7DHjzZni-I,1524
|
36
|
+
panther-1.4.0.dist-info/METADATA,sha256=AnzClL3p1FGVv2WWYBoSfJdMrIG3If4tq43T4zXx_Sk,5124
|
37
|
+
panther-1.4.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
38
|
+
panther-1.4.0.dist-info/entry_points.txt,sha256=6GPxYFGuzVfNB4YpHFJvYex6iWah5_tLnirAHwj2Qsg,51
|
39
|
+
panther-1.4.0.dist-info/top_level.txt,sha256=VbBs02JGXTIoHMzsX-eLOk2MCbBZzQbLhWiYpI7xI2g,8
|
40
|
+
panther-1.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|