tina4-python 0.2.193__tar.gz → 0.2.195__tar.gz
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.
- {tina4_python-0.2.193 → tina4_python-0.2.195}/PKG-INFO +1 -1
- {tina4_python-0.2.193 → tina4_python-0.2.195}/pyproject.toml +2 -1
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Router.py +12 -4
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Session.py +94 -1
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Webserver.py +6 -8
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/__init__.py +8 -12
- {tina4_python-0.2.193 → tina4_python-0.2.195}/.gitignore +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/README.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Api.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Auth.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/CLAUDE.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/CRUD.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Constant.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Database.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/DatabaseResult.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/DatabaseTypes.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Debug.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/DevReload.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Env.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/FieldTypes.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/HtmlElement.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Localization.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Messages.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/MiddleWare.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Migration.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/ORM.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Queue.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Request.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Response.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/ShellColors.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Swagger.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Template.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Testing.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/WSDL.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/Websocket.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/cli.py +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/messages.pot +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/css/readme.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/favicon.ico +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/images/403.png +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/images/404.png +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/images/500.png +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/images/logo.png +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/images/readme.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/js/readme.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/js/reconnecting-websocket.js +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/js/tina4helper.js +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/swagger/index.html +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/swagger/oauth2-redirect.html +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/templates/components/crud.twig +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/templates/errors/403.twig +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/templates/errors/404.twig +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/templates/errors/500.twig +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/templates/readme.md +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/af/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/af/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/en/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/en/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/es/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/es/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/fr/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/fr/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/ja/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/ja/LC_MESSAGES/messages.po +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/zh/LC_MESSAGES/messages.mo +0 -0
- {tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/zh/LC_MESSAGES/messages.po +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "tina4-python"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.195"
|
|
4
4
|
description = "Tina4Python - This is not another framework for Python"
|
|
5
5
|
authors = [
|
|
6
6
|
{name = "Andre van Zuydam",email = "andrevanzuydam@gmail.com"}
|
|
@@ -32,6 +32,7 @@ dev = [
|
|
|
32
32
|
"pydoc-markdown>=4.8.2",
|
|
33
33
|
"pytest>=8.3.5",
|
|
34
34
|
"pytest-asyncio>=1.3.0",
|
|
35
|
+
"pytest-cov>=7.0.0",
|
|
35
36
|
"python-keycloak>=5.8.1",
|
|
36
37
|
"ruff>=0.11.9",
|
|
37
38
|
"safety>=3.5.0",
|
|
@@ -354,6 +354,7 @@ class Router:
|
|
|
354
354
|
tina4_python.tina4_current_request = {"url": url, "headers": headers}
|
|
355
355
|
|
|
356
356
|
validated = False
|
|
357
|
+
has_form_token = False
|
|
357
358
|
# we can add other methods later but right now we validate gets, posts and other risky methods
|
|
358
359
|
if method in [Constant.TINA4_GET, Constant.TINA4_POST, Constant.TINA4_PUT, Constant.TINA4_PATCH,
|
|
359
360
|
Constant.TINA4_DELETE]:
|
|
@@ -372,16 +373,19 @@ class Router:
|
|
|
372
373
|
token = headers["authorization"].replace("Bearer", "").strip()
|
|
373
374
|
if tina4_python.tina4_auth.valid(token):
|
|
374
375
|
validated = True
|
|
376
|
+
has_form_token = True
|
|
375
377
|
|
|
376
378
|
if request["params"] is not None and "formToken" in request["params"]:
|
|
377
379
|
token = request["params"]["formToken"]
|
|
378
380
|
if tina4_python.tina4_auth.valid(token):
|
|
379
381
|
validated = True
|
|
382
|
+
has_form_token = True
|
|
380
383
|
|
|
381
384
|
if request["body"] is not None and "formToken" in request["body"]:
|
|
382
385
|
token = request["body"]["formToken"]
|
|
383
386
|
if tina4_python.tina4_auth.valid(token):
|
|
384
387
|
validated = True
|
|
388
|
+
has_form_token = True
|
|
385
389
|
|
|
386
390
|
if request["body"] is not None and "formToken" in request["body"]:
|
|
387
391
|
request["params"]["formToken"] = request["body"]["formToken"]
|
|
@@ -521,7 +525,8 @@ class Router:
|
|
|
521
525
|
return Response(result.content, result.http_code, result.content_type)
|
|
522
526
|
|
|
523
527
|
if result is not None:
|
|
524
|
-
|
|
528
|
+
if has_form_token:
|
|
529
|
+
result.headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
525
530
|
if "cache" in route and route["cache"] is not None:
|
|
526
531
|
if not route["cache"]["cached"]:
|
|
527
532
|
result.headers["Cache-Control"] = "max-age=1, must-revalidate"
|
|
@@ -542,7 +547,9 @@ class Router:
|
|
|
542
547
|
if result is None and route_matched:
|
|
543
548
|
output = buffer.getvalue()
|
|
544
549
|
if output:
|
|
545
|
-
fresh_headers = {
|
|
550
|
+
fresh_headers = {}
|
|
551
|
+
if has_form_token:
|
|
552
|
+
fresh_headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
546
553
|
try:
|
|
547
554
|
return Response(json.loads(output), Constant.HTTP_OK, Constant.APPLICATION_JSON, fresh_headers)
|
|
548
555
|
except Exception:
|
|
@@ -566,10 +573,11 @@ class Router:
|
|
|
566
573
|
)
|
|
567
574
|
|
|
568
575
|
twig_headers = {
|
|
569
|
-
"FreshToken": tina4_python.tina4_auth.get_token({"path": url}),
|
|
570
576
|
"Cache-Control": "max-age=-1, public",
|
|
571
577
|
"Pragma": "no-cache"
|
|
572
578
|
}
|
|
579
|
+
if has_form_token:
|
|
580
|
+
twig_headers["FreshToken"] = tina4_python.tina4_auth.get_token({"path": url})
|
|
573
581
|
content = Template.render_twig_template(twig_file, {"request": tina4_python.tina4_current_request})
|
|
574
582
|
if content != "":
|
|
575
583
|
return Response(content, Constant.HTTP_OK, Constant.TEXT_HTML, twig_headers)
|
|
@@ -579,7 +587,7 @@ class Router:
|
|
|
579
587
|
"errors/404.twig", {"server": {"url": url}})
|
|
580
588
|
return Response(content, Constant.HTTP_NOT_FOUND, Constant.TEXT_HTML)
|
|
581
589
|
|
|
582
|
-
|
|
590
|
+
# FreshToken already set on line 524 inside the route loop
|
|
583
591
|
return result
|
|
584
592
|
|
|
585
593
|
@staticmethod
|
|
@@ -30,7 +30,7 @@ Typical usage inside a route handler::
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
__all__ = [
|
|
33
|
-
"Session", "SessionHandler", "SessionFileHandler",
|
|
33
|
+
"Session", "LazySession", "SessionHandler", "SessionFileHandler",
|
|
34
34
|
"SessionRedisHandler", "SessionValkeyHandler",
|
|
35
35
|
"SessionMongoHandler",
|
|
36
36
|
]
|
|
@@ -685,3 +685,96 @@ class Session:
|
|
|
685
685
|
for key, value in self.session_values.items():
|
|
686
686
|
if key != "expires":
|
|
687
687
|
yield key, value
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
class LazySession:
|
|
691
|
+
"""Proxy that defers expensive Session creation until first use.
|
|
692
|
+
|
|
693
|
+
Creating and starting a ``Session`` requires RSA key signing (~1ms
|
|
694
|
+
per call) which dominates request latency for API routes that never
|
|
695
|
+
touch the session. ``LazySession`` wraps the session creation
|
|
696
|
+
parameters and only instantiates the real ``Session`` when a method
|
|
697
|
+
like ``set()``, ``get()``, or ``load()`` is called.
|
|
698
|
+
|
|
699
|
+
The ``activated`` property lets the response builder know whether
|
|
700
|
+
to emit a ``Set-Cookie`` header.
|
|
701
|
+
"""
|
|
702
|
+
|
|
703
|
+
def __init__(self, name, path, handler, cookies):
|
|
704
|
+
self._name = name
|
|
705
|
+
self._path = path
|
|
706
|
+
self._handler = handler
|
|
707
|
+
self._cookies = cookies
|
|
708
|
+
self._real = None
|
|
709
|
+
|
|
710
|
+
@property
|
|
711
|
+
def activated(self):
|
|
712
|
+
"""True if the real Session has been created."""
|
|
713
|
+
return self._real is not None
|
|
714
|
+
|
|
715
|
+
def _activate(self):
|
|
716
|
+
"""Create and start/load the real Session on first access."""
|
|
717
|
+
if self._real is None:
|
|
718
|
+
self._real = Session(self._name, self._path, self._handler)
|
|
719
|
+
if self._name in self._cookies:
|
|
720
|
+
self._real.load(self._cookies[self._name])
|
|
721
|
+
else:
|
|
722
|
+
self._cookies[self._name] = self._real.start()
|
|
723
|
+
return self._real
|
|
724
|
+
|
|
725
|
+
# --- Forwarded Session API ---
|
|
726
|
+
|
|
727
|
+
@property
|
|
728
|
+
def session_name(self):
|
|
729
|
+
return self._name
|
|
730
|
+
|
|
731
|
+
@property
|
|
732
|
+
def session_values(self):
|
|
733
|
+
if self._real is None:
|
|
734
|
+
return {}
|
|
735
|
+
return self._real.session_values
|
|
736
|
+
|
|
737
|
+
@property
|
|
738
|
+
def session_hash(self):
|
|
739
|
+
if self._real is None:
|
|
740
|
+
return ""
|
|
741
|
+
return self._real.session_hash
|
|
742
|
+
|
|
743
|
+
@session_hash.setter
|
|
744
|
+
def session_hash(self, value):
|
|
745
|
+
self._activate().session_hash = value
|
|
746
|
+
|
|
747
|
+
def start(self, session_hash=None):
|
|
748
|
+
result = self._activate().start(session_hash)
|
|
749
|
+
# Keep cookie dict in sync with the (possibly new) session hash
|
|
750
|
+
self._cookies[self._name] = result
|
|
751
|
+
return result
|
|
752
|
+
|
|
753
|
+
def load(self, session_hash):
|
|
754
|
+
self._activate().load(session_hash)
|
|
755
|
+
# Keep cookie dict in sync with loaded session hash
|
|
756
|
+
self._cookies[self._name] = self._real.session_hash
|
|
757
|
+
|
|
758
|
+
def set(self, key, value):
|
|
759
|
+
return self._activate().set(key, value)
|
|
760
|
+
|
|
761
|
+
def get(self, key):
|
|
762
|
+
return self._activate().get(key)
|
|
763
|
+
|
|
764
|
+
def unset(self, key):
|
|
765
|
+
return self._activate().unset(key)
|
|
766
|
+
|
|
767
|
+
def close(self):
|
|
768
|
+
if self._real is not None:
|
|
769
|
+
return self._real.close()
|
|
770
|
+
return True
|
|
771
|
+
|
|
772
|
+
def save(self):
|
|
773
|
+
if self._real is not None:
|
|
774
|
+
return self._real.save()
|
|
775
|
+
return True
|
|
776
|
+
|
|
777
|
+
def __iter__(self):
|
|
778
|
+
if self._real is not None:
|
|
779
|
+
return iter(self._real)
|
|
780
|
+
return iter([])
|
|
@@ -434,9 +434,10 @@ class Webserver:
|
|
|
434
434
|
self.send_header("Content-Type", response.content_type or "text/html", headers)
|
|
435
435
|
await self.send_basic_headers(headers)
|
|
436
436
|
|
|
437
|
-
# Preserve session cookie
|
|
437
|
+
# Preserve session cookie (only if session was used)
|
|
438
438
|
session_name = os.getenv("TINA4_SESSION", "PY_SESS")
|
|
439
|
-
|
|
439
|
+
session_activated = not hasattr(self.session, 'activated') or self.session.activated
|
|
440
|
+
if session_activated and session_name in self.cookies:
|
|
440
441
|
self.send_header("Set-Cookie", f"{session_name}={self.cookies[session_name]}", headers)
|
|
441
442
|
|
|
442
443
|
# Custom headers from route
|
|
@@ -585,14 +586,11 @@ class Webserver:
|
|
|
585
586
|
name, val = part.strip().split("=", 1)
|
|
586
587
|
self.cookies[name] = val
|
|
587
588
|
|
|
589
|
+
from tina4_python.Session import LazySession
|
|
588
590
|
session_name = os.getenv("TINA4_SESSION", "PY_SESS")
|
|
589
591
|
session_folder = os.getenv("TINA4_SESSION_FOLDER", os.path.join(tina4_python.root_path, "sessions"))
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
if session_name in self.cookies:
|
|
593
|
-
self.session.load(self.cookies[session_name])
|
|
594
|
-
else:
|
|
595
|
-
self.cookies[session_name] = self.session.start()
|
|
592
|
+
session_handler = os.getenv("TINA4_SESSION_HANDLER", "SessionFileHandler")
|
|
593
|
+
self.session = LazySession(session_name, session_folder, session_handler, self.cookies)
|
|
596
594
|
|
|
597
595
|
# ------------------------------------------------------------------
|
|
598
596
|
# Route or WebSocket
|
|
@@ -21,8 +21,6 @@ Just `pip install tina4-python` and run your project – everything just works.
|
|
|
21
21
|
"""
|
|
22
22
|
import asyncio
|
|
23
23
|
import os
|
|
24
|
-
if os.getenv("TINA4_DEBUG_LEVEL", "") == "":
|
|
25
|
-
os.environ["TINA4_DEBUG_LEVEL"] = "DEBUG"
|
|
26
24
|
|
|
27
25
|
import shutil
|
|
28
26
|
import importlib
|
|
@@ -46,7 +44,7 @@ from tina4_python.Auth import Auth
|
|
|
46
44
|
from tina4_python.Debug import Debug
|
|
47
45
|
from tina4_python.Debug import setup_logging
|
|
48
46
|
from tina4_python.ShellColors import ShellColors
|
|
49
|
-
from tina4_python.Session import Session
|
|
47
|
+
from tina4_python.Session import Session, LazySession
|
|
50
48
|
from tina4_python.HtmlElement import add_html_helpers
|
|
51
49
|
from tina4_python import ShellColors
|
|
52
50
|
from tina4_python.Constant import TINA4_LOG_INFO, TINA4_LOG_ALL, TINA4_LOG_DEBUG
|
|
@@ -428,15 +426,13 @@ async def app(scope, receive, send):
|
|
|
428
426
|
|
|
429
427
|
webserver.cookies = cookie_list
|
|
430
428
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
else:
|
|
439
|
-
webserver.cookies[os.getenv("TINA4_SESSION", "PY_SESS")] = webserver.session.start()
|
|
429
|
+
session_name = os.getenv("TINA4_SESSION", "PY_SESS")
|
|
430
|
+
webserver.session = LazySession(
|
|
431
|
+
session_name,
|
|
432
|
+
os.getenv("TINA4_SESSION_FOLDER", root_path + os.sep + "sessions"),
|
|
433
|
+
os.getenv("TINA4_SESSION_HANDLER", "SessionFileHandler"),
|
|
434
|
+
webserver.cookies,
|
|
435
|
+
)
|
|
440
436
|
|
|
441
437
|
tina4_response, tina4_headers = await webserver.get_response(webserver.method, scope=scope, reader=receive, writer=send, asgi_response=True)
|
|
442
438
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/js/reconnecting-websocket.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/public/swagger/oauth2-redirect.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/af/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/af/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/en/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/en/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/es/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/es/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/fr/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/fr/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/ja/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/ja/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/zh/LC_MESSAGES/messages.mo
RENAMED
|
File without changes
|
{tina4_python-0.2.193 → tina4_python-0.2.195}/tina4_python/translations/zh/LC_MESSAGES/messages.po
RENAMED
|
File without changes
|