From 829afdc1425940b2015d43ca3440cbd57b2308af Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 15:49:59 +0000 Subject: [PATCH 01/10] doc header fixes --- ...flask_imp_auth-generate_alphanumeric_validator.md | 4 ++-- .../_md/v3/flask_imp_auth-generate_csrf_token.md | 4 ++-- .../v3/flask_imp_auth-generate_email_validator.md | 4 ++-- .../v3/flask_imp_auth-generate_numeric_validator.md | 2 +- .../_md/v3/flask_imp_auth-generate_password.md | 2 +- archive_docs/_md/v3/flask_imp_auth-generate_salt.md | 2 +- .../_md/v3/flask_imp_auth-is_email_address_valid.md | 4 ++-- .../_md/v3/flask_imp_security-api_login_check.md | 2 +- .../_md/v3/flask_imp_security-permission_check.md | 12 ++++++------ ...flask_imp_auth-generate_alphanumeric_validator.md | 4 ++-- .../_md/v4/flask_imp_auth-generate_csrf_token.md | 4 ++-- .../v4/flask_imp_auth-generate_email_validator.md | 4 ++-- .../v4/flask_imp_auth-generate_numeric_validator.md | 2 +- .../_md/v4/flask_imp_auth-generate_password.md | 2 +- archive_docs/_md/v4/flask_imp_auth-generate_salt.md | 2 +- .../_md/v4/flask_imp_auth-is_email_address_valid.md | 4 ++-- .../_md/v4/flask_imp_security-api_login_check.md | 2 +- .../_md/v4/flask_imp_security-permission_check.md | 12 ++++++------ ...flask_imp_auth-generate_alphanumeric_validator.md | 4 ++-- .../_md/v5/flask_imp_auth-generate_csrf_token.md | 4 ++-- .../v5/flask_imp_auth-generate_email_validator.md | 4 ++-- .../v5/flask_imp_auth-generate_numeric_validator.md | 2 +- .../_md/v5/flask_imp_auth-generate_password.md | 2 +- archive_docs/_md/v5/flask_imp_auth-generate_salt.md | 2 +- .../_md/v5/flask_imp_auth-is_email_address_valid.md | 4 ++-- .../_md/v5/flask_imp_security-api_login_check.md | 2 +- .../_md/v5/flask_imp_security-permission_check.md | 12 ++++++------ docs/Auth/flask_imp_auth-authenticate_password.md | 2 +- docs/Auth/flask_imp_auth-encrypt_password.md | 2 +- ...flask_imp_auth-generate_alphanumeric_validator.md | 2 +- docs/Auth/flask_imp_auth-generate_csrf_token.md | 2 +- docs/Auth/flask_imp_auth-generate_email_validator.md | 2 +- .../flask_imp_auth-generate_numeric_validator.md | 2 +- docs/Auth/flask_imp_auth-generate_password.md | 2 +- docs/Auth/flask_imp_auth-generate_salt.md | 2 +- docs/Auth/flask_imp_auth-is_email_address_valid.md | 6 +++--- docs/Auth/flask_imp_auth-is_username_valid.md | 4 ++-- docs/Imp/Imp-import_app_resources.md | 6 +++--- docs/Imp/Imp-import_blueprint.md | 4 ++-- docs/Imp/Imp-import_models.md | 4 ++-- docs/Security/flask_imp_security-api_login_check.md | 4 ++-- docs/Security/flask_imp_security-login_check.md | 4 ++-- docs/Security/flask_imp_security-permission_check.md | 2 +- 43 files changed, 79 insertions(+), 79 deletions(-) diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md index f7cbe3d8..c0d0ccdc 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md @@ -17,8 +17,8 @@ Generates a random alphanumeric string of the given length. (letters are capitalized) -##### Example: +*Example:* ```python generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md index 80c18f66..ce6df31b 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md @@ -19,8 +19,8 @@ For use in Cross-Site Request Forgery. Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. -##### Example: +*Example:* ```python generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md index 3e66f143..acdced31 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md @@ -17,10 +17,10 @@ Uses `generate_alphanumeric_validator` with a length of 8 to generate a random alphanumeric value for the specific use of validating accounts via email. -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) +See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) for more information. -##### Example: +*Example:* ```python generate_email_validator() # >>> 'A1B2C3D4' diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md index ba19ff99..c0d7dc76 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md @@ -20,7 +20,7 @@ If the length is 4, it will generate a number between 1111 and 9999. For use in MFA email, or unique filename generation. -##### Example: +*Example:* ```python generate_numeric_validator(4) # >>> 1234 diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_password.md b/archive_docs/_md/v3/flask_imp_auth-generate_password.md index ec1588da..b6f8fda0 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_password.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_password.md @@ -19,7 +19,7 @@ The Default length is 3. Style options: "animals", "colors", "mixed" - defaults to "mixed" -##### Example: +*Example:* ```python generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_salt.md b/archive_docs/_md/v3/flask_imp_auth-generate_salt.md index 523746fa..f21615f5 100644 --- a/archive_docs/_md/v3/flask_imp_auth-generate_salt.md +++ b/archive_docs/_md/v3/flask_imp_auth-generate_salt.md @@ -19,7 +19,7 @@ The Default length is 4. For use in password hashing and storage of passwords in the database. -##### Example: +*Example:* ```python generate_salt() # >>> '*!$%' diff --git a/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md index a6af7dde..1990e24a 100644 --- a/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md +++ b/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md @@ -37,10 +37,10 @@ email@example.com (Joe Smith) email@111.222.333.44444 ``` -##### Example: +*Example:* ```python is_email_address_valid('hello@example.com') # >>> True is_email_address_valid('hello@hello@example.com') # >>> False -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v3/flask_imp_security-api_login_check.md b/archive_docs/_md/v3/flask_imp_security-api_login_check.md index 8b1ba3f7..e021ecbe 100644 --- a/archive_docs/_md/v3/flask_imp_security-api_login_check.md +++ b/archive_docs/_md/v3/flask_imp_security-api_login_check.md @@ -28,7 +28,7 @@ A decorator that is used to secure API routes that return JSON responses. `fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. -##### Example: +*Example:* ```python @bp.route("/api/resource", methods=["GET"]) diff --git a/archive_docs/_md/v3/flask_imp_security-permission_check.md b/archive_docs/_md/v3/flask_imp_security-permission_check.md index 22041c81..73278e12 100644 --- a/archive_docs/_md/v3/flask_imp_security-permission_check.md +++ b/archive_docs/_md/v3/flask_imp_security-permission_check.md @@ -36,19 +36,19 @@ A decorator that checks if the specified session key exists and its value(s) mat `message_category` The category of the flash message. -##### Example: +*Example:* ```python @bp.route("/admin-page", methods=["GET"]) @login_check( - 'logged_in', - True, + 'logged_in', + True, 'blueprint.login_page' ) # can be mixed with login_check @permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', + 'permissions', + ['admin'], + fail_endpoint='www.index', message="Failed message" ) def admin_page(): diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md index f7cbe3d8..c0d0ccdc 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md @@ -17,8 +17,8 @@ Generates a random alphanumeric string of the given length. (letters are capitalized) -##### Example: +*Example:* ```python generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md index 80c18f66..ce6df31b 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md @@ -19,8 +19,8 @@ For use in Cross-Site Request Forgery. Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. -##### Example: +*Example:* ```python generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md index 3e66f143..acdced31 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md @@ -17,10 +17,10 @@ Uses `generate_alphanumeric_validator` with a length of 8 to generate a random alphanumeric value for the specific use of validating accounts via email. -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) +See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) for more information. -##### Example: +*Example:* ```python generate_email_validator() # >>> 'A1B2C3D4' diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md index ba19ff99..c0d7dc76 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md @@ -20,7 +20,7 @@ If the length is 4, it will generate a number between 1111 and 9999. For use in MFA email, or unique filename generation. -##### Example: +*Example:* ```python generate_numeric_validator(4) # >>> 1234 diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_password.md b/archive_docs/_md/v4/flask_imp_auth-generate_password.md index ec1588da..b6f8fda0 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_password.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_password.md @@ -19,7 +19,7 @@ The Default length is 3. Style options: "animals", "colors", "mixed" - defaults to "mixed" -##### Example: +*Example:* ```python generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_salt.md b/archive_docs/_md/v4/flask_imp_auth-generate_salt.md index 523746fa..f21615f5 100644 --- a/archive_docs/_md/v4/flask_imp_auth-generate_salt.md +++ b/archive_docs/_md/v4/flask_imp_auth-generate_salt.md @@ -19,7 +19,7 @@ The Default length is 4. For use in password hashing and storage of passwords in the database. -##### Example: +*Example:* ```python generate_salt() # >>> '*!$%' diff --git a/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md index a6af7dde..1990e24a 100644 --- a/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md +++ b/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md @@ -37,10 +37,10 @@ email@example.com (Joe Smith) email@111.222.333.44444 ``` -##### Example: +*Example:* ```python is_email_address_valid('hello@example.com') # >>> True is_email_address_valid('hello@hello@example.com') # >>> False -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v4/flask_imp_security-api_login_check.md b/archive_docs/_md/v4/flask_imp_security-api_login_check.md index 8b1ba3f7..e021ecbe 100644 --- a/archive_docs/_md/v4/flask_imp_security-api_login_check.md +++ b/archive_docs/_md/v4/flask_imp_security-api_login_check.md @@ -28,7 +28,7 @@ A decorator that is used to secure API routes that return JSON responses. `fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. -##### Example: +*Example:* ```python @bp.route("/api/resource", methods=["GET"]) diff --git a/archive_docs/_md/v4/flask_imp_security-permission_check.md b/archive_docs/_md/v4/flask_imp_security-permission_check.md index 22041c81..73278e12 100644 --- a/archive_docs/_md/v4/flask_imp_security-permission_check.md +++ b/archive_docs/_md/v4/flask_imp_security-permission_check.md @@ -36,19 +36,19 @@ A decorator that checks if the specified session key exists and its value(s) mat `message_category` The category of the flash message. -##### Example: +*Example:* ```python @bp.route("/admin-page", methods=["GET"]) @login_check( - 'logged_in', - True, + 'logged_in', + True, 'blueprint.login_page' ) # can be mixed with login_check @permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', + 'permissions', + ['admin'], + fail_endpoint='www.index', message="Failed message" ) def admin_page(): diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md index f7cbe3d8..c0d0ccdc 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md @@ -17,8 +17,8 @@ Generates a random alphanumeric string of the given length. (letters are capitalized) -##### Example: +*Example:* ```python generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md index 80c18f66..ce6df31b 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md @@ -19,8 +19,8 @@ For use in Cross-Site Request Forgery. Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. -##### Example: +*Example:* ```python generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md index 3e66f143..acdced31 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md @@ -17,10 +17,10 @@ Uses `generate_alphanumeric_validator` with a length of 8 to generate a random alphanumeric value for the specific use of validating accounts via email. -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) +See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) for more information. -##### Example: +*Example:* ```python generate_email_validator() # >>> 'A1B2C3D4' diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md index ba19ff99..c0d7dc76 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md @@ -20,7 +20,7 @@ If the length is 4, it will generate a number between 1111 and 9999. For use in MFA email, or unique filename generation. -##### Example: +*Example:* ```python generate_numeric_validator(4) # >>> 1234 diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_password.md b/archive_docs/_md/v5/flask_imp_auth-generate_password.md index ec1588da..b6f8fda0 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_password.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_password.md @@ -19,7 +19,7 @@ The Default length is 3. Style options: "animals", "colors", "mixed" - defaults to "mixed" -##### Example: +*Example:* ```python generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_salt.md b/archive_docs/_md/v5/flask_imp_auth-generate_salt.md index 523746fa..f21615f5 100644 --- a/archive_docs/_md/v5/flask_imp_auth-generate_salt.md +++ b/archive_docs/_md/v5/flask_imp_auth-generate_salt.md @@ -19,7 +19,7 @@ The Default length is 4. For use in password hashing and storage of passwords in the database. -##### Example: +*Example:* ```python generate_salt() # >>> '*!$%' diff --git a/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md index a6af7dde..1990e24a 100644 --- a/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md +++ b/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md @@ -37,10 +37,10 @@ email@example.com (Joe Smith) email@111.222.333.44444 ``` -##### Example: +*Example:* ```python is_email_address_valid('hello@example.com') # >>> True is_email_address_valid('hello@hello@example.com') # >>> False -``` \ No newline at end of file +``` diff --git a/archive_docs/_md/v5/flask_imp_security-api_login_check.md b/archive_docs/_md/v5/flask_imp_security-api_login_check.md index 8b1ba3f7..e021ecbe 100644 --- a/archive_docs/_md/v5/flask_imp_security-api_login_check.md +++ b/archive_docs/_md/v5/flask_imp_security-api_login_check.md @@ -28,7 +28,7 @@ A decorator that is used to secure API routes that return JSON responses. `fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. -##### Example: +*Example:* ```python @bp.route("/api/resource", methods=["GET"]) diff --git a/archive_docs/_md/v5/flask_imp_security-permission_check.md b/archive_docs/_md/v5/flask_imp_security-permission_check.md index 22041c81..73278e12 100644 --- a/archive_docs/_md/v5/flask_imp_security-permission_check.md +++ b/archive_docs/_md/v5/flask_imp_security-permission_check.md @@ -36,19 +36,19 @@ A decorator that checks if the specified session key exists and its value(s) mat `message_category` The category of the flash message. -##### Example: +*Example:* ```python @bp.route("/admin-page", methods=["GET"]) @login_check( - 'logged_in', - True, + 'logged_in', + True, 'blueprint.login_page' ) # can be mixed with login_check @permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', + 'permissions', + ['admin'], + fail_endpoint='www.index', message="Failed message" ) def admin_page(): diff --git a/docs/Auth/flask_imp_auth-authenticate_password.md b/docs/Auth/flask_imp_auth-authenticate_password.md index ab278277..eb62a376 100644 --- a/docs/Auth/flask_imp_auth-authenticate_password.md +++ b/docs/Auth/flask_imp_auth-authenticate_password.md @@ -38,7 +38,7 @@ If you are using socketio, you must set use_multiprocessing to False (default). - You must know the position of the pepper used to hash the password. - You must know the encryption level used to hash the password. -#### Authentication Scenario: +**Authentication Scenario:** ``` Plain password: "password" diff --git a/docs/Auth/flask_imp_auth-encrypt_password.md b/docs/Auth/flask_imp_auth-encrypt_password.md index 1c386fa3..378fb380 100644 --- a/docs/Auth/flask_imp_auth-encrypt_password.md +++ b/docs/Auth/flask_imp_auth-encrypt_password.md @@ -34,7 +34,7 @@ Can set the pepper position, "start" or "end", defaults to "end". - You must inform the authenticate_password function of the position of the pepper used to hash the password. - You must inform the authenticate_password function of the encryption level used to hash the password. -#### Encryption Scenario: +**Encryption Scenario:** ``` Plain password: "password" diff --git a/docs/Auth/flask_imp_auth-generate_alphanumeric_validator.md b/docs/Auth/flask_imp_auth-generate_alphanumeric_validator.md index 2eb09149..a848c3b2 100644 --- a/docs/Auth/flask_imp_auth-generate_alphanumeric_validator.md +++ b/docs/Auth/flask_imp_auth-generate_alphanumeric_validator.md @@ -14,7 +14,7 @@ Generates a random alphanumeric string of the given length. (letters are capitalized) -##### Example: +*Example:* ```python generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' diff --git a/docs/Auth/flask_imp_auth-generate_csrf_token.md b/docs/Auth/flask_imp_auth-generate_csrf_token.md index 74667fc7..bdf0cd41 100644 --- a/docs/Auth/flask_imp_auth-generate_csrf_token.md +++ b/docs/Auth/flask_imp_auth-generate_csrf_token.md @@ -16,7 +16,7 @@ For use in Cross-Site Request Forgery. Also used by the [flask_imp.security / csrf_protect](../Security/flask_imp_security-include_csrf.md) decorator. -##### Example: +*Example:* ```python generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' diff --git a/docs/Auth/flask_imp_auth-generate_email_validator.md b/docs/Auth/flask_imp_auth-generate_email_validator.md index 7b154c65..55b7accf 100644 --- a/docs/Auth/flask_imp_auth-generate_email_validator.md +++ b/docs/Auth/flask_imp_auth-generate_email_validator.md @@ -17,7 +17,7 @@ validating accounts via email. See [flask_imp.auth / generate_alphanumeric_validator](../Auth/flask_imp_auth-generate_alphanumeric_validator.md) for more information. -##### Example: +*Example:* ```python generate_email_validator() # >>> 'A1B2C3D4' diff --git a/docs/Auth/flask_imp_auth-generate_numeric_validator.md b/docs/Auth/flask_imp_auth-generate_numeric_validator.md index de5a28b1..e2cee35f 100644 --- a/docs/Auth/flask_imp_auth-generate_numeric_validator.md +++ b/docs/Auth/flask_imp_auth-generate_numeric_validator.md @@ -17,7 +17,7 @@ If the length is 4, it will generate a number between 1111 and 9999. For use in MFA email, or unique filename generation. -##### Example: +*Example:* ```python generate_numeric_validator(4) # >>> 1234 diff --git a/docs/Auth/flask_imp_auth-generate_password.md b/docs/Auth/flask_imp_auth-generate_password.md index adcbd958..c8b8b9de 100644 --- a/docs/Auth/flask_imp_auth-generate_password.md +++ b/docs/Auth/flask_imp_auth-generate_password.md @@ -16,7 +16,7 @@ The Default length is 3. Style options: "animals", "colors", "mixed" - defaults to "mixed" -##### Example: +*Example:* ```python generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' diff --git a/docs/Auth/flask_imp_auth-generate_salt.md b/docs/Auth/flask_imp_auth-generate_salt.md index 1c97a17b..84bb2b55 100644 --- a/docs/Auth/flask_imp_auth-generate_salt.md +++ b/docs/Auth/flask_imp_auth-generate_salt.md @@ -16,7 +16,7 @@ The Default length is 4. For use in password hashing and storage of passwords in the database. -##### Example: +*Example:* ```python generate_salt() # >>> '*!$%' diff --git a/docs/Auth/flask_imp_auth-is_email_address_valid.md b/docs/Auth/flask_imp_auth-is_email_address_valid.md index fe619d5b..f848acdc 100644 --- a/docs/Auth/flask_imp_auth-is_email_address_valid.md +++ b/docs/Auth/flask_imp_auth-is_email_address_valid.md @@ -18,7 +18,7 @@ Is not completely RFC 5322 compliant, but it is good enough for most use cases. Here are examples of mistakes that it will not catch: -##### Valid but fails: +**Valid but fails:** ```text email@[123.123.123.123] @@ -27,14 +27,14 @@ very.unusual.“@”.unusual.com@example.com very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com ``` -##### Invalid but passes: +**Invalid but passes:** ```text email@example.com (Joe Smith) email@111.222.333.44444 ``` -##### Example: +*Example:* ```python is_email_address_valid('hello@example.com') # >>> True diff --git a/docs/Auth/flask_imp_auth-is_username_valid.md b/docs/Auth/flask_imp_auth-is_username_valid.md index 30f1e1e2..4836a79a 100644 --- a/docs/Auth/flask_imp_auth-is_username_valid.md +++ b/docs/Auth/flask_imp_auth-is_username_valid.md @@ -19,7 +19,7 @@ Valid usernames can only include letters, numbers, ., -, and _ but cannot begin or end with the last three mentioned. -##### Example "all": +**Example "all":** ```python is_username_valid("username", allowed=["all"]) @@ -35,7 +35,7 @@ user_name : WILL PASS : True _user_name : WILL PASS : False ``` -##### Example "dot", "dash": +**Example "dot", "dash":** ```python diff --git a/docs/Imp/Imp-import_app_resources.md b/docs/Imp/Imp-import_app_resources.md index 1bb0d265..561fcb41 100644 --- a/docs/Imp/Imp-import_app_resources.md +++ b/docs/Imp/Imp-import_app_resources.md @@ -24,7 +24,7 @@ Routes, context processors, cli, etc. If no static and or template folder is found, the static and or template folder will be set to None in the Flask app config. -#### Small example of usage: +**Small example of usage:** ```python imp.import_app_resources(folder="resources") @@ -61,7 +61,7 @@ def index(): return render_template("index.html") ``` -#### How factories work +## How factories work Factories are functions that are called when importing the app resources. Here's an example: @@ -83,7 +83,7 @@ def development_cli(app): print("dev cli command") ``` -#### Scoping imports +## Scoping imports By default, all files and folders will be imported. diff --git a/docs/Imp/Imp-import_blueprint.md b/docs/Imp/Imp-import_blueprint.md index ec10505b..bfd348b0 100644 --- a/docs/Imp/Imp-import_blueprint.md +++ b/docs/Imp/Imp-import_blueprint.md @@ -41,7 +41,7 @@ Flask-Imp Blueprints have the ability to auto import resources, and initialize s For more information on how Flask-Imp Blueprints work, see the [ImpBlueprint / Introduction](../ImpBlueprint/ImpBlueprint-Introduction.md) -##### Example of 'my_blueprint' as a Flask-Imp Blueprint: +**Example of 'my_blueprint' as a Flask-Imp Blueprint:** ```text app @@ -91,7 +91,7 @@ def index(): return "regular_blueprint" ``` -##### Example of 'my_blueprint' as a standard Flask Blueprint: +**Example of 'my_blueprint' as a standard Flask Blueprint:** ```text app diff --git a/docs/Imp/Imp-import_models.md b/docs/Imp/Imp-import_models.md index 0a045085..f9361d46 100644 --- a/docs/Imp/Imp-import_models.md +++ b/docs/Imp/Imp-import_models.md @@ -11,7 +11,7 @@ Imports all the models from the given file or folder relative to the Flask app r Each Model that is imported will be available in the `imp.model` lookup method. See [Imp / model](../Imp/Imp-model.md) for more information. -##### Example of importing models from a file +*Example of importing models from a file* ```text app @@ -57,7 +57,7 @@ class User(db.Model): attribute = db.Column(db.String(255)) ``` -##### Example of importing models from a folder +*Example of importing models from a folder* ```text app diff --git a/docs/Security/flask_imp_security-api_login_check.md b/docs/Security/flask_imp_security-api_login_check.md index 7d3c3fee..a6feb264 100644 --- a/docs/Security/flask_imp_security-api_login_check.md +++ b/docs/Security/flask_imp_security-api_login_check.md @@ -33,7 +33,7 @@ A decorator that is used to secure API routes that return JSON responses. `fail_status` The status code to return on failure. `401` by default. -##### Example: +*Example:* ```python @bp.route("/api/resource", methods=["GET"]) @@ -42,7 +42,7 @@ def api_page(): ... ``` -##### Example of defined fail_json: +**Example of defined fail_json:** ```python @bp.route("/api/resource", methods=["GET"]) diff --git a/docs/Security/flask_imp_security-login_check.md b/docs/Security/flask_imp_security-login_check.md index 5d634a9a..7b6fb13d 100644 --- a/docs/Security/flask_imp_security-login_check.md +++ b/docs/Security/flask_imp_security-login_check.md @@ -42,7 +42,7 @@ A decorator that checks if the specified session key exists and contains the spe `abort_status` The status code to return if the check fails. -##### Example of a route that requires a user to be logged in: +**Example of a route that requires a user to be logged in:** ```python @bp.route("/admin", methods=["GET"]) @@ -56,7 +56,7 @@ def admin_page(): ... ``` -##### Example of a route that if the user is already logged in, redirects to the specified endpoint: +**Example of a route that if the user is already logged in, redirects to the specified endpoint:** ```python @bp.route("/login-page", methods=["GET"]) diff --git a/docs/Security/flask_imp_security-permission_check.md b/docs/Security/flask_imp_security-permission_check.md index 4b448ba1..c536cc85 100644 --- a/docs/Security/flask_imp_security-permission_check.md +++ b/docs/Security/flask_imp_security-permission_check.md @@ -41,7 +41,7 @@ A decorator that checks if the specified session key exists and its value(s) mat `abort_status` The status code to return if the check fails. -##### Example: +*Example:* ```python @bp.route("/admin-page", methods=["GET"]) From a80f12cafa79360f83fdc8ef802ed1ae4a048428 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 15:50:21 +0000 Subject: [PATCH 02/10] remove old docs --- archive_docs/__init__.py | 60 -- archive_docs/_md/v3/Blueprint-Introduction.md | 77 -- archive_docs/_md/v3/Blueprint-config-toml.md | 152 --- archive_docs/_md/v3/Blueprint-init.md | 17 - .../_md/v3/Blueprint_x-import_models.md | 80 -- .../v3/Blueprint_x-import_nested_blueprint.md | 70 -- .../Blueprint_x-import_nested_blueprints.md | 59 -- .../_md/v3/Blueprint_x-import_resources.md | 53 - .../_md/v3/Blueprint_x-init_session.md | 19 - archive_docs/_md/v3/Blueprint_x-tmpl.md | 45 - .../v3/CLI Commands-flask-imp blueprint.md | 90 -- .../_md/v3/CLI Commands-flask-imp init.md | 226 ----- archive_docs/_md/v3/Imp-Introduction.md | 82 -- archive_docs/_md/v3/Imp-load-env-vars.md | 30 - archive_docs/_md/v3/Imp-x-config-toml.md | 137 --- .../_md/v3/Imp_x-import_app_resources.md | 106 -- archive_docs/_md/v3/Imp_x-import_blueprint.md | 116 --- .../_md/v3/Imp_x-import_blueprints.md | 50 - archive_docs/_md/v3/Imp_x-import_models.md | 83 -- archive_docs/_md/v3/Imp_x-init_app-init.md | 33 - archive_docs/_md/v3/Imp_x-init_session.md | 48 - archive_docs/_md/v3/Imp_x-model.md | 57 -- archive_docs/_md/v3/__index__.md | 117 --- archive_docs/_md/v3/__menu__.md | 45 - .../flask_imp_auth-authenticate_password.md | 63 -- .../_md/v3/flask_imp_auth-encrypt_password.md | 53 - ...mp_auth-generate_alphanumeric_validator.md | 24 - .../v3/flask_imp_auth-generate_csrf_token.md | 26 - ...flask_imp_auth-generate_email_validator.md | 27 - ...ask_imp_auth-generate_numeric_validator.md | 27 - .../v3/flask_imp_auth-generate_password.md | 26 - .../v3/flask_imp_auth-generate_private_key.md | 38 - .../_md/v3/flask_imp_auth-generate_salt.md | 46 - .../flask_imp_auth-is_email_address_valid.md | 46 - .../v3/flask_imp_auth-is_username_valid.md | 58 -- .../v3/flask_imp_security-api_login_check.md | 47 - .../_md/v3/flask_imp_security-include_csrf.md | 48 - .../_md/v3/flask_imp_security-login_check.md | 66 -- .../flask_imp_security-pass_function_check.md | 8 - .../v3/flask_imp_security-permission_check.md | 57 -- archive_docs/_md/v4/Blueprint-Introduction.md | 80 -- archive_docs/_md/v4/Blueprint-config-x.md | 160 --- archive_docs/_md/v4/Blueprint-init.md | 17 - .../_md/v4/Blueprint_x-import_models.md | 80 -- .../v4/Blueprint_x-import_nested_blueprint.md | 70 -- .../Blueprint_x-import_nested_blueprints.md | 59 -- .../_md/v4/Blueprint_x-import_resources.md | 53 - .../_md/v4/Blueprint_x-init_session.md | 19 - archive_docs/_md/v4/Blueprint_x-tmpl.md | 45 - .../v4/CLI Commands-flask-imp blueprint.md | 107 -- .../_md/v4/CLI Commands-flask-imp init.md | 262 ----- archive_docs/_md/v4/Imp-Introduction.md | 78 -- archive_docs/_md/v4/Imp-config-x.md | 285 ------ .../_md/v4/Imp_x-import_app_resources.md | 106 -- archive_docs/_md/v4/Imp_x-import_blueprint.md | 116 --- .../_md/v4/Imp_x-import_blueprints.md | 50 - archive_docs/_md/v4/Imp_x-import_models.md | 83 -- archive_docs/_md/v4/Imp_x-init_app-init.md | 32 - archive_docs/_md/v4/Imp_x-init_session.md | 48 - archive_docs/_md/v4/Imp_x-model.md | 57 -- archive_docs/_md/v4/__index__.md | 201 ---- archive_docs/_md/v4/__menu__.md | 44 - .../flask_imp_auth-authenticate_password.md | 63 -- .../_md/v4/flask_imp_auth-encrypt_password.md | 53 - ...mp_auth-generate_alphanumeric_validator.md | 24 - .../v4/flask_imp_auth-generate_csrf_token.md | 26 - ...flask_imp_auth-generate_email_validator.md | 27 - ...ask_imp_auth-generate_numeric_validator.md | 27 - .../v4/flask_imp_auth-generate_password.md | 26 - .../v4/flask_imp_auth-generate_private_key.md | 38 - .../_md/v4/flask_imp_auth-generate_salt.md | 46 - .../flask_imp_auth-is_email_address_valid.md | 46 - .../v4/flask_imp_auth-is_username_valid.md | 58 -- .../v4/flask_imp_security-api_login_check.md | 47 - .../_md/v4/flask_imp_security-include_csrf.md | 48 - .../_md/v4/flask_imp_security-login_check.md | 66 -- .../flask_imp_security-pass_function_check.md | 114 --- .../v4/flask_imp_security-permission_check.md | 57 -- .../v5/CLI Commands-flask-imp blueprint.md | 101 -- .../_md/v5/CLI Commands-flask-imp init.md | 218 ---- archive_docs/_md/v5/Imp-Introduction.md | 92 -- .../_md/v5/Imp-import_app_resources.md | 106 -- archive_docs/_md/v5/Imp-import_blueprint.md | 121 --- archive_docs/_md/v5/Imp-import_blueprints.md | 50 - archive_docs/_md/v5/Imp-import_models.md | 83 -- archive_docs/_md/v5/Imp-init_app-init.md | 22 - archive_docs/_md/v5/Imp-init_session.md | 48 - archive_docs/_md/v5/Imp-model.md | 57 -- .../_md/v5/ImpBlueprint-Introduction.md | 75 -- .../_md/v5/ImpBlueprint-import_models.md | 88 -- .../ImpBlueprint-import_nested_blueprint.md | 78 -- .../ImpBlueprint-import_nested_blueprints.md | 60 -- .../_md/v5/ImpBlueprint-import_resources.md | 57 -- archive_docs/_md/v5/ImpBlueprint-init.md | 17 - archive_docs/_md/v5/ImpBlueprint-tmpl.md | 44 - archive_docs/_md/v5/__index__.md | 121 --- archive_docs/_md/v5/__menu__.md | 47 - .../flask_imp_auth-authenticate_password.md | 63 -- .../_md/v5/flask_imp_auth-encrypt_password.md | 53 - ...mp_auth-generate_alphanumeric_validator.md | 24 - .../v5/flask_imp_auth-generate_csrf_token.md | 26 - ...flask_imp_auth-generate_email_validator.md | 27 - ...ask_imp_auth-generate_numeric_validator.md | 27 - .../v5/flask_imp_auth-generate_password.md | 26 - .../v5/flask_imp_auth-generate_private_key.md | 38 - .../_md/v5/flask_imp_auth-generate_salt.md | 46 - .../flask_imp_auth-is_email_address_valid.md | 46 - .../v5/flask_imp_auth-is_username_valid.md | 58 -- .../_md/v5/flask_imp_config-databaseconfig.md | 31 - .../_md/v5/flask_imp_config-flaskconfig.md | 59 -- .../v5/flask_imp_config-impblueprintconfig.md | 37 - .../_md/v5/flask_imp_config-impconfig.md | 49 - .../v5/flask_imp_config-sqldatabaseconfig.md | 28 - .../flask_imp_config-sqlitedatabaseconfig.md | 25 - .../v5/flask_imp_security-api_login_check.md | 47 - .../_md/v5/flask_imp_security-include_csrf.md | 48 - .../_md/v5/flask_imp_security-login_check.md | 66 -- .../flask_imp_security-pass_function_check.md | 114 --- .../v5/flask_imp_security-permission_check.md | 57 -- archive_docs/_ssg/__init__.py | 3 - archive_docs/_ssg/compiler.py | 132 --- archive_docs/_ssg/exceptions.py | 38 - archive_docs/_ssg/helpers.py | 53 - archive_docs/_ssg/render_engines.py | 18 - archive_docs/_templates/__main__.html | 26 - archive_docs/_templates/__menu__.html | 37 - archive_docs/_templates/index.html | 26 - archive_docs/_templates/main_index.html | 15 - archive_docs/config.py | 7 - archive_docs/index.html | 15 - archive_docs/v3/blueprint-config-toml.html | 384 -------- archive_docs/v3/blueprint-init.html | 266 ----- archive_docs/v3/blueprint-introduction.html | 318 ------ .../v3/blueprint_x-import_models.html | 312 ------ .../blueprint_x-import_nested_blueprint.html | 307 ------ .../blueprint_x-import_nested_blueprints.html | 300 ------ .../v3/blueprint_x-import_resources.html | 296 ------ archive_docs/v3/blueprint_x-init_session.html | 268 ----- archive_docs/v3/blueprint_x-tmpl.html | 289 ------ .../v3/cli_commands-flask-imp_blueprint.html | 320 ------ .../v3/cli_commands-flask-imp_init.html | 433 -------- .../flask_imp_auth-authenticate_password.html | 301 ------ .../v3/flask_imp_auth-encrypt_password.html | 293 ------ ..._auth-generate_alphanumeric_validator.html | 269 ----- .../flask_imp_auth-generate_csrf_token.html | 270 ----- ...ask_imp_auth-generate_email_validator.html | 272 ----- ...k_imp_auth-generate_numeric_validator.html | 270 ----- .../v3/flask_imp_auth-generate_password.html | 270 ----- .../flask_imp_auth-generate_private_key.html | 284 ------ .../v3/flask_imp_auth-generate_salt.html | 287 ------ ...flask_imp_auth-is_email_address_valid.html | 284 ------ .../v3/flask_imp_auth-is_username_valid.html | 293 ------ .../flask_imp_security-api_login_check.html | 285 ------ .../v3/flask_imp_security-include_csrf.html | 289 ------ .../v3/flask_imp_security-login_check.html | 302 ------ ...lask_imp_security-pass_function_check.html | 261 ----- .../flask_imp_security-permission_check.html | 295 ------ archive_docs/v3/imp-introduction.html | 318 ------ archive_docs/v3/imp-load-env-vars.html | 277 ------ archive_docs/v3/imp-x-config-toml.html | 373 ------- .../v3/imp_x-import_app_resources.html | 328 ------- archive_docs/v3/imp_x-import_blueprint.html | 343 ------- archive_docs/v3/imp_x-import_blueprints.html | 295 ------ archive_docs/v3/imp_x-import_models.html | 318 ------ archive_docs/v3/imp_x-init_app-init.html | 278 ------ archive_docs/v3/imp_x-init_session.html | 287 ------ archive_docs/v3/imp_x-model.html | 294 ------ archive_docs/v3/index.html | 336 ------- archive_docs/v3/static/Flask-Imp-Medium.png | Bin 7987 -> 0 bytes .../v3/static/android-chrome-192x192.png | Bin 15163 -> 0 bytes .../v3/static/android-chrome-256x256.png | Bin 20999 -> 0 bytes .../v3/static/android-chrome-96x96.png | Bin 6119 -> 0 bytes archive_docs/v3/static/apple-touch-icon.png | Bin 13882 -> 0 bytes archive_docs/v3/static/browserconfig.xml | 9 - archive_docs/v3/static/favicon-16x16.png | Bin 1210 -> 0 bytes archive_docs/v3/static/favicon-32x32.png | Bin 1873 -> 0 bytes archive_docs/v3/static/favicon.ico | Bin 15086 -> 0 bytes archive_docs/v3/static/mstile-150x150.png | Bin 9755 -> 0 bytes .../v3/static/pygments.emacs-dull.css | 69 -- archive_docs/v3/static/safari-pinned-tab.svg | 17 - archive_docs/v3/static/site.webmanifest | 19 - archive_docs/v3/static/water.css | 929 ------------------ archive_docs/v4/blueprint-config-x.html | 370 ------- archive_docs/v4/blueprint-init.html | 262 ----- archive_docs/v4/blueprint-introduction.html | 316 ------ .../v4/blueprint_x-import_models.html | 308 ------ .../blueprint_x-import_nested_blueprint.html | 303 ------ .../blueprint_x-import_nested_blueprints.html | 296 ------ .../v4/blueprint_x-import_resources.html | 292 ------ archive_docs/v4/blueprint_x-init_session.html | 264 ----- archive_docs/v4/blueprint_x-tmpl.html | 285 ------ .../v4/cli_commands-flask-imp_blueprint.html | 328 ------- .../v4/cli_commands-flask-imp_init.html | 453 --------- .../flask_imp_auth-authenticate_password.html | 297 ------ .../v4/flask_imp_auth-encrypt_password.html | 289 ------ ..._auth-generate_alphanumeric_validator.html | 265 ----- .../flask_imp_auth-generate_csrf_token.html | 266 ----- ...ask_imp_auth-generate_email_validator.html | 268 ----- ...k_imp_auth-generate_numeric_validator.html | 266 ----- .../v4/flask_imp_auth-generate_password.html | 266 ----- .../flask_imp_auth-generate_private_key.html | 280 ------ .../v4/flask_imp_auth-generate_salt.html | 283 ------ ...flask_imp_auth-is_email_address_valid.html | 280 ------ .../v4/flask_imp_auth-is_username_valid.html | 289 ------ .../flask_imp_security-api_login_check.html | 281 ------ .../v4/flask_imp_security-include_csrf.html | 285 ------ .../v4/flask_imp_security-login_check.html | 298 ------ ...lask_imp_security-pass_function_check.html | 346 ------- .../flask_imp_security-permission_check.html | 291 ------ archive_docs/v4/imp-config-x.html | 488 --------- archive_docs/v4/imp-introduction.html | 312 ------ .../v4/imp_x-import_app_resources.html | 324 ------ archive_docs/v4/imp_x-import_blueprint.html | 339 ------- archive_docs/v4/imp_x-import_blueprints.html | 291 ------ archive_docs/v4/imp_x-import_models.html | 314 ------ archive_docs/v4/imp_x-init_app-init.html | 274 ------ archive_docs/v4/imp_x-init_session.html | 283 ------ archive_docs/v4/imp_x-model.html | 290 ------ archive_docs/v4/index.html | 414 -------- archive_docs/v4/static/Flask-Imp-Medium.png | Bin 7987 -> 0 bytes .../v4/static/android-chrome-192x192.png | Bin 15163 -> 0 bytes .../v4/static/android-chrome-256x256.png | Bin 20999 -> 0 bytes .../v4/static/android-chrome-96x96.png | Bin 6119 -> 0 bytes archive_docs/v4/static/apple-touch-icon.png | Bin 13882 -> 0 bytes archive_docs/v4/static/browserconfig.xml | 9 - archive_docs/v4/static/favicon-16x16.png | Bin 1210 -> 0 bytes archive_docs/v4/static/favicon-32x32.png | Bin 1873 -> 0 bytes archive_docs/v4/static/favicon.ico | Bin 15086 -> 0 bytes archive_docs/v4/static/mstile-150x150.png | Bin 9755 -> 0 bytes .../v4/static/pygments.emacs-dull.css | 69 -- archive_docs/v4/static/safari-pinned-tab.svg | 17 - archive_docs/v4/static/site.webmanifest | 19 - archive_docs/v4/static/water.css | 929 ------------------ .../v5/cli_commands-flask-imp_blueprint.html | 330 ------- .../v5/cli_commands-flask-imp_init.html | 427 -------- .../flask_imp_auth-authenticate_password.html | 303 ------ .../v5/flask_imp_auth-encrypt_password.html | 295 ------ ..._auth-generate_alphanumeric_validator.html | 271 ----- .../flask_imp_auth-generate_csrf_token.html | 272 ----- ...ask_imp_auth-generate_email_validator.html | 274 ------ ...k_imp_auth-generate_numeric_validator.html | 272 ----- .../v5/flask_imp_auth-generate_password.html | 272 ----- .../flask_imp_auth-generate_private_key.html | 286 ------ .../v5/flask_imp_auth-generate_salt.html | 289 ------ ...flask_imp_auth-is_email_address_valid.html | 286 ------ .../v5/flask_imp_auth-is_username_valid.html | 295 ------ .../v5/flask_imp_config-databaseconfig.html | 281 ------ .../v5/flask_imp_config-flaskconfig.html | 306 ------ .../flask_imp_config-impblueprintconfig.html | 284 ------ .../v5/flask_imp_config-impconfig.html | 298 ------ .../flask_imp_config-sqldatabaseconfig.html | 278 ------ ...flask_imp_config-sqlitedatabaseconfig.html | 275 ------ .../flask_imp_security-api_login_check.html | 287 ------ .../v5/flask_imp_security-include_csrf.html | 291 ------ .../v5/flask_imp_security-login_check.html | 304 ------ ...lask_imp_security-pass_function_check.html | 352 ------- .../flask_imp_security-permission_check.html | 297 ------ archive_docs/v5/imp-import_app_resources.html | 330 ------- archive_docs/v5/imp-import_blueprint.html | 350 ------- archive_docs/v5/imp-import_blueprints.html | 297 ------ archive_docs/v5/imp-import_models.html | 320 ------ archive_docs/v5/imp-init_app-init.html | 274 ------ archive_docs/v5/imp-init_session.html | 289 ------ archive_docs/v5/imp-introduction.html | 329 ------- archive_docs/v5/imp-model.html | 296 ------ .../v5/impblueprint-import_models.html | 322 ------ .../impblueprint-import_nested_blueprint.html | 317 ------ ...impblueprint-import_nested_blueprints.html | 303 ------ .../v5/impblueprint-import_resources.html | 302 ------ archive_docs/v5/impblueprint-init.html | 268 ----- .../v5/impblueprint-introduction.html | 317 ------ archive_docs/v5/impblueprint-tmpl.html | 290 ------ archive_docs/v5/index.html | 343 ------- archive_docs/v5/static/Flask-Imp-Medium.png | Bin 7987 -> 0 bytes .../v5/static/android-chrome-192x192.png | Bin 15163 -> 0 bytes .../v5/static/android-chrome-256x256.png | Bin 20999 -> 0 bytes .../v5/static/android-chrome-96x96.png | Bin 6119 -> 0 bytes archive_docs/v5/static/apple-touch-icon.png | Bin 13882 -> 0 bytes archive_docs/v5/static/browserconfig.xml | 9 - archive_docs/v5/static/favicon-16x16.png | Bin 1210 -> 0 bytes archive_docs/v5/static/favicon-32x32.png | Bin 1873 -> 0 bytes archive_docs/v5/static/favicon.ico | Bin 15086 -> 0 bytes archive_docs/v5/static/mstile-150x150.png | Bin 9755 -> 0 bytes .../v5/static/pygments.emacs-dull.css | 69 -- archive_docs/v5/static/safari-pinned-tab.svg | 17 - archive_docs/v5/static/site.webmanifest | 19 - archive_docs/v5/static/water.css | 929 ------------------ 287 files changed, 46202 deletions(-) delete mode 100644 archive_docs/__init__.py delete mode 100644 archive_docs/_md/v3/Blueprint-Introduction.md delete mode 100644 archive_docs/_md/v3/Blueprint-config-toml.md delete mode 100644 archive_docs/_md/v3/Blueprint-init.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-import_models.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-import_nested_blueprint.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-import_nested_blueprints.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-import_resources.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-init_session.md delete mode 100644 archive_docs/_md/v3/Blueprint_x-tmpl.md delete mode 100644 archive_docs/_md/v3/CLI Commands-flask-imp blueprint.md delete mode 100644 archive_docs/_md/v3/CLI Commands-flask-imp init.md delete mode 100644 archive_docs/_md/v3/Imp-Introduction.md delete mode 100644 archive_docs/_md/v3/Imp-load-env-vars.md delete mode 100644 archive_docs/_md/v3/Imp-x-config-toml.md delete mode 100644 archive_docs/_md/v3/Imp_x-import_app_resources.md delete mode 100644 archive_docs/_md/v3/Imp_x-import_blueprint.md delete mode 100644 archive_docs/_md/v3/Imp_x-import_blueprints.md delete mode 100644 archive_docs/_md/v3/Imp_x-import_models.md delete mode 100644 archive_docs/_md/v3/Imp_x-init_app-init.md delete mode 100644 archive_docs/_md/v3/Imp_x-init_session.md delete mode 100644 archive_docs/_md/v3/Imp_x-model.md delete mode 100644 archive_docs/_md/v3/__index__.md delete mode 100644 archive_docs/_md/v3/__menu__.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-authenticate_password.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-encrypt_password.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_password.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_private_key.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-generate_salt.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md delete mode 100644 archive_docs/_md/v3/flask_imp_auth-is_username_valid.md delete mode 100644 archive_docs/_md/v3/flask_imp_security-api_login_check.md delete mode 100644 archive_docs/_md/v3/flask_imp_security-include_csrf.md delete mode 100644 archive_docs/_md/v3/flask_imp_security-login_check.md delete mode 100644 archive_docs/_md/v3/flask_imp_security-pass_function_check.md delete mode 100644 archive_docs/_md/v3/flask_imp_security-permission_check.md delete mode 100644 archive_docs/_md/v4/Blueprint-Introduction.md delete mode 100644 archive_docs/_md/v4/Blueprint-config-x.md delete mode 100644 archive_docs/_md/v4/Blueprint-init.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-import_models.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-import_nested_blueprint.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-import_nested_blueprints.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-import_resources.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-init_session.md delete mode 100644 archive_docs/_md/v4/Blueprint_x-tmpl.md delete mode 100644 archive_docs/_md/v4/CLI Commands-flask-imp blueprint.md delete mode 100644 archive_docs/_md/v4/CLI Commands-flask-imp init.md delete mode 100644 archive_docs/_md/v4/Imp-Introduction.md delete mode 100644 archive_docs/_md/v4/Imp-config-x.md delete mode 100644 archive_docs/_md/v4/Imp_x-import_app_resources.md delete mode 100644 archive_docs/_md/v4/Imp_x-import_blueprint.md delete mode 100644 archive_docs/_md/v4/Imp_x-import_blueprints.md delete mode 100644 archive_docs/_md/v4/Imp_x-import_models.md delete mode 100644 archive_docs/_md/v4/Imp_x-init_app-init.md delete mode 100644 archive_docs/_md/v4/Imp_x-init_session.md delete mode 100644 archive_docs/_md/v4/Imp_x-model.md delete mode 100644 archive_docs/_md/v4/__index__.md delete mode 100644 archive_docs/_md/v4/__menu__.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-authenticate_password.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-encrypt_password.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_password.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_private_key.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-generate_salt.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md delete mode 100644 archive_docs/_md/v4/flask_imp_auth-is_username_valid.md delete mode 100644 archive_docs/_md/v4/flask_imp_security-api_login_check.md delete mode 100644 archive_docs/_md/v4/flask_imp_security-include_csrf.md delete mode 100644 archive_docs/_md/v4/flask_imp_security-login_check.md delete mode 100644 archive_docs/_md/v4/flask_imp_security-pass_function_check.md delete mode 100644 archive_docs/_md/v4/flask_imp_security-permission_check.md delete mode 100644 archive_docs/_md/v5/CLI Commands-flask-imp blueprint.md delete mode 100644 archive_docs/_md/v5/CLI Commands-flask-imp init.md delete mode 100644 archive_docs/_md/v5/Imp-Introduction.md delete mode 100644 archive_docs/_md/v5/Imp-import_app_resources.md delete mode 100644 archive_docs/_md/v5/Imp-import_blueprint.md delete mode 100644 archive_docs/_md/v5/Imp-import_blueprints.md delete mode 100644 archive_docs/_md/v5/Imp-import_models.md delete mode 100644 archive_docs/_md/v5/Imp-init_app-init.md delete mode 100644 archive_docs/_md/v5/Imp-init_session.md delete mode 100644 archive_docs/_md/v5/Imp-model.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-Introduction.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-import_models.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-import_nested_blueprint.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-import_nested_blueprints.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-import_resources.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-init.md delete mode 100644 archive_docs/_md/v5/ImpBlueprint-tmpl.md delete mode 100644 archive_docs/_md/v5/__index__.md delete mode 100644 archive_docs/_md/v5/__menu__.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-authenticate_password.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-encrypt_password.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_password.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_private_key.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-generate_salt.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md delete mode 100644 archive_docs/_md/v5/flask_imp_auth-is_username_valid.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-databaseconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-flaskconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-impblueprintconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-impconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-sqldatabaseconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_config-sqlitedatabaseconfig.md delete mode 100644 archive_docs/_md/v5/flask_imp_security-api_login_check.md delete mode 100644 archive_docs/_md/v5/flask_imp_security-include_csrf.md delete mode 100644 archive_docs/_md/v5/flask_imp_security-login_check.md delete mode 100644 archive_docs/_md/v5/flask_imp_security-pass_function_check.md delete mode 100644 archive_docs/_md/v5/flask_imp_security-permission_check.md delete mode 100644 archive_docs/_ssg/__init__.py delete mode 100644 archive_docs/_ssg/compiler.py delete mode 100644 archive_docs/_ssg/exceptions.py delete mode 100644 archive_docs/_ssg/helpers.py delete mode 100644 archive_docs/_ssg/render_engines.py delete mode 100644 archive_docs/_templates/__main__.html delete mode 100644 archive_docs/_templates/__menu__.html delete mode 100644 archive_docs/_templates/index.html delete mode 100644 archive_docs/_templates/main_index.html delete mode 100644 archive_docs/config.py delete mode 100644 archive_docs/index.html delete mode 100644 archive_docs/v3/blueprint-config-toml.html delete mode 100644 archive_docs/v3/blueprint-init.html delete mode 100644 archive_docs/v3/blueprint-introduction.html delete mode 100644 archive_docs/v3/blueprint_x-import_models.html delete mode 100644 archive_docs/v3/blueprint_x-import_nested_blueprint.html delete mode 100644 archive_docs/v3/blueprint_x-import_nested_blueprints.html delete mode 100644 archive_docs/v3/blueprint_x-import_resources.html delete mode 100644 archive_docs/v3/blueprint_x-init_session.html delete mode 100644 archive_docs/v3/blueprint_x-tmpl.html delete mode 100644 archive_docs/v3/cli_commands-flask-imp_blueprint.html delete mode 100644 archive_docs/v3/cli_commands-flask-imp_init.html delete mode 100644 archive_docs/v3/flask_imp_auth-authenticate_password.html delete mode 100644 archive_docs/v3/flask_imp_auth-encrypt_password.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_alphanumeric_validator.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_csrf_token.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_email_validator.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_numeric_validator.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_password.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_private_key.html delete mode 100644 archive_docs/v3/flask_imp_auth-generate_salt.html delete mode 100644 archive_docs/v3/flask_imp_auth-is_email_address_valid.html delete mode 100644 archive_docs/v3/flask_imp_auth-is_username_valid.html delete mode 100644 archive_docs/v3/flask_imp_security-api_login_check.html delete mode 100644 archive_docs/v3/flask_imp_security-include_csrf.html delete mode 100644 archive_docs/v3/flask_imp_security-login_check.html delete mode 100644 archive_docs/v3/flask_imp_security-pass_function_check.html delete mode 100644 archive_docs/v3/flask_imp_security-permission_check.html delete mode 100644 archive_docs/v3/imp-introduction.html delete mode 100644 archive_docs/v3/imp-load-env-vars.html delete mode 100644 archive_docs/v3/imp-x-config-toml.html delete mode 100644 archive_docs/v3/imp_x-import_app_resources.html delete mode 100644 archive_docs/v3/imp_x-import_blueprint.html delete mode 100644 archive_docs/v3/imp_x-import_blueprints.html delete mode 100644 archive_docs/v3/imp_x-import_models.html delete mode 100644 archive_docs/v3/imp_x-init_app-init.html delete mode 100644 archive_docs/v3/imp_x-init_session.html delete mode 100644 archive_docs/v3/imp_x-model.html delete mode 100644 archive_docs/v3/index.html delete mode 100644 archive_docs/v3/static/Flask-Imp-Medium.png delete mode 100644 archive_docs/v3/static/android-chrome-192x192.png delete mode 100644 archive_docs/v3/static/android-chrome-256x256.png delete mode 100644 archive_docs/v3/static/android-chrome-96x96.png delete mode 100644 archive_docs/v3/static/apple-touch-icon.png delete mode 100644 archive_docs/v3/static/browserconfig.xml delete mode 100644 archive_docs/v3/static/favicon-16x16.png delete mode 100644 archive_docs/v3/static/favicon-32x32.png delete mode 100644 archive_docs/v3/static/favicon.ico delete mode 100644 archive_docs/v3/static/mstile-150x150.png delete mode 100644 archive_docs/v3/static/pygments.emacs-dull.css delete mode 100644 archive_docs/v3/static/safari-pinned-tab.svg delete mode 100644 archive_docs/v3/static/site.webmanifest delete mode 100644 archive_docs/v3/static/water.css delete mode 100644 archive_docs/v4/blueprint-config-x.html delete mode 100644 archive_docs/v4/blueprint-init.html delete mode 100644 archive_docs/v4/blueprint-introduction.html delete mode 100644 archive_docs/v4/blueprint_x-import_models.html delete mode 100644 archive_docs/v4/blueprint_x-import_nested_blueprint.html delete mode 100644 archive_docs/v4/blueprint_x-import_nested_blueprints.html delete mode 100644 archive_docs/v4/blueprint_x-import_resources.html delete mode 100644 archive_docs/v4/blueprint_x-init_session.html delete mode 100644 archive_docs/v4/blueprint_x-tmpl.html delete mode 100644 archive_docs/v4/cli_commands-flask-imp_blueprint.html delete mode 100644 archive_docs/v4/cli_commands-flask-imp_init.html delete mode 100644 archive_docs/v4/flask_imp_auth-authenticate_password.html delete mode 100644 archive_docs/v4/flask_imp_auth-encrypt_password.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_alphanumeric_validator.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_csrf_token.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_email_validator.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_numeric_validator.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_password.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_private_key.html delete mode 100644 archive_docs/v4/flask_imp_auth-generate_salt.html delete mode 100644 archive_docs/v4/flask_imp_auth-is_email_address_valid.html delete mode 100644 archive_docs/v4/flask_imp_auth-is_username_valid.html delete mode 100644 archive_docs/v4/flask_imp_security-api_login_check.html delete mode 100644 archive_docs/v4/flask_imp_security-include_csrf.html delete mode 100644 archive_docs/v4/flask_imp_security-login_check.html delete mode 100644 archive_docs/v4/flask_imp_security-pass_function_check.html delete mode 100644 archive_docs/v4/flask_imp_security-permission_check.html delete mode 100644 archive_docs/v4/imp-config-x.html delete mode 100644 archive_docs/v4/imp-introduction.html delete mode 100644 archive_docs/v4/imp_x-import_app_resources.html delete mode 100644 archive_docs/v4/imp_x-import_blueprint.html delete mode 100644 archive_docs/v4/imp_x-import_blueprints.html delete mode 100644 archive_docs/v4/imp_x-import_models.html delete mode 100644 archive_docs/v4/imp_x-init_app-init.html delete mode 100644 archive_docs/v4/imp_x-init_session.html delete mode 100644 archive_docs/v4/imp_x-model.html delete mode 100644 archive_docs/v4/index.html delete mode 100644 archive_docs/v4/static/Flask-Imp-Medium.png delete mode 100644 archive_docs/v4/static/android-chrome-192x192.png delete mode 100644 archive_docs/v4/static/android-chrome-256x256.png delete mode 100644 archive_docs/v4/static/android-chrome-96x96.png delete mode 100644 archive_docs/v4/static/apple-touch-icon.png delete mode 100644 archive_docs/v4/static/browserconfig.xml delete mode 100644 archive_docs/v4/static/favicon-16x16.png delete mode 100644 archive_docs/v4/static/favicon-32x32.png delete mode 100644 archive_docs/v4/static/favicon.ico delete mode 100644 archive_docs/v4/static/mstile-150x150.png delete mode 100644 archive_docs/v4/static/pygments.emacs-dull.css delete mode 100644 archive_docs/v4/static/safari-pinned-tab.svg delete mode 100644 archive_docs/v4/static/site.webmanifest delete mode 100644 archive_docs/v4/static/water.css delete mode 100644 archive_docs/v5/cli_commands-flask-imp_blueprint.html delete mode 100644 archive_docs/v5/cli_commands-flask-imp_init.html delete mode 100644 archive_docs/v5/flask_imp_auth-authenticate_password.html delete mode 100644 archive_docs/v5/flask_imp_auth-encrypt_password.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_alphanumeric_validator.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_csrf_token.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_email_validator.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_numeric_validator.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_password.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_private_key.html delete mode 100644 archive_docs/v5/flask_imp_auth-generate_salt.html delete mode 100644 archive_docs/v5/flask_imp_auth-is_email_address_valid.html delete mode 100644 archive_docs/v5/flask_imp_auth-is_username_valid.html delete mode 100644 archive_docs/v5/flask_imp_config-databaseconfig.html delete mode 100644 archive_docs/v5/flask_imp_config-flaskconfig.html delete mode 100644 archive_docs/v5/flask_imp_config-impblueprintconfig.html delete mode 100644 archive_docs/v5/flask_imp_config-impconfig.html delete mode 100644 archive_docs/v5/flask_imp_config-sqldatabaseconfig.html delete mode 100644 archive_docs/v5/flask_imp_config-sqlitedatabaseconfig.html delete mode 100644 archive_docs/v5/flask_imp_security-api_login_check.html delete mode 100644 archive_docs/v5/flask_imp_security-include_csrf.html delete mode 100644 archive_docs/v5/flask_imp_security-login_check.html delete mode 100644 archive_docs/v5/flask_imp_security-pass_function_check.html delete mode 100644 archive_docs/v5/flask_imp_security-permission_check.html delete mode 100644 archive_docs/v5/imp-import_app_resources.html delete mode 100644 archive_docs/v5/imp-import_blueprint.html delete mode 100644 archive_docs/v5/imp-import_blueprints.html delete mode 100644 archive_docs/v5/imp-import_models.html delete mode 100644 archive_docs/v5/imp-init_app-init.html delete mode 100644 archive_docs/v5/imp-init_session.html delete mode 100644 archive_docs/v5/imp-introduction.html delete mode 100644 archive_docs/v5/imp-model.html delete mode 100644 archive_docs/v5/impblueprint-import_models.html delete mode 100644 archive_docs/v5/impblueprint-import_nested_blueprint.html delete mode 100644 archive_docs/v5/impblueprint-import_nested_blueprints.html delete mode 100644 archive_docs/v5/impblueprint-import_resources.html delete mode 100644 archive_docs/v5/impblueprint-init.html delete mode 100644 archive_docs/v5/impblueprint-introduction.html delete mode 100644 archive_docs/v5/impblueprint-tmpl.html delete mode 100644 archive_docs/v5/index.html delete mode 100644 archive_docs/v5/static/Flask-Imp-Medium.png delete mode 100644 archive_docs/v5/static/android-chrome-192x192.png delete mode 100644 archive_docs/v5/static/android-chrome-256x256.png delete mode 100644 archive_docs/v5/static/android-chrome-96x96.png delete mode 100644 archive_docs/v5/static/apple-touch-icon.png delete mode 100644 archive_docs/v5/static/browserconfig.xml delete mode 100644 archive_docs/v5/static/favicon-16x16.png delete mode 100644 archive_docs/v5/static/favicon-32x32.png delete mode 100644 archive_docs/v5/static/favicon.ico delete mode 100644 archive_docs/v5/static/mstile-150x150.png delete mode 100644 archive_docs/v5/static/pygments.emacs-dull.css delete mode 100644 archive_docs/v5/static/safari-pinned-tab.svg delete mode 100644 archive_docs/v5/static/site.webmanifest delete mode 100644 archive_docs/v5/static/water.css diff --git a/archive_docs/__init__.py b/archive_docs/__init__.py deleted file mode 100644 index 3e4c634d..00000000 --- a/archive_docs/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -from pathlib import Path -from time import sleep - -import click -from flask import Flask - -from .config import Config -from ._ssg import compiler - -cwd = Path(__file__).parent - - -def create_app(): - app = Flask(__name__) - app.template_folder = "_templates" - - doc_path = Path(cwd / Config.latest) - markdown_path = Path(cwd / "_md" / Config.latest) - - @app.cli.command("compile") - @click.option("--watch", is_flag=True, help="Watch for file changes") - def compile_site(watch): - if watch: - watching_files = {} - - def change_loop(): - change = False - updated = [] - for file in markdown_path.glob("**/*.md"): - if file not in watching_files: - watching_files[file] = file.stat().st_mtime - updated.append(file) - change = True - else: - if file.stat().st_mtime > watching_files[file]: - watching_files[file] = file.stat().st_mtime - updated.append(file) - change = True - - if change: - print("Update detected, recompiling...") - for file in updated: - print(f" - {file}") - - compiler(doc_path, markdown_path) - - print("Watching for changes...") - - while True: - change_loop() - sleep(1) - - else: - compiler(doc_path, markdown_path) - - @app.route("/") - def index(): - return "To use run the following command: flask --app gdocs compile" - - return app diff --git a/archive_docs/_md/v3/Blueprint-Introduction.md b/archive_docs/_md/v3/Blueprint-Introduction.md deleted file mode 100644 index 919acb9b..00000000 --- a/archive_docs/_md/v3/Blueprint-Introduction.md +++ /dev/null @@ -1,77 +0,0 @@ -``` -Menu = Blueprint/Introduction -Title = Flask-Imp Blueprint Introduction -``` - -The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints. - -The Flask-Imp Blueprint reads configuration from a config.toml file, which is located in the same directory as the -`__init__.py` file. - -Here's an example of a Flask-Imp Blueprint structure: - -```text -www/ -├── nested_blueprints/ -│ ├── blueprint_one/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.toml -│ └── blueprint_two/ -│ ├── ... -│ ├── __init__.py -│ └── config.toml -├── standalone_nested_blueprint/ -│ ├── ... -│ ├── __init__.py -│ └── config.toml -├── models/ -│ └── ... -├── routes/ -│ └── index.py -├── static/ -│ └── ... -├── templates/ -│ └── www/ -│ └── index.html -├── __init__.py -└── config.toml -``` - -File: `__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("models") -bp.import_nested_blueprints("nested_blueprints") -bp.import_nested_blueprint("standalone_nested_blueprint") - - -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` - -That `config.toml` file is loaded during the `__init__` method of the Blueprint class. -To see more about the config file see: [Blueprint / config.toml](blueprint-config-toml.html) - -`import_resources` method will walk one level deep into the `routes` folder, and import all `.py` files as modules. -For more information see: [Blueprint.x / import_resources](blueprint_x-import_resources.html) - -`import_models` works the same as `imp.import_models`, it will look for instances of `db.Model` and import them. These -will also be available in the model lookup method `imp.model`. -For more information see: [Imp.x / import_models](imp_x-import_models.html) - -`import_nested_blueprints` will do the same as `imp.import_blueprints`, but will register the blueprints found as -nested to the current blueprint. For example `www.blueprint_one.index` - -`import_nested_blueprint` behaves the same as `import_nested_blueprints`, but will only import a single blueprint. - -`bp.init_session` will load the session variables from the config file into the session object. For more information -see: [Blueprint.x / init_session](blueprint_x-init_session.html) and -[Blueprint / config.toml](blueprint-config-toml.html) diff --git a/archive_docs/_md/v3/Blueprint-config-toml.md b/archive_docs/_md/v3/Blueprint-config-toml.md deleted file mode 100644 index 29de4a68..00000000 --- a/archive_docs/_md/v3/Blueprint-config-toml.md +++ /dev/null @@ -1,152 +0,0 @@ -``` -Menu = Blueprint/config.toml -Title = The Flask-Imp Blueprint Config File -``` - -The Flask-Imp Blueprint will load configuration from a `config.toml` file, which is located in the same directory as the -`__init__.py` file. - -File: `config.toml` - -```toml -enabled = "yes" - -[settings] -url_prefix = "" -subdomain = "" -url_defaults = { } -static_folder = "" -template_folder = "" -static_url_path = "" -#root_path = "" -#cli_group = "" - -[session] -var = "" - -# Set ENABLED to true to allow the blueprint -# to create a database bind, change settings accordingly. -[DATABASE_BIND] -ENABLED = true -DIALECT = "sqlite" -DATABASE_NAME = "example" -LOCATION = "" -PORT = "" -USERNAME = "" -PASSWORD = "" -``` - -This config reflects the args that are passed to a regular Flask Blueprint class, the addition of the ability to -enable/disable the Blueprint, and set session variables. - -For more information about the args of a regular Flask Blueprint see: -[Flask docs (Blueprint)](https://flask.palletsprojects.com/en/3.0.x/api/#flask.Blueprint) - -You can also allow the blueprint to create a database bind, by setting `ENABLED` to `true` in the `DATABASE_BIND` -section. - -This will add to the Flask app's `SQLALCHEMY_BINDS` config variable, and allows blueprints to be more modular -with their database connections. - -Including the attribute `__bind_key__` in the blueprint's model(s) will match the model to the database bind. - -```python -class User(db.Model): - __bind_key__ = "example" - ... -``` - -##### Example of advance use case for blueprint config files: - -```text -testing_blueprint/ -├── routes/ -│ └── index.py -├── static/ -│ └── ... -├── templates/ -│ └── www/ -│ └── index.html -├── __init__.py -├── pro_config.py -└── dev_config.toml -``` - -```python -from app import app -from flask_imp import Blueprint - -bp = Blueprint( - __name__, - config_file="dev_config.toml" if app.config["DEBUG"] else "pro_config.py" -) - -bp.import_resources("routes") - - -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` - -File: `pro_config.py` - -```toml -enabled = "no" - -[settings] -#url_prefix = "" -#subdomain = "" -#url_defaults = { } -#static_folder = "" -#template_folder = "" -#static_url_path = "" -#root_path = "" -#cli_group = "" - -[session] -#var = "" - -# Set ENABLED to true to allow the blueprint -# to create a database bind, change settings accordingly. -[DATABASE_BIND] -ENABLED = false -DIALECT = "sqlite" -DATABASE_NAME = "example" -LOCATION = "" -PORT = "" -USERNAME = "" -PASSWORD = "" -``` - -File: `dev_config.py` - -```toml -enabled = "yes" - -[settings] -url_prefix = "/testing" -#subdomain = "" -#url_defaults = { } -static_folder = "static" -template_folder = "templates" -#static_url_path = "" -#root_path = "" -#cli_group = "" - -[session] -#var = "" - -# Set ENABLED to true to allow the blueprint -# to create a database bind, change settings accordingly. -[DATABASE_BIND] -ENABLED = true -DIALECT = "sqlite" -DATABASE_NAME = "example" -LOCATION = "" -PORT = "" -USERNAME = "" -PASSWORD = "" -``` - -In the example above, the `testing_blueprint` will only be enabled if the Flask app is running in debug mode. \ No newline at end of file diff --git a/archive_docs/_md/v3/Blueprint-init.md b/archive_docs/_md/v3/Blueprint-init.md deleted file mode 100644 index 78d60d5f..00000000 --- a/archive_docs/_md/v3/Blueprint-init.md +++ /dev/null @@ -1,17 +0,0 @@ -``` -Menu = Blueprint.x/__init__ -Title = Flask-Imp Blueprint __init__ -``` - -```python -Blueprint(dunder_name: str, config_file: str = "config.toml") -> None -``` - ---- - -Initializes the Flask-Imp Blueprint. - -`dunder_name` should always be set to `__name__` - -`config_file` is the name of the config file to load. -It will be loaded from the same directory as the `__init__.py` file. diff --git a/archive_docs/_md/v3/Blueprint_x-import_models.md b/archive_docs/_md/v3/Blueprint_x-import_models.md deleted file mode 100644 index d919ae65..00000000 --- a/archive_docs/_md/v3/Blueprint_x-import_models.md +++ /dev/null @@ -1,80 +0,0 @@ -``` -Menu = Blueprint.x/import_models -Title = Blueprint.import_models -``` - -```python -import_models(folder: str = "models") -> None -``` - ---- - -Will import all the models from the given folder relative to the Blueprint's root directory. - -Works the same as [Imp.x / import_models](imp_x-import_models.html) but relative to the Blueprint root. - -Blueprint models will also be available in the [Imp.x / model](imp_x-model.html) lookup. - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── animal_models.py -│ -├── __init__.py -└── config.toml -``` - -**or** - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── models/ -│ └── animals.py -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("animal_models.py") -``` - -**or** - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("models") -``` - -File: `my_blueprint/animal_models.py` or `my_blueprint/models/animals.py` - -```python -from app import db - - -class Animals(db.Model): - animal_id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(64), index=True, unique=True) - species = db.Column(db.String(64), index=True, unique=True) -``` - - - diff --git a/archive_docs/_md/v3/Blueprint_x-import_nested_blueprint.md b/archive_docs/_md/v3/Blueprint_x-import_nested_blueprint.md deleted file mode 100644 index d8139c3d..00000000 --- a/archive_docs/_md/v3/Blueprint_x-import_nested_blueprint.md +++ /dev/null @@ -1,70 +0,0 @@ -``` -Menu = Blueprint.x/import_nested_blueprint -Title = Blueprint.import_nested_blueprint -``` - -```python -import_nested_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root. - -Works the same as [Imp.x / import_blueprint](imp_x-import_blueprint.html) but relative to the Blueprint root. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.my_nested_blueprint.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── my_nested_blueprint/ -│ ├── routes/ -│ │ └── index.py -│ ├── static/... -│ ├── templates/... -│ ├── __init__.py -│ └── config.toml -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_nested_blueprint("my_nested_blueprint") -``` - -File: `my_blueprint/my_nested_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -``` - -File: `my_blueprint/my_nested_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/Blueprint_x-import_nested_blueprints.md b/archive_docs/_md/v3/Blueprint_x-import_nested_blueprints.md deleted file mode 100644 index 16bdc2a7..00000000 --- a/archive_docs/_md/v3/Blueprint_x-import_nested_blueprints.md +++ /dev/null @@ -1,59 +0,0 @@ -``` -Menu = Blueprint.x/import_nested_blueprints -Title = Blueprint.import_nested_blueprints -``` - -```python -import_nested_blueprints(self, folder: str) -> None -``` - ---- - -Will import all the Blueprints from the given folder relative to the Blueprint's root directory. - -Uses [Blueprint.x / import_nested_blueprint](blueprint_x-import_nested_blueprint.html) to import blueprints from -the specified folder. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.nested_bp_one.index')` - -`url_for('my_blueprint.nested_bp_two.index')` - -`url_for('my_blueprint.nested_bp_three.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── nested_blueprints/ -│ │ -│ ├── nested_bp_one/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.toml -│ ├── nested_bp_two/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.toml -│ └── nested_bp_three/ -│ ├── ... -│ ├── __init__.py -│ └── config.toml -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_nested_blueprints("nested_blueprints") -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/Blueprint_x-import_resources.md b/archive_docs/_md/v3/Blueprint_x-import_resources.md deleted file mode 100644 index dc5043d9..00000000 --- a/archive_docs/_md/v3/Blueprint_x-import_resources.md +++ /dev/null @@ -1,53 +0,0 @@ -``` -Menu = Blueprint.x/import_resources -Title = Blueprint.import_resources -``` - -```python -import_resources(folder: str = "routes") -> None -``` - ---- - -Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory. - -```text -my_blueprint -├── user_routes -│ ├── user_dashboard.py -│ └── user_settings.py -├── car_routes -│ ├── car_dashboard.py -│ └── car_settings.py -├── static/... -├── templates/ -│ └── my_blueprint/ -│ ├── user_dashboard.html -│ └── ... -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("user_routes") -bp.import_resources("car_routes") -``` - -File: `my_blueprint/user_routes/user_dashboard.py` - -```python -from flask import render_template - -from .. import bp - -@bp.route("/user-dashboard") -def user_dashboard(): - return render_template(bp.tmpl("user_dashboard.html")) -``` diff --git a/archive_docs/_md/v3/Blueprint_x-init_session.md b/archive_docs/_md/v3/Blueprint_x-init_session.md deleted file mode 100644 index 5a6bd55f..00000000 --- a/archive_docs/_md/v3/Blueprint_x-init_session.md +++ /dev/null @@ -1,19 +0,0 @@ -``` -Menu = Blueprint.x/init_session -Title = Blueprint.init_session -``` - -```python -init_session() -> None -``` - ---- - -Has the same functionality as [Imp.x / init_session](imp_x-init_session.html) but loads session key values from the -Blueprint's config file. - -```python -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/Blueprint_x-tmpl.md b/archive_docs/_md/v3/Blueprint_x-tmpl.md deleted file mode 100644 index dd23bed6..00000000 --- a/archive_docs/_md/v3/Blueprint_x-tmpl.md +++ /dev/null @@ -1,45 +0,0 @@ -``` -Menu = Blueprint.x/tmpl -Title = Blueprint.tmpl -``` - -```python -tmpl(template: str) -> str -``` - ---- - -Scopes the template lookup to the name of the blueprint (this takes from the `__name__` attribute of the Blueprint). - -Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder. - -```text -my_blueprint/ -├── routes/ -│ └── index.py -├── static/... -│ -├── templates/ -│ └── my_blueprint/ -│ └── index.html -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` - -`bp.tmpl("index.html")` will output `"my_blueprint/index.html"`. diff --git a/archive_docs/_md/v3/CLI Commands-flask-imp blueprint.md b/archive_docs/_md/v3/CLI Commands-flask-imp blueprint.md deleted file mode 100644 index 1b1d5347..00000000 --- a/archive_docs/_md/v3/CLI Commands-flask-imp blueprint.md +++ /dev/null @@ -1,90 +0,0 @@ -``` -Menu = CLI Commands/flask-imp blueprint -Title = Generate a Flask-Imp Blueprint -``` - -Flask-Imp has its own type of blueprint. It can read some configuration from a toml file and has some extra methods for -auto importing. - -```bash -flask-imp blueprint --help -``` - -To generate a Flask-Imp blueprint, run the following command: - -```bash -flask-imp blueprint -``` - -After running this command, you will be prompted to enter the location of where you want to create your blueprint: - -```text -~ $ flask-imp blueprint -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: -``` - -As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder `app/blueprints`, you would enter `app/blueprints` in the prompt. - -```text -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: app/blueprints -``` - -You will then be prompted to enter a name for your blueprint: - -```text -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: app/blueprints -Name of the blueprint to create [my_new_blueprint]: -``` - -The default name is 'my_new_blueprint', we will change this to 'admin' - -```text -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: app/blueprints -Name of the blueprint to create [my_new_blueprint]: admin -``` - -After creating your blueprint, the folder structure will look like this: - -```text -app/ -├── blueprints -│ └── admin -│ ├── routes -│ │ └── index.py -│ │ -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ │ -│ ├── templates -│ │ └── www -│ │ ├── extends -│ │ │ └── main.html -│ │ ├── includes -│ │ │ ├── footer.html -│ │ │ └── header.html -│ │ └── index.html -│ │ -│ ├── __init__.py -│ └─── config.toml -│ -... -``` - -This is a self-contained blueprint, so it has its own static, templates and routes folders. You can now navigate ' -/admin' - -You can streamline this process by specifying the name of the blueprint and the folder to create it in, like so: - -```bash -flask-imp blueprint -n admin -f app/blueprints -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/CLI Commands-flask-imp init.md b/archive_docs/_md/v3/CLI Commands-flask-imp init.md deleted file mode 100644 index 91b86e7f..00000000 --- a/archive_docs/_md/v3/CLI Commands-flask-imp init.md +++ /dev/null @@ -1,226 +0,0 @@ -``` -Menu = CLI Commands/flask-imp init -Title = Initialising a Flask-Imp Project -``` - -Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp. - -```bash -flask-imp init --help -``` - -## Create a new project - -Make sure you are in the virtual environment, and at the root of your project folder, then run the following command: - -```bash -flask-imp init -``` - -After running this command, you will be prompted to choose what type of app you want to deploy: - -```text -~ $ flask-imp init -What type of app would you like to create? (full, slim, minimal) [full]: -``` - -See below for the differences between the app types. - -After this, you will be prompted to enter a name for your app: - -```text -~ $ flask-imp init -What would you like to call your app? [app]: -``` - -'app' is the default name, so if you just press enter, your app will be called 'app'. You will then see this output: - -```text -=================== -Flask app deployed! -=================== - -Your app has the default name of 'app' -Flask will automatically look for this! -Run: flask run --debug - -``` - -If you called your app something other than 'app', like 'new' for example, you will see: - -```text -=================== -Flask app deployed! -=================== - -Your app has the name of 'new' -Run: flask --app new run --debug - -``` - -As you can see from the output, it gives you instructions on how to start your app, depending on the name you gave it. - -You should see a new folder that has been given the name you specified in -the `flask-imp init` command. - -### Additional options - -You can also specify a name for your app in the command itself, like so: - -```bash -flask-imp init -n my_app -``` - -This will create a new app called 'my_app'. - -You can also deploy a slim app, that will have one blueprint and no models, like so: - -```bash -flask-imp init -n my_app --slim -``` - -You can also deploy a minimal app, that will have no blueprints, models, or extensions, like so: - -```bash -flask-imp init -n my_app --minimal -``` - -## init Folder structures - -### Full app - -`flask-imp init`: - -```text -app/ -├── blueprints -│ └── www -│ ├── config.toml -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── context_processors -│ │ └── context_processors.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── filters -│ │ └── filters.py -│ ├── routes -│ │ └── routes.py -│ ├── static -│ │ └── favicon.ico -│ └── templates -│ ├── errors -│ │ ├── 400.html -│ │ ├── 401.html -│ │ ├── 403.html -│ │ ├── 404.html -│ │ ├── 405.html -│ │ └── 500.html -│ └── index.html -│ -├── models -│ ├── example_user_table.py -│ └── __init__.py -│ -├── __init__.py -└── default.config.toml -``` - -### Slim app - -`flask-imp init --slim`: - -```text -app/ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── static -│ │ └── favicon.ico -│ └── templates -│ └── errors -│ ├── 400.html -│ ├── 401.html -│ ├── 403.html -│ ├── 404.html -│ ├── 405.html -│ └── 500.html -│ -├── www -│ ├── config.toml -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -├── __init__.py -└── default.config.toml -``` - -### Minimal app - -`flask-imp init --minimal`: - -```text -app/ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── favicon.ico -│ ├── templates -│ │ └── index.html -│ └── routes.py -│ -├── __init__.py -└── default.config.toml -``` diff --git a/archive_docs/_md/v3/Imp-Introduction.md b/archive_docs/_md/v3/Imp-Introduction.md deleted file mode 100644 index e07c91f6..00000000 --- a/archive_docs/_md/v3/Imp-Introduction.md +++ /dev/null @@ -1,82 +0,0 @@ -``` -Menu = Imp/Introduction -Title = Flask-Imp Introduction -``` - -Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources from a Flask application. It uses the importlib module to achieve this. - -Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using only -Blueprints. However, you can use Flask-Imp without using Blueprints. - -Here's an example of a standard Flask-Imp project structure: - -```text -app/ -├── blueprints/ -│ ├── admin/... -│ ├── api/... -│ └── www/... -├── resources/ -│ ├── filters/... -│ ├── context_processors/... -│ ├── static/... -│ └── templates/... -├── models/... -├── default.config.toml -└── __init__.py -``` - -Here's an example of the `app/__init__.py` file: - -```python -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from flask_imp import Imp - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - db.init_app(app) - - imp.import_app_resources("resources") - imp.import_models("models") - imp.import_blueprints("blueprints") - - return app -``` - -During `imp.init_app` the `default.config.toml` file will load variables under `[FLASK]` into the Flask app config. -It will also load variables under `[DATABASE]` into the Flask app config as `SQLALCHEMY_DATABASE_URI`. - -Values under `[SESSION]` can be loaded with: - -```python -@app.before_request -def before_request(): - imp._init_session() -``` - -See more about the config file here: [Imp / x.config.toml](imp-x-config-toml.html) - -`import_app_resources` will walk one level deep into the `resources` folder, and import all `.py` files as modules. It will -also check for the existence of a `static` and `templates` folder, and register them with the Flask app. - -There is a couple of options for `import_app_resources` to control what -is imported, see: [Imp.x / import_app_resources](imp_x-import_app_resources.html) - -`import_models` will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via `imp.model` - -See more about how import_models and the lookup -here: [Imp.x / import_models](imp_x-import_models.html) and [Imp.x / model](imp_x-model.html) - -`import_blueprints` expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's `__init__.py` file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app. - -See more about how importing blueprints work here: [Blueprint / Introduction](blueprint-introduction.html) diff --git a/archive_docs/_md/v3/Imp-load-env-vars.md b/archive_docs/_md/v3/Imp-load-env-vars.md deleted file mode 100644 index 4b2548f6..00000000 --- a/archive_docs/_md/v3/Imp-load-env-vars.md +++ /dev/null @@ -1,30 +0,0 @@ -``` -Menu = Imp/Load Env Variables -Title = Load Enviroment Variables into the Config File -``` - -`<>` markers can be used to find variables set in the environment. For example: - -**File: `default.config.toml`** -```toml -[FLASK] -# ... - -ERROR_404_HELP = true -SERVER_NAME = "" -APPLICATION_ROOT = "/" - -# ... -``` - -`` will be replaced by the value of `FLASK_SERVER_NAME` - -**Development `.env`** -```text -FLASK_SERVER_NAME=localhost:5000 -``` - -**Production `.env`** -```text -FLASK_SERVER_NAME=mysite.com -``` diff --git a/archive_docs/_md/v3/Imp-x-config-toml.md b/archive_docs/_md/v3/Imp-x-config-toml.md deleted file mode 100644 index 32e27c92..00000000 --- a/archive_docs/_md/v3/Imp-x-config-toml.md +++ /dev/null @@ -1,137 +0,0 @@ -``` -Menu = Imp/x.config.toml -Title = The Flask-Imp Config File -``` - -Flask-Imp loads configuration settings from a toml file found in the root of your app package. - -`app/default.config.toml` is the default config file, this will be created if no config file is found or set. - -Here's an example file structure: - -```text -Project/ -├── app/ -│ ├── ... -│ ├── __init__.py -│ └── default.config.toml -├── venv/... -└── ... -``` - -Here's an example of the default config file that is created: - -```toml -# Flask-Imp Config File -# ------------------------ -# Updates the Flask app config with the variables below. -# If any variable below does not exist in the standard Flask env -# vars it is created and will be accessible using -# app.config. All key names defined below will be -# capitalised when imported. -[FLASK] -DEBUG = false -#PROPAGATE_EXCEPTIONS = true -TRAP_HTTP_EXCEPTIONS = false -#TRAP_BAD_REQUEST_ERRORS = true -SECRET_KEY = "super_secret_key" -SESSION_COOKIE_NAME = "session" -#SESSION_COOKIE_DOMAIN = "domain-here.com" -#SESSION_COOKIE_PATH = "/" -SESSION_COOKIE_HTTPONLY = true -SESSION_COOKIE_SECURE = false -SESSION_COOKIE_SAMESITE = "Lax" -PERMANENT_SESSION_LIFETIME = 3600 # 1 hour -SESSION_REFRESH_EACH_REQUEST = true -USE_X_SENDFILE = false -#SEND_FILE_MAX_AGE_DEFAULT = 43200 -ERROR_404_HELP = true -#SERVER_NAME = "localhost:5000" -APPLICATION_ROOT = "/" -PREFERRED_URL_SCHEME = "http" -#MAX_CONTENT_LENGTH = 0 -#TEMPLATES_AUTO_RELOAD = true -EXPLAIN_TEMPLATE_LOADING = false -MAX_COOKIE_SIZE = 4093 - - -# This will set the default session variables for the app. -# Anything here will be accessible using session["your_var_name"] -# or session.get("your_var_name") -[SESSION] -logged_in = false - -# These settings are spcific to the Flask-SQLAlchemy extension. -# Anything here will be accessible using app.config -[SQLALCHEMY] -SQLALCHEMY_ECHO = false -SQLALCHEMY_TRACK_MODIFICATIONS = false -SQLALCHEMY_RECORD_QUERIES = false -# Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy. -# This sets the file extension for SQLite databases, and where to create the folder -# that the database will be stored in. true will create the folder on the same level as your -# app, false will create the folder in the app root. -SQLITE_DB_EXTENSION = ".sqlite" -SQLITE_STORE_IN_PARENT = true - -# [DATABASE.MAIN] is loaded as SQLALCHEMY_DATABASE_URI -# Dialets = mysql / postgresql / sqlite / oracle / mssql - -# Uncomment below to generate the SQLALCHEMY_DATABASE_URI. -#[DATABASE.MAIN] -#ENABLED = true -#DIALECT = "sqlite" -#DATABASE_NAME = "database" -#LOCATION = "db" -#PORT = "" -#USERNAME = "database" -#PASSWORD = "password" - -# Adding another database is as simple as adding a new section. -# [DATABASE.ANOTHER] will then be accessible using SQLALCHEMY_BINDS -# The bind key will be stored as a lowercase value, so "ANOTHER" will -# be accessible as "another" -# You can then use the bind key in the model as follows: -# class MyModel(db.Model): -# __bind_key__ = "another" -# ... - -# Uncomment below to generate and add to SQLALCHEMY_BINDS. -#[DATABASE.ANOTHER] -#ENABLED = true -#DIALECT = "sqlite" -#DATABASE_NAME = "database_another" -#LOCATION = "db" -#PORT = "" -#USERNAME = "user" -#PASSWORD = "password" - -``` - -To change what config file is loaded, you can set the `IMP_CONFIG` environment -variable to the name of the config file you want to load. - -For example, given the following folder structure: - -```text -Project/ -├── app/ -│ ├── ... -│ ├── __init__.py -│ ├── production.config.toml -│ └── default.config.toml -├── venv/... -└── ... -``` - -You'd set the `IMP_CONFIG=production.config.toml` - -Or you can set the file in the `imp.init_app()` method: - -```python - -def create_app(): - app = Flask(__name__) - imp.init_app(app, app_config_file="production.config.toml") - -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/Imp_x-import_app_resources.md b/archive_docs/_md/v3/Imp_x-import_app_resources.md deleted file mode 100644 index 4504f5a3..00000000 --- a/archive_docs/_md/v3/Imp_x-import_app_resources.md +++ /dev/null @@ -1,106 +0,0 @@ -``` -Menu = Imp.x/import_app_resources -Title = Imp.import_app_resources -``` - -```python -import_app_resources( - folder: str = "resources", - factories: Optional[List] = None, - static_folder: str = "static", - templates_folder: str = "templates", - files_to_import: Optional[List] = None, - folders_to_import: Optional[List] = None, - ) -> None -``` - ---- - -Import standard app resources from the specified folder. - -This will import any resources that have been set to the Flask app. - -Routes, context processors, cli, etc. - -**Can only be called once.** - -If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config. - -#### Small example of usage: - -```python -imp.import_app_resources(folder="resources") -# or -imp.import_app_resources() -# as the default folder is "resources" -``` - -Folder Structure: `resources` - -```text -app -├── resources -│ ├── routes.py -│ ├── app_fac.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ └── templates -│ └── index.html -└── ... -... -``` - -File: `routes.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -#### How factories work - -Factories are functions that are called when importing the app resources. Here's an example: - -```python -imp.import_app_resources( - folder="resources", - factories=["development_cli"] -) -``` - -`["development_cli"]` => `development_cli(app)` function will be called, and the current app will be passed in. - -File: `app_fac.py` - -```python -def development_cli(app): - @app.cli.command("dev") - def dev(): - print("dev cli command") -``` - -#### Scoping imports - -By default, all files and folders will be imported. - -To disable this, set `files_to_import` and or -`folders_to_import` to `[None]`. - -```python -imp.import_app_resources(scope_import=[None], folders_to_import=[None]) -``` - -To scope the imports, set the `files_to_import` and or `folders_to_import` to a list of files and or folders. - -`files_to_import=["cli.py", "routes.py"]` => will only import the files `resources/cli.py` -and `resources/routes.py` - -`folders_to_import=["template_filters", "context_processors"]` => will import all files in the folders -`resources/template_filters/*.py` and `resources/context_processors/*.py` diff --git a/archive_docs/_md/v3/Imp_x-import_blueprint.md b/archive_docs/_md/v3/Imp_x-import_blueprint.md deleted file mode 100644 index 6439315a..00000000 --- a/archive_docs/_md/v3/Imp_x-import_blueprint.md +++ /dev/null @@ -1,116 +0,0 @@ -``` -Menu = Imp.x/import_blueprint -Title = Imp.import_blueprint -``` - -```python -import_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root. - - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprint("my_blueprint") - - return app -``` - -Flask-Imp Blueprints have the ability to import configuration from a toml file, import resources, and initialize session -variables. - -For more information on how Flask-Imp Blueprints work, see the [Blueprint / Introduction](blueprint-introduction.html) - -##### Example of 'my_blueprint' as a Flask-Imp Blueprint: - -```text -app -├── my_blueprint -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ ├── templates -│ │ └── my_blueprint -│ │ └── index.html -│ ├── __init__.py -│ └── config.toml -└── ... -``` - -File: `__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") - - -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` - -File: `routes / index.py` - -```python -from .. import bp - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -##### Example of 'my_blueprint' as a standard Flask Blueprint: - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -└── ... -``` - -File: `__init__.py` - -```python -from flask import Blueprint - -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint") - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -Both of the above examples will work with `imp.import_blueprint("my_blueprint")`, they will be registered -with the Flask app, and will be accessible via `url_for("my_blueprint.index")`. \ No newline at end of file diff --git a/archive_docs/_md/v3/Imp_x-import_blueprints.md b/archive_docs/_md/v3/Imp_x-import_blueprints.md deleted file mode 100644 index 5f7d3a78..00000000 --- a/archive_docs/_md/v3/Imp_x-import_blueprints.md +++ /dev/null @@ -1,50 +0,0 @@ -``` -Menu = Imp.x/import_blueprints -Title = Imp.import_blueprints -``` - -```python -import_blueprints(self, folder: str) -> None -``` - ---- - -Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root. - -```text -app/ -├── blueprints/ -│ ├── admin/ -│ │ ├── ... -│ │ └── __init__.py -│ ├── www/ -│ │ ├── ... -│ │ └── __init__.py -│ └── api/ -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprints("blueprints") - - return app -``` - -This will import all Blueprints from the `blueprints` folder using the `Imp.import_blueprint` method. -See [Imp.x / import_blueprint](imp_x-import_blueprint.html) for more information. \ No newline at end of file diff --git a/archive_docs/_md/v3/Imp_x-import_models.md b/archive_docs/_md/v3/Imp_x-import_models.md deleted file mode 100644 index 32f5e1d9..00000000 --- a/archive_docs/_md/v3/Imp_x-import_models.md +++ /dev/null @@ -1,83 +0,0 @@ -``` -Menu = Imp.x/import_models -Title = Imp.import_models -``` - -```python -import_models(file_or_folder: str) -> None -``` - ---- - -Imports all the models from the given file or folder relative to the Flask app root. - -Each Model that is imported will be available in the `imp.model` lookup method. -See [Imp.x / model](imp_x-model.html) for more information. - -##### Example of importing models from a file - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── users_model.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python - -from flask import Flask -from flask_sqlalchemy import SQLAlchemy - -from flask_imp import Imp - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - db.init_app(app) # must be below imp.init_app - - imp.import_blueprint("my_blueprint") - imp.import_models("users_model.py") - - return app -``` - -File: `app/users_model.py` - -```python -from app import db - - -class User(db.Model): - attribute = db.Column(db.String(255)) -``` - -##### Example of importing models from a folder - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── models/ -│ ├── boats.py -│ ├── cars.py -│ └── users.py -├── ... -└── __init__.py -``` - -```python -def create_app(): - ... - imp.import_models("models") - ... -``` diff --git a/archive_docs/_md/v3/Imp_x-init_app-init.md b/archive_docs/_md/v3/Imp_x-init_app-init.md deleted file mode 100644 index 4e9127c8..00000000 --- a/archive_docs/_md/v3/Imp_x-init_app-init.md +++ /dev/null @@ -1,33 +0,0 @@ -``` -Menu = Imp.x/init_app, __init__ -Title = Imp.init_app, __init__ -``` - -```python -init_app( - app: Flask, - app_config_file: Optional[str] = None, - ignore_missing_env_variables: bool = False -) -> None -# -or- -Imp( - app: Optional[Flask] = None, - app_config_file: Optional[str] = None, - ignore_missing_env_variables: bool = False -) -> None -``` - ---- - -Initializes the flask app to work with flask-imp. - -If no `app_config_file` specified, an attempt to read `IMP_CONFIG` from the environment will be made. - -If `IMP_CONFIG` is not in the environment variables, an attempt to load `default.config.toml` will be made. - -`default.config.toml` will be created, and used if not found. - -If `ignore_missing_env_variables` is `True`, then missing environment variables will be ignored. - -If `ignore_missing_env_variables` is `False` (default), then missing environment variables will raise a ValueError - diff --git a/archive_docs/_md/v3/Imp_x-init_session.md b/archive_docs/_md/v3/Imp_x-init_session.md deleted file mode 100644 index b7c9a1d5..00000000 --- a/archive_docs/_md/v3/Imp_x-init_session.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = Imp.x/init_session -Title = Imp.init_session -``` - -```python -init_session() -> None -``` - ---- - -Initialize the session variables found in the config. Commonly used in `app.before_request`. - -```python -@app.before_request -def before_request(): - imp._init_session() -``` - -File: `default.config.toml` - -```toml -... -[SESSION] -logged_in = false -... -``` - -`logged_in` is now available in the session. - -```python -@app.route('/get-session-value') -def login(): - print(session['logged_in']) - return "Check Terminal" -``` - -`Output: False` - -Can also be used to reset the values in the session. Here's an example: - -```python -@app.route('/logout') -def logout(): - session.clear() - imp._init_session() - return redirect(url_for('index')) -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/Imp_x-model.md b/archive_docs/_md/v3/Imp_x-model.md deleted file mode 100644 index 71c55243..00000000 --- a/archive_docs/_md/v3/Imp_x-model.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = Imp.x/model -Title = Imp.model -``` - -```python -model(class_: str) -> DefaultMeta -``` - ---- - -Returns the SQLAlchemy model class for the given class name that was imported using `Imp.import_models` or -`Blueprint.import_models`. - -This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting. - -For example: - -```python -from app.models.boats import Boats -from app.models.cars import Cars -``` - -Can be replaced with: - -```python -from app import imp - -Boats = imp.model("Boats") -Cars = imp.model("Cars") -``` - -Or used directly: - -```python -from app import imp - -all_boats = imp.model("Boats").select_all() -``` - - -file: `models/boats.py` - -```python -from app import db - - -class Boats(db.Model): - name = db.Column(db.String()) - - @classmethod - def select_all(cls): - return db.session.execute( - db.select(cls) - ).scalars().all() -``` diff --git a/archive_docs/_md/v3/__index__.md b/archive_docs/_md/v3/__index__.md deleted file mode 100644 index 59f864d9..00000000 --- a/archive_docs/_md/v3/__index__.md +++ /dev/null @@ -1,117 +0,0 @@ -# Welcome to the Flask-Imp Documentation - -## What is Flask-Imp? - -Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication. - -## Install Flask-Imp - -```bash -pip install flask-imp -``` - -## Getting Started - -To get started right away, you can utilize the CLI commands to create a new Flask-Imp project. - -```bash -flask-imp init -``` - -### Minimal Flask-Imp Setup - -Run the following command to create a minimal Flask-Imp project. - -```bash -flask-imp init -n app --minimal -``` - -See [CLI Commands / flask-imp init](cli_commands-flask-imp_init.html) for more information. - -### Build minimal manually - -#### Folder Structure - -```text -app/ -├── resources/ -│ ├── static/... -│ ├── templates/ -│ │ └── index.html -│ └── index.py -├── default.config.toml -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_app_resources() - # Takes argument 'folder' default folder is 'resources' - - return app -``` - -File: `app/resources/index.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -File: `app/resources/templates/index.html` - -```html - - - - - Flask-Imp - - -

Flask-Imp

- - -``` - ---- - -We recommend using a virtual environment, then installing Flask-Imp. - -**Linux / MacOS** - -```bash -python3 -m venv venv -``` - -```bash -source venv/bin/activate -``` - -**Windows** - -```bash -python -m venv venv -``` - -```text -.\venv\Scripts\activate -``` - diff --git a/archive_docs/_md/v3/__menu__.md b/archive_docs/_md/v3/__menu__.md deleted file mode 100644 index 205f3902..00000000 --- a/archive_docs/_md/v3/__menu__.md +++ /dev/null @@ -1,45 +0,0 @@ -- CLI Commands - - flask-imp init - - flask-imp blueprint -- Imp - - Introduction - - x.config.toml - - Load Env Variables -- Blueprint - - Introduction - - config.toml -- Imp.x - - init_app, __init__ - - init_session - - import_app_resources - - import_blueprint - - import_blueprints - - import_models - - model - - model_meta -- Blueprint.x - - __init__ - - init_session - - import_resources - - import_nested_blueprint - - import_nested_blueprints - - import_models - - tmpl -- flask_imp.security - - login_check - - permission_check - - pass_function_check - - api_login_check - - include_csrf -- flask_imp.auth - - encrypt_password - - authenticate_password - - generate_password - - generate_salt - - generate_csrf_token - - generate_private_key - - generate_email_validator - - generate_numeric_validator - - generate_alphanumeric_validator - - is_email_address_valid - - is_username_valid diff --git a/archive_docs/_md/v3/flask_imp_auth-authenticate_password.md b/archive_docs/_md/v3/flask_imp_auth-authenticate_password.md deleted file mode 100644 index d255ae7a..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-authenticate_password.md +++ /dev/null @@ -1,63 +0,0 @@ -``` -Menu = flask_imp.auth/authenticate_password -Title = authenticate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import authenticate_password -``` - -```python -authenticate_password( - input_password: str, - database_password: str, - database_salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end", - use_multiprocessing: bool = False -) -> bool -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / encrypt_password](flask_imp_auth-encrypt_password.html) function. - -Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match. - -**Note:** - -**use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.** - -If you are using socketio, you must set use_multiprocessing to False (default). - -**Note:** - -- You must know the pepper length used to hash the password. -- You must know the position of the pepper used to hash the password. -- You must know the encryption level used to hash the password. - -#### Authentication Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -```python -input_password = "password" -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database -database_salt = "^%$*" # pulled from database - -authenticate_password( - input_password, - database_password, - database_salt -) # >>> True -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-encrypt_password.md b/archive_docs/_md/v3/flask_imp_auth-encrypt_password.md deleted file mode 100644 index 0287b119..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-encrypt_password.md +++ /dev/null @@ -1,53 +0,0 @@ -``` -Menu = flask_imp.auth/encrypt_password -Title = encrypt_password - flask_imp.auth -``` - -```python -from flask_imp.auth import encrypt_password -``` - -```python -encrypt_password( - password: str, - salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end" -) -> str -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / authenticate_password](flask_imp_auth-authenticate_password.html) function. - -Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified. - -Can set the encryption level to 256 or 512, defaults to 512. - -Can set the pepper length, defaults to 1. Max is 3. - -Can set the pepper position, "start" or "end", defaults to "end". - -**Note:** - -- You must inform the authenticate_password function of the pepper length used to hash the password. -- You must inform the authenticate_password function of the position of the pepper used to hash the password. -- You must inform the authenticate_password function of the encryption level used to hash the password. - -#### Encryption Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -1. Pepper is added to the end of the plain password: "passwordA" -2. Salt is added to the end of the peppered password: "passwordA^%$*" -3. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." -4. Salt and hashed password are then stored in the database. - diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md deleted file mode 100644 index c0d0ccdc..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_alphanumeric_validator.md +++ /dev/null @@ -1,24 +0,0 @@ -``` -Menu = flask_imp.auth/generate_alphanumeric_validator -Title = generate_alphanumeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_alphanumeric_validator -``` - -```python -generate_alphanumeric_validator(length: int = 8) -> str -``` - ---- - -Generates a random alphanumeric string of the given length. - -(letters are capitalized) - -*Example:* - -```python -generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md deleted file mode 100644 index ce6df31b..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_csrf_token.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_csrf_token -Title = generate_csrf_token - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_csrf_token -``` - -```python -generate_csrf_token() -> str -``` - ---- - -Generates a SHA1 using the current date and time. - -For use in Cross-Site Request Forgery. - -Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. - -*Example:* - -```python -generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md deleted file mode 100644 index acdced31..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_email_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_email_validator -Title = generate_email_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_email_validator -``` - -```python -generate_email_validator() -> str -``` - ---- - -Uses `generate_alphanumeric_validator` with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email. - -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) -for more information. - -*Example:* - -```python -generate_email_validator() # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md deleted file mode 100644 index c0d7dc76..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_numeric_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_numeric_validator -Title = generate_numeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_numeric_validator -``` - -```python -generate_numeric_validator(length: int) -> int -``` - ---- - - -Generates random choice between 1 * (length) and 9 * (length). - -If the length is 4, it will generate a number between 1111 and 9999. - -For use in MFA email, or unique filename generation. - -*Example:* - -```python -generate_numeric_validator(4) # >>> 1234 -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_password.md b/archive_docs/_md/v3/flask_imp_auth-generate_password.md deleted file mode 100644 index b6f8fda0..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_password.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_password -Title = generate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_password -``` - -```python -generate_password(style: str = "mixed", length: int = 3) -> str -``` - ---- - -Generates a password of (length) characters. - -The Default length is 3. - -Style options: "animals", "colors", "mixed" - defaults to "mixed" - -*Example:* - -```python -generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_private_key.md b/archive_docs/_md/v3/flask_imp_auth-generate_private_key.md deleted file mode 100644 index 63938598..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_private_key.md +++ /dev/null @@ -1,38 +0,0 @@ -``` -Menu = flask_imp.auth/generate_private_key -Title = generate_private_key - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_private_key -``` - -```python -generate_private_key(hook: t.Optional[str]) -> str -``` - ---- - -Generates a sha256 private key from a passed in hook value. - -If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000. - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt, - private_key=generate_private_key(hook=username) - ) - ... -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-generate_salt.md b/archive_docs/_md/v3/flask_imp_auth-generate_salt.md deleted file mode 100644 index f21615f5..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-generate_salt.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/generate_salt -Title = generate_salt - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_salt -``` - -```python -generate_salt(length: int = 4) -> str -``` - ---- - -Generates a string of (length) characters of punctuation. - -The Default length is 4. - -For use in password hashing and storage of passwords in the database. - -*Example:* - -```python -generate_salt() # >>> '*!$%' -``` - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt - ) - ... -``` - diff --git a/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md deleted file mode 100644 index 1990e24a..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-is_email_address_valid.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/is_email_address_valid -Title = is_email_address_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_email_address_valid -``` - -```python -is_email_address_valid( - email_address: str -) -> bool -``` - ---- - -Checks if an email address is valid. - -Is not completely RFC 5322 compliant, but it is good enough for most use cases. - -Here are examples of mistakes that it will not catch: - -##### Valid but fails: - -```text -email@[123.123.123.123] -“email”@example.com -very.unusual.“@”.unusual.com@example.com -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com -``` - -##### Invalid but passes: - -```text -email@example.com (Joe Smith) -email@111.222.333.44444 -``` - -*Example:* - -```python -is_email_address_valid('hello@example.com') # >>> True - -is_email_address_valid('hello@hello@example.com') # >>> False -``` diff --git a/archive_docs/_md/v3/flask_imp_auth-is_username_valid.md b/archive_docs/_md/v3/flask_imp_auth-is_username_valid.md deleted file mode 100644 index 68cdf070..00000000 --- a/archive_docs/_md/v3/flask_imp_auth-is_username_valid.md +++ /dev/null @@ -1,58 +0,0 @@ -``` -Menu = flask_imp.auth/is_username_valid -Title = is_username_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_username_valid -``` - -```python -is_username_valid( - username: str, - allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None -) -> bool -``` - ---- - -Checks if a username is valid. - -Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned. - -##### Example "all": - -```python -is_username_valid("username", allowed=["all"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user_name : WILL PASS : True -_user_name : WILL PASS : False -``` - -##### Example "dot", "dash": - -```python - -is_username_valid("username", allowed=["dot", "dash"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user-name.name : WILL PASS : True -user_name : WILL PASS : False -_user_name : WILL PASS : False -.user.name : WILL PASS : False -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/flask_imp_security-api_login_check.md b/archive_docs/_md/v3/flask_imp_security-api_login_check.md deleted file mode 100644 index e021ecbe..00000000 --- a/archive_docs/_md/v3/flask_imp_security-api_login_check.md +++ /dev/null @@ -1,47 +0,0 @@ -``` -Menu = flask_imp.security/api_login_check -Title = api_login_check - flask_imp.security -``` - - -```python -from flask_imp.security import api_login_check -``` - -```python -api_login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_json: t.Optional[t.Dict[str, t.Any]] = None -) -``` - -`@api_login_check(...)` - ---- - -A decorator that is used to secure API routes that return JSON responses. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. - -*Example:* - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True) -def api_page(): - ... -``` - -##### Example of defined fail_json: - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."}) -def api_page(): - ... -``` diff --git a/archive_docs/_md/v3/flask_imp_security-include_csrf.md b/archive_docs/_md/v3/flask_imp_security-include_csrf.md deleted file mode 100644 index 5f367974..00000000 --- a/archive_docs/_md/v3/flask_imp_security-include_csrf.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = flask_imp.security/include_csrf -Title = include_csrf - flask_imp.security -``` - -```python -from flask_imp.security import include_csrf -``` - -```python -include_csrf( - session_key: str = "csrf", - form_key: str = "csrf", - abort_code: int = 401 -) -``` - -`@include_csrf(...)` - ---- - - -A decorator that handles CSRF protection. - -On a **GET** request, a CSRF token is generated and stored in the session key -specified by the session_key parameter. - -On a **POST** request, the form_key specified is checked against the session_key -specified. - -- If they match, the request is allowed to continue. -- If no match, the response will be abort(abort_code), default 401. - -```python -@bp.route("/admin", methods=["GET", "POST"]) -@include_csrf(session_key="csrf", form_key="csrf") -def admin_page(): - ... - # You must pass in the CSRF token from the session into the template. - # Then add to the form. - return render_template("admin.html", csrf=session.get("csrf")) -``` - -Form key: - -```html - -``` \ No newline at end of file diff --git a/archive_docs/_md/v3/flask_imp_security-login_check.md b/archive_docs/_md/v3/flask_imp_security-login_check.md deleted file mode 100644 index f95cebde..00000000 --- a/archive_docs/_md/v3/flask_imp_security-login_check.md +++ /dev/null @@ -1,66 +0,0 @@ -``` -Menu = flask_imp.security/login_check -Title = login_check - flask_imp.security -``` - -```python -from flask_imp.security import login_check -``` - -```python -login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - pass_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@login_check(...)` - ---- - -A decorator that checks if the specified session key exists and contains the specified value. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -##### Example of a route that requires a user to be logged in: - -```python -@bp.route("/admin", methods=["GET"]) -@login_check( - 'logged_in', - True, - fail_endpoint='blueprint.login_page', - message="Login needed" -) -def admin_page(): - ... -``` - -##### Example of a route that if the user is already logged in, redirects to the specified endpoint: - -```python -@bp.route("/login-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - pass_endpoint='blueprint.admin_page', - message="Already logged in" -) -def login_page(): - ... -``` diff --git a/archive_docs/_md/v3/flask_imp_security-pass_function_check.md b/archive_docs/_md/v3/flask_imp_security-pass_function_check.md deleted file mode 100644 index 0f991f07..00000000 --- a/archive_docs/_md/v3/flask_imp_security-pass_function_check.md +++ /dev/null @@ -1,8 +0,0 @@ -``` -Menu = flask_imp.security/pass_function_check -Title = pass_function_check - flask_imp.security -``` - -```python -from flask_imp.security import pass_function_check -``` diff --git a/archive_docs/_md/v3/flask_imp_security-permission_check.md b/archive_docs/_md/v3/flask_imp_security-permission_check.md deleted file mode 100644 index 73278e12..00000000 --- a/archive_docs/_md/v3/flask_imp_security-permission_check.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = flask_imp.security/permission_check -Title = permission_check - flask_imp.security -``` - -```python -from flask_imp.security import permission_check -``` - -```python -permission_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@permission_check(...)` - ---- - -A decorator that checks if the specified session key exists and its value(s) match the specified value(s). - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -*Example:* - -```python -@bp.route("/admin-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - 'blueprint.login_page' -) # can be mixed with login_check -@permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', - message="Failed message" -) -def admin_page(): - ... -``` - diff --git a/archive_docs/_md/v4/Blueprint-Introduction.md b/archive_docs/_md/v4/Blueprint-Introduction.md deleted file mode 100644 index c8f70560..00000000 --- a/archive_docs/_md/v4/Blueprint-Introduction.md +++ /dev/null @@ -1,80 +0,0 @@ -``` -Menu = Blueprint/Introduction -Title = Flask-Imp Blueprint Introduction -``` - -The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints. - -The Flask-Imp Blueprint by default, reads configuration from a config.toml file or from a config class, -which is located in the same directory as the -`__init__.py` file. - -Here's an example of a Flask-Imp Blueprint structure: - -```text -www/ -├── nested_blueprints/ -│ ├── blueprint_one/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.py -│ └── blueprint_two/ -│ ├── ... -│ ├── __init__.py -│ └── config.py -├── standalone_nested_blueprint/ -│ ├── ... -│ ├── __init__.py -│ └── config.py -├── models/ -│ └── ... -├── routes/ -│ └── index.py -├── static/ -│ └── ... -├── templates/ -│ └── www/ -│ └── index.html -├── __init__.py -└── config.py -``` - -File: `__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("models") -bp.import_nested_blueprints("nested_blueprints") -bp.import_nested_blueprint("standalone_nested_blueprint") - - -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` - -During the `__init__` method of the Blueprint class, if the config argument is not set to `None`, the Blueprint will -attempt to load the configuration from either `config.toml` file or a `Config` class from a `config.py` file. - -To see more about configuration see: [Blueprint / config.x](blueprint-config-x.html) - -`import_resources` method will walk one level deep into the `routes` folder, and import all `.py` files as modules. -For more information see: [Blueprint.x / import_resources](blueprint_x-import_resources.html) - -`import_models` works the same as `imp.import_models`, it will look for instances of `db.Model` and import them. These -will also be available in the model lookup method `imp.model`. -For more information see: [Imp.x / import_models](imp_x-import_models.html) - -`import_nested_blueprints` will do the same as `imp.import_blueprints`, but will register the blueprints found as -nested to the current blueprint. For example `www.blueprint_one.index` - -`import_nested_blueprint` behaves the same as `import_nested_blueprints`, but will only import a single blueprint. - -`bp.init_session` will load the session variables from the config file into the session object. For more information -see: [Blueprint.x / init_session](blueprint_x-init_session.html) and -[Blueprint / config.x](blueprint-config-x.html) diff --git a/archive_docs/_md/v4/Blueprint-config-x.md b/archive_docs/_md/v4/Blueprint-config-x.md deleted file mode 100644 index 206e7c15..00000000 --- a/archive_docs/_md/v4/Blueprint-config-x.md +++ /dev/null @@ -1,160 +0,0 @@ -``` -Menu = Blueprint/config.x -Title = The Flask-Imp Blueprint Config File -``` - ---- - -**Recommendation:** Try and favour the use of a py file for your -configuration settings, as this will trigger reloads under -debug mode. - -Also, the bonus of being able to use Python to programmatically -set values is nice. - ---- - -The Flask-Imp Blueprint loads configuration settings from either a class -defined in a module or from a toml file. - -This file needs to sit next to the `__init__.py` file. - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) # will look for config.toml / config.py w/ Config class -# or -bp = Blueprint(__name__, config="config.Development") # will look for Development class in config.py -# or -bp = Blueprint(__name__, config="development.toml") # will look for development.toml file -``` - -For more information about the `config` parameter see: [Imp / config.x](Imp-config-x.html) - -### Using environment variables - -#### toml - -In a toml config, you can set environment variables by using `{{ }}` - -```toml -TEST_VALUE = "{{ test_value }}" -``` - -You can also set the type of the variable by using `:type` after the variable name. - -```toml -TEST_VALUE = "{{ test_value:int }}" -``` - -**Supported types are `int`, `float`, `bool`, `str`.** - -#### py - -In a py config, you can set environment variables by using `os.getenv`. - -```python -TEST_VALUE = os.getenv("TEST_VALUE", "default_value_here") -``` - -### Example `config.py` configuration file: - -```python -from flask_imp import ImpBlueprintConfig, DatabaseConfig - - -class Config(ImpBlueprintConfig): - ENABLED: bool = True - URL_PREFIX: str = "/" - # SUBDOMAIN: str = "" - # URL_DEFAULTS: dict = {} - STATIC_FOLDER: str = "static" - TEMPLATE_FOLDER: str = "templates" - STATIC_URL_PATH: str = "/static" - # ROOT_PATH: str = "" - # CLI_GROUP: str = "" - - INIT_SESSION: dict = { - "www_session": "yes" - } - - DATABASE_BINDS: set[DatabaseConfig] = { - DatabaseConfig( - ENABLED=True, - DIALECT="sqlite", - NAME="www", - BIND_KEY="www", - LOCATION="", - PORT=0, - USERNAME="", - PASSWORD="", - ) - } -``` - -### Example `config.toml` configuration file: - -```toml -ENABLED = "yes" - -[SETTINGS] -URL_PREFIX = "/" -#SUBDOMAIN = "" -#URL_DEFAULTS = {} -STATIC_FOLDER = "static" -TEMPLATE_FOLDER = "templates" -STATIC_URL_PATH = "/static" -#ROOT_PATH = "" -#CLI_GROUP = "" - -[SESSION] -www_session = "yes" - -# Set ENABLED to true to allow the blueprint -# to create a database bind, change settings accordingly. -[DATABASE_BIND] -ENABLED = true -DIALECT = "sqlite" -DATABASE_NAME = "www" -BIND_KEY = "www" -LOCATION = "" -PORT = "" -USERNAME = "" -PASSWORD = "" -``` - -These config files reflect the args that are passed to a regular Flask Blueprint class, -with the addition of the ability to enable/disable the Blueprint, set session variables and -include database binds. - -For more information about the args of a regular Flask Blueprint see: -[Flask docs (Blueprint)](https://flask.palletsprojects.com/en/3.0.x/api/#flask.Blueprint) - -### Session Variables - -You can set the default session variables for the blueprint by setting values in `INIT_SESSION`, these can be loaded -using the before_request function in the blueprint. - -```python -@blueprint.before_app_request -def load_session(): - blueprint._init_session() -``` - -### Database Binds - -You can also allow the blueprint to create a database bind, by setting `ENABLED` to `true` in the `DATABASE_BIND` -section of the toml file, or by adding to the `DATABASE_BINDS` set of the `Config` class. - -**Using a py config file will allow you to set multiple database binds for the blueprint.** - -This will add to the Flask app's `SQLALCHEMY_BINDS` config variable, and allows blueprints to be more modular -with their database connections. - -Including the attribute `__bind_key__` in the blueprint's model(s) will match the model to the database bind. - -```python -class User(db.Model): - __bind_key__ = "example" - ... -``` diff --git a/archive_docs/_md/v4/Blueprint-init.md b/archive_docs/_md/v4/Blueprint-init.md deleted file mode 100644 index 78d60d5f..00000000 --- a/archive_docs/_md/v4/Blueprint-init.md +++ /dev/null @@ -1,17 +0,0 @@ -``` -Menu = Blueprint.x/__init__ -Title = Flask-Imp Blueprint __init__ -``` - -```python -Blueprint(dunder_name: str, config_file: str = "config.toml") -> None -``` - ---- - -Initializes the Flask-Imp Blueprint. - -`dunder_name` should always be set to `__name__` - -`config_file` is the name of the config file to load. -It will be loaded from the same directory as the `__init__.py` file. diff --git a/archive_docs/_md/v4/Blueprint_x-import_models.md b/archive_docs/_md/v4/Blueprint_x-import_models.md deleted file mode 100644 index d919ae65..00000000 --- a/archive_docs/_md/v4/Blueprint_x-import_models.md +++ /dev/null @@ -1,80 +0,0 @@ -``` -Menu = Blueprint.x/import_models -Title = Blueprint.import_models -``` - -```python -import_models(folder: str = "models") -> None -``` - ---- - -Will import all the models from the given folder relative to the Blueprint's root directory. - -Works the same as [Imp.x / import_models](imp_x-import_models.html) but relative to the Blueprint root. - -Blueprint models will also be available in the [Imp.x / model](imp_x-model.html) lookup. - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── animal_models.py -│ -├── __init__.py -└── config.toml -``` - -**or** - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── models/ -│ └── animals.py -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("animal_models.py") -``` - -**or** - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_models("models") -``` - -File: `my_blueprint/animal_models.py` or `my_blueprint/models/animals.py` - -```python -from app import db - - -class Animals(db.Model): - animal_id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(64), index=True, unique=True) - species = db.Column(db.String(64), index=True, unique=True) -``` - - - diff --git a/archive_docs/_md/v4/Blueprint_x-import_nested_blueprint.md b/archive_docs/_md/v4/Blueprint_x-import_nested_blueprint.md deleted file mode 100644 index d8139c3d..00000000 --- a/archive_docs/_md/v4/Blueprint_x-import_nested_blueprint.md +++ /dev/null @@ -1,70 +0,0 @@ -``` -Menu = Blueprint.x/import_nested_blueprint -Title = Blueprint.import_nested_blueprint -``` - -```python -import_nested_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root. - -Works the same as [Imp.x / import_blueprint](imp_x-import_blueprint.html) but relative to the Blueprint root. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.my_nested_blueprint.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── my_nested_blueprint/ -│ ├── routes/ -│ │ └── index.py -│ ├── static/... -│ ├── templates/... -│ ├── __init__.py -│ └── config.toml -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_nested_blueprint("my_nested_blueprint") -``` - -File: `my_blueprint/my_nested_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -``` - -File: `my_blueprint/my_nested_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/Blueprint_x-import_nested_blueprints.md b/archive_docs/_md/v4/Blueprint_x-import_nested_blueprints.md deleted file mode 100644 index 16bdc2a7..00000000 --- a/archive_docs/_md/v4/Blueprint_x-import_nested_blueprints.md +++ /dev/null @@ -1,59 +0,0 @@ -``` -Menu = Blueprint.x/import_nested_blueprints -Title = Blueprint.import_nested_blueprints -``` - -```python -import_nested_blueprints(self, folder: str) -> None -``` - ---- - -Will import all the Blueprints from the given folder relative to the Blueprint's root directory. - -Uses [Blueprint.x / import_nested_blueprint](blueprint_x-import_nested_blueprint.html) to import blueprints from -the specified folder. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.nested_bp_one.index')` - -`url_for('my_blueprint.nested_bp_two.index')` - -`url_for('my_blueprint.nested_bp_three.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── nested_blueprints/ -│ │ -│ ├── nested_bp_one/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.toml -│ ├── nested_bp_two/ -│ │ ├── ... -│ │ ├── __init__.py -│ │ └── config.toml -│ └── nested_bp_three/ -│ ├── ... -│ ├── __init__.py -│ └── config.toml -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") -bp.import_nested_blueprints("nested_blueprints") -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/Blueprint_x-import_resources.md b/archive_docs/_md/v4/Blueprint_x-import_resources.md deleted file mode 100644 index dc5043d9..00000000 --- a/archive_docs/_md/v4/Blueprint_x-import_resources.md +++ /dev/null @@ -1,53 +0,0 @@ -``` -Menu = Blueprint.x/import_resources -Title = Blueprint.import_resources -``` - -```python -import_resources(folder: str = "routes") -> None -``` - ---- - -Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory. - -```text -my_blueprint -├── user_routes -│ ├── user_dashboard.py -│ └── user_settings.py -├── car_routes -│ ├── car_dashboard.py -│ └── car_settings.py -├── static/... -├── templates/ -│ └── my_blueprint/ -│ ├── user_dashboard.html -│ └── ... -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("user_routes") -bp.import_resources("car_routes") -``` - -File: `my_blueprint/user_routes/user_dashboard.py` - -```python -from flask import render_template - -from .. import bp - -@bp.route("/user-dashboard") -def user_dashboard(): - return render_template(bp.tmpl("user_dashboard.html")) -``` diff --git a/archive_docs/_md/v4/Blueprint_x-init_session.md b/archive_docs/_md/v4/Blueprint_x-init_session.md deleted file mode 100644 index 5a6bd55f..00000000 --- a/archive_docs/_md/v4/Blueprint_x-init_session.md +++ /dev/null @@ -1,19 +0,0 @@ -``` -Menu = Blueprint.x/init_session -Title = Blueprint.init_session -``` - -```python -init_session() -> None -``` - ---- - -Has the same functionality as [Imp.x / init_session](imp_x-init_session.html) but loads session key values from the -Blueprint's config file. - -```python -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/Blueprint_x-tmpl.md b/archive_docs/_md/v4/Blueprint_x-tmpl.md deleted file mode 100644 index dd23bed6..00000000 --- a/archive_docs/_md/v4/Blueprint_x-tmpl.md +++ /dev/null @@ -1,45 +0,0 @@ -``` -Menu = Blueprint.x/tmpl -Title = Blueprint.tmpl -``` - -```python -tmpl(template: str) -> str -``` - ---- - -Scopes the template lookup to the name of the blueprint (this takes from the `__name__` attribute of the Blueprint). - -Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder. - -```text -my_blueprint/ -├── routes/ -│ └── index.py -├── static/... -│ -├── templates/ -│ └── my_blueprint/ -│ └── index.html -│ -├── __init__.py -└── config.toml -``` - -File: `my_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` - -`bp.tmpl("index.html")` will output `"my_blueprint/index.html"`. diff --git a/archive_docs/_md/v4/CLI Commands-flask-imp blueprint.md b/archive_docs/_md/v4/CLI Commands-flask-imp blueprint.md deleted file mode 100644 index 8aca1dcc..00000000 --- a/archive_docs/_md/v4/CLI Commands-flask-imp blueprint.md +++ /dev/null @@ -1,107 +0,0 @@ -``` -Menu = CLI Commands/flask-imp blueprint -Title = Generate a Flask-Imp Blueprint -``` - -Flask-Imp has its own type of blueprint. It can read some configuration from a toml file and has some extra methods for -auto importing. - -```bash -flask-imp blueprint --help -``` - -To generate a Flask-Imp blueprint, run the following command: - -```bash -flask-imp blueprint -``` - -After running this command, you will be prompted to enter the location of where you want to create your blueprint: - -```text -~ $ flask-imp blueprint -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: -``` - -As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder `app/blueprints`, you would enter `app/blueprints` in the prompt. - -```text -~ $ flask-imp blueprint -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: app/blueprints -``` - -You will then be prompted to enter a name for your blueprint: - -```text -~ $ flask-imp blueprint -... -Name of the blueprint to create [my_new_blueprint]: -``` - -The default name is 'my_new_blueprint', we will change this to 'admin' - -```text -~ $ flask-imp blueprint -... -Name of the blueprint to create [my_new_blueprint]: admin -``` - -Finally, you will be asked what type of configuration file you would like to use: - -```text -~ $ flask-imp blueprint -... -What type of config file would you like to use? (py, toml) [py]: -``` - -`py` is recommended, as it is more flexible. - -After creating your blueprint, the folder structure will look like this: - -```text -app/ -├── blueprints -│ └── admin -│ ├── routes -│ │ └── index.py -│ │ -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ │ -│ ├── templates -│ │ └── www -│ │ ├── extends -│ │ │ └── main.html -│ │ ├── includes -│ │ │ ├── footer.html -│ │ │ └── header.html -│ │ └── index.html -│ │ -│ ├── __init__.py -│ └─── config.py -│ -... -``` - -This is a self-contained blueprint, so it has its own static, templates and routes folders. You can now navigate ' -/admin' - -You can streamline this process by specifying the name of the blueprint, the folder to -create it in and the configuration to use, like so: - -```bash -flask-imp blueprint -n admin -f app/blueprints --pyconfig -``` -or -```bash -flask-imp blueprint -n admin -f app/blueprints --tomlconfig -``` -for a toml config. \ No newline at end of file diff --git a/archive_docs/_md/v4/CLI Commands-flask-imp init.md b/archive_docs/_md/v4/CLI Commands-flask-imp init.md deleted file mode 100644 index abe4cd94..00000000 --- a/archive_docs/_md/v4/CLI Commands-flask-imp init.md +++ /dev/null @@ -1,262 +0,0 @@ -``` -Menu = CLI Commands/flask-imp init -Title = Initialising a Flask-Imp Project -``` - -Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp. - -```bash -flask-imp init --help -``` - -## Create a new project - -Make sure you are in the virtual environment, and at the root of your -project folder, then run the following command: - -```bash -flask-imp init -``` - -After running this command, you will be prompted to choose what type of -app you want to deploy: - -```text -~ $ flask-imp init -What type of app would you like to create? (full, slim, minimal) [full]: -``` - -See below for the differences between the app types. - -After this, you will be prompted to enter a name for your app: - -```text -~ $ flask-imp init -... -What would you like to call your app? [app]: -``` - -'app' is the default name, so if you just press enter, your app will be -called 'app'. You will then see this output: - -Next you will be asked what configuration file you would like to use: - -```text -~ $ flask-imp init -... -What type of config file would you like to use? (py, toml) [py]: -``` - -`py` is recommended, as it is more flexible. - - -```text -~ FILES CREATED WILL LOOP OUT HERE ~ - -=================== -Flask app deployed! -=================== - -Your app has the default name of 'app' -Flask will automatically look for this! -Run: flask run --debug - -``` - -If you called your app something other than 'app', like 'new' for example, you will see: - -```text -~ FILES CREATED WILL LOOP OUT HERE ~ - -=================== -Flask app deployed! -=================== - -Your app has the name of 'new' -Run: flask --app new run --debug - -``` - -As you can see from the output, it gives you instructions on how to start your app, -depending on the name you gave it. - -You should see a new folder that has been given the name you specified in -the `flask-imp init` command. - -### Additional options - -You can also specify a name for your app in the command itself, like so: - -```bash -flask-imp init -n my_app -``` - -This will create a new app called 'my_app'. - -You can also deploy a slim app, that will have one blueprint and no models, like so: - -```bash -flask-imp init -n my_app --slim -``` - -You can also deploy a minimal app, that will have no blueprints, models, or extensions, like so: - -```bash -flask-imp init -n my_app --minimal -``` - -This also works for what configuration file you would like to use: - -```bash -flask-imp init -n my_app --pyconfig -``` -or -```bash -flask-imp init -n my_app --tomlconfig -``` - -This will create a new minimal app called 'my_app' with a python configuration file. - -```bash -flask-imp init -n my_app --minimal --pyconfig -``` - -## init Folder structures - -### Full app - -`flask-imp init --full`: - -```text -app/ -├── blueprints -│ └── www -│ ├── config.py -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── context_processors -│ │ └── context_processors.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── filters -│ │ └── filters.py -│ ├── routes -│ │ └── routes.py -│ ├── static -│ │ └── favicon.ico -│ └── templates -│ ├── errors -│ │ ├── 400.html -│ │ ├── 401.html -│ │ ├── 403.html -│ │ ├── 404.html -│ │ ├── 405.html -│ │ └── 500.html -│ └── index.html -│ -├── models -│ ├── example_user_table.py -│ └── __init__.py -│ -├── __init__.py -└── config.py -``` - -### Slim app - -`flask-imp init --slim`: - -```text -app/ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── static -│ │ └── favicon.ico -│ └── templates -│ └── errors -│ ├── 400.html -│ ├── 401.html -│ ├── 403.html -│ ├── 404.html -│ ├── 405.html -│ └── 500.html -│ -├── www -│ ├── config.py -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -├── __init__.py -└── config.py -``` - -### Minimal app - -`flask-imp init --minimal`: - -```text -app/ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── favicon.ico -│ ├── templates -│ │ └── index.html -│ └── routes.py -│ -├── __init__.py -└── config.py -``` diff --git a/archive_docs/_md/v4/Imp-Introduction.md b/archive_docs/_md/v4/Imp-Introduction.md deleted file mode 100644 index 85e468af..00000000 --- a/archive_docs/_md/v4/Imp-Introduction.md +++ /dev/null @@ -1,78 +0,0 @@ -``` -Menu = Imp/Introduction -Title = Flask-Imp Introduction -``` - -Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources from a Flask application. It uses the importlib module to achieve this. - -Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using only -Blueprints. However, you can use Flask-Imp without using Blueprints. - -Here's an example of a standard Flask-Imp project structure: - -```text -app/ -├── blueprints/ -│ ├── admin/... -│ ├── api/... -│ └── www/... -├── resources/ -│ ├── filters/... -│ ├── context_processors/... -│ ├── static/... -│ └── templates/... -├── models/... -├── config.py -└── __init__.py -``` - -Here's an example of the `app/__init__.py` file: - -```python -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from flask_imp import Imp - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - db.init_app(app) - - imp.import_app_resources("resources") - imp.import_models("models") - imp.import_blueprints("blueprints") - - return app -``` - -The `init_app` method of the Imp class will automatically load configuration -if the config argument is not set to `None`. - -An attempt to load the configuration from either `config.toml` file or a `Config` -class from a `config.py` file will be made. - -For more information about the `config` parameter see: [Imp / config.x](imp-config-x.html) - -`import_app_resources` will walk one level deep into the `resources` folder, and import -all `.py` files as modules. -It will also check for the existence of a `static` and `templates` folder, and register them with the Flask app. - -There is a couple of options for `import_app_resources` to control what -is imported, see: [Imp.x / import_app_resources](imp_x-import_app_resources.html) - -`import_models` will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via `imp.model` - -See more about how import_models and the lookup -here: [Imp.x / import_models](imp_x-import_models.html) and [Imp.x / model](imp_x-model.html) - -`import_blueprints` expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's `__init__.py` file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app. - -See more about how importing blueprints work here: [Blueprint / Introduction](blueprint-introduction.html) diff --git a/archive_docs/_md/v4/Imp-config-x.md b/archive_docs/_md/v4/Imp-config-x.md deleted file mode 100644 index 94c0de56..00000000 --- a/archive_docs/_md/v4/Imp-config-x.md +++ /dev/null @@ -1,285 +0,0 @@ -``` -Menu = Imp/config.x -Title = The Flask-Imp Config File -``` - ---- - -**Recommendation:** Try and favour the use of a py file for your -configuration settings, as this will trigger reloads under -debug mode. - -Also, the bonus of being able to use Python to programmatically -set values is nice. - ---- - -Flask-Imp loads configuration settings from either a class -defined in a module or from a toml file. - -**This example:** - -```python - -def create_app(): - app = Flask(__name__) - imp.init_app(app, config="dev.config.toml") - -``` - -Will load configuration from the `dev.config.toml` file. - -**This example:** - -```python - -def create_app(): - app = Flask(__name__) - imp.init_app(app, config="config.Config") - -``` - -Will load the configuration from the `Config` class from the `config.py` file. - -Both of these files need to be located in the root of the app. - -The config class must be an instance of `ImpConfig` from `flask_imp`. - -You can also set the config by using the `IMP_CONFIG` environment -variable, but you will need to omit or set the `config` parameter to `None`. - -For example, given the following folder structure: - -```text -Project/ -├── app/ -│ ├── ... -│ ├── __init__.py -│ ├── config.py -│ └── dev.config.toml -├── venv/... -└── ... -``` - -You'd set the `IMP_CONFIG=dev.config.toml` and this will load the `dev.config.toml` file. - -### Using environment variables - -#### toml - -In a toml config, you can set environment variables by using `{{ }}` - -```toml -TEST_VALUE = "{{ test_value }}" -``` - -You can also set the type of the variable by using `:type` after the variable name. - -```toml -TEST_VALUE = "{{ test_value:int }}" -``` - -**Supported types are `int`, `float`, `bool`, `str`.** - -#### py - -In a py config, you can set environment variables by using `os.getenv`. - -```python -TEST_VALUE = os.getenv("TEST_VALUE", "default_value_here") -``` - -### Example `config.py` configuration file: - -```text -Project/ -├── app/ -│ ├── ... -│ ├── __init__.py -│ └── config.py -├── venv/... -└── ... -``` - -```python -from flask_imp import ( - FlaskConfig, - ImpConfig, - DatabaseConfig -) - - -class Config(ImpConfig): - FLASK = FlaskConfig( - # DEBUG=False, - # PROPAGATE_EXCEPTIONS = True, - TRAP_HTTP_EXCEPTIONS=False, - # TRAP_BAD_REQUEST_ERRORS = True, - SECRET_KEY="flask-imp", # CHANGE ME - SESSION_COOKIE_NAME="session", - # SESSION_COOKIE_DOMAIN = "domain-here.com", - # SESSION_COOKIE_PATH = "/", - SESSION_COOKIE_HTTPONLY=True, - SESSION_COOKIE_SECURE=False, - SESSION_COOKIE_SAMESITE="Lax", - PERMANENT_SESSION_LIFETIME=3600, # 1 hour, - SESSION_REFRESH_EACH_REQUEST=True, - USE_X_SENDFILE=False, - # SEND_FILE_MAX_AGE_DEFAULT = 43200, - ERROR_404_HELP=True, - # SERVER_NAME = "localhost:5000", - APPLICATION_ROOT="/", - PREFERRED_URL_SCHEME="http", - # MAX_CONTENT_LENGTH = 0, - # TEMPLATES_AUTO_RELOAD = True, - EXPLAIN_TEMPLATE_LOADING=False, - MAX_COOKIE_SIZE=4093, - ) - - # This will set the default session variables for the app. - INIT_SESSION = { - "logged_in": False, - } - - # Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy. - # This sets the file extension for SQLite databases, and where to create the folder - # that the database will be stored in. - # True will create the folder on the same level as your - # app, False will create the folder in the app root. - SQLITE_DB_EXTENSION = ".sqlite" - SQLITE_STORE_IN_PARENT = False - # - - # SQLAlchemy settings that will be passed to Flask - # Any SQLAlchemy setting here will overwrite anything - # set in the config above - SQLALCHEMY_ECHO = False - SQLALCHEMY_TRACK_MODIFICATIONS = False - SQLALCHEMY_RECORD_QUERIES = False - # - - # Main database settings, this will be converted to SQLALCHEMY_DATABASE_URI - DATABASE_MAIN = DatabaseConfig( - ENABLED=True, - DIALECT="sqlite", - NAME="main", - LOCATION="", - PORT=0, - USERNAME="", - PASSWORD="", - ) - - # Binds are additional databases that can be used in your app - # These will be added to the SQLALCHEMY_BINDS dictionary - # DATABASE_BINDS = { - # DatabaseConfig( - # ENABLED=True, - # DIALECT="sqlite", - # NAME="additional_database", - # BIND_KEY="additional_database", - # LOCATION="", - # PORT=0, - # USERNAME="", - # PASSWORD="", - # ) - # } -``` - -### Example `config.toml` configuration file: - -```text -Project/ -├── app/ -│ ├── ... -│ ├── __init__.py -│ └── config.toml -├── venv/... -└── ... -``` - -```toml -# Flask-Imp Config File -# ------------------------ -# Updates the Flask app config with the variables below. -# If any variable below does not exist in the standard Flask env -# vars it is created and will be accessible using -# app.config. All key names defined below will be -# capitalised when imported. -[FLASK] -#DEBUG = false -#PROPAGATE_EXCEPTIONS = true -TRAP_HTTP_EXCEPTIONS = false -#TRAP_BAD_REQUEST_ERRORS = true -SECRET_KEY = "super_secret_key" -SESSION_COOKIE_NAME = "session" -#SESSION_COOKIE_DOMAIN = "domain-here.com" -#SESSION_COOKIE_PATH = "/" -SESSION_COOKIE_HTTPONLY = true -SESSION_COOKIE_SECURE = false -SESSION_COOKIE_SAMESITE = "Lax" -PERMANENT_SESSION_LIFETIME = 3600 # 1 hour -SESSION_REFRESH_EACH_REQUEST = true -USE_X_SENDFILE = false -#SEND_FILE_MAX_AGE_DEFAULT = 43200 -ERROR_404_HELP = true -#SERVER_NAME = "localhost:5000" -APPLICATION_ROOT = "/" -PREFERRED_URL_SCHEME = "http" -#MAX_CONTENT_LENGTH = 0 -#TEMPLATES_AUTO_RELOAD = true -EXPLAIN_TEMPLATE_LOADING = false -MAX_COOKIE_SIZE = 4093 - - -# This will set the default session variables for the app. -# Anything here will be accessible using session["your_var_name"] -# or session.get("your_var_name") -[SESSION] -logged_in = false - -# These settings are spcific to the Flask-SQLAlchemy extension. -# Anything here will be accessible using app.config -[SQLALCHEMY] -SQLALCHEMY_ECHO = false -SQLALCHEMY_TRACK_MODIFICATIONS = false -SQLALCHEMY_RECORD_QUERIES = false -# Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy. -# This sets the file extension for SQLite databases, and where to create the folder -# that the database will be stored in. true will create the folder on the same level as your -# app, false will create the folder in the app root. -SQLITE_DB_EXTENSION = ".sqlite" -SQLITE_STORE_IN_PARENT = true - -# [DATABASE.MAIN] is loaded as SQLALCHEMY_DATABASE_URI -# Dialets = mysql / postgresql / sqlite / oracle / mssql - -# Uncomment below to generate the SQLALCHEMY_DATABASE_URI. -[DATABASE.MAIN] -ENABLED = true -DIALECT = "sqlite" -NAME = "database" -LOCATION = "db" -PORT = "" -USERNAME = "" -PASSWORD = "" - -# Adding another database is as simple as adding a new section. -# [DATABASE.ANOTHER] will then be accessible using SQLALCHEMY_BINDS -# The bind key will be stored as a lowercase value, so "ANOTHER" will -# be accessible as "another" -# You can then use the bind key in the model as follows: -# class MyModel(db.Model): -# __bind_key__ = "another" -# ... - -# Uncomment below to generate and add to SQLALCHEMY_BINDS. -#[DATABASE.ANOTHER] -#ENABLED = true -#DIALECT = "sqlite" -#NAME = "database_another" -#LOCATION = "db" -#PORT = "" -#USERNAME = "user" -#PASSWORD = "password" - -``` diff --git a/archive_docs/_md/v4/Imp_x-import_app_resources.md b/archive_docs/_md/v4/Imp_x-import_app_resources.md deleted file mode 100644 index 4504f5a3..00000000 --- a/archive_docs/_md/v4/Imp_x-import_app_resources.md +++ /dev/null @@ -1,106 +0,0 @@ -``` -Menu = Imp.x/import_app_resources -Title = Imp.import_app_resources -``` - -```python -import_app_resources( - folder: str = "resources", - factories: Optional[List] = None, - static_folder: str = "static", - templates_folder: str = "templates", - files_to_import: Optional[List] = None, - folders_to_import: Optional[List] = None, - ) -> None -``` - ---- - -Import standard app resources from the specified folder. - -This will import any resources that have been set to the Flask app. - -Routes, context processors, cli, etc. - -**Can only be called once.** - -If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config. - -#### Small example of usage: - -```python -imp.import_app_resources(folder="resources") -# or -imp.import_app_resources() -# as the default folder is "resources" -``` - -Folder Structure: `resources` - -```text -app -├── resources -│ ├── routes.py -│ ├── app_fac.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ └── templates -│ └── index.html -└── ... -... -``` - -File: `routes.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -#### How factories work - -Factories are functions that are called when importing the app resources. Here's an example: - -```python -imp.import_app_resources( - folder="resources", - factories=["development_cli"] -) -``` - -`["development_cli"]` => `development_cli(app)` function will be called, and the current app will be passed in. - -File: `app_fac.py` - -```python -def development_cli(app): - @app.cli.command("dev") - def dev(): - print("dev cli command") -``` - -#### Scoping imports - -By default, all files and folders will be imported. - -To disable this, set `files_to_import` and or -`folders_to_import` to `[None]`. - -```python -imp.import_app_resources(scope_import=[None], folders_to_import=[None]) -``` - -To scope the imports, set the `files_to_import` and or `folders_to_import` to a list of files and or folders. - -`files_to_import=["cli.py", "routes.py"]` => will only import the files `resources/cli.py` -and `resources/routes.py` - -`folders_to_import=["template_filters", "context_processors"]` => will import all files in the folders -`resources/template_filters/*.py` and `resources/context_processors/*.py` diff --git a/archive_docs/_md/v4/Imp_x-import_blueprint.md b/archive_docs/_md/v4/Imp_x-import_blueprint.md deleted file mode 100644 index 6439315a..00000000 --- a/archive_docs/_md/v4/Imp_x-import_blueprint.md +++ /dev/null @@ -1,116 +0,0 @@ -``` -Menu = Imp.x/import_blueprint -Title = Imp.import_blueprint -``` - -```python -import_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root. - - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprint("my_blueprint") - - return app -``` - -Flask-Imp Blueprints have the ability to import configuration from a toml file, import resources, and initialize session -variables. - -For more information on how Flask-Imp Blueprints work, see the [Blueprint / Introduction](blueprint-introduction.html) - -##### Example of 'my_blueprint' as a Flask-Imp Blueprint: - -```text -app -├── my_blueprint -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ ├── templates -│ │ └── my_blueprint -│ │ └── index.html -│ ├── __init__.py -│ └── config.toml -└── ... -``` - -File: `__init__.py` - -```python -from flask_imp import Blueprint - -bp = Blueprint(__name__) - -bp.import_resources("routes") - - -@bp.before_app_request -def before_app_request(): - bp._init_session() -``` - -File: `routes / index.py` - -```python -from .. import bp - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -##### Example of 'my_blueprint' as a standard Flask Blueprint: - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -└── ... -``` - -File: `__init__.py` - -```python -from flask import Blueprint - -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint") - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -Both of the above examples will work with `imp.import_blueprint("my_blueprint")`, they will be registered -with the Flask app, and will be accessible via `url_for("my_blueprint.index")`. \ No newline at end of file diff --git a/archive_docs/_md/v4/Imp_x-import_blueprints.md b/archive_docs/_md/v4/Imp_x-import_blueprints.md deleted file mode 100644 index 5f7d3a78..00000000 --- a/archive_docs/_md/v4/Imp_x-import_blueprints.md +++ /dev/null @@ -1,50 +0,0 @@ -``` -Menu = Imp.x/import_blueprints -Title = Imp.import_blueprints -``` - -```python -import_blueprints(self, folder: str) -> None -``` - ---- - -Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root. - -```text -app/ -├── blueprints/ -│ ├── admin/ -│ │ ├── ... -│ │ └── __init__.py -│ ├── www/ -│ │ ├── ... -│ │ └── __init__.py -│ └── api/ -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprints("blueprints") - - return app -``` - -This will import all Blueprints from the `blueprints` folder using the `Imp.import_blueprint` method. -See [Imp.x / import_blueprint](imp_x-import_blueprint.html) for more information. \ No newline at end of file diff --git a/archive_docs/_md/v4/Imp_x-import_models.md b/archive_docs/_md/v4/Imp_x-import_models.md deleted file mode 100644 index 32f5e1d9..00000000 --- a/archive_docs/_md/v4/Imp_x-import_models.md +++ /dev/null @@ -1,83 +0,0 @@ -``` -Menu = Imp.x/import_models -Title = Imp.import_models -``` - -```python -import_models(file_or_folder: str) -> None -``` - ---- - -Imports all the models from the given file or folder relative to the Flask app root. - -Each Model that is imported will be available in the `imp.model` lookup method. -See [Imp.x / model](imp_x-model.html) for more information. - -##### Example of importing models from a file - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── users_model.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python - -from flask import Flask -from flask_sqlalchemy import SQLAlchemy - -from flask_imp import Imp - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - db.init_app(app) # must be below imp.init_app - - imp.import_blueprint("my_blueprint") - imp.import_models("users_model.py") - - return app -``` - -File: `app/users_model.py` - -```python -from app import db - - -class User(db.Model): - attribute = db.Column(db.String(255)) -``` - -##### Example of importing models from a folder - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── models/ -│ ├── boats.py -│ ├── cars.py -│ └── users.py -├── ... -└── __init__.py -``` - -```python -def create_app(): - ... - imp.import_models("models") - ... -``` diff --git a/archive_docs/_md/v4/Imp_x-init_app-init.md b/archive_docs/_md/v4/Imp_x-init_app-init.md deleted file mode 100644 index bdf0a4fb..00000000 --- a/archive_docs/_md/v4/Imp_x-init_app-init.md +++ /dev/null @@ -1,32 +0,0 @@ -``` -Menu = Imp.x/init_app, __init__ -Title = Imp.init_app, __init__ -``` - -```python -def init_app( - app: Flask, - config: t.Union[str, ImpConfig] = os.environ.get("IMP_CONFIG") -) -> None: -# -or- -Imp( - app: Flask, - config: t.Union[str, ImpConfig] = os.environ.get("IMP_CONFIG") -) -> None -``` - ---- - -Initializes the flask app to work with flask-imp. - -If no `config` specified, an attempt to read `IMP_CONFIG` from the environment will be made. - -The config value can be a toml file `my_config.toml`, for example; or an import string. An example -of an import string would be `config.Config` where `config` is the module and `Config` is the class. - -If `IMP_CONFIG` is not in the environment variables, an attempt to load `config.toml` will be made. - -If `config.toml` is not found, an attempt to load a class called `Config` from `config.py` will be made. -The Config class must be an instance of `ImpConfig` `from flask_imp import ImpConfig`. - -An exception will be raised if none of the above methods are successful. diff --git a/archive_docs/_md/v4/Imp_x-init_session.md b/archive_docs/_md/v4/Imp_x-init_session.md deleted file mode 100644 index 7bdea6d6..00000000 --- a/archive_docs/_md/v4/Imp_x-init_session.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = Imp.x/init_session -Title = Imp.init_session -``` - -```python -init_session() -> None -``` - ---- - -Initialize the session variables found in the config. Commonly used in `app.before_request`. - -```python -@app.before_request -def before_request(): - imp._init_session() -``` - -File: `config.toml` - -```toml -... -[SESSION] -logged_in = false -... -``` - -`logged_in` is now available in the session. - -```python -@app.route('/get-session-value') -def login(): - print(session['logged_in']) - return "Check Terminal" -``` - -`Output: False` - -Can also be used to reset the values in the session. Here's an example: - -```python -@app.route('/logout') -def logout(): - session.clear() - imp._init_session() - return redirect(url_for('index')) -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/Imp_x-model.md b/archive_docs/_md/v4/Imp_x-model.md deleted file mode 100644 index 71c55243..00000000 --- a/archive_docs/_md/v4/Imp_x-model.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = Imp.x/model -Title = Imp.model -``` - -```python -model(class_: str) -> DefaultMeta -``` - ---- - -Returns the SQLAlchemy model class for the given class name that was imported using `Imp.import_models` or -`Blueprint.import_models`. - -This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting. - -For example: - -```python -from app.models.boats import Boats -from app.models.cars import Cars -``` - -Can be replaced with: - -```python -from app import imp - -Boats = imp.model("Boats") -Cars = imp.model("Cars") -``` - -Or used directly: - -```python -from app import imp - -all_boats = imp.model("Boats").select_all() -``` - - -file: `models/boats.py` - -```python -from app import db - - -class Boats(db.Model): - name = db.Column(db.String()) - - @classmethod - def select_all(cls): - return db.session.execute( - db.select(cls) - ).scalars().all() -``` diff --git a/archive_docs/_md/v4/__index__.md b/archive_docs/_md/v4/__index__.md deleted file mode 100644 index 2c57c108..00000000 --- a/archive_docs/_md/v4/__index__.md +++ /dev/null @@ -1,201 +0,0 @@ -# Welcome to the Flask-Imp Documentation - -## What is Flask-Imp? - -Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication. - -## Install Flask-Imp - -```bash -pip install flask-imp -``` - -## Getting Started - -To get started right away, you can use the CLI commands to create a new Flask-Imp project. - -```bash -flask-imp init -``` - -### Minimal Flask-Imp Setup - -Run the following command to create a minimal Flask-Imp project. - -```bash -flask-imp init -n app --minimal --pyconfig -``` - -See [CLI Commands / flask-imp init](cli_commands-flask-imp_init.html) for more information. - -### The minimal structure - -#### Folder Structure - -```text -app/ -├── resources/ -│ ├── static/... -│ ├── templates/ -│ │ └── index.html -│ └── index.py -├── config.py -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_app_resources() - # Takes argument 'folder' default folder is 'resources' - - return app -``` - -File: `app/config.py` - -```python -from flask_imp import ( - FlaskConfig, - ImpConfig, - DatabaseConfig -) - - -class Config(ImpConfig): - FLASK = FlaskConfig( - # DEBUG=False, - # PROPAGATE_EXCEPTIONS = True, - TRAP_HTTP_EXCEPTIONS=False, - # TRAP_BAD_REQUEST_ERRORS = True, - SECRET_KEY="flask-imp", - SESSION_COOKIE_NAME="session", - # SESSION_COOKIE_DOMAIN = "domain-here.com", - # SESSION_COOKIE_PATH = "/", - SESSION_COOKIE_HTTPONLY=True, - SESSION_COOKIE_SECURE=False, - SESSION_COOKIE_SAMESITE="Lax", - PERMANENT_SESSION_LIFETIME=3600, # 1 hour, - SESSION_REFRESH_EACH_REQUEST=True, - USE_X_SENDFILE=False, - # SEND_FILE_MAX_AGE_DEFAULT = 43200, - ERROR_404_HELP=True, - # SERVER_NAME = "localhost:5000", - APPLICATION_ROOT="/", - PREFERRED_URL_SCHEME="http", - # MAX_CONTENT_LENGTH = 0, - # TEMPLATES_AUTO_RELOAD = True, - EXPLAIN_TEMPLATE_LOADING=False, - MAX_COOKIE_SIZE=4093, - ) - - # INIT_SESSION = { - # "logged_in": False, - # } - - # Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy. - # This sets the file extension for SQLite databases, and where to create the folder - # that the database will be stored in. - # True will create the folder on the same level as your - # app, False will create the folder in the app root. - SQLITE_DB_EXTENSION = ".sqlite" - SQLITE_STORE_IN_PARENT = False - # - - # SQLAlchemy settings that will be passed to Flask - # Any SQLAlchemy setting here will overwrite anything - # set in the config above - SQLALCHEMY_ECHO = False - SQLALCHEMY_TRACK_MODIFICATIONS = False - SQLALCHEMY_RECORD_QUERIES = False - # - - # Main database settings, this will be turned int the SQLALCHEMY_DATABASE_URI - # DATABASE_MAIN = DatabaseConfig( - # ENABLED=True, - # DIALECT="sqlite", - # NAME="main", - # LOCATION="", - # PORT=0, - # USERNAME="", - # PASSWORD="", - # ) - - # Binds are additional databases that can be used in your app - # These will be added to the SQLALCHEMY_BINDS dictionary - # DATABASE_BINDS = { - # DatabaseConfig( - # ENABLED=True, - # DIALECT="sqlite", - # NAME="additional_database", - # BIND_KEY="additional_database", - # LOCATION="", - # PORT=0, - # USERNAME="", - # PASSWORD="", - # ) - # } -``` - -File: `app/resources/index.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -File: `app/resources/templates/index.html` - -```html - - - - - Flask-Imp - - -

Flask-Imp

- - -``` - ---- - -Setting up a virtual environment is recommended. - -**Linux / Darwin** - -```bash -python3 -m venv venv -``` - -```bash -source venv/bin/activate -``` - -**Windows** - -```bash -python -m venv venv -``` - -```text -.\venv\Scripts\activate -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/__menu__.md b/archive_docs/_md/v4/__menu__.md deleted file mode 100644 index 3bb5e433..00000000 --- a/archive_docs/_md/v4/__menu__.md +++ /dev/null @@ -1,44 +0,0 @@ -- CLI Commands - - flask-imp init - - flask-imp blueprint -- Imp - - Introduction - - config.x -- Blueprint - - Introduction - - config.x -- Imp.x - - init_app, __init__ - - init_session - - import_app_resources - - import_blueprint - - import_blueprints - - import_models - - model - - model_meta -- Blueprint.x - - __init__ - - init_session - - import_resources - - import_nested_blueprint - - import_nested_blueprints - - import_models - - tmpl -- flask_imp.security - - login_check - - permission_check - - pass_function_check - - api_login_check - - include_csrf -- flask_imp.auth - - encrypt_password - - authenticate_password - - generate_password - - generate_salt - - generate_csrf_token - - generate_private_key - - generate_email_validator - - generate_numeric_validator - - generate_alphanumeric_validator - - is_email_address_valid - - is_username_valid diff --git a/archive_docs/_md/v4/flask_imp_auth-authenticate_password.md b/archive_docs/_md/v4/flask_imp_auth-authenticate_password.md deleted file mode 100644 index d255ae7a..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-authenticate_password.md +++ /dev/null @@ -1,63 +0,0 @@ -``` -Menu = flask_imp.auth/authenticate_password -Title = authenticate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import authenticate_password -``` - -```python -authenticate_password( - input_password: str, - database_password: str, - database_salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end", - use_multiprocessing: bool = False -) -> bool -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / encrypt_password](flask_imp_auth-encrypt_password.html) function. - -Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match. - -**Note:** - -**use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.** - -If you are using socketio, you must set use_multiprocessing to False (default). - -**Note:** - -- You must know the pepper length used to hash the password. -- You must know the position of the pepper used to hash the password. -- You must know the encryption level used to hash the password. - -#### Authentication Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -```python -input_password = "password" -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database -database_salt = "^%$*" # pulled from database - -authenticate_password( - input_password, - database_password, - database_salt -) # >>> True -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-encrypt_password.md b/archive_docs/_md/v4/flask_imp_auth-encrypt_password.md deleted file mode 100644 index 0287b119..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-encrypt_password.md +++ /dev/null @@ -1,53 +0,0 @@ -``` -Menu = flask_imp.auth/encrypt_password -Title = encrypt_password - flask_imp.auth -``` - -```python -from flask_imp.auth import encrypt_password -``` - -```python -encrypt_password( - password: str, - salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end" -) -> str -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / authenticate_password](flask_imp_auth-authenticate_password.html) function. - -Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified. - -Can set the encryption level to 256 or 512, defaults to 512. - -Can set the pepper length, defaults to 1. Max is 3. - -Can set the pepper position, "start" or "end", defaults to "end". - -**Note:** - -- You must inform the authenticate_password function of the pepper length used to hash the password. -- You must inform the authenticate_password function of the position of the pepper used to hash the password. -- You must inform the authenticate_password function of the encryption level used to hash the password. - -#### Encryption Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -1. Pepper is added to the end of the plain password: "passwordA" -2. Salt is added to the end of the peppered password: "passwordA^%$*" -3. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." -4. Salt and hashed password are then stored in the database. - diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md deleted file mode 100644 index c0d0ccdc..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_alphanumeric_validator.md +++ /dev/null @@ -1,24 +0,0 @@ -``` -Menu = flask_imp.auth/generate_alphanumeric_validator -Title = generate_alphanumeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_alphanumeric_validator -``` - -```python -generate_alphanumeric_validator(length: int = 8) -> str -``` - ---- - -Generates a random alphanumeric string of the given length. - -(letters are capitalized) - -*Example:* - -```python -generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md deleted file mode 100644 index ce6df31b..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_csrf_token.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_csrf_token -Title = generate_csrf_token - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_csrf_token -``` - -```python -generate_csrf_token() -> str -``` - ---- - -Generates a SHA1 using the current date and time. - -For use in Cross-Site Request Forgery. - -Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. - -*Example:* - -```python -generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md deleted file mode 100644 index acdced31..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_email_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_email_validator -Title = generate_email_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_email_validator -``` - -```python -generate_email_validator() -> str -``` - ---- - -Uses `generate_alphanumeric_validator` with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email. - -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) -for more information. - -*Example:* - -```python -generate_email_validator() # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md deleted file mode 100644 index c0d7dc76..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_numeric_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_numeric_validator -Title = generate_numeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_numeric_validator -``` - -```python -generate_numeric_validator(length: int) -> int -``` - ---- - - -Generates random choice between 1 * (length) and 9 * (length). - -If the length is 4, it will generate a number between 1111 and 9999. - -For use in MFA email, or unique filename generation. - -*Example:* - -```python -generate_numeric_validator(4) # >>> 1234 -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_password.md b/archive_docs/_md/v4/flask_imp_auth-generate_password.md deleted file mode 100644 index b6f8fda0..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_password.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_password -Title = generate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_password -``` - -```python -generate_password(style: str = "mixed", length: int = 3) -> str -``` - ---- - -Generates a password of (length) characters. - -The Default length is 3. - -Style options: "animals", "colors", "mixed" - defaults to "mixed" - -*Example:* - -```python -generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_private_key.md b/archive_docs/_md/v4/flask_imp_auth-generate_private_key.md deleted file mode 100644 index 63938598..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_private_key.md +++ /dev/null @@ -1,38 +0,0 @@ -``` -Menu = flask_imp.auth/generate_private_key -Title = generate_private_key - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_private_key -``` - -```python -generate_private_key(hook: t.Optional[str]) -> str -``` - ---- - -Generates a sha256 private key from a passed in hook value. - -If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000. - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt, - private_key=generate_private_key(hook=username) - ) - ... -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-generate_salt.md b/archive_docs/_md/v4/flask_imp_auth-generate_salt.md deleted file mode 100644 index f21615f5..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-generate_salt.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/generate_salt -Title = generate_salt - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_salt -``` - -```python -generate_salt(length: int = 4) -> str -``` - ---- - -Generates a string of (length) characters of punctuation. - -The Default length is 4. - -For use in password hashing and storage of passwords in the database. - -*Example:* - -```python -generate_salt() # >>> '*!$%' -``` - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt - ) - ... -``` - diff --git a/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md deleted file mode 100644 index 1990e24a..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-is_email_address_valid.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/is_email_address_valid -Title = is_email_address_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_email_address_valid -``` - -```python -is_email_address_valid( - email_address: str -) -> bool -``` - ---- - -Checks if an email address is valid. - -Is not completely RFC 5322 compliant, but it is good enough for most use cases. - -Here are examples of mistakes that it will not catch: - -##### Valid but fails: - -```text -email@[123.123.123.123] -“email”@example.com -very.unusual.“@”.unusual.com@example.com -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com -``` - -##### Invalid but passes: - -```text -email@example.com (Joe Smith) -email@111.222.333.44444 -``` - -*Example:* - -```python -is_email_address_valid('hello@example.com') # >>> True - -is_email_address_valid('hello@hello@example.com') # >>> False -``` diff --git a/archive_docs/_md/v4/flask_imp_auth-is_username_valid.md b/archive_docs/_md/v4/flask_imp_auth-is_username_valid.md deleted file mode 100644 index 68cdf070..00000000 --- a/archive_docs/_md/v4/flask_imp_auth-is_username_valid.md +++ /dev/null @@ -1,58 +0,0 @@ -``` -Menu = flask_imp.auth/is_username_valid -Title = is_username_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_username_valid -``` - -```python -is_username_valid( - username: str, - allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None -) -> bool -``` - ---- - -Checks if a username is valid. - -Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned. - -##### Example "all": - -```python -is_username_valid("username", allowed=["all"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user_name : WILL PASS : True -_user_name : WILL PASS : False -``` - -##### Example "dot", "dash": - -```python - -is_username_valid("username", allowed=["dot", "dash"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user-name.name : WILL PASS : True -user_name : WILL PASS : False -_user_name : WILL PASS : False -.user.name : WILL PASS : False -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/flask_imp_security-api_login_check.md b/archive_docs/_md/v4/flask_imp_security-api_login_check.md deleted file mode 100644 index e021ecbe..00000000 --- a/archive_docs/_md/v4/flask_imp_security-api_login_check.md +++ /dev/null @@ -1,47 +0,0 @@ -``` -Menu = flask_imp.security/api_login_check -Title = api_login_check - flask_imp.security -``` - - -```python -from flask_imp.security import api_login_check -``` - -```python -api_login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_json: t.Optional[t.Dict[str, t.Any]] = None -) -``` - -`@api_login_check(...)` - ---- - -A decorator that is used to secure API routes that return JSON responses. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. - -*Example:* - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True) -def api_page(): - ... -``` - -##### Example of defined fail_json: - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."}) -def api_page(): - ... -``` diff --git a/archive_docs/_md/v4/flask_imp_security-include_csrf.md b/archive_docs/_md/v4/flask_imp_security-include_csrf.md deleted file mode 100644 index 5f367974..00000000 --- a/archive_docs/_md/v4/flask_imp_security-include_csrf.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = flask_imp.security/include_csrf -Title = include_csrf - flask_imp.security -``` - -```python -from flask_imp.security import include_csrf -``` - -```python -include_csrf( - session_key: str = "csrf", - form_key: str = "csrf", - abort_code: int = 401 -) -``` - -`@include_csrf(...)` - ---- - - -A decorator that handles CSRF protection. - -On a **GET** request, a CSRF token is generated and stored in the session key -specified by the session_key parameter. - -On a **POST** request, the form_key specified is checked against the session_key -specified. - -- If they match, the request is allowed to continue. -- If no match, the response will be abort(abort_code), default 401. - -```python -@bp.route("/admin", methods=["GET", "POST"]) -@include_csrf(session_key="csrf", form_key="csrf") -def admin_page(): - ... - # You must pass in the CSRF token from the session into the template. - # Then add to the form. - return render_template("admin.html", csrf=session.get("csrf")) -``` - -Form key: - -```html - -``` \ No newline at end of file diff --git a/archive_docs/_md/v4/flask_imp_security-login_check.md b/archive_docs/_md/v4/flask_imp_security-login_check.md deleted file mode 100644 index f95cebde..00000000 --- a/archive_docs/_md/v4/flask_imp_security-login_check.md +++ /dev/null @@ -1,66 +0,0 @@ -``` -Menu = flask_imp.security/login_check -Title = login_check - flask_imp.security -``` - -```python -from flask_imp.security import login_check -``` - -```python -login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - pass_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@login_check(...)` - ---- - -A decorator that checks if the specified session key exists and contains the specified value. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -##### Example of a route that requires a user to be logged in: - -```python -@bp.route("/admin", methods=["GET"]) -@login_check( - 'logged_in', - True, - fail_endpoint='blueprint.login_page', - message="Login needed" -) -def admin_page(): - ... -``` - -##### Example of a route that if the user is already logged in, redirects to the specified endpoint: - -```python -@bp.route("/login-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - pass_endpoint='blueprint.admin_page', - message="Already logged in" -) -def login_page(): - ... -``` diff --git a/archive_docs/_md/v4/flask_imp_security-pass_function_check.md b/archive_docs/_md/v4/flask_imp_security-pass_function_check.md deleted file mode 100644 index 07ed2f35..00000000 --- a/archive_docs/_md/v4/flask_imp_security-pass_function_check.md +++ /dev/null @@ -1,114 +0,0 @@ -``` -Menu = flask_imp.security/pass_function_check -Title = pass_function_check - flask_imp.security -``` - -```python -from flask_imp.security import pass_function_check -``` - -```python -def pass_function_check( - function: t.Callable, - predefined_args: t.Optional[t.Dict] = None, - fail_endpoint: t.Optional[str] = None, - pass_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message", - fail_on_missing_kwargs: bool = False, - with_app_context: bool = False, -) -``` - -**NOTE: This was added mostly as an experimental feature, but ended up being useful in some cases.** - -A decorator that takes the result of a function and checks if it is True or False. - -URL variables from `@route` will be read by this decorator. -To use URL variables in your passed in function, -make sure your functions argument(s) name(s) match the name(s) of the URL variable(s). - -**Example:** - -```python -def check_if_number(value): - if isinstance(value, int): - return True - return False - -@bp.route("/admin-page/", methods=["GET"]) -@login_check('logged_in', True, 'blueprint.login_page') # can be mixed with login_check -@pass_function_check( - check_if_number, - predefined_args=None, - fail_endpoint='www.index', - message="Failed message" -) -def admin_page(): - ... - -@bp.route("/admin-page/", methods=["GET"]) -@login_check('logged_in', True, 'blueprint.login_page') # can be mixed with login_check -@pass_function_check( - check_if_number, - predefined_args={'value': 10}, - fail_endpoint='www.index', - message="Failed message" -) -def admin_page_overwrite(): - ... -``` - -**Advanced use case:** - -Here's an example of accessing flask.session from within the passed in function. including the -`with_app_context` parameter, the function will be called with `app_context()`. - -```python -from flask import current_app -from flask import session - -... - -def check_if_number(number=1, session_=None): - if session_: - print(session_) - try: - int(number) - return True - except ValueError: - return False - -@bp.route("/pass-func-check-with-url-var/", methods=["GET"]) -@pass_function_check( - check_if_number, - predefined_args={'number': 10, 'session_': session}, - fail_endpoint="www.index", - with_app_context=True -) -def admin_page_overwrite_with_session(): - ... -``` - -If you pass in a predefined arg that has the same key name as a session variable that exists, the value -of that predefined arg will be replaced with the session variable value. - -```python -session['car'] = 'Toyota' -... -def check_function(car): - if car == 'Toyota': - return True - return False -... -@bp.route("/pass-func-check-with-url-var/", methods=["GET"]) -@pass_function_check( - check_function, - predefined_args={'car': session}, - ... - -``` - -This will pass, as pass_function_check will replace the value of the predefined arg 'car' with the value -of the session variable 'car'. diff --git a/archive_docs/_md/v4/flask_imp_security-permission_check.md b/archive_docs/_md/v4/flask_imp_security-permission_check.md deleted file mode 100644 index 73278e12..00000000 --- a/archive_docs/_md/v4/flask_imp_security-permission_check.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = flask_imp.security/permission_check -Title = permission_check - flask_imp.security -``` - -```python -from flask_imp.security import permission_check -``` - -```python -permission_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@permission_check(...)` - ---- - -A decorator that checks if the specified session key exists and its value(s) match the specified value(s). - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -*Example:* - -```python -@bp.route("/admin-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - 'blueprint.login_page' -) # can be mixed with login_check -@permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', - message="Failed message" -) -def admin_page(): - ... -``` - diff --git a/archive_docs/_md/v5/CLI Commands-flask-imp blueprint.md b/archive_docs/_md/v5/CLI Commands-flask-imp blueprint.md deleted file mode 100644 index fe2191c6..00000000 --- a/archive_docs/_md/v5/CLI Commands-flask-imp blueprint.md +++ /dev/null @@ -1,101 +0,0 @@ -``` -Menu = CLI Commands/flask-imp blueprint -Title = Generate a Flask-Imp Blueprint -``` - -Flask-Imp has its own type of blueprint. It comes with some methods to auto import routes, and models etc... see -[ImpBlueprint / Introduction](impblueprint-introduction.html) for more information. - -You have the option to generate a regular template rendering blueprint, or a API blueprint that returns a JSON response. - -```bash -flask-imp blueprint --help -``` -or -```bash -flask-imp api-blueprint --help -``` - -To generate a Flask-Imp blueprint, run the following command: - -```bash -flask-imp blueprint -``` -or -```bash -flask-imp api-blueprint -``` - -After running this command, you will be prompted to enter the location of where you want to create your blueprint: - -```text -~ $ flask-imp blueprint -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: -``` - -As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder `app/blueprints`, you would enter `app/blueprints` in the prompt. - -```text -~ $ flask-imp blueprint -(Creation is relative to the current working directory) -Folder to create blueprint in [Current Working Directory]: app/blueprints -``` - -You will then be prompted to enter a name for your blueprint: - -```text -~ $ flask-imp blueprint -... -Name of the blueprint to create [my_new_blueprint]: -``` - -The default name is 'my_new_blueprint', we will change this to 'admin' - -```text -~ $ flask-imp blueprint -... -Name of the blueprint to create [my_new_blueprint]: admin -``` - -After creating your blueprint, the folder structure will look like this: - -```text -app/ -├── blueprints -│ └── admin -│ ├── routes -│ │ └── index.py -│ │ -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ │ -│ ├── templates -│ │ └── www -│ │ ├── extends -│ │ │ └── main.html -│ │ ├── includes -│ │ │ ├── footer.html -│ │ │ └── header.html -│ │ └── index.html -│ │ -│ └── __init__.py -│ -... -``` - -This is a self-contained blueprint, so it has its own static, templates and routes folders. -You can now navigate '/admin' - -You can streamline this process by specifying the name of the blueprint, the folder to -create it in and the configuration to use, like so: - -```bash -flask-imp blueprint -n admin -f app/blueprints -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/CLI Commands-flask-imp init.md b/archive_docs/_md/v5/CLI Commands-flask-imp init.md deleted file mode 100644 index d4144b43..00000000 --- a/archive_docs/_md/v5/CLI Commands-flask-imp init.md +++ /dev/null @@ -1,218 +0,0 @@ -``` -Menu = CLI Commands/flask-imp init -Title = Initialising a Flask-Imp Project -``` - -Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp. - -```bash -flask-imp init --help -``` - -## Create a new project - -Make sure you are in the virtual environment, and at the root of your -project folder, then run the following command: - -```bash -flask-imp init -``` - -After running this command, you will be prompted to choose what type of -app you want to deploy: - -```text -~ $ flask-imp init -What type of app would you like to create? (minimal, slim, full) [minimal]: -``` - -See below for the differences between the app types. - -After this, you will be prompted to enter a name for your app: - -```text -~ $ flask-imp init -... -What would you like to call your app? [app]: -``` - -'app' is the default name, so if you just press enter, your app will be -called 'app'. You will then see this output: - -```text -~ FILES CREATED WILL LOOP OUT HERE ~ - -=================== -Flask app deployed! -=================== - -Your app has the default name of 'app' -Flask will automatically look for this! -Run: flask run --debug - -``` - -If you called your app something other than 'app', like 'new' for example, you will see: - -```text -~ FILES CREATED WILL LOOP OUT HERE ~ - -=================== -Flask app deployed! -=================== - -Your app has the name of 'new' -Run: flask --app new run --debug - -``` - -As you can see from the output, it gives you instructions on how to start your app, -depending on the name you gave it. - -You should see a new folder that has been given the name you specified in -the `flask-imp init` command. - -### Additional options - -You can also specify a name for your app in the command itself, like so: - -```bash -flask-imp init -n my_app -``` - -This will create a new app called 'my_app'. -The default will be a minimal app, this has no blueprints or database models. - -You can also deploy a slim app, that will have one blueprint and no database models, like so: - -```bash -flask-imp init -n my_app --slim -``` - -You can also deploy a full app that is setup for multiple blueprints and database models, like so: - -```bash -flask-imp init -n my_app --full -``` - -## init Folder structures - -### Minimal app (default) - -`flask-imp init --minimal`: - -```text -app/ -├── resources -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── favicon.ico -│ ├── templates -│ │ └── index.html -│ └── routes.py -│ -└── __init__.py -``` - -### Slim app - -`flask-imp init --slim`: - -```text -app/ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── favicon.ico -│ └── templates -│ └── error.html -│ -├── www -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -└── __init__.py -``` - -### Full app - -`flask-imp init --full`: - -```text -app/ -├── blueprints -│ └── www -│ ├── __init__.py -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ ├── css -│ │ │ └── water.css -│ │ ├── img -│ │ │ └── flask-imp-logo.png -│ │ └── js -│ │ └── main.js -│ └── templates -│ └── www -│ ├── extends -│ │ └── main.html -│ ├── includes -│ │ ├── footer.html -│ │ └── header.html -│ └── index.html -│ -├── extensions -│ └── __init__.py -│ -├── resources -│ ├── cli -│ │ └── cli.py -│ ├── context_processors -│ │ └── context_processors.py -│ ├── error_handlers -│ │ └── error_handlers.py -│ ├── filters -│ │ └── filters.py -│ ├── routes -│ │ └── routes.py -│ ├── static -│ │ └── favicon.ico -│ └── templates -│ └── error.html -│ -├── models -│ └── example_user_table.py -│ -└── __init__.py -``` diff --git a/archive_docs/_md/v5/Imp-Introduction.md b/archive_docs/_md/v5/Imp-Introduction.md deleted file mode 100644 index e4a8479b..00000000 --- a/archive_docs/_md/v5/Imp-Introduction.md +++ /dev/null @@ -1,92 +0,0 @@ -``` -Menu = Imp/Introduction -Title = Flask-Imp Introduction -``` - -Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources. It uses the importlib module to achieve this. - -Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using -Blueprints. However, you can use Flask-Imp without using Blueprints. - -Here's an example of a standard Flask-Imp project structure: - -```text -app/ -├── blueprints/ -│ ├── admin/... -│ ├── api/... -│ └── www/... -├── resources/ -│ ├── filters/... -│ ├── context_processors/... -│ ├── static/... -│ └── templates/... -├── models/... -└── __init__.py -``` - -Here's an example of the `app/__init__.py` file: - -```python -from flask import Flask -from flask_sqlalchemy import SQLAlchemy -from flask_imp import Imp -from flask_imp.config import FlaskConfig, ImpConfig - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - FlaskConfig( - secret_key="super_secret_key", - app_instance=app, - ) - - imp.init_app(app, config=ImpConfig( - init_session={"logged_in": False}, - )) - imp.import_app_resources("resources") - imp.import_models("models") - imp.import_blueprints("blueprints") - - db.init_app(app) - - return app -``` - -The Flask configuration can be loaded from any standard Flask configuration method, or from the `FlaskConfig` class -shown above. - -This class contains the standard Flask configuration options found in the Flask documentation. - -The `ImpConfig` class is used to configure the `Imp` instance. - -The `init_session` option of the `ImpConfig` class is used to set the initial session variables for the Flask app. -This happens before the request is processed. - -`ImpConfig` also has the ability to set `SQLALCHEMY_DATABASE_URI` and `SQLALCHEMY_BINDS` - -For more information about the configuration setting see -[flask_imp_config-impconfig.md](flask_imp_config-impconfig.html). - -`import_app_resources` will walk one level deep into the `resources` folder, and import -all `.py` files as modules. -It will also check for the existence of a `static` and `templates` folder, and register them with the Flask app. - -There is a couple of options for `import_app_resources` to control what -is imported, see: [Imp / import_app_resources](imp-import_app_resources.html) - -`import_models` will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via `imp.model` - -See more about how import_models and the lookup -here: [Imp / import_models](imp-import_models.html) and [Imp / model](imp-model.html) - -`import_blueprints` expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's `__init__.py` file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app. - -See more about how importing blueprints work here: [ImpBlueprint / Introduction](impblueprint-introduction.html) diff --git a/archive_docs/_md/v5/Imp-import_app_resources.md b/archive_docs/_md/v5/Imp-import_app_resources.md deleted file mode 100644 index 3f0f3ec4..00000000 --- a/archive_docs/_md/v5/Imp-import_app_resources.md +++ /dev/null @@ -1,106 +0,0 @@ -``` -Menu = Imp/import_app_resources -Title = Imp.import_app_resources -``` - -```python -import_app_resources( - folder: str = "resources", - factories: Optional[List] = None, - static_folder: str = "static", - templates_folder: str = "templates", - files_to_import: Optional[List] = None, - folders_to_import: Optional[List] = None, - ) -> None -``` - ---- - -Import standard app resources from the specified folder. - -This will import any resources that have been set to the Flask app. - -Routes, context processors, cli, etc. - -**Can only be called once.** - -If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config. - -#### Small example of usage: - -```python -imp.import_app_resources(folder="resources") -# or -imp.import_app_resources() -# as the default folder is "resources" -``` - -Folder Structure: `resources` - -```text -app -├── resources -│ ├── routes.py -│ ├── app_fac.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ └── templates -│ └── index.html -└── ... -... -``` - -File: `routes.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -#### How factories work - -Factories are functions that are called when importing the app resources. Here's an example: - -```python -imp.import_app_resources( - folder="resources", - factories=["development_cli"] -) -``` - -`["development_cli"]` => `development_cli(app)` function will be called, and the current app will be passed in. - -File: `app_fac.py` - -```python -def development_cli(app): - @app.cli.command("dev") - def dev(): - print("dev cli command") -``` - -#### Scoping imports - -By default, all files and folders will be imported. - -To disable this, set `files_to_import` and or -`folders_to_import` to `[None]`. - -```python -imp.import_app_resources(scope_import=[None], folders_to_import=[None]) -``` - -To scope the imports, set the `files_to_import` and or `folders_to_import` to a list of files and or folders. - -`files_to_import=["cli.py", "routes.py"]` => will only import the files `resources/cli.py` -and `resources/routes.py` - -`folders_to_import=["template_filters", "context_processors"]` => will import all files in the folders -`resources/template_filters/*.py` and `resources/context_processors/*.py` diff --git a/archive_docs/_md/v5/Imp-import_blueprint.md b/archive_docs/_md/v5/Imp-import_blueprint.md deleted file mode 100644 index 6613538e..00000000 --- a/archive_docs/_md/v5/Imp-import_blueprint.md +++ /dev/null @@ -1,121 +0,0 @@ -``` -Menu = Imp/import_blueprint -Title = Imp.import_blueprint -``` - -```python -import_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root. - - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprint("my_blueprint") - - return app -``` - -Flask-Imp Blueprints have the ability to auto import resources, and initialize session variables. - -For more information on how Flask-Imp Blueprints work, see the [ImpBlueprint / Introduction](impblueprint-introduction.html) - -##### Example of 'my_blueprint' as a Flask-Imp Blueprint: - -```text -app -├── my_blueprint -│ ├── routes -│ │ └── index.py -│ ├── static -│ │ └── css -│ │ └── style.css -│ ├── templates -│ │ └── my_blueprint -│ │ └── index.html -│ ├── __init__.py -│ └── config.toml -└── ... -``` - -File: `__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint( - __name__, - ImpBlueprintConfig( - enabled=True, - url_prefix="/my-blueprint", - static_folder="static", - template_folder="templates", - static_url_path="/static/my_blueprint", - init_session={"my_blueprint": "session_value"}, - ), -) - -bp.import_resources("routes") -``` - -File: `routes / index.py` - -```python -from .. import bp - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -##### Example of 'my_blueprint' as a standard Flask Blueprint: - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -└── ... -``` - -File: `__init__.py` - -```python -from flask import Blueprint - -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint") - - -@bp.route("/") -def index(): - return "regular_blueprint" -``` - -Both of the above examples will work with `imp.import_blueprint("my_blueprint")`, they will be registered -with the Flask app, and will be accessible via `url_for("my_blueprint.index")`. \ No newline at end of file diff --git a/archive_docs/_md/v5/Imp-import_blueprints.md b/archive_docs/_md/v5/Imp-import_blueprints.md deleted file mode 100644 index e3087235..00000000 --- a/archive_docs/_md/v5/Imp-import_blueprints.md +++ /dev/null @@ -1,50 +0,0 @@ -``` -Menu = Imp/import_blueprints -Title = Imp.import_blueprints -``` - -```python -import_blueprints(self, folder: str) -> None -``` - ---- - -Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root. - -```text -app/ -├── blueprints/ -│ ├── admin/ -│ │ ├── ... -│ │ └── __init__.py -│ ├── www/ -│ │ ├── ... -│ │ └── __init__.py -│ └── api/ -│ ├── ... -│ └── __init__.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp - -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - - imp.import_blueprints("blueprints") - - return app -``` - -This will import all Blueprints from the `blueprints` folder using the `Imp.import_blueprint` method. -See [Imp / import_blueprint](imp-import_blueprint.html) for more information. \ No newline at end of file diff --git a/archive_docs/_md/v5/Imp-import_models.md b/archive_docs/_md/v5/Imp-import_models.md deleted file mode 100644 index 90f85edb..00000000 --- a/archive_docs/_md/v5/Imp-import_models.md +++ /dev/null @@ -1,83 +0,0 @@ -``` -Menu = Imp/import_models -Title = Imp.import_models -``` - -```python -import_models(file_or_folder: str) -> None -``` - ---- - -Imports all the models from the given file or folder relative to the Flask app root. - -Each Model that is imported will be available in the `imp.model` lookup method. -See [Imp / model](imp-model.html) for more information. - -##### Example of importing models from a file - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── users_model.py -├── ... -└── __init__.py -``` - -File: `app/__init__.py` - -```python - -from flask import Flask -from flask_sqlalchemy import SQLAlchemy - -from flask_imp import Imp - -db = SQLAlchemy() -imp = Imp() - - -def create_app(): - app = Flask(__name__) - imp.init_app(app) - db.init_app(app) # must be below imp.init_app - - imp.import_blueprint("my_blueprint") - imp.import_models("users_model.py") - - return app -``` - -File: `app/users_model.py` - -```python -from app import db - - -class User(db.Model): - attribute = db.Column(db.String(255)) -``` - -##### Example of importing models from a folder - -```text -app -├── my_blueprint -│ ├── ... -│ └── __init__.py -├── models/ -│ ├── boats.py -│ ├── cars.py -│ └── users.py -├── ... -└── __init__.py -``` - -```python -def create_app(): - ... - imp.import_models("models") - ... -``` diff --git a/archive_docs/_md/v5/Imp-init_app-init.md b/archive_docs/_md/v5/Imp-init_app-init.md deleted file mode 100644 index 4bff0f9c..00000000 --- a/archive_docs/_md/v5/Imp-init_app-init.md +++ /dev/null @@ -1,22 +0,0 @@ -``` -Menu = Imp/init_app, __init__ -Title = Imp.init_app, __init__ -``` - -```python -def init_app( - app: Flask, - config: ImpConfig -) -> None: -# -or- -Imp( - app: Flask, - config: ImpConfig -) -``` - ---- - -Initializes the flask app to work with flask-imp. - -See [flask_imp_config-impconfig.md](flask_imp_config-impconfig.html) for more information on the `ImpConfig` class. diff --git a/archive_docs/_md/v5/Imp-init_session.md b/archive_docs/_md/v5/Imp-init_session.md deleted file mode 100644 index 92d80b37..00000000 --- a/archive_docs/_md/v5/Imp-init_session.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = Imp/init_session -Title = Imp.init_session -``` - -```python -init_session() -> None -``` - ---- - -Initialize the session variables found in the config. Commonly used in `app.before_request`. - -```python -@app.before_request -def before_request(): - imp._init_session() -``` - -File: `config.toml` - -```toml -... -[SESSION] -logged_in = false -... -``` - -`logged_in` is now available in the session. - -```python -@app.route('/get-session-value') -def login(): - print(session['logged_in']) - return "Check Terminal" -``` - -`Output: False` - -Can also be used to reset the values in the session. Here's an example: - -```python -@app.route('/logout') -def logout(): - session.clear() - imp._init_session() - return redirect(url_for('index')) -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/Imp-model.md b/archive_docs/_md/v5/Imp-model.md deleted file mode 100644 index ce8e061e..00000000 --- a/archive_docs/_md/v5/Imp-model.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = Imp/model -Title = Imp.model -``` - -```python -model(class_: str) -> DefaultMeta -``` - ---- - -Returns the SQLAlchemy model class for the given class name that was imported using `Imp.import_models` or -`Blueprint.import_models`. - -This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting. - -For example: - -```python -from app.models.boats import Boats -from app.models.cars import Cars -``` - -Can be replaced with: - -```python -from app import imp - -Boats = imp.model("Boats") -Cars = imp.model("Cars") -``` - -Or used directly: - -```python -from app import imp - -all_boats = imp.model("Boats").select_all() -``` - - -file: `models/boats.py` - -```python -from app import db - - -class Boats(db.Model): - name = db.Column(db.String()) - - @classmethod - def select_all(cls): - return db.session.execute( - db.select(cls) - ).scalars().all() -``` diff --git a/archive_docs/_md/v5/ImpBlueprint-Introduction.md b/archive_docs/_md/v5/ImpBlueprint-Introduction.md deleted file mode 100644 index 5ab0b5ec..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-Introduction.md +++ /dev/null @@ -1,75 +0,0 @@ -``` -Menu = ImpBlueprint/Introduction -Title = Flask-Imp Blueprint Introduction -``` - -The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints. - -The Flask-Imp Blueprint requires you to provide the `ImpBlueprintConfig` class as the second argument to the Blueprint. - -Here's an example of a Flask-Imp Blueprint structure: - -```text -www/ -├── nested_blueprints/ -│ ├── blueprint_one/ -│ │ ├── ... -│ │ └── __init__.py -│ └── blueprint_two/ -│ ├── ... -│ └── __init__.py -├── standalone_nested_blueprint/ -│ ├── ... -│ └── __init__.py -├── models/ -│ └── ... -├── routes/ -│ └── index.py -├── static/ -│ └── ... -├── templates/ -│ └── www/ -│ └── index.html -└── __init__.py -``` - -File: `__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - url_prefix="/www", - static_folder="static", - template_folder="templates", - init_session={"logged_in": False}, -)) - -bp.import_resources("routes") -bp.import_models("models") -bp.import_nested_blueprints("nested_blueprints") -bp.import_nested_blueprint("standalone_nested_blueprint") -``` - -The `ImpBlueprintConfig` class is used to configure the Blueprint. It provides a little more flexibility than the -standard Flask Blueprint configuration, like the ability to enable or disable the Blueprint. - -`ImpBlueprintConfig`'s `init_session` works the same as `ImpConfig`'s `init_session`, this will add the session data to -the Flask app's session object on initialization of the Flask app. - -To see more about configuration see: [flask_imp.config / ImpBlueprintConfig](flask_imp_config-impblueprintconfig.html) - -`import_resources` method will walk one level deep into the `routes` folder, and import all `.py` files as modules. -For more information see: [ImpBlueprint / import_resources](impblueprint-import_resources.html) - -`import_models` works the same as `imp.import_models`, it will look for instances of `db.Model` and import them. These -will also be available in the model lookup method `imp.model`. -For more information see: [Imp / import_models](imp-import_models.html) - -`import_nested_blueprints` will do the same as `imp.import_blueprints`, but will register the blueprints found as -nested to the current blueprint. For example `www.blueprint_one.index` - -`import_nested_blueprint` behaves the same as `import_nested_blueprints`, but will only import a single blueprint. diff --git a/archive_docs/_md/v5/ImpBlueprint-import_models.md b/archive_docs/_md/v5/ImpBlueprint-import_models.md deleted file mode 100644 index a8c44a1e..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-import_models.md +++ /dev/null @@ -1,88 +0,0 @@ -``` -Menu = ImpBlueprint/import_models -Title = ImpBlueprint.import_models -``` - -```python -import_models(folder: str = "models") -> None -``` - ---- - -Will import all the models from the given folder relative to the Blueprint's root directory. - -Works the same as [Imp / import_models](imp-import_models.html) but relative to the Blueprint root. - -Blueprint models will also be available in the [Imp / model](imp-model.html) lookup. - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── animal_models.py -│ -├── __init__.py -``` - -**or** - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── models/ -│ └── animals.py -│ -├── __init__.py -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("routes") -bp.import_models("animal_models.py") -``` - -**or** - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("routes") -bp.import_models("models") -``` - -File: `my_blueprint/animal_models.py` or `my_blueprint/models/animals.py` - -```python -from app import db - - -class Animals(db.Model): - animal_id = db.Column(db.Integer, primary_key=True) - name = db.Column(db.String(64), index=True, unique=True) - species = db.Column(db.String(64), index=True, unique=True) -``` - - - diff --git a/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprint.md b/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprint.md deleted file mode 100644 index 1bed20dc..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprint.md +++ /dev/null @@ -1,78 +0,0 @@ -``` -Menu = ImpBlueprint/import_nested_blueprint -Title = ImpBlueprint.import_nested_blueprint -``` - -```python -import_nested_blueprint(self, blueprint: str) -> None -``` - ---- - -Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root. - -Works the same as [Imp / import_blueprint](imp-import_blueprint.html) but relative to the Blueprint root. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.my_nested_blueprint.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── my_nested_blueprint/ -│ ├── routes/ -│ │ └── index.py -│ ├── static/... -│ ├── templates/... -│ ├── __init__.py -│ -├── __init__.py -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("routes") -bp.import_nested_blueprint("my_nested_blueprint") -``` - -File: `my_blueprint/my_nested_blueprint/__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("routes") -``` - -File: `my_blueprint/my_nested_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprints.md b/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprints.md deleted file mode 100644 index d14fa862..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-import_nested_blueprints.md +++ /dev/null @@ -1,60 +0,0 @@ -``` -Menu = ImpBlueprint/import_nested_blueprints -Title = ImpBlueprint.import_nested_blueprints -``` - -```python -import_nested_blueprints(self, folder: str) -> None -``` - ---- - -Will import all the Blueprints from the given folder relative to the Blueprint's root directory. - -Uses [Blueprint / import_nested_blueprint](blueprint-import_nested_blueprint.html) to import blueprints from -the specified folder. - -Blueprints that are imported this way will be scoped to the parent Blueprint that imported them. - -`url_for('my_blueprint.nested_bp_one.index')` - -`url_for('my_blueprint.nested_bp_two.index')` - -`url_for('my_blueprint.nested_bp_three.index')` - -```text -my_blueprint/ -├── routes/... -├── static/... -├── templates/... -│ -├── nested_blueprints/ -│ │ -│ ├── nested_bp_one/ -│ │ ├── ... -│ │ ├── __init__.py -│ ├── nested_bp_two/ -│ │ ├── ... -│ │ ├── __init__.py -│ └── nested_bp_three/ -│ ├── ... -│ ├── __init__.py -│ -├── __init__.py -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("routes") -bp.import_nested_blueprints("nested_blueprints") -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/ImpBlueprint-import_resources.md b/archive_docs/_md/v5/ImpBlueprint-import_resources.md deleted file mode 100644 index 16bbea2e..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-import_resources.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = ImpBlueprint/import_resources -Title = ImpBlueprint.import_resources -``` - -```python -import_resources(folder: str = "routes") -> None -``` - ---- - -Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory. - -```text -my_blueprint -├── user_routes -│ ├── user_dashboard.py -│ └── user_settings.py -├── car_routes -│ ├── car_dashboard.py -│ └── car_settings.py -├── static/... -├── templates/ -│ └── my_blueprint/ -│ ├── user_dashboard.html -│ └── ... -├── __init__.py -``` - -File: `my_blueprint/__init__.py` - -```python -from flask_imp import ImpBlueprint -from flask_imp.config import ImpBlueprintConfig - -bp = ImpBlueprint(__name__, ImpBlueprintConfig( - enabled=True, - static_folder="static", - template_folder="templates", -)) - -bp.import_resources("user_routes") -bp.import_resources("car_routes") -``` - -File: `my_blueprint/user_routes/user_dashboard.py` - -```python -from flask import render_template - -from .. import bp - -@bp.route("/user-dashboard") -def user_dashboard(): - return render_template(bp.tmpl("user_dashboard.html")) -``` diff --git a/archive_docs/_md/v5/ImpBlueprint-init.md b/archive_docs/_md/v5/ImpBlueprint-init.md deleted file mode 100644 index e51e3915..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-init.md +++ /dev/null @@ -1,17 +0,0 @@ -``` -Menu = ImpBlueprint/__init__ -Title = Flask-Imp Blueprint __init__ -``` - -```python -ImpBlueprint(dunder_name: str, config: ImpBlueprintConfig) -> None -``` - ---- - -Initializes the Flask-Imp Blueprint. - -`dunder_name` should always be set to `__name__` - -`config` is an instance of `ImpBlueprintConfig` that will be used to load the Blueprint's configuration. -See [flask_imp.config / ImpBlueprintConfig](flask_imp_config-impblueprintconfig.html) for more information. diff --git a/archive_docs/_md/v5/ImpBlueprint-tmpl.md b/archive_docs/_md/v5/ImpBlueprint-tmpl.md deleted file mode 100644 index b727f46a..00000000 --- a/archive_docs/_md/v5/ImpBlueprint-tmpl.md +++ /dev/null @@ -1,44 +0,0 @@ -``` -Menu = ImpBlueprint/tmpl -Title = ImpBlueprint.tmpl -``` - -```python -tmpl(template: str) -> str -``` - ---- - -Scopes the template lookup to the name of the blueprint (this takes from the `__name__` attribute of the Blueprint). - -Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder. - -```text -my_blueprint/ -├── routes/ -│ └── index.py -├── static/... -│ -├── templates/ -│ └── my_blueprint/ -│ └── index.html -│ -├── __init__.py -``` - -File: `my_blueprint/routes/index.py` - -```python -from flask import render_template - -from .. import bp - - -@bp.route("/") -def index(): - return render_template(bp.tmpl("index.html")) -``` - -`bp.tmpl("index.html")` will output `"my_blueprint/index.html"`. diff --git a/archive_docs/_md/v5/__index__.md b/archive_docs/_md/v5/__index__.md deleted file mode 100644 index faace10e..00000000 --- a/archive_docs/_md/v5/__index__.md +++ /dev/null @@ -1,121 +0,0 @@ -# Welcome to the Flask-Imp Documentation - -## What is Flask-Imp? - -Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication. - -## Install Flask-Imp - -```bash -pip install flask-imp -``` - -## Getting Started - -To get started right away, you can use the CLI commands to create a new Flask-Imp project. - -```bash -flask-imp init -``` - -### Minimal Flask-Imp Setup - -Run the following command to create a minimal Flask-Imp project. - -```bash -flask-imp init -n app --minimal -``` - -See [CLI Commands / flask-imp init](cli_commands-flask-imp_init.html) for more information. - -### The minimal structure - -#### Folder Structure - -```text -app/ -├── resources/ -│ ├── static/... -│ ├── templates/ -│ │ └── index.html -│ └── index.py -└── __init__.py -``` - -File: `app/__init__.py` - -```python -from flask import Flask - -from flask_imp import Imp -from flask_imp.config import FlaskConfig, ImpConfig - -imp = Imp() - - -def create_app(): - app = Flask(__name__, static_url_path="/") - FlaskConfig( - secret_key="secret_key", - app_instance=app - ) - - imp.init_app(app, ImpConfig()) - - imp.import_app_resources() - # Takes argument 'folder' default folder is 'resources' - - return app -``` - -File: `app/resources/routes.py` - -```python -from flask import current_app as app -from flask import render_template - - -@app.route("/") -def index(): - return render_template("index.html") -``` - -File: `app/resources/templates/index.html` - -```html - - - - - Flask-Imp - - -

Flask-Imp

- - -``` - ---- - -Setting up a virtual environment is recommended. - -**Linux / Darwin** - -```bash -python3 -m venv venv -``` - -```bash -source venv/bin/activate -``` - -**Windows** - -```bash -python -m venv venv -``` - -```text -.\venv\Scripts\activate -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/__menu__.md b/archive_docs/_md/v5/__menu__.md deleted file mode 100644 index 6d17619b..00000000 --- a/archive_docs/_md/v5/__menu__.md +++ /dev/null @@ -1,47 +0,0 @@ -- CLI Commands - - flask-imp init - - flask-imp blueprint -- Imp - - Introduction - - init_app, __init__ - - init_session - - import_app_resources - - import_blueprint - - import_blueprints - - import_models - - model - - model_meta -- ImpBlueprint - - Introduction - - __init__ - - init_session - - import_resources - - import_nested_blueprint - - import_nested_blueprints - - import_models - - tmpl -- flask_imp.config - - FlaskConfig - - ImpConfig - - ImpBlueprintConfig - - DatabaseConfig - - SQLDatabaseConfig - - SQLiteDatabaseConfig -- flask_imp.security - - login_check - - permission_check - - pass_function_check - - api_login_check - - include_csrf -- flask_imp.auth - - encrypt_password - - authenticate_password - - generate_password - - generate_salt - - generate_csrf_token - - generate_private_key - - generate_email_validator - - generate_numeric_validator - - generate_alphanumeric_validator - - is_email_address_valid - - is_username_valid diff --git a/archive_docs/_md/v5/flask_imp_auth-authenticate_password.md b/archive_docs/_md/v5/flask_imp_auth-authenticate_password.md deleted file mode 100644 index d255ae7a..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-authenticate_password.md +++ /dev/null @@ -1,63 +0,0 @@ -``` -Menu = flask_imp.auth/authenticate_password -Title = authenticate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import authenticate_password -``` - -```python -authenticate_password( - input_password: str, - database_password: str, - database_salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end", - use_multiprocessing: bool = False -) -> bool -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / encrypt_password](flask_imp_auth-encrypt_password.html) function. - -Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match. - -**Note:** - -**use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.** - -If you are using socketio, you must set use_multiprocessing to False (default). - -**Note:** - -- You must know the pepper length used to hash the password. -- You must know the position of the pepper used to hash the password. -- You must know the encryption level used to hash the password. - -#### Authentication Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -```python -input_password = "password" -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database -database_salt = "^%$*" # pulled from database - -authenticate_password( - input_password, - database_password, - database_salt -) # >>> True -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-encrypt_password.md b/archive_docs/_md/v5/flask_imp_auth-encrypt_password.md deleted file mode 100644 index 0287b119..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-encrypt_password.md +++ /dev/null @@ -1,53 +0,0 @@ -``` -Menu = flask_imp.auth/encrypt_password -Title = encrypt_password - flask_imp.auth -``` - -```python -from flask_imp.auth import encrypt_password -``` - -```python -encrypt_password( - password: str, - salt: str, - encryption_level: int = 512, - pepper_length: int = 1, - pepper_position: t.Literal["start", "end"] = "end" -) -> str -``` - ---- - -For use in password hashing. - -To be used alongside the [flask_imp.auth / authenticate_password](flask_imp_auth-authenticate_password.html) function. - -Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified. - -Can set the encryption level to 256 or 512, defaults to 512. - -Can set the pepper length, defaults to 1. Max is 3. - -Can set the pepper position, "start" or "end", defaults to "end". - -**Note:** - -- You must inform the authenticate_password function of the pepper length used to hash the password. -- You must inform the authenticate_password function of the position of the pepper used to hash the password. -- You must inform the authenticate_password function of the encryption level used to hash the password. - -#### Encryption Scenario: - -``` -Plain password: "password" -Generated salt: "^%$*" (randomly generated) -Generated pepper (length 1): "A" (randomly generated) -Pepper position: "end" -``` - -1. Pepper is added to the end of the plain password: "passwordA" -2. Salt is added to the end of the peppered password: "passwordA^%$*" -3. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." -4. Salt and hashed password are then stored in the database. - diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md deleted file mode 100644 index c0d0ccdc..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_alphanumeric_validator.md +++ /dev/null @@ -1,24 +0,0 @@ -``` -Menu = flask_imp.auth/generate_alphanumeric_validator -Title = generate_alphanumeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_alphanumeric_validator -``` - -```python -generate_alphanumeric_validator(length: int = 8) -> str -``` - ---- - -Generates a random alphanumeric string of the given length. - -(letters are capitalized) - -*Example:* - -```python -generate_alphanumeric_validator(8) # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md b/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md deleted file mode 100644 index ce6df31b..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_csrf_token.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_csrf_token -Title = generate_csrf_token - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_csrf_token -``` - -```python -generate_csrf_token() -> str -``` - ---- - -Generates a SHA1 using the current date and time. - -For use in Cross-Site Request Forgery. - -Also used by the [flask_imp.security / csrf_protect](flask_imp_security-include_csrf.html) decorator. - -*Example:* - -```python -generate_csrf_token() # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0' -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md deleted file mode 100644 index acdced31..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_email_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_email_validator -Title = generate_email_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_email_validator -``` - -```python -generate_email_validator() -> str -``` - ---- - -Uses `generate_alphanumeric_validator` with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email. - -See [flask_imp.auth / generate_alphanumeric_validator](flask_imp_auth-generate_alphanumeric_validator.html) -for more information. - -*Example:* - -```python -generate_email_validator() # >>> 'A1B2C3D4' -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md b/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md deleted file mode 100644 index c0d7dc76..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_numeric_validator.md +++ /dev/null @@ -1,27 +0,0 @@ -``` -Menu = flask_imp.auth/generate_numeric_validator -Title = generate_numeric_validator - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_numeric_validator -``` - -```python -generate_numeric_validator(length: int) -> int -``` - ---- - - -Generates random choice between 1 * (length) and 9 * (length). - -If the length is 4, it will generate a number between 1111 and 9999. - -For use in MFA email, or unique filename generation. - -*Example:* - -```python -generate_numeric_validator(4) # >>> 1234 -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_password.md b/archive_docs/_md/v5/flask_imp_auth-generate_password.md deleted file mode 100644 index b6f8fda0..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_password.md +++ /dev/null @@ -1,26 +0,0 @@ -``` -Menu = flask_imp.auth/generate_password -Title = generate_password - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_password -``` - -```python -generate_password(style: str = "mixed", length: int = 3) -> str -``` - ---- - -Generates a password of (length) characters. - -The Default length is 3. - -Style options: "animals", "colors", "mixed" - defaults to "mixed" - -*Example:* - -```python -generate_password(style="animals", length=3) # >>> 'Cat-Goat-Pig12' -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_private_key.md b/archive_docs/_md/v5/flask_imp_auth-generate_private_key.md deleted file mode 100644 index 63938598..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_private_key.md +++ /dev/null @@ -1,38 +0,0 @@ -``` -Menu = flask_imp.auth/generate_private_key -Title = generate_private_key - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_private_key -``` - -```python -generate_private_key(hook: t.Optional[str]) -> str -``` - ---- - -Generates a sha256 private key from a passed in hook value. - -If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000. - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt, - private_key=generate_private_key(hook=username) - ) - ... -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-generate_salt.md b/archive_docs/_md/v5/flask_imp_auth-generate_salt.md deleted file mode 100644 index f21615f5..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-generate_salt.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/generate_salt -Title = generate_salt - flask_imp.auth -``` - -```python -from flask_imp.auth import generate_salt -``` - -```python -generate_salt(length: int = 4) -> str -``` - ---- - -Generates a string of (length) characters of punctuation. - -The Default length is 4. - -For use in password hashing and storage of passwords in the database. - -*Example:* - -```python -generate_salt() # >>> '*!$%' -``` - -```python -@app.route('/register', methods=['GET', 'POST']) -def register(): - if request.method == "POST": - ... - salt = generate_salt() - password = request.form.get('password') - encrypted_password = encrypt_password(password, salt) - ... - - user = User( - username=username, - email=email, - password=encrypted_password, - salt=salt - ) - ... -``` - diff --git a/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md b/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md deleted file mode 100644 index 1990e24a..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-is_email_address_valid.md +++ /dev/null @@ -1,46 +0,0 @@ -``` -Menu = flask_imp.auth/is_email_address_valid -Title = is_email_address_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_email_address_valid -``` - -```python -is_email_address_valid( - email_address: str -) -> bool -``` - ---- - -Checks if an email address is valid. - -Is not completely RFC 5322 compliant, but it is good enough for most use cases. - -Here are examples of mistakes that it will not catch: - -##### Valid but fails: - -```text -email@[123.123.123.123] -“email”@example.com -very.unusual.“@”.unusual.com@example.com -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com -``` - -##### Invalid but passes: - -```text -email@example.com (Joe Smith) -email@111.222.333.44444 -``` - -*Example:* - -```python -is_email_address_valid('hello@example.com') # >>> True - -is_email_address_valid('hello@hello@example.com') # >>> False -``` diff --git a/archive_docs/_md/v5/flask_imp_auth-is_username_valid.md b/archive_docs/_md/v5/flask_imp_auth-is_username_valid.md deleted file mode 100644 index 68cdf070..00000000 --- a/archive_docs/_md/v5/flask_imp_auth-is_username_valid.md +++ /dev/null @@ -1,58 +0,0 @@ -``` -Menu = flask_imp.auth/is_username_valid -Title = is_username_valid - flask_imp.auth -``` - -```python -from flask_imp.auth import is_username_valid -``` - -```python -is_username_valid( - username: str, - allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None -) -> bool -``` - ---- - -Checks if a username is valid. - -Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned. - -##### Example "all": - -```python -is_username_valid("username", allowed=["all"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user_name : WILL PASS : True -_user_name : WILL PASS : False -``` - -##### Example "dot", "dash": - -```python - -is_username_valid("username", allowed=["dot", "dash"]) -``` - -Output: - -```text -username : WILL PASS : True -user.name : WILL PASS : True -user-name : WILL PASS : True -user-name.name : WILL PASS : True -user_name : WILL PASS : False -_user_name : WILL PASS : False -.user.name : WILL PASS : False -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-databaseconfig.md b/archive_docs/_md/v5/flask_imp_config-databaseconfig.md deleted file mode 100644 index 423bf8e4..00000000 --- a/archive_docs/_md/v5/flask_imp_config-databaseconfig.md +++ /dev/null @@ -1,31 +0,0 @@ -``` -Menu = flask_imp.config/DatabaseConfig -Title = DatabaseConfig - flask_imp.config -``` - -```python -from flask_imp.config import DatabaseConfig -``` - -```python -DatabaseConfig( - enabled: bool = False, - dialect: t.Literal[ - "mysql", "postgresql", "sqlite", "oracle", "mssql" - ] = "sqlite", - name: str = "database", - bind_key: str = "", - location: str = "", - port: int = 0, - username: str = "", - password: str = "", - sqlite_db_extension: str = ".sqlite" -) -``` - ---- - -A class that holds a database configuration. - -This configuration is parsed into a database URI and -used in either the `SQLALCHEMY_DATABASE_URI` or `SQLALCHEMY_BINDS` configuration variables. \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-flaskconfig.md b/archive_docs/_md/v5/flask_imp_config-flaskconfig.md deleted file mode 100644 index 60adaab7..00000000 --- a/archive_docs/_md/v5/flask_imp_config-flaskconfig.md +++ /dev/null @@ -1,59 +0,0 @@ -``` -Menu = flask_imp.config/FlaskConfig -Title = FlaskConfig - flask_imp.config -``` - -```python -from flask_imp.config import FlaskConfig -``` - -```python -FlaskConfig( - debug: t.Optional[bool] = None, - propagate_exceptions: t.Optional[bool] = None, - trap_http_exceptions: t.Optional[bool] = None, - trap_bad_request_errors: t.Optional[bool] = None, - secret_key: t.Optional[str] = None, - session_cookie_name: t.Optional[str] = None, - session_cookie_domain: t.Optional[str] = None, - session_cookie_path: t.Optional[str] = None, - session_cookie_httponly: t.Optional[bool] = None, - session_cookie_secure: t.Optional[bool] = None, - session_cookie_samesite: t.Optional[t.Literal["Lax", "Strict"]] = None, - permanent_session_lifetime: t.Optional[int] = None, - session_refresh_each_request: t.Optional[bool] = None, - use_x_sendfile: t.Optional[bool] = None, - send_file_max_age_default: t.Optional[int] = None, - error_404_help: t.Optional[bool] = None, - server_name: t.Optional[str] = None, - application_root: t.Optional[str] = None, - preferred_url_scheme: t.Optional[str] = None, - max_content_length: t.Optional[int] = None, - templates_auto_reload: t.Optional[bool] = None, - explain_template_loading: t.Optional[bool] = None, - max_cookie_size: t.Optional[int] = None, - app_instance: t.Optional["Flask"] = None -) -``` - ---- - -A class that holds a Flask configuration values. - -You can set the configuration values to the app instance by either passing the app instance to the `app_instance` -parameter or by calling the `apply_config` method on the `FlaskConfig` instance. - -```python -def create_app(): - app = Flask(__name__) - FlaskConfig(debug=True, app_instance=app) - return app -``` -or -```python -def create_app(): - app = Flask(__name__) - config = FlaskConfig(debug=True) - config.apply_config(app) - return app -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-impblueprintconfig.md b/archive_docs/_md/v5/flask_imp_config-impblueprintconfig.md deleted file mode 100644 index 85674a06..00000000 --- a/archive_docs/_md/v5/flask_imp_config-impblueprintconfig.md +++ /dev/null @@ -1,37 +0,0 @@ -``` -Menu = flask_imp.config/ImpBlueprintConfig -Title = ImpBlueprintConfig - flask_imp.config -``` - -```python -from flask_imp.config import ImpBlueprintConfig -``` - -```python -ImpBlueprintConfig( - enabled: bool = False, - url_prefix: str = None, - subdomain: str = None, - url_defaults: dict = None, - static_folder: t.Optional[str] = None, - template_folder: t.Optional[str] = None, - static_url_path: t.Optional[str] = None, - root_path: str = None, - cli_group: str = None, - init_session: dict = None, - database_binds: t.Iterable[DatabaseConfig] = None -) -``` - ---- - -A class that holds a Flask-Imp blueprint configuration. - -Most of these values are passed to the `Blueprint` class when the blueprint is registered. - -The `enabled` argument is used to enable or disable the blueprint. This is useful for feature flags. - -`init_session` is used to set the session values in the main `before_request` function. - -`database_binds` is a list of `DatabaseConfig` instances that are used to create `SQLALCHEMY_BINDS` configuration -variables. Again this is useful for feature flags, or for creating multiple databases per blueprint. \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-impconfig.md b/archive_docs/_md/v5/flask_imp_config-impconfig.md deleted file mode 100644 index f90309c3..00000000 --- a/archive_docs/_md/v5/flask_imp_config-impconfig.md +++ /dev/null @@ -1,49 +0,0 @@ -``` -Menu = flask_imp.config/ImpConfig -Title = ImpConfig - flask_imp.config -``` - -```python -from flask_imp.config import ImpConfig -``` - -```python -ImpConfig( - init_session: t.Optional[t.Dict[str, t.Any]] = None, - database_main: t.Optional[ - t.Union[DatabaseConfig, SQLiteDatabaseConfig, SQLDatabaseConfig] - ] = None, - database_binds: t.Optional[ - t.List[t.Union[DatabaseConfig, SQLiteDatabaseConfig, SQLDatabaseConfig]] - ] = None, -) -``` - ---- - -The `ImpConfig` class is used to set the initial session, the main database, and any additional databases -that the application will use. - -```python -imp_config = ImpConfig( - init_session={"key": "value"}, - database_main=SQLiteDatabaseConfig( - name="test1", - ), - database_binds=[ - DatabaseConfig( - enabled=True, - dialect="sqlite", - name="test2", - bind_key="test2" - ) - ] -) - - -def create_app(): - app = Flask(__name__) - FlaskConfig(debug=True, app_instance=app) - imp.init_app(app, imp_config) - ... -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-sqldatabaseconfig.md b/archive_docs/_md/v5/flask_imp_config-sqldatabaseconfig.md deleted file mode 100644 index d7b6e494..00000000 --- a/archive_docs/_md/v5/flask_imp_config-sqldatabaseconfig.md +++ /dev/null @@ -1,28 +0,0 @@ -``` -Menu = flask_imp.config/SQLDatabaseConfig -Title = SQLDatabaseConfig - flask_imp.config -``` - -```python -from flask_imp.config import SQLDatabaseConfig -``` - -```python -SQLDatabaseConfig( - dialect: t.Literal["mysql", "postgresql", "oracle", "mssql"], - enabled: bool = True, - name: str = "database", - bind_key: str = "", - location: str = "", - port: int = 0, - username: str = "", - password: str = "", -) -``` - ---- - -A class that holds a SQL database configuration. - -This configuration is parsed into a database URI and -used in either the `SQLALCHEMY_DATABASE_URI` or `SQLALCHEMY_BINDS` configuration variables. \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_config-sqlitedatabaseconfig.md b/archive_docs/_md/v5/flask_imp_config-sqlitedatabaseconfig.md deleted file mode 100644 index 532ea0b3..00000000 --- a/archive_docs/_md/v5/flask_imp_config-sqlitedatabaseconfig.md +++ /dev/null @@ -1,25 +0,0 @@ -``` -Menu = flask_imp.config/SQLiteDatabaseConfig -Title = SQLiteDatabaseConfig - flask_imp.config -``` - -```python -from flask_imp.config import SQLiteDatabaseConfig -``` - -```python -SQLiteDatabaseConfig( - enabled: bool = True, - name: str = "database", - bind_key: str = "", - sqlite_db_extension: str = ".sqlite", - location: t.Optional[Path] = None, -) -``` - ---- - -A class that holds a SQLite database configuration. - -This configuration is parsed into a database URI and -used in either the `SQLALCHEMY_DATABASE_URI` or `SQLALCHEMY_BINDS` configuration variables. \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_security-api_login_check.md b/archive_docs/_md/v5/flask_imp_security-api_login_check.md deleted file mode 100644 index e021ecbe..00000000 --- a/archive_docs/_md/v5/flask_imp_security-api_login_check.md +++ /dev/null @@ -1,47 +0,0 @@ -``` -Menu = flask_imp.security/api_login_check -Title = api_login_check - flask_imp.security -``` - - -```python -from flask_imp.security import api_login_check -``` - -```python -api_login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_json: t.Optional[t.Dict[str, t.Any]] = None -) -``` - -`@api_login_check(...)` - ---- - -A decorator that is used to secure API routes that return JSON responses. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_json` JSON that is returned on failure. `{"error": "You are not logged in."}` by default. - -*Example:* - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True) -def api_page(): - ... -``` - -##### Example of defined fail_json: - -```python -@bp.route("/api/resource", methods=["GET"]) -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."}) -def api_page(): - ... -``` diff --git a/archive_docs/_md/v5/flask_imp_security-include_csrf.md b/archive_docs/_md/v5/flask_imp_security-include_csrf.md deleted file mode 100644 index 5f367974..00000000 --- a/archive_docs/_md/v5/flask_imp_security-include_csrf.md +++ /dev/null @@ -1,48 +0,0 @@ -``` -Menu = flask_imp.security/include_csrf -Title = include_csrf - flask_imp.security -``` - -```python -from flask_imp.security import include_csrf -``` - -```python -include_csrf( - session_key: str = "csrf", - form_key: str = "csrf", - abort_code: int = 401 -) -``` - -`@include_csrf(...)` - ---- - - -A decorator that handles CSRF protection. - -On a **GET** request, a CSRF token is generated and stored in the session key -specified by the session_key parameter. - -On a **POST** request, the form_key specified is checked against the session_key -specified. - -- If they match, the request is allowed to continue. -- If no match, the response will be abort(abort_code), default 401. - -```python -@bp.route("/admin", methods=["GET", "POST"]) -@include_csrf(session_key="csrf", form_key="csrf") -def admin_page(): - ... - # You must pass in the CSRF token from the session into the template. - # Then add to the form. - return render_template("admin.html", csrf=session.get("csrf")) -``` - -Form key: - -```html - -``` \ No newline at end of file diff --git a/archive_docs/_md/v5/flask_imp_security-login_check.md b/archive_docs/_md/v5/flask_imp_security-login_check.md deleted file mode 100644 index f95cebde..00000000 --- a/archive_docs/_md/v5/flask_imp_security-login_check.md +++ /dev/null @@ -1,66 +0,0 @@ -``` -Menu = flask_imp.security/login_check -Title = login_check - flask_imp.security -``` - -```python -from flask_imp.security import login_check -``` - -```python -login_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - pass_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@login_check(...)` - ---- - -A decorator that checks if the specified session key exists and contains the specified value. - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -##### Example of a route that requires a user to be logged in: - -```python -@bp.route("/admin", methods=["GET"]) -@login_check( - 'logged_in', - True, - fail_endpoint='blueprint.login_page', - message="Login needed" -) -def admin_page(): - ... -``` - -##### Example of a route that if the user is already logged in, redirects to the specified endpoint: - -```python -@bp.route("/login-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - pass_endpoint='blueprint.admin_page', - message="Already logged in" -) -def login_page(): - ... -``` diff --git a/archive_docs/_md/v5/flask_imp_security-pass_function_check.md b/archive_docs/_md/v5/flask_imp_security-pass_function_check.md deleted file mode 100644 index 07ed2f35..00000000 --- a/archive_docs/_md/v5/flask_imp_security-pass_function_check.md +++ /dev/null @@ -1,114 +0,0 @@ -``` -Menu = flask_imp.security/pass_function_check -Title = pass_function_check - flask_imp.security -``` - -```python -from flask_imp.security import pass_function_check -``` - -```python -def pass_function_check( - function: t.Callable, - predefined_args: t.Optional[t.Dict] = None, - fail_endpoint: t.Optional[str] = None, - pass_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message", - fail_on_missing_kwargs: bool = False, - with_app_context: bool = False, -) -``` - -**NOTE: This was added mostly as an experimental feature, but ended up being useful in some cases.** - -A decorator that takes the result of a function and checks if it is True or False. - -URL variables from `@route` will be read by this decorator. -To use URL variables in your passed in function, -make sure your functions argument(s) name(s) match the name(s) of the URL variable(s). - -**Example:** - -```python -def check_if_number(value): - if isinstance(value, int): - return True - return False - -@bp.route("/admin-page/", methods=["GET"]) -@login_check('logged_in', True, 'blueprint.login_page') # can be mixed with login_check -@pass_function_check( - check_if_number, - predefined_args=None, - fail_endpoint='www.index', - message="Failed message" -) -def admin_page(): - ... - -@bp.route("/admin-page/", methods=["GET"]) -@login_check('logged_in', True, 'blueprint.login_page') # can be mixed with login_check -@pass_function_check( - check_if_number, - predefined_args={'value': 10}, - fail_endpoint='www.index', - message="Failed message" -) -def admin_page_overwrite(): - ... -``` - -**Advanced use case:** - -Here's an example of accessing flask.session from within the passed in function. including the -`with_app_context` parameter, the function will be called with `app_context()`. - -```python -from flask import current_app -from flask import session - -... - -def check_if_number(number=1, session_=None): - if session_: - print(session_) - try: - int(number) - return True - except ValueError: - return False - -@bp.route("/pass-func-check-with-url-var/", methods=["GET"]) -@pass_function_check( - check_if_number, - predefined_args={'number': 10, 'session_': session}, - fail_endpoint="www.index", - with_app_context=True -) -def admin_page_overwrite_with_session(): - ... -``` - -If you pass in a predefined arg that has the same key name as a session variable that exists, the value -of that predefined arg will be replaced with the session variable value. - -```python -session['car'] = 'Toyota' -... -def check_function(car): - if car == 'Toyota': - return True - return False -... -@bp.route("/pass-func-check-with-url-var/", methods=["GET"]) -@pass_function_check( - check_function, - predefined_args={'car': session}, - ... - -``` - -This will pass, as pass_function_check will replace the value of the predefined arg 'car' with the value -of the session variable 'car'. diff --git a/archive_docs/_md/v5/flask_imp_security-permission_check.md b/archive_docs/_md/v5/flask_imp_security-permission_check.md deleted file mode 100644 index 73278e12..00000000 --- a/archive_docs/_md/v5/flask_imp_security-permission_check.md +++ /dev/null @@ -1,57 +0,0 @@ -``` -Menu = flask_imp.security/permission_check -Title = permission_check - flask_imp.security -``` - -```python -from flask_imp.security import permission_check -``` - -```python -permission_check( - session_key: str, - values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool], - fail_endpoint: t.Optional[str] = None, - endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None, - message: t.Optional[str] = None, - message_category: str = "message" -) -``` - -`@permission_check(...)` - ---- - -A decorator that checks if the specified session key exists and its value(s) match the specified value(s). - -`session_key` The session key to check for. - -`values_allowed` A list of or singular value(s) that the session key must contain. - -`fail_endpoint` The endpoint to redirect to if the session key does not exist or does not contain the specified values. - -`endpoint_kwargs` A dictionary of keyword arguments to pass to the redirect endpoint. - -`message` If a message is specified, a flash message is shown. - -`message_category` The category of the flash message. - -*Example:* - -```python -@bp.route("/admin-page", methods=["GET"]) -@login_check( - 'logged_in', - True, - 'blueprint.login_page' -) # can be mixed with login_check -@permission_check( - 'permissions', - ['admin'], - fail_endpoint='www.index', - message="Failed message" -) -def admin_page(): - ... -``` - diff --git a/archive_docs/_ssg/__init__.py b/archive_docs/_ssg/__init__.py deleted file mode 100644 index 9648d99d..00000000 --- a/archive_docs/_ssg/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .compiler import compiler - -__all__ = ["compiler"] diff --git a/archive_docs/_ssg/compiler.py b/archive_docs/_ssg/compiler.py deleted file mode 100644 index dbf0a991..00000000 --- a/archive_docs/_ssg/compiler.py +++ /dev/null @@ -1,132 +0,0 @@ -import re -import typing as t -from pathlib import Path - -import mistune -from flask import render_template - -from .exceptions import NoPostDefinition -from .helpers import get_relative_files_in_the_docs_folder, pytz_dt_now, post_date -from .render_engines import HighlightRenderer - - -def _raw_markdown_processor(raw_markdown: str) -> tuple[t.Optional[list], str, str]: - """ - :param raw_markdown: The raw markdown to process - :return: publish: bool, date: str, title: str, description: str, post: str - """ - if not raw_markdown.startswith("```"): - raise NoPostDefinition - - split_md = raw_markdown.split("```")[1:] - raw_meta = split_md[0] - - menu_ptn = re.compile(r"Menu =(.*?)\n", re.IGNORECASE) - title_ptn = re.compile(r"Title =(.*?)\n", re.IGNORECASE) - - try: - menu = menu_ptn.findall(raw_meta)[0].strip().split("/") - except (ValueError, IndexError, TypeError) as _: - menu = None - - try: - title = title_ptn.findall(raw_meta)[0].strip() - except (ValueError, IndexError, TypeError) as _: - title = "[Unable to find Title]" - - try: - post = "```".join(split_md[1:]) - except (IndexError, TypeError, ValueError) as _: - post = "[Unable to find Post]" - - return menu, title, post - - -def compiler(docs_dir: Path, markdown_dir: Path): - docs_dir.mkdir(exist_ok=True) - markdown_dir.mkdir(exist_ok=True) - - markdown_menu = markdown_dir / "__menu__.md" - markdown_index = markdown_dir / "__index__.md" - - markdown_menu_dict = dict() - - with open(markdown_menu, mode="r") as menu_file: - for line in menu_file.readlines(): - if line.startswith("-"): - line_strip = line.strip() - markdown_menu_dict[line_strip.replace("- ", "").strip()] = { - "page": "", - "pages": [], - } - continue - - if line.startswith(" ") or line.startswith("\t"): - line_strip = line.strip() - if line_strip.startswith("-"): - markdown_menu_dict[list(markdown_menu_dict.keys())[-1]][ - "pages" - ].append({line_strip.replace("- ", "").strip(): ""}) - - main_index_html = docs_dir.parent / "index.html" - index_html = docs_dir / "index.html" - - docs_dir_files = get_relative_files_in_the_docs_folder(docs_dir) - markdown_dir_files = markdown_dir.glob("*.md") - html_engine = mistune.create_markdown(renderer=HighlightRenderer()) - - html_pages = dict() - dt_date = pytz_dt_now() - - main_index_html.unlink(missing_ok=True) - main_index_html.write_text( - render_template("main_index.html", latest_version=docs_dir.name) - ) - - for file in docs_dir_files: - (docs_dir / f"{file}.html").unlink() - - for file in markdown_dir_files: - if "__" in file.stem: - continue - - raw_markdown = file.read_text() - menu, title, post = _raw_markdown_processor(raw_markdown) - html_filename = f'{file.stem.lower().replace(" ", "_")}.html' - - html_pages[html_filename] = { - "menu": menu, - "title": title, - "content": html_engine(post), - } - - if menu is not None: - if len(menu) == 1: - markdown_menu_dict[menu[0]]["page"] = html_filename - else: - for keys in markdown_menu_dict[menu[0]]["pages"]: - if menu[1] in keys.keys(): - keys[menu[1]] = html_filename - - # write html files - for page, meta in html_pages.items(): - with open(docs_dir / page, mode="w") as html_file: - html_file.write( - render_template( - "__main__.html", - menu=markdown_menu_dict, - title=meta["title"], - date=post_date(dt_date), - content=meta["content"], - ) - ) - - # write main index.html - index_html.write_text( - render_template( - "index.html", - menu=markdown_menu_dict, - date=post_date(dt_date), - index=html_engine(markdown_index.read_text()), - ) - ) diff --git a/archive_docs/_ssg/exceptions.py b/archive_docs/_ssg/exceptions.py deleted file mode 100644 index f34ca083..00000000 --- a/archive_docs/_ssg/exceptions.py +++ /dev/null @@ -1,38 +0,0 @@ -class NoPostDefinition(Exception): - builtin_msg = f"""\n -No post definition found! - -{"_" * 10}TOP_OF_FILE{"_" * 10} -``` -Publish = Bool -Date = 0000-00-00 00:00:00 +0100 or set-on-compile -Title = String -Description = String -``` - -Must be at the top of the file, and must be followed by a blank line. - -""" - - def __str__(self): - return self.builtin_msg - - -class ErrorInPostDefinition(Exception): - builtin_msg = f"""\n -There is an error in the post description! - -{"_" * 10}TOP_OF_FILE{"_" * 10} -``` -Publish = Bool -Date = 0000-00-00 00:00:00 +0100 or set-on-compile -Title = String -Description = String -``` - -Must be at the top of the file, and must be followed by a blank line. - -""" - - def __str__(self): - return self.builtin_msg diff --git a/archive_docs/_ssg/helpers.py b/archive_docs/_ssg/helpers.py deleted file mode 100644 index c6dbe988..00000000 --- a/archive_docs/_ssg/helpers.py +++ /dev/null @@ -1,53 +0,0 @@ -import re -from datetime import datetime -from pathlib import Path - -from pytz import timezone - -local_tz = timezone("Europe/London") - - -def pytz_dt_now() -> datetime: - return datetime.now(local_tz) - - -def pytz_dt_epoch() -> float: - return pytz_dt_now().timestamp() - - -def pytz_dt_now_str(mask: str = "%Y-%m-%d %H:%M:%S %z") -> str: - return datetime.now(local_tz).strftime(mask) - - -def pytz_dt_to_str(pytz_dt: datetime, mask: str = "%Y-%m-%d %H:%M:%S %z") -> str: - return pytz_dt.strftime(mask) - - -def pytz_dt_str_to_dt(pytz_dt_str: str) -> datetime: - """ - :param pytz_dt_str: "2020-01-01 00:00:00 +0000" - """ - return datetime.strptime(pytz_dt_str, "%Y-%m-%d %H:%M:%S %z") - - -def post_date(pytz_dt: datetime) -> str: - return pytz_dt.strftime("%a, %d %b %Y") - - -def switch_date(content, new_date): - pattern = re.compile(r'date="(.*?)"', re.IGNORECASE) - return pattern.sub(f'date="{new_date}"', content) - - -def get_relative_files_in_the_docs_folder(docs_dir: Path) -> list: - _ = [] - for f in docs_dir.glob("*.html"): - if f.stem == "index": - continue - _.append(f.stem) - - return _ - - -def excessive_br_cleanup(base_xml: str) -> str: - return base_xml.replace("


", "

").replace("

    ", "
      ") diff --git a/archive_docs/_ssg/render_engines.py b/archive_docs/_ssg/render_engines.py deleted file mode 100644 index cff2fe94..00000000 --- a/archive_docs/_ssg/render_engines.py +++ /dev/null @@ -1,18 +0,0 @@ -import mistune -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import get_lexer_by_name -from pygments.util import ClassNotFound - - -class HighlightRenderer(mistune.HTMLRenderer): - def block_code(self, code, info=None): - if info: - if info == "jinja2": - info = "jinja" - try: - lexer = get_lexer_by_name(info, stripall=True) - except ClassNotFound: - lexer = get_lexer_by_name("text", stripall=True) - return highlight(code, lexer, HtmlFormatter()) - return "
      " + mistune.escape(code) + "
      " diff --git a/archive_docs/_templates/__main__.html b/archive_docs/_templates/__main__.html deleted file mode 100644 index 9120c5dd..00000000 --- a/archive_docs/_templates/__main__.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - {{ title|title }} | Flask-Imp - - - - - - - - - - - - -{% include "__menu__.html" %} - -
      -

      {{ title }}

      - {{ content|safe }} -
      - - - \ No newline at end of file diff --git a/archive_docs/_templates/__menu__.html b/archive_docs/_templates/__menu__.html deleted file mode 100644 index 4850e80c..00000000 --- a/archive_docs/_templates/__menu__.html +++ /dev/null @@ -1,37 +0,0 @@ - diff --git a/archive_docs/_templates/index.html b/archive_docs/_templates/index.html deleted file mode 100644 index 3bebf6fb..00000000 --- a/archive_docs/_templates/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Flask-Imp - - - - - - - - - - - - -{% include "__menu__.html" %} - -
      - {{ index|safe }} -
      - - - - \ No newline at end of file diff --git a/archive_docs/_templates/main_index.html b/archive_docs/_templates/main_index.html deleted file mode 100644 index c2d3abf3..00000000 --- a/archive_docs/_templates/main_index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Redirecting to latest... - - - - -Click here if redirection is not working. - - - \ No newline at end of file diff --git a/archive_docs/config.py b/archive_docs/config.py deleted file mode 100644 index bec94c00..00000000 --- a/archive_docs/config.py +++ /dev/null @@ -1,7 +0,0 @@ -from dataclasses import dataclass - - -@dataclass -class Config: - latest = "v5" - versions = ["v3", "v4", "v5"] diff --git a/archive_docs/index.html b/archive_docs/index.html deleted file mode 100644 index 1c12861d..00000000 --- a/archive_docs/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Redirecting to latest... - - - - -Click here if redirection is not working. - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint-config-toml.html b/archive_docs/v3/blueprint-config-toml.html deleted file mode 100644 index 0916c2eb..00000000 --- a/archive_docs/v3/blueprint-config-toml.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - - The Flask-Imp Blueprint Config File | Flask-Imp - - - - - - - - - - - - - - -
      -

      The Flask-Imp Blueprint Config File

      -

      The Flask-Imp Blueprint will load configuration from a config.toml file, which is located in the same directory as the -__init__.py file.

      -

      File: config.toml

      -
      enabled = "yes"
      -
      -[settings]
      -url_prefix = ""
      -subdomain = ""
      -url_defaults = { }
      -static_folder = ""
      -template_folder = ""
      -static_url_path = ""
      -#root_path = ""
      -#cli_group = ""
      -
      -[session]
      -var = ""
      -
      -# Set ENABLED to true to allow the blueprint
      -# to create a database bind, change settings accordingly.
      -[DATABASE_BIND]
      -ENABLED = true
      -DIALECT = "sqlite"
      -DATABASE_NAME = "example"
      -LOCATION = ""
      -PORT = ""
      -USERNAME = ""
      -PASSWORD = ""
      -
      -

      This config reflects the args that are passed to a regular Flask Blueprint class, the addition of the ability to -enable/disable the Blueprint, and set session variables.

      -

      For more information about the args of a regular Flask Blueprint see: -Flask docs (Blueprint)

      -

      You can also allow the blueprint to create a database bind, by setting ENABLED to true in the DATABASE_BIND -section.

      -

      This will add to the Flask app's SQLALCHEMY_BINDS config variable, and allows blueprints to be more modular -with their database connections.

      -

      Including the attribute __bind_key__ in the blueprint's model(s) will match the model to the database bind.

      -
      class User(db.Model):
      -    __bind_key__ = "example"
      -    ...
      -
      -
      Example of advance use case for blueprint config files:
      -
      testing_blueprint/
      -├── routes/
      -│   └── index.py
      -├── static/
      -│   └── ...
      -├── templates/
      -│   └── www/
      -│       └── index.html
      -├── __init__.py
      -├── pro_config.py
      -└── dev_config.toml
      -
      -
      from app import app
      -from flask_imp import Blueprint
      -
      -bp = Blueprint(
      -    __name__,
      -    config_file="dev_config.toml" if app.config["DEBUG"] else "pro_config.py"
      -)
      -
      -bp.import_resources("routes")
      -
      -
      -@bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      -

      File: pro_config.py

      -
      enabled = "no"
      -
      -[settings]
      -#url_prefix = ""
      -#subdomain = ""
      -#url_defaults = { }
      -#static_folder = ""
      -#template_folder = ""
      -#static_url_path = ""
      -#root_path = ""
      -#cli_group = ""
      -
      -[session]
      -#var = ""
      -
      -# Set ENABLED to true to allow the blueprint
      -# to create a database bind, change settings accordingly.
      -[DATABASE_BIND]
      -ENABLED = false
      -DIALECT = "sqlite"
      -DATABASE_NAME = "example"
      -LOCATION = ""
      -PORT = ""
      -USERNAME = ""
      -PASSWORD = ""
      -
      -

      File: dev_config.py

      -
      enabled = "yes"
      -
      -[settings]
      -url_prefix = "/testing"
      -#subdomain = ""
      -#url_defaults = { }
      -static_folder = "static"
      -template_folder = "templates"
      -#static_url_path = ""
      -#root_path = ""
      -#cli_group = ""
      -
      -[session]
      -#var = ""
      -
      -# Set ENABLED to true to allow the blueprint
      -# to create a database bind, change settings accordingly.
      -[DATABASE_BIND]
      -ENABLED = true
      -DIALECT = "sqlite"
      -DATABASE_NAME = "example"
      -LOCATION = ""
      -PORT = ""
      -USERNAME = ""
      -PASSWORD = ""
      -
      -

      In the example above, the testing_blueprint will only be enabled if the Flask app is running in debug mode.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint-init.html b/archive_docs/v3/blueprint-init.html deleted file mode 100644 index 4eae1982..00000000 --- a/archive_docs/v3/blueprint-init.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - Flask-Imp Blueprint __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint __init__

      -
      Blueprint(dunder_name: str, config_file: str = "config.toml") -> None
      -
      -
      -

      Initializes the Flask-Imp Blueprint.

      -

      dunder_name should always be set to __name__

      -

      config_file is the name of the config file to load. -It will be loaded from the same directory as the __init__.py file.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint-introduction.html b/archive_docs/v3/blueprint-introduction.html deleted file mode 100644 index 9b47a7c3..00000000 --- a/archive_docs/v3/blueprint-introduction.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - Flask-Imp Blueprint Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint Introduction

      -

      The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints.

      -

      The Flask-Imp Blueprint reads configuration from a config.toml file, which is located in the same directory as the -__init__.py file.

      -

      Here's an example of a Flask-Imp Blueprint structure:

      -
      www/
      -├── nested_blueprints/
      -│   ├── blueprint_one/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.toml
      -│   └── blueprint_two/
      -│       ├── ...
      -│       ├── __init__.py
      -│       └── config.toml
      -├── standalone_nested_blueprint/
      -│   ├── ...
      -│   ├── __init__.py
      -│   └── config.toml
      -├── models/
      -│   └── ...
      -├── routes/
      -│   └── index.py
      -├── static/
      -│   └── ...
      -├── templates/
      -│   └── www/
      -│       └── index.html
      -├── __init__.py
      -└── config.toml
      -
      -

      File: __init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -bp.import_nested_blueprints("nested_blueprints")
      -bp.import_nested_blueprint("standalone_nested_blueprint")
      -
      -
      -@bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      -

      That config.toml file is loaded during the __init__ method of the Blueprint class. -To see more about the config file see: Blueprint / config.toml

      -

      import_resources method will walk one level deep into the routes folder, and import all .py files as modules. -For more information see: Blueprint.x / import_resources

      -

      import_models works the same as imp.import_models, it will look for instances of db.Model and import them. These -will also be available in the model lookup method imp.model. -For more information see: Imp.x / import_models

      -

      import_nested_blueprints will do the same as imp.import_blueprints, but will register the blueprints found as -nested to the current blueprint. For example www.blueprint_one.index

      -

      import_nested_blueprint behaves the same as import_nested_blueprints, but will only import a single blueprint.

      -

      bp.init_session will load the session variables from the config file into the session object. For more information -see: Blueprint.x / init_session and -Blueprint / config.toml

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-import_models.html b/archive_docs/v3/blueprint_x-import_models.html deleted file mode 100644 index 1aaeffb1..00000000 --- a/archive_docs/v3/blueprint_x-import_models.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - Blueprint.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_models

      -
      import_models(folder: str = "models") -> None
      -
      -
      -

      Will import all the models from the given folder relative to the Blueprint's root directory.

      -

      Works the same as Imp.x / import_models but relative to the Blueprint root.

      -

      Blueprint models will also be available in the Imp.x / model lookup.

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── animal_models.py
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      or

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── models/
      -│   └── animals.py
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("animal_models.py")
      -
      -

      or

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -
      -

      File: my_blueprint/animal_models.py or my_blueprint/models/animals.py

      -
      from app import db
      -
      -
      -class Animals(db.Model):
      -    animal_id = db.Column(db.Integer, primary_key=True)
      -    name = db.Column(db.String(64), index=True, unique=True)
      -    species = db.Column(db.String(64), index=True, unique=True)
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-import_nested_blueprint.html b/archive_docs/v3/blueprint_x-import_nested_blueprint.html deleted file mode 100644 index 9f5c9603..00000000 --- a/archive_docs/v3/blueprint_x-import_nested_blueprint.html +++ /dev/null @@ -1,307 +0,0 @@ - - - - - Blueprint.import_nested_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_nested_blueprint

      -
      import_nested_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root.

      -

      Works the same as Imp.x / import_blueprint but relative to the Blueprint root.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.my_nested_blueprint.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── my_nested_blueprint/
      -│   ├── routes/
      -│   │   └── index.py
      -│   ├── static/...
      -│   ├── templates/...
      -│   ├── __init__.py
      -│   └── config.toml
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprint("my_nested_blueprint")
      -
      -

      File: my_blueprint/my_nested_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -
      -

      File: my_blueprint/my_nested_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-import_nested_blueprints.html b/archive_docs/v3/blueprint_x-import_nested_blueprints.html deleted file mode 100644 index fd7ab6a0..00000000 --- a/archive_docs/v3/blueprint_x-import_nested_blueprints.html +++ /dev/null @@ -1,300 +0,0 @@ - - - - - Blueprint.import_nested_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_nested_blueprints

      -
      import_nested_blueprints(self, folder: str) -> None
      -
      -
      -

      Will import all the Blueprints from the given folder relative to the Blueprint's root directory.

      -

      Uses Blueprint.x / import_nested_blueprint to import blueprints from -the specified folder.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.nested_bp_one.index')

      -

      url_for('my_blueprint.nested_bp_two.index')

      -

      url_for('my_blueprint.nested_bp_three.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── nested_blueprints/
      -│   │
      -│   ├── nested_bp_one/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.toml
      -│   ├── nested_bp_two/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.toml
      -│   └── nested_bp_three/
      -│       ├── ...
      -│       ├── __init__.py
      -│       └── config.toml
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprints("nested_blueprints")
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-import_resources.html b/archive_docs/v3/blueprint_x-import_resources.html deleted file mode 100644 index 1266902f..00000000 --- a/archive_docs/v3/blueprint_x-import_resources.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - Blueprint.import_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_resources

      -
      import_resources(folder: str = "routes") -> None
      -
      -
      -

      Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory.

      -
      my_blueprint
      -├── user_routes
      -│   ├── user_dashboard.py
      -│   └── user_settings.py
      -├── car_routes
      -│   ├── car_dashboard.py
      -│   └── car_settings.py
      -├── static/...
      -├── templates/
      -│   └── my_blueprint/
      -│       ├── user_dashboard.html
      -│       └── ...
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("user_routes")
      -bp.import_resources("car_routes")
      -
      -

      File: my_blueprint/user_routes/user_dashboard.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -@bp.route("/user-dashboard")
      -def user_dashboard():
      -    return render_template(bp.tmpl("user_dashboard.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-init_session.html b/archive_docs/v3/blueprint_x-init_session.html deleted file mode 100644 index d38d6ad4..00000000 --- a/archive_docs/v3/blueprint_x-init_session.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - Blueprint.init_session | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.init_session

      -
      init_session() -> None
      -
      -
      -

      Has the same functionality as Imp.x / init_session but loads session key values from the -Blueprint's config file.

      -
      @bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/blueprint_x-tmpl.html b/archive_docs/v3/blueprint_x-tmpl.html deleted file mode 100644 index a8948a4b..00000000 --- a/archive_docs/v3/blueprint_x-tmpl.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Blueprint.tmpl | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.tmpl

      -
      tmpl(template: str) -> str
      -
      -
      -

      Scopes the template lookup to the name of the blueprint (this takes from the __name__ attribute of the Blueprint).

      -

      Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder.

      -
      my_blueprint/
      -├── routes/
      -│   └── index.py
      -├── static/...
      -│
      -├── templates/
      -│   └── my_blueprint/
      -│       └── index.html
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      -

      bp.tmpl("index.html") will output "my_blueprint/index.html".

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/cli_commands-flask-imp_blueprint.html b/archive_docs/v3/cli_commands-flask-imp_blueprint.html deleted file mode 100644 index db12a2b0..00000000 --- a/archive_docs/v3/cli_commands-flask-imp_blueprint.html +++ /dev/null @@ -1,320 +0,0 @@ - - - - - Generate A Flask-Imp Blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Generate a Flask-Imp Blueprint

      -

      Flask-Imp has its own type of blueprint. It can read some configuration from a toml file and has some extra methods for -auto importing.

      -
      flask-imp blueprint --help
      -
      -

      To generate a Flask-Imp blueprint, run the following command:

      -
      flask-imp blueprint
      -
      -

      After running this command, you will be prompted to enter the location of where you want to create your blueprint:

      -
      ~ $ flask-imp blueprint
      -(Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]:
      -
      -

      As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder app/blueprints, you would enter app/blueprints in the prompt.

      -
      (Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]: app/blueprints
      -
      -

      You will then be prompted to enter a name for your blueprint:

      -
      (Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]: app/blueprints 
      -Name of the blueprint to create [my_new_blueprint]:
      -
      -

      The default name is 'my_new_blueprint', we will change this to 'admin'

      -
      (Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]: app/blueprints 
      -Name of the blueprint to create [my_new_blueprint]: admin
      -
      -

      After creating your blueprint, the folder structure will look like this:

      -
      app/
      -├── blueprints
      -│   └── admin
      -│       ├── routes
      -│       │   └── index.py
      -│       │
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       │
      -│       ├── templates
      -│       │   └── www
      -│       │       ├── extends
      -│       │       │   └── main.html
      -│       │       ├── includes
      -│       │       │   ├── footer.html
      -│       │       │   └── header.html
      -│       │       └── index.html
      -│       │
      -│       ├── __init__.py
      -│       └─── config.toml
      -│
      -...
      -
      -

      This is a self-contained blueprint, so it has its own static, templates and routes folders. You can now navigate ' -/admin'

      -

      You can streamline this process by specifying the name of the blueprint and the folder to create it in, like so:

      -
      flask-imp blueprint -n admin -f app/blueprints
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/cli_commands-flask-imp_init.html b/archive_docs/v3/cli_commands-flask-imp_init.html deleted file mode 100644 index ddd589a5..00000000 --- a/archive_docs/v3/cli_commands-flask-imp_init.html +++ /dev/null @@ -1,433 +0,0 @@ - - - - - Initialising A Flask-Imp Project | Flask-Imp - - - - - - - - - - - - - - -
      -

      Initialising a Flask-Imp Project

      -

      Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp.

      -
      flask-imp init --help
      -
      -

      Create a new project

      -

      Make sure you are in the virtual environment, and at the root of your project folder, then run the following command:

      -
      flask-imp init
      -
      -

      After running this command, you will be prompted to choose what type of app you want to deploy:

      -
      ~ $ flask-imp init
      -What type of app would you like to create? (full, slim, minimal) [full]:
      -
      -

      See below for the differences between the app types.

      -

      After this, you will be prompted to enter a name for your app:

      -
      ~ $ flask-imp init
      -What would you like to call your app? [app]:
      -
      -

      'app' is the default name, so if you just press enter, your app will be called 'app'. You will then see this output:

      -
      ===================
      -Flask app deployed!
      -===================
      - 
      -Your app has the default name of 'app'
      -Flask will automatically look for this!
      -Run: flask run --debug
      -
      -

      If you called your app something other than 'app', like 'new' for example, you will see:

      -
      ===================
      -Flask app deployed!
      -===================
      -
      -Your app has the name of 'new'
      -Run: flask --app new run --debug
      -
      -

      As you can see from the output, it gives you instructions on how to start your app, depending on the name you gave it.

      -

      You should see a new folder that has been given the name you specified in -the flask-imp init command.

      -

      Additional options

      -

      You can also specify a name for your app in the command itself, like so:

      -
      flask-imp init -n my_app
      -
      -

      This will create a new app called 'my_app'.

      -

      You can also deploy a slim app, that will have one blueprint and no models, like so:

      -
      flask-imp init -n my_app --slim
      -
      -

      You can also deploy a minimal app, that will have no blueprints, models, or extensions, like so:

      -
      flask-imp init -n my_app --minimal
      -
      -

      init Folder structures

      -

      Full app

      -

      flask-imp init:

      -
      app/
      -├── blueprints
      -│   └── www
      -│       ├── config.toml
      -│       ├── __init__.py
      -│       ├── routes
      -│       │   └── index.py
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       └── templates
      -│           └── www
      -│               ├── extends
      -│               │   └── main.html
      -│               ├── includes
      -│               │   ├── footer.html
      -│               │   └── header.html
      -│               └── index.html
      -│
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── context_processors
      -│   │   └── context_processors.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── filters
      -│   │   └── filters.py
      -│   ├── routes
      -│   │   └── routes.py
      -│   ├── static
      -│   │   └── favicon.ico
      -│   └── templates
      -│       ├── errors
      -│       │   ├── 400.html
      -│       │   ├── 401.html
      -│       │   ├── 403.html
      -│       │   ├── 404.html
      -│       │   ├── 405.html
      -│       │   └── 500.html
      -│       └── index.html
      -│
      -├── models
      -│   ├── example_user_table.py
      -│   └── __init__.py
      -│
      -├── __init__.py
      -└── default.config.toml
      -
      -

      Slim app

      -

      flask-imp init --slim:

      -
      app/
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── static
      -│   │   └── favicon.ico
      -│   └── templates
      -│       └── errors
      -│           ├── 400.html
      -│           ├── 401.html
      -│           ├── 403.html
      -│           ├── 404.html
      -│           ├── 405.html
      -│           └── 500.html
      -│
      -├── www
      -│   ├── config.toml
      -│   ├── __init__.py
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── js
      -│   │       └── main.js
      -│   └── templates
      -│       └── www
      -│           ├── extends
      -│           │   └── main.html
      -│           ├── includes
      -│           │   ├── footer.html
      -│           │   └── header.html
      -│           └── index.html
      -│
      -├── __init__.py
      -└── default.config.toml
      -
      -

      Minimal app

      -

      flask-imp init --minimal:

      -
      app/
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── favicon.ico
      -│   ├── templates
      -│   │   └── index.html
      -│   └── routes.py
      -│
      -├── __init__.py
      -└── default.config.toml
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-authenticate_password.html b/archive_docs/v3/flask_imp_auth-authenticate_password.html deleted file mode 100644 index 0416efb0..00000000 --- a/archive_docs/v3/flask_imp_auth-authenticate_password.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - - Authenticate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      authenticate_password - flask_imp.auth

      -
      from flask_imp.auth import authenticate_password
      -
      -
      authenticate_password(
      -    input_password: str,
      -    database_password: str,
      -    database_salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end",
      -    use_multiprocessing: bool = False
      -) -> bool
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / encrypt_password function.

      -

      Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match.

      -

      Note:

      -

      use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.

      -

      If you are using socketio, you must set use_multiprocessing to False (default).

      -

      Note:

      -
        -
      • You must know the pepper length used to hash the password.
      • -
      • You must know the position of the pepper used to hash the password.
      • -
      • You must know the encryption level used to hash the password.
      • -
      -

      Authentication Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
      input_password = "password"
      -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database
      -database_salt = "^%$*" # pulled from database
      -
      -authenticate_password(
      -    input_password,
      -    database_password,
      -    database_salt
      -)  # >>> True
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-encrypt_password.html b/archive_docs/v3/flask_imp_auth-encrypt_password.html deleted file mode 100644 index 8079f4e2..00000000 --- a/archive_docs/v3/flask_imp_auth-encrypt_password.html +++ /dev/null @@ -1,293 +0,0 @@ - - - - - Encrypt_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      encrypt_password - flask_imp.auth

      -
      from flask_imp.auth import encrypt_password
      -
      -
      encrypt_password(
      -    password: str,
      -    salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end"
      -) -> str
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / authenticate_password function.

      -

      Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified.

      -

      Can set the encryption level to 256 or 512, defaults to 512.

      -

      Can set the pepper length, defaults to 1. Max is 3.

      -

      Can set the pepper position, "start" or "end", defaults to "end".

      -

      Note:

      -
        -
      • You must inform the authenticate_password function of the pepper length used to hash the password.
      • -
      • You must inform the authenticate_password function of the position of the pepper used to hash the password.
      • -
      • You must inform the authenticate_password function of the encryption level used to hash the password.
      • -
      -

      Encryption Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
        -
      1. Pepper is added to the end of the plain password: "passwordA"
      2. -
      3. Salt is added to the end of the peppered password: "passwordA^%$*"
      4. -
      5. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..."
      6. -
      7. Salt and hashed password are then stored in the database.
      8. -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_alphanumeric_validator.html b/archive_docs/v3/flask_imp_auth-generate_alphanumeric_validator.html deleted file mode 100644 index 80f57035..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_alphanumeric_validator.html +++ /dev/null @@ -1,269 +0,0 @@ - - - - - Generate_alphanumeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_alphanumeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_alphanumeric_validator
      -
      -
      generate_alphanumeric_validator(length: int = 8) -> str
      -
      -
      -

      Generates a random alphanumeric string of the given length.

      -

      (letters are capitalized)

      -
      Example:
      -
      generate_alphanumeric_validator(8)  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_csrf_token.html b/archive_docs/v3/flask_imp_auth-generate_csrf_token.html deleted file mode 100644 index 1cab20ac..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_csrf_token.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - Generate_csrf_token - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_csrf_token - flask_imp.auth

      -
      from flask_imp.auth import generate_csrf_token
      -
      -
      generate_csrf_token() -> str
      -
      -
      -

      Generates a SHA1 using the current date and time.

      -

      For use in Cross-Site Request Forgery.

      -

      Also used by the flask_imp.security / csrf_protect decorator.

      -
      Example:
      -
      generate_csrf_token()  # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_email_validator.html b/archive_docs/v3/flask_imp_auth-generate_email_validator.html deleted file mode 100644 index a2d4a35c..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_email_validator.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - Generate_email_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_email_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_email_validator
      -
      -
      generate_email_validator() -> str
      -
      -
      -

      Uses generate_alphanumeric_validator with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email.

      -

      See flask_imp.auth / generate_alphanumeric_validator -for more information.

      -
      Example:
      -
      generate_email_validator()  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_numeric_validator.html b/archive_docs/v3/flask_imp_auth-generate_numeric_validator.html deleted file mode 100644 index fb8e6c2d..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_numeric_validator.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - Generate_numeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_numeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_numeric_validator
      -
      -
      generate_numeric_validator(length: int) -> int
      -
      -
      -

      Generates random choice between 1 * (length) and 9 * (length).

      -

      If the length is 4, it will generate a number between 1111 and 9999.

      -

      For use in MFA email, or unique filename generation.

      -
      Example:
      -
      generate_numeric_validator(4)  # >>> 1234
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_password.html b/archive_docs/v3/flask_imp_auth-generate_password.html deleted file mode 100644 index e6bc430d..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_password.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - Generate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_password - flask_imp.auth

      -
      from flask_imp.auth import generate_password
      -
      -
      generate_password(style: str = "mixed", length: int = 3) -> str
      -
      -
      -

      Generates a password of (length) characters.

      -

      The Default length is 3.

      -

      Style options: "animals", "colors", "mixed" - defaults to "mixed"

      -
      Example:
      -
      generate_password(style="animals", length=3)  # >>> 'Cat-Goat-Pig12'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_private_key.html b/archive_docs/v3/flask_imp_auth-generate_private_key.html deleted file mode 100644 index b7f48bb3..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_private_key.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - Generate_private_key - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_private_key - flask_imp.auth

      -
      from flask_imp.auth import generate_private_key
      -
      -
      generate_private_key(hook: t.Optional[str]) -> str
      -
      -
      -

      Generates a sha256 private key from a passed in hook value.

      -

      If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000.

      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt,
      -            private_key=generate_private_key(hook=username)
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-generate_salt.html b/archive_docs/v3/flask_imp_auth-generate_salt.html deleted file mode 100644 index fbe5dc0c..00000000 --- a/archive_docs/v3/flask_imp_auth-generate_salt.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - Generate_salt - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_salt - flask_imp.auth

      -
      from flask_imp.auth import generate_salt
      -
      -
      generate_salt(length: int = 4) -> str
      -
      -
      -

      Generates a string of (length) characters of punctuation.

      -

      The Default length is 4.

      -

      For use in password hashing and storage of passwords in the database.

      -
      Example:
      -
      generate_salt()  # >>> '*!$%'
      -
      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-is_email_address_valid.html b/archive_docs/v3/flask_imp_auth-is_email_address_valid.html deleted file mode 100644 index bb8d331c..00000000 --- a/archive_docs/v3/flask_imp_auth-is_email_address_valid.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - Is_email_address_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_email_address_valid - flask_imp.auth

      -
      from flask_imp.auth import is_email_address_valid
      -
      -
      is_email_address_valid(
      -    email_address: str
      -) -> bool
      -
      -
      -

      Checks if an email address is valid.

      -

      Is not completely RFC 5322 compliant, but it is good enough for most use cases.

      -

      Here are examples of mistakes that it will not catch:

      -
      Valid but fails:
      -
      email@[123.123.123.123]
      -“email”@example.com
      -very.unusual.“@”.unusual.com@example.com
      -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com
      -
      -
      Invalid but passes:
      -
      email@example.com (Joe Smith)
      -email@111.222.333.44444
      -
      -
      Example:
      -
      is_email_address_valid('hello@example.com')  # >>> True
      -
      -is_email_address_valid('hello@hello@example.com')  # >>> False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_auth-is_username_valid.html b/archive_docs/v3/flask_imp_auth-is_username_valid.html deleted file mode 100644 index a351d37f..00000000 --- a/archive_docs/v3/flask_imp_auth-is_username_valid.html +++ /dev/null @@ -1,293 +0,0 @@ - - - - - Is_username_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_username_valid - flask_imp.auth

      -
      from flask_imp.auth import is_username_valid
      -
      -
      is_username_valid(
      -    username: str,
      -    allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None
      -) -> bool
      -
      -
      -

      Checks if a username is valid.

      -

      Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned.

      -
      Example "all":
      -
      is_username_valid("username", allowed=["all"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user_name : WILL PASS : True
      -_user_name : WILL PASS : False
      -
      -
      Example "dot", "dash":
      -
      is_username_valid("username", allowed=["dot", "dash"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user-name.name : WILL PASS : True
      -user_name : WILL PASS : False
      -_user_name : WILL PASS : False
      -.user.name : WILL PASS : False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_security-api_login_check.html b/archive_docs/v3/flask_imp_security-api_login_check.html deleted file mode 100644 index a9612e8f..00000000 --- a/archive_docs/v3/flask_imp_security-api_login_check.html +++ /dev/null @@ -1,285 +0,0 @@ - - - - - Api_login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      api_login_check - flask_imp.security

      -
      from flask_imp.security import api_login_check
      -
      -
      api_login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_json: t.Optional[t.Dict[str, t.Any]] = None
      -)
      -
      -

      @api_login_check(...)

      -
      -

      A decorator that is used to secure API routes that return JSON responses.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_json JSON that is returned on failure. {"error": "You are not logged in."} by default.

      -
      Example:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True)
      -def api_page():
      -    ...
      -
      -
      Example of defined fail_json:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."})
      -def api_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_security-include_csrf.html b/archive_docs/v3/flask_imp_security-include_csrf.html deleted file mode 100644 index ef2d641f..00000000 --- a/archive_docs/v3/flask_imp_security-include_csrf.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Include_csrf - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      include_csrf - flask_imp.security

      -
      from flask_imp.security import include_csrf
      -
      -
      include_csrf(
      -    session_key: str = "csrf",
      -    form_key: str = "csrf",
      -    abort_code: int = 401
      -)
      -
      -

      @include_csrf(...)

      -
      -

      A decorator that handles CSRF protection.

      -

      On a GET request, a CSRF token is generated and stored in the session key -specified by the session_key parameter.

      -

      On a POST request, the form_key specified is checked against the session_key -specified.

      -
        -
      • If they match, the request is allowed to continue.
      • -
      • If no match, the response will be abort(abort_code), default 401.
      • -
      -
      @bp.route("/admin", methods=["GET", "POST"])
      -@include_csrf(session_key="csrf", form_key="csrf")
      -def admin_page():
      -    ...
      -    # You must pass in the CSRF token from the session into the template.
      -    # Then add <input type="hidden" name="csrf" value="{{ csrf }}"> to the form.
      -    return render_template("admin.html", csrf=session.get("csrf"))
      -
      -

      Form key:

      -
      <input type="hidden" name="csrf" value="{{ csrf }}">
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_security-login_check.html b/archive_docs/v3/flask_imp_security-login_check.html deleted file mode 100644 index 98dd54da..00000000 --- a/archive_docs/v3/flask_imp_security-login_check.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - - Login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      login_check - flask_imp.security

      -
      from flask_imp.security import login_check
      -
      -
      login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    pass_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @login_check(...)

      -
      -

      A decorator that checks if the specified session key exists and contains the specified value.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example of a route that requires a user to be logged in:
      -
      @bp.route("/admin", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    fail_endpoint='blueprint.login_page',
      -    message="Login needed"
      -)
      -def admin_page():
      -    ...
      -
      -
      Example of a route that if the user is already logged in, redirects to the specified endpoint:
      -
      @bp.route("/login-page", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    pass_endpoint='blueprint.admin_page',
      -    message="Already logged in"
      -)
      -def login_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_security-pass_function_check.html b/archive_docs/v3/flask_imp_security-pass_function_check.html deleted file mode 100644 index 6bcec06c..00000000 --- a/archive_docs/v3/flask_imp_security-pass_function_check.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - - Pass_function_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      pass_function_check - flask_imp.security

      -
      from flask_imp.security import pass_function_check
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/flask_imp_security-permission_check.html b/archive_docs/v3/flask_imp_security-permission_check.html deleted file mode 100644 index 3fbb4dd9..00000000 --- a/archive_docs/v3/flask_imp_security-permission_check.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - Permission_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      permission_check - flask_imp.security

      -
      from flask_imp.security import permission_check
      -
      -
      permission_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @permission_check(...)

      -
      -

      A decorator that checks if the specified session key exists and its value(s) match the specified value(s).

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example:
      -
      @bp.route("/admin-page", methods=["GET"])
      -@login_check(
      -    'logged_in', 
      -    True, 
      -    'blueprint.login_page'
      -)  # can be mixed with login_check
      -@permission_check(
      -    'permissions', 
      -    ['admin'], 
      -    fail_endpoint='www.index', 
      -    message="Failed message"
      -)
      -def admin_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp-introduction.html b/archive_docs/v3/imp-introduction.html deleted file mode 100644 index a833ea4b..00000000 --- a/archive_docs/v3/imp-introduction.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - Flask-Imp Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Introduction

      -

      Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources from a Flask application. It uses the importlib module to achieve this.

      -

      Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using only -Blueprints. However, you can use Flask-Imp without using Blueprints.

      -

      Here's an example of a standard Flask-Imp project structure:

      -
      app/
      -├── blueprints/
      -│   ├── admin/...
      -│   ├── api/...
      -│   └── www/...
      -├── resources/
      -│   ├── filters/...
      -│   ├── context_processors/...
      -│   ├── static/...
      -│   └── templates/...
      -├── models/...
      -├── default.config.toml
      -└── __init__.py
      -
      -

      Here's an example of the app/__init__.py file:

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -from flask_imp import Imp
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -    db.init_app(app)
      -
      -    imp.import_app_resources("resources")
      -    imp.import_models("models")
      -    imp.import_blueprints("blueprints")
      -
      -    return app
      -
      -

      During imp.init_app the default.config.toml file will load variables under [FLASK] into the Flask app config. -It will also load variables under [DATABASE] into the Flask app config as SQLALCHEMY_DATABASE_URI.

      -

      Values under [SESSION] can be loaded with:

      -
      @app.before_request
      -def before_request():
      -    imp.init_session()
      -
      -

      See more about the config file here: Imp / x.config.toml

      -

      import_app_resources will walk one level deep into the resources folder, and import all .py files as modules. It will -also check for the existence of a static and templates folder, and register them with the Flask app.

      -

      There is a couple of options for import_app_resources to control what -is imported, see: Imp.x / import_app_resources

      -

      import_models will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via imp.model

      -

      See more about how import_models and the lookup -here: Imp.x / import_models and Imp.x / model

      -

      import_blueprints expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's __init__.py file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app.

      -

      See more about how importing blueprints work here: Blueprint / Introduction

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp-load-env-vars.html b/archive_docs/v3/imp-load-env-vars.html deleted file mode 100644 index 821ef8be..00000000 --- a/archive_docs/v3/imp-load-env-vars.html +++ /dev/null @@ -1,277 +0,0 @@ - - - - - Load Enviroment Variables Into The Config File | Flask-Imp - - - - - - - - - - - - - - -
      -

      Load Enviroment Variables into the Config File

      -

      <> markers can be used to find variables set in the environment. For example:

      -

      File: default.config.toml

      -
      [FLASK]
      -# ...
      -
      -ERROR_404_HELP = true
      -SERVER_NAME = "<FLASK_SERVER_NAME>"
      -APPLICATION_ROOT = "/"
      -
      -# ...
      -
      -

      <FLASK_SERVER_NAME> will be replaced by the value of FLASK_SERVER_NAME

      -

      Development .env

      -
      FLASK_SERVER_NAME=localhost:5000
      -
      -

      Production .env

      -
      FLASK_SERVER_NAME=mysite.com
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp-x-config-toml.html b/archive_docs/v3/imp-x-config-toml.html deleted file mode 100644 index b7bc02b8..00000000 --- a/archive_docs/v3/imp-x-config-toml.html +++ /dev/null @@ -1,373 +0,0 @@ - - - - - The Flask-Imp Config File | Flask-Imp - - - - - - - - - - - - - - -
      -

      The Flask-Imp Config File

      -

      Flask-Imp loads configuration settings from a toml file found in the root of your app package.

      -

      app/default.config.toml is the default config file, this will be created if no config file is found or set.

      -

      Here's an example file structure:

      -
      Project/
      -├── app/
      -│   ├── ...
      -│   ├── __init__.py
      -│   └── default.config.toml
      -├── venv/...
      -└── ...
      -
      -

      Here's an example of the default config file that is created:

      -
      # Flask-Imp Config File
      -# ------------------------
      -# Updates the Flask app config with the variables below.
      -# If any variable below does not exist in the standard Flask env
      -# vars it is created and will be accessible using
      -# app.config. All key names defined below will be
      -# capitalised when imported.
      -[FLASK]
      -DEBUG = false
      -#PROPAGATE_EXCEPTIONS = true
      -TRAP_HTTP_EXCEPTIONS = false
      -#TRAP_BAD_REQUEST_ERRORS = true
      -SECRET_KEY = "super_secret_key"
      -SESSION_COOKIE_NAME = "session"
      -#SESSION_COOKIE_DOMAIN = "domain-here.com"
      -#SESSION_COOKIE_PATH = "/"
      -SESSION_COOKIE_HTTPONLY = true
      -SESSION_COOKIE_SECURE = false
      -SESSION_COOKIE_SAMESITE = "Lax"
      -PERMANENT_SESSION_LIFETIME = 3600  # 1 hour
      -SESSION_REFRESH_EACH_REQUEST = true
      -USE_X_SENDFILE = false
      -#SEND_FILE_MAX_AGE_DEFAULT = 43200
      -ERROR_404_HELP = true
      -#SERVER_NAME = "localhost:5000"
      -APPLICATION_ROOT = "/"
      -PREFERRED_URL_SCHEME = "http"
      -#MAX_CONTENT_LENGTH = 0
      -#TEMPLATES_AUTO_RELOAD = true
      -EXPLAIN_TEMPLATE_LOADING = false
      -MAX_COOKIE_SIZE = 4093
      -
      -
      -# This will set the default session variables for the app.
      -# Anything here will be accessible using session["your_var_name"]
      -# or session.get("your_var_name")
      -[SESSION]
      -logged_in = false
      -
      -# These settings are spcific to the Flask-SQLAlchemy extension.
      -# Anything here will be accessible using app.config
      -[SQLALCHEMY]
      -SQLALCHEMY_ECHO = false
      -SQLALCHEMY_TRACK_MODIFICATIONS = false
      -SQLALCHEMY_RECORD_QUERIES = false
      -# Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy.
      -# This sets the file extension for SQLite databases, and where to create the folder
      -# that the database will be stored in. true will create the folder on the same level as your
      -# app, false will create the folder in the app root.
      -SQLITE_DB_EXTENSION = ".sqlite"
      -SQLITE_STORE_IN_PARENT = true
      -
      -# [DATABASE.MAIN] is loaded as SQLALCHEMY_DATABASE_URI
      -# Dialets = mysql / postgresql / sqlite / oracle / mssql
      -
      -# Uncomment below to generate the SQLALCHEMY_DATABASE_URI.
      -#[DATABASE.MAIN]
      -#ENABLED = true
      -#DIALECT = "sqlite"
      -#DATABASE_NAME = "database"
      -#LOCATION = "db"
      -#PORT = ""
      -#USERNAME = "database"
      -#PASSWORD = "password"
      -
      -# Adding another database is as simple as adding a new section.
      -# [DATABASE.ANOTHER] will then be accessible using SQLALCHEMY_BINDS
      -# The bind key will be stored as a lowercase value, so "ANOTHER" will
      -# be accessible as "another"
      -# You can then use the bind key in the model as follows:
      -# class MyModel(db.Model):
      -#     __bind_key__ = "another"
      -#     ...
      -
      -# Uncomment below to generate and add to SQLALCHEMY_BINDS.
      -#[DATABASE.ANOTHER]
      -#ENABLED = true
      -#DIALECT = "sqlite"
      -#DATABASE_NAME = "database_another"
      -#LOCATION = "db"
      -#PORT = ""
      -#USERNAME = "user"
      -#PASSWORD = "password"
      -
      -

      To change what config file is loaded, you can set the IMP_CONFIG environment -variable to the name of the config file you want to load.

      -

      For example, given the following folder structure:

      -
      Project/
      -├── app/
      -│   ├── ...
      -│   ├── __init__.py
      -│   ├── production.config.toml
      -│   └── default.config.toml
      -├── venv/...
      -└── ...
      -
      -

      You'd set the IMP_CONFIG=production.config.toml

      -

      Or you can set the file in the imp.init_app() method:

      -
      def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app, app_config_file="production.config.toml")
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-import_app_resources.html b/archive_docs/v3/imp_x-import_app_resources.html deleted file mode 100644 index 33a60247..00000000 --- a/archive_docs/v3/imp_x-import_app_resources.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - Imp.import_app_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_app_resources

      -
      import_app_resources(
      -    folder: str = "resources",
      -    factories: Optional[List] = None,
      -    static_folder: str = "static",
      -    templates_folder: str = "templates",
      -    files_to_import: Optional[List] = None,
      -    folders_to_import: Optional[List] = None,
      -    ) -> None
      -
      -
      -

      Import standard app resources from the specified folder.

      -

      This will import any resources that have been set to the Flask app.

      -

      Routes, context processors, cli, etc.

      -

      Can only be called once.

      -

      If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config.

      -

      Small example of usage:

      -
      imp.import_app_resources(folder="resources")
      -# or
      -imp.import_app_resources()
      -# as the default folder is "resources"
      -
      -

      Folder Structure: resources

      -
      app
      -├── resources
      -│   ├── routes.py
      -│   ├── app_fac.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   └── templates
      -│       └── index.html
      -└── ...
      -...
      -
      -

      File: routes.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      How factories work

      -

      Factories are functions that are called when importing the app resources. Here's an example:

      -
      imp.import_app_resources(
      -    folder="resources",
      -    factories=["development_cli"]
      -)
      -
      -

      ["development_cli"] => development_cli(app) function will be called, and the current app will be passed in.

      -

      File: app_fac.py

      -
      def development_cli(app):
      -    @app.cli.command("dev")
      -    def dev():
      -        print("dev cli command")
      -
      -

      Scoping imports

      -

      By default, all files and folders will be imported.

      -

      To disable this, set files_to_import and or -folders_to_import to [None].

      -
      imp.import_app_resources(files_to_import=[None], folders_to_import=[None])
      -
      -

      To scope the imports, set the files_to_import and or folders_to_import to a list of files and or folders.

      -

      files_to_import=["cli.py", "routes.py"] => will only import the files resources/cli.py -and resources/routes.py

      -

      folders_to_import=["template_filters", "context_processors"] => will import all files in the folders -resources/template_filters/*.py and resources/context_processors/*.py

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-import_blueprint.html b/archive_docs/v3/imp_x-import_blueprint.html deleted file mode 100644 index 52528109..00000000 --- a/archive_docs/v3/imp_x-import_blueprint.html +++ /dev/null @@ -1,343 +0,0 @@ - - - - - Imp.import_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprint

      -
      import_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root.

      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprint("my_blueprint")
      -
      -    return app
      -
      -

      Flask-Imp Blueprints have the ability to import configuration from a toml file, import resources, and initialize session -variables.

      -

      For more information on how Flask-Imp Blueprints work, see the Blueprint / Introduction

      -
      Example of 'my_blueprint' as a Flask-Imp Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   ├── templates
      -│   │   └── my_blueprint
      -│   │       └── index.html
      -│   ├── __init__.py
      -│   └── config.toml
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -
      -
      -@bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      -

      File: routes / index.py

      -
      from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -
      Example of 'my_blueprint' as a standard Flask Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask import Blueprint
      -
      -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint")
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -

      Both of the above examples will work with imp.import_blueprint("my_blueprint"), they will be registered -with the Flask app, and will be accessible via url_for("my_blueprint.index").

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-import_blueprints.html b/archive_docs/v3/imp_x-import_blueprints.html deleted file mode 100644 index 239adc29..00000000 --- a/archive_docs/v3/imp_x-import_blueprints.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - Imp.import_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprints

      -
      import_blueprints(self, folder: str) -> None
      -
      -
      -

      Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root.

      -
      app/
      -├── blueprints/
      -│   ├── admin/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   ├── www/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   └── api/
      -│       ├── ...
      -│       └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprints("blueprints")
      -
      -    return app
      -
      -

      This will import all Blueprints from the blueprints folder using the Imp.import_blueprint method. -See Imp.x / import_blueprint for more information.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-import_models.html b/archive_docs/v3/imp_x-import_models.html deleted file mode 100644 index 012524d0..00000000 --- a/archive_docs/v3/imp_x-import_models.html +++ /dev/null @@ -1,318 +0,0 @@ - - - - - Imp.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_models

      -
      import_models(file_or_folder: str) -> None
      -
      -
      -

      Imports all the models from the given file or folder relative to the Flask app root.

      -

      Each Model that is imported will be available in the imp.model lookup method. -See Imp.x / model for more information.

      -
      Example of importing models from a file
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── users_model.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -
      -from flask_imp import Imp
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -    db.init_app(app)  # must be below imp.init_app
      -
      -    imp.import_blueprint("my_blueprint")
      -    imp.import_models("users_model.py")
      -
      -    return app
      -
      -

      File: app/users_model.py

      -
      from app import db
      -
      -
      -class User(db.Model):
      -    attribute = db.Column(db.String(255))
      -
      -
      Example of importing models from a folder
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── models/
      -│   ├── boats.py
      -│   ├── cars.py
      -│   └── users.py
      -├── ...
      -└── __init__.py
      -
      -
      def create_app():
      -    ...
      -    imp.import_models("models")
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-init_app-init.html b/archive_docs/v3/imp_x-init_app-init.html deleted file mode 100644 index e75a6127..00000000 --- a/archive_docs/v3/imp_x-init_app-init.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - Imp.init_app, __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_app, __init__

      -
      init_app(
      -    app: Flask,
      -    app_config_file: Optional[str] = None,
      -    ignore_missing_env_variables: bool = False
      -) -> None
      -# -or- 
      -Imp(
      -    app: Optional[Flask] = None,
      -    app_config_file: Optional[str] = None,
      -    ignore_missing_env_variables: bool = False
      -) -> None
      -
      -
      -

      Initializes the flask app to work with flask-imp.

      -

      If no app_config_file specified, an attempt to read IMP_CONFIG from the environment will be made.

      -

      If IMP_CONFIG is not in the environment variables, an attempt to load default.config.toml will be made.

      -

      default.config.toml will be created, and used if not found.

      -

      If ignore_missing_env_variables is True, then missing environment variables will be ignored.

      -

      If ignore_missing_env_variables is False (default), then missing environment variables will raise a ValueError

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-init_session.html b/archive_docs/v3/imp_x-init_session.html deleted file mode 100644 index d0148503..00000000 --- a/archive_docs/v3/imp_x-init_session.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - Imp.init_session | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_session

      -
      init_session() -> None
      -
      -
      -

      Initialize the session variables found in the config. Commonly used in app.before_request.

      -
      @app.before_request
      -def before_request():
      -    imp.init_session()
      -
      -

      File: default.config.toml

      -
      ...
      -[SESSION]
      -logged_in = false
      -...
      -
      -

      logged_in is now available in the session.

      -
      @app.route('/get-session-value')
      -def login():
      -    print(session['logged_in'])
      -    return "Check Terminal"
      -
      -

      Output: False

      -

      Can also be used to reset the values in the session. Here's an example:

      -
      @app.route('/logout')
      -def logout():
      -    session.clear()
      -    imp.init_session()
      -    return redirect(url_for('index'))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/imp_x-model.html b/archive_docs/v3/imp_x-model.html deleted file mode 100644 index 364994f9..00000000 --- a/archive_docs/v3/imp_x-model.html +++ /dev/null @@ -1,294 +0,0 @@ - - - - - Imp.model | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.model

      -
      model(class_: str) -> DefaultMeta
      -
      -
      -

      Returns the SQLAlchemy model class for the given class name that was imported using Imp.import_models or -Blueprint.import_models.

      -

      This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting.

      -

      For example:

      -
      from app.models.boats import Boats
      -from app.models.cars import Cars
      -
      -

      Can be replaced with:

      -
      from app import imp
      -
      -Boats = imp.model("Boats")
      -Cars = imp.model("Cars")
      -
      -

      Or used directly:

      -
      from app import imp
      -
      -all_boats = imp.model("Boats").select_all()
      -
      -

      file: models/boats.py

      -
      from app import db
      -
      -
      -class Boats(db.Model):
      -    name = db.Column(db.String())
      -
      -    @classmethod
      -    def select_all(cls):
      -        return db.session.execute(
      -            db.select(cls)
      -        ).scalars().all()
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v3/index.html b/archive_docs/v3/index.html deleted file mode 100644 index 368882a1..00000000 --- a/archive_docs/v3/index.html +++ /dev/null @@ -1,336 +0,0 @@ - - - - - Flask-Imp - - - - - - - - - - - - - - -
      -

      Welcome to the Flask-Imp Documentation

      -

      What is Flask-Imp?

      -

      Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication.

      -

      Install Flask-Imp

      -
      pip install flask-imp
      -
      -

      Getting Started

      -

      To get started right away, you can utilize the CLI commands to create a new Flask-Imp project.

      -
      flask-imp init
      -
      -

      Minimal Flask-Imp Setup

      -

      Run the following command to create a minimal Flask-Imp project.

      -
      flask-imp init -n app --minimal
      -
      -

      See CLI Commands / flask-imp init for more information.

      -

      Build minimal manually

      -

      Folder Structure

      -
      app/
      -├── resources/
      -│   ├── static/...
      -│   ├── templates/
      -│   │   └── index.html
      -│   └── index.py
      -├── default.config.toml
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_app_resources()
      -    # Takes argument 'folder' default folder is 'resources'
      -
      -    return app
      -
      -

      File: app/resources/index.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      File: app/resources/templates/index.html

      -
      <!DOCTYPE html>
      -<html lang="en">
      -<head>
      -    <meta charset="UTF-8">
      -    <title>Flask-Imp</title>
      -</head>
      -<body>
      -<h1>Flask-Imp</h1>
      -</body>
      -</html>
      -
      -
      -

      We recommend using a virtual environment, then installing Flask-Imp.

      -

      Linux / MacOS

      -
      python3 -m venv venv
      -
      -
      source venv/bin/activate
      -
      -

      Windows

      -
      python -m venv venv
      -
      -
      .\venv\Scripts\activate
      -
      - -
      - - - - \ No newline at end of file diff --git a/archive_docs/v3/static/Flask-Imp-Medium.png b/archive_docs/v3/static/Flask-Imp-Medium.png deleted file mode 100644 index 1140eb4cc5c4f9538ea0a3c788db40a8fe08a663..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7987 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 diff --git a/archive_docs/v3/static/android-chrome-192x192.png b/archive_docs/v3/static/android-chrome-192x192.png deleted file mode 100644 index 1207f940bfb8ce81bb79fded911cd9167265ce42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15163 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 diff --git a/archive_docs/v3/static/android-chrome-256x256.png b/archive_docs/v3/static/android-chrome-256x256.png deleted file mode 100644 index 34e3d27479cf54144da963f21a635d7487f171ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20999 zcmV*9Kybf_P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Ri2^9$_AjF{Ys{jB{gGod|RCwC$y?Kmm*?r&l z`JHp`t)=(3&3p6a%|62+DGgKTrUNDm;j=V0;h+9$lO%x+s0P&%;g71?YCU`Ec7W{4V$9%?*7|5pMa=tvttGI43uB zEfuB|a`Zz~I0%Mz_XOR=m&04>%%~Rbi%pz!h4!`NiQO%(pJ_9N^ zTqP_fk4ghL9vF1NJ`TJPUi%%ug>VmW1r-LK$^1?>+=elKgyR*cz<2`{B5wg7pu*zo zzzqfhrqnDdOc<2_7z4sC4+9NL!p(%|7Tt-Xq1Q?^J7=Kw_ZZmkCrw)`O@cf;A2vx0 z1D`~x4Y9hqS_*+-)1xvY#)wJ)j1LCg#RYZVeLCFEq3Zif=)|w16TMX5YvKPR20QXe zTl_FEL0%5eKgmECbi?CP19%I#1N=6s4ZMqL4%fqHDvSvyabiskhIaaxf#)4y4ps4= zXCMeZi7xtc=)!oOYWz#Q2i!wV0|&ehyczB{!)u$U-=K|-TL$<_J2)CD4dCbybWvXh z{xx*6{!ZW-;8_M^EW7+)1;x|AQw;ncWfbCl)UkLE_$A;KR7()lhmarSODa5wN&t)o zS-6$na~OEt&0!CE${@QumZ4keA4$;9{$gT$+pVAQ* zq4DPO_$ulw{QIbo{cSWGvGflNYhyqaP1p^U39vUTx}*OH zI+6YWYNtMjPPiKC>4v?NYbuNf2KWIqs`4dt(SLv@A+>?tD z5$@;0rBJbxVBHC_zwRnEPW zi86Ws@HQGjcm@4!ucF$)dqDRzYXYa;2T)eveG2$#wB~-{NJp$NEr=M*@0ZcYz%${s z9vVWtcHAd<+&C2iU?{X#hV)9Jj0@p@nSyoe-9c$T4s>sQ(<-yqhVZte;4@Ez%QZ;|J%UNqJD$!p^kn+F_S)kAgsBn8S)Fvga8Qm9JjGz>Ef`N&>;tX9K0*M1Zf|`}L7@Do4cdSy zk1r1nq8HJ6+i+iq3XoEW478F5HIZZgLH38T6g(L^SU^5y>+y70e* zO6?k2pC5C~j=tFI5>CQyJy+;1Z}7|)1&MdmoG!z?=q{g%%F{wrV5MTnMUT-nLN11`7zAip zOD3u%0CbGL2e58!UvNx0N;3e|A8-x$yWzFh&@iGUP?McRv*09a00uaV*69~0QO7gK zeNrU^U8n$ah2u<-b0N!U26g?hEM>09Styj&uHg!d_uI9E;e!o5*lQa)$o6FX4!vZX z|6s3c8v2lba97X8&<$q8?YPF4vD}Q6Dq$^(Shp4rv`o-brr%r`rgZx}8a5nmpY|P8 z0F=>#6NeKc0Ctq^3IiM8483+NFsQ0)`p-S$QJWp8c}MIW7LW1z*?zCBpF6WwyUQcPbsHvhyD}59Wq3#_yLLR97N@rp*BoL-}HCYBU?u+61I#8^xuAVsO z;E53c0SW5uPk{dx?W$8U$xbAdcc&e1yysk=F<%rsk!E;-OKFd#B4;H}b-|-5yZFH# zu0rF{-ujb-$a`$iXf8X|oS*Hs0dPZ626ZA@ZpSqQ_&7?~u$FgfbzE>Hc8nR)Ql@5n z8o(byW&ZB~eg+L0{>Law@z!yl;6X9<0$|AAkI{177f`AD0!r91k?@}N9t+GDh0@WK zUU}eLmeO>N3%Ppm&*mv}MZsKA1g&6-_p=eB-_kfNUb~Blk$ClAxKab~o`u3C5Vnlz`z?<7^2+&E_HfM5Ow)IOuZ8)V0>w$t2BuyB1jMMl|A&A-k2+nR zoaFg8yr=0LpKfm{+z$uiJ&mHEQE1bjOKE9VYbc^+Bi5ss zcWMn<*3veHH|h=LUY{Pn!P#(gz<-UBlKw|}5!~X0Xagrj0C)!cZslzv>#Y2ee!p!| zUDhN09myemTerf&G3<_%ke{F-#&X{saWHP7pMo!1PUk0-+UI z)@;nZD8U2o*6Os4;l7=Ul8!Fg+wiNXdHT1);~Px5DKK>!z>v*vQ30@s#`k}mLC?Lh zqwXAwMZptU4~OtfugiRqZxcBuM$DfuMBWqof`%*l+o{imJ5j-$(+J8&WQo0{E8BAy z5Y1|wFzV=B{ZVvH{TABT^gfV=uE$d;2&PT|1YAOE`2Ta@GYn$>6ZvIh@A-lD7U%Pf zE4?mWgqnBwsnwTe4-aHdde50GWhGAmc%jpxYYf+u1_saT^(MFCm;&Kik{pL{j?gr8 z0sb=ZCxO3$h6t~t`~p*lX%zrvT}hJxN8iNq`30zXPZDkfuXQw(sH4JQIBmDWxM9@! z0zibvdm-^IWb5b~UIwXqvg3Xtr>JN!s63tOsWBCM+K}4+IO^;90`L=PA;uHoV-sWN zjlAdSUXM9f^ow)mik#Sc=7U;VbB&``k#{7n@&!y1xdDb z#}CDw=L$#7JFa9Y0<7dYE4dbhJ(+fCx`JA83Raj5BJVjHOoFp{5Am9ge6yDEUQ*+g z<~#;ZH`FXla3Uq)_NUN!{qtyZlGjkdFf}-K4Iu3PPXd>LzlN$$k24@}Joa-0O>8k} zTCYbqpQfD8dU#+d%cyzBLQ&v>1?Q+S&=z9vsrkxKm;^kK8cWw0HjPFI-mf=Vvk~8J zH1KFqQ$Cq|f|6P2Ch$J+KLTGv^H|=wdiCnDPl##J0Gg-+XjnUFPtw=wB}r&l*0pfhx48kLGb-- z|6!?SLut*_GnJe`?2I5J&N1h59?McZupULUjHPGHBukP#s@Z-5%@TZTb#*lbvg7m# z9H$0QN4xFjz<-FwP@7EI&c7GR)IYZ4B`3#vE_entZQbr(+EA5Z;6l!G_zPL#M|(Xjt$jnl^lF zm}nZ+>gp<2u3RY#DqaBo7}~b!i>R7ZviMFt1SpKsW}Q!an4xmuz5hx2`Jx%nL+Fao z79kTMBbX0?{pUms#0i4Pz?U=cauV;kkY~&}N6T6mf3Z=?GE~lU0p7cECmrgaMUOaU2(ZRLIb+WXV0q{|+Bx__b|Jyu18Qg`-1@ilk3O0vb}x z1DOd-#1zZJeS!*reh-34`UEDa0hA8$dEl?3MLicdA*{VSp^ILp%eCel%UQ}ZTde~h zqtqET0+-$zC9A0?3dA8xcoIBKKm4B+jsgKLr5cjIkac;k)8>`A1>UY}smYBf?#J-P z0E?!!{}dYT_GtR>2TXV~oTLCa7j8{d{lCl!T=+ZTMcA?tiF18Y&63amASi$Jz7Zip z5g3FLw)dwhjmT(**o2M)CCRFBj>u;`mZkK>C@F~uy-<-j29!V93c40txChM_n3#m0 zh!gP2l`8`C>u5MDE`<*_7Dq=8txZoq0Aboksc`{LqZQcyE>-rqJ@c$TU^EfpAKNU<4qryU- z^HOUAk8q*aWiAvEjS}UL6{GxwweSTsJT*LX-Upj*A0f#KyP{-xx*NybjuPHz%puoqT_vDzr?^xhbm3%Xb@gl5by|FZv zE(J;&L_s$&?al$tL%n1hK3S|(Qw0swdoHCt66e{nT2c5xtU25=q?_5D@Uk=-2QcO5GP=o!O@jV2y=tlME_0_7g1 z!PrLVh;TnhgapsB_sn}wGt?p+JE8Uog9jFioX>1+0-i-za63-;XN${yX5ul7=mp?E zLpA3NO%=AlM~uloFfya2O!K{RdoDI!SI>wH=daYF25_Iv$sK4wDpty473ZqUH z9<>HAoa_8YfgeOo)R}iumwo^xtc<9|371^)(C)nBI0w+JBNd^AXgf0CLMT3pDn;N> zIGd#`=NTq=SiaGm<8BmVz28P0b3_OO=BqEEAOAfLuj|&Q>S&V#R-K77t-!T zHGrKc8)^XD5JL=opTIJn`cTX93Xg{Mp2yP;;=y>w<5`9SetBV$wy~q$=`Nvuv<)8bjMg6bMlW$sNZoJUk)OAPmX?VLiNC z52Phk#Ng2olw3rB(k9yq&dM$p3!D!X3=KTc4V)~+!ka?w!<0FT-#9(4lFT)OW;;fF{)rqKr9t=xEm zrLZ#rVS9^rH}v|55rxC%jJWsUk#&|(=(7O)3AE7X`xt~Xrg8311O`~nGE%FGb;FGz zHSh>1f0#m`8`y}_z)lp)^a`$NL==1}T@!IW&*+JvXUwR^uly-`;r?YbWq4y0A;Cin zfFXJ>(CnqZ47`N;0Z#SeFEQr|GGmFnV z>t#<#M%vmcVz9x^F{0G^0}Ftmu%Ac!_I)4P!n=wh?Lcl!$PhFXqDiCEFA5X|Lc2U$ z(N+lY2|EAdfJaTIl{}+s3?IcYsWHj|J=#s+8MN#0ZvcLEb=7mou;5WOfFA??NVxWC z=`u7G@W56G1GcR;p@_XZ*2JLw!l4YtH$-LnlK0Gs=bSJ4QhxfcV)7`Pz`WSq;;FR5 zdr6(P(F($Jv_65K0zL)&97pUjbl62(R{A}MQhS~Hu;0UwieV#;S;{gZU!0i5Q%=~f zK#m|-44%ZpJie+h+yhEM?)gl+MIplbNsU*VbE9k{zl{3czKF`|cTg_D1LLp)UH&@v*dSJ^_&6G<~+$)%cwlz8&5hkpO6- zk+)BxPQXpZEdX}d{ucE@R*|B8VAlEqmsKhjskDH7z~HGlM;ZuYMuf7%mLoJADf@36 z#20W-4WMl1@gne-(3pRPN1$gc_mYH_EM;!G@_`P7K^n2Jg>c?G<|%iCN)QY~fTg^L z0MB;S{rmN~Ij+YEW;9iV^T3~F&{gOvhX~djL;wit^(Wk~pv4Lm9)UuHuC=%mt}mA} zt3VCUwg^73AVzm=fuGSFLm2I znWn5;%SRzicto?{`_ah2zXEQpuC5CEObptu2@r=bcp4=soLPq7aliwGs1WF<1 za_AS)sK6@f7+eE>Yd`KO0o7&8ig zz)L7O&wGqm19%qrJTuzf%LqgUo;%a!`!2MxQt-LQKO!w6?sOIq;FsSy$A{~6?zENc z^DxMap=&MiG4lhC3uSKvfcqY5A}so%(gt=Q_Kv4|9qvUD^Uh(sr+4%$K|#ZTPjG;B zx~l*vQwkYm7R~(cXT(!Dp;ri23|pxobB44~Y9|p-WIU14TyN(ESDCkaqFnT@|F}vU z9!9wZ81KiCJ0Y;Y)Zm9{05Mwim!dpmUt|Vz|GkIBq~N7e<5|iVTN?oU^Mxfgj$ShS0}Mj;%V;Fvq0xXx34qIJz403a=;Vfto}rVg zd#2ShIB!{QIJ}3amLpc`jw?%B2(Z=>u5ZK`fz8zJOB--9=pa1nC_Cw-;c-udH26Le zPJv3f57b=2**wJo4d>_@b5!DxI=V?O0FMK=ID!CJ1b!0z9j_esV2ukRu+g);a^t}^ z2Aiqn-TO6-<9m2!rNi%j`U7f_qi)Y5-h#kauFcWSA05oeLo$##CF!yr=!6Wo`(Ddp z4RFyP){8Pb@W4WmvryzXgiFm71Kfz?qa3!>(9Z$C5BN3U&cpuUQM>wZE3}z`^F!^O z!e`T-NjK<-pP+}Mh^vDM_;x6dI0@2}PA=E9FYsrdp| zmRdwlL+*rc-e}OxAI$^rg8F|NOn_l1Q?B&8S~M{v-qW0|edW*)JTG-REEfg0=i^a~ z$}(CU^da!|hkft?0WcH+XrSRggW41)8b)9~&Tt5q7q$f!l?*`JT0S9o%# zi~7Cwm_}6a&i!SKc-DIsYhq0l@~~Xbs6{P$g%Fwj{bZ$Gd>W^HfzpZ@G;P=mG-os) z;xM?7r#R85K)FF2VV*S5{sCtIR##UIA@Hy>BCwkVAiz`M0A+XI6V3SRf%&AzzxCql zSmU_YS>U^OALC!VH%D4nBIBrA&!^5`=c&c}81a1ST*l+`_jqh>9Ra?2^BHoVXfG&K z3&@>Nxcz(eJ+sFSbP$v=Jykmq<{-CEj*?=Ccl<^;S5 zJc&B=-(#1G!M#iXgE|x$5Mp>EPh)B5`I>z(8`%A2+mYVfEwRo2z_1LYT5+!Y%$uKAdPTH}w)?+d! zET%bGZfHm9gxzZ|JM|3{hmZrCAvI_jUyTb8dC$cx1t68$C|HBeqME#*{(yaH0A)(y zOU%%3k~_=Itz}~4cx!E$H`f-iW@sPsaHD+@11#23e(cH`bPJ+2_5OeV;(d~)Y6~LJ z*|gmIsEz~9c2X#y9X-4wy79h$JMBmj?u6OZK!}IB?4DL6UYUfA_pDjVtvEhvmf&Ty zh9^gxi1c=TU^f9^fKQ_WU?w0yw=jI;)(S>ot(#zt+b-SuW%`~hGkoV8E0~U>b4SgB zi_duGbI1Cf1RHtoei(E8b&D9dw9#f!Qs#;r@o=rtU?X~PXbnn~F>~pZheVkTu#O=W z&zYgdBc}}>NWA08w1f4Yx9fH4&SBsvoB@}C&jB3*bMQ{=`EqqAXX-8C5NnRhv{aedCeTeTWq1lb|I z#h3B$)4kKdc4w$=OEaTv9vaqrmWmwfJ$2{QfcKtM4n1QQPzJ9p_VDFJu#NVsbpF+t zLB?MR_PhAqCtDQM^8}ALzkJ$_ z{ZVJN9Qd$ki_inM5DY?sr{VXXVL3}M&SCI8mZiMd?U0MG-e?}S!}MclLEk!>9Mnd& zfj))>z&vU*lv3l=nPZKjU^z=Mo(Fd6zBcb4?&SxVD+;nKjXNOrj(SlLRZhSM z;DHtrdJHJd_{{7+2ObMyu_(BZrKDnz#-R^YYV{F=!oEEPzzUi;V3<+npNGMVFrR0f z@AWjMf5=7ZfrTt1a*pr$g>5=itte>bc@^^71rAsjO{y~9u`px~oJK6?8Hx9_jXBCr zTv}5Rs?ld?LQo&4ZkK;3WOP}2dmiVs&ggyMwA=pMAd|@&9o7KOp@agSQ>Xy|)ST;= zXYQPcr9!YDQ>^X^%meMSg@$u1oX`%zlR%D6zAc2?Vp#Ex+5xI9X9XUZFLLIJoGoKH zljm$&dz8c=i-z`7G#{XkVFAztE}+`jsSH(%*RacO+t9*Nja=MFWm<6TJx%AxL}(qpHbBq~ere|$yJ-M9r&I$d!%>bM zwvmU={rDOS%Q?UBw=a@s5C0h)LYdOyfy6oH@|;>xV7;pZz(XKF51}Wrt>I|x6gp1J zuFF@_9#I@~Cpt7KSE&Kq-TB6DI>qT5>7h&C%MP^>MA1HnMnJ2ErQZ{7aMV*gya&W- z+w~ugk&MOzlP@a!h@liO^7ad!`TnpduD#O$55_)ZB9>}uo@1P6sn;VjhFFBe7;MEOejs!aQf9On z#Xcc;mWqPr(OSs~S{b-B^c=uPsC`hHy~CUpr*5nAQu5f#0|Q{pJ{Ep}gg=oh@ZJ*{ z!BW)#927&jS3~^;P8WnwMLN2}S#+%z1Oe~_y6c|}Z#Fo642k9CIc;^>)ir3fOdrPhNTQzexJI;81nHbIZ zwSG>`93Z15wIR{x_K(M zW4KMT--jwx{s_an|K1-y?yEb|IF0uIZi8^dbchFdY0E01oL#bnP8)paXO|h_y}3D7 zvXm>GwmJlDgfoV_QG`c`5t6*nkYSc;oqv((aeT77il66*_joZ-X#o3%15yz>Uf2qG z6-|G73WdCA2>EQDWALn7OHbr5*I#Gg1E_-vfCWx*_TMl{u~;B%L=lO1<=fy||G$|?n|hlW=lz!50a%f5jn z<9DS2>;@;o^?IFNqd{}|4BmTQ`0Qs%78Y55_gxC_;rhpLU3=dybz2(aH(^)zz;2`; zE=Rmju>u|(f)d;1XnE{B?$ngBdW6I|&Se?mJyGq@dvzUc8d`FG^b>wglQ7*EJc9S& z!meGW^(uAMz$SIO{3r165v{iWL%}oX#aNF2sT#`CFLktw-qw1c>?2+<2m@9Cy!XT_ zXIOdud7O7VyZQy1i;H|<%95^WOEjOxAs@SsHld+>_+iWBfKaHx4EK+g*zS}uDUU_CSgNvP$} zJr#!qKs@|{qtXBX5D{z?@%Yov@R`rN%pd;ApQLaF=g*wM8pD@<=yPBU@4JF`H#ac? zty|a0JKc~1ESO#w$#YyS$W&v8;{Iw%2yD z>pjLR=b(fJ8&RR$1LbET=dk$xg0aq@=+xv53>p5^Oj_$5%_8ro1|Je-BG5Jg5VK1O z{Aq;`gIjMjSX^A>;)U}RML`nB;63M-ml0!VEiSS?um1ln8{ z@$X~|nwIk$2Q-=A?=L}ZZx{vwz`&qD;MDs7y!Xt_&oj5Mz}(zCKlKNGic1$R5Lru9 zs_!B!o;iaNq4n5BUc3Axv2!$=^F(PzqrC+pNRexOK;Zu?O@nT&L1rV`QOqk#EBb4M zaA6}&iM?YfJfF*RlF%AzG3${T%T^R4cy1>(+SYO>iSYU?Y-45cla#53)8uYBCYYd%m?t68VaR4G}dh}o2e!YI^e+AV_R3H`1 z=Q)d6Mx!XSotkq*LypNwz#(+Pa;W#S1ZEf8h3lcN)}ZTsn+Y(>W43QdaLhU9z&u!W z;k>7C4hjb@?9h3JIHz%aYbc@!M2O-T;yAPx3$cIiF-EkeTMWh+B5R3*2H?HN2bI5U zOkzO)FYK}*%5^9f0rNzRk_McX|8Q zf1R{&EWZ97&b;<*u!efQ&gRNx-um1Z@CZ-czQOXwecWr`(E^~Y4b0u!G?tc-m9wPA zaCT{#OHV$@b1%M#2hKkE6r1boB+WUz_Y}@k1P#E6&<$Dxz`aDH3vbLX0NT>5Q52lb zQs(oV73cWm#yT5u!e*?gG9NUWq{h%4;+EglJP-wdQz`%eyz>-U z&W#&4c;n6QVT_Q(G4)!FdR={^*Y2%x^VS`rkFP;qVDH{RI$L-f(R=z?{9_k6_vDj! z;KJEu&UD(y;v%?$?A~2^AALyt+zS*-E9BNtTUp`!V;8yn#1*`EY}~)k-8*;4vkdP& z&bw_Dg`R;*-cKWv0d<)dq2?U1(dMJZdyNVN=h#Y?l8K=m7ID{F@?Zk&dz{Mq;s4oj zjzs!A@}7Dvd^ipZ+61&6zW2caiuwY<0B6%4%b|ee6Rk~cz-c1{_@LQjJxwz9k=H~GtEC%hw0GB%*nnli;wAa6e!=MZYdY}u$Au=#OgV}*){>Kqf zIssuw08|Jw(1>7++UM3p#zZ*P%02JjqMi&t|;{0IdBpZ zboBdt@DGSFeSg4FE@ivzy?c19%mW-|hZu*QuEi^U+j;4IIiUwWgQHCESq%Y>86_HaAZ?zkoM}{HdpD zTzP^Ye)d^Bp7|)EW-UexB2cTn$eBx*uu+7uhOE=&)?07#t#{t#x4!*tM1(ireV46v z`$&twgh!oz>rvcS`R^tPiF3?{+=L6g4v%-+Y=#WQ^(f|Ek|2cC;}MN*DPXp&hCcDI z8O6lTF;~o~zaUF#76oT}-M*voAPZVh3UTeEqandr6A0yRs^;G4j#~);)Df8H8DuFQ zT>$UC^%n8M0*&=e@Sg8qTxOxsAX-|+q$$POb8zk)h+tP%Xe=#pacL14B>t4YQxwP4 z=I7{iIuvVo&J!Z(0U*aHkdjFcjb@YPe*otE6A+G>n zIZK(#b4XYe?p02NA<1MEHBtrp$(7Oh)10r*aPi-nalytMi|vBt25u!bSFhTs2* z7kK>4N`LXTIvuh+XK8*OBf^bq*Ld^QSNZa9{wD8VyGD|xoPFbUOq#OV>*5hUYBcB> z(+{iFoEG!sBD~X_>xc0Ud`abl;1s+b3Y2cu>R9i%*zJaF!;H_h@8U(cRjacVMSNIq z0PLAibm((I1w$Ft_@L3i(BR!>6OV8gu~9^w4A==S4M%8HxsY zv~i7^N~044l>pcSKE&=zl|0Wf4a?Q*U@hK3;XKw_>Pbv39t@?3Y^xt|K<+*5PKV7_ zi&~np&~B3yIrZQ-D4RdH;2S7+!I54Q0}sA7+bElu>#kdK4kr@o1h(f6jH6RbpMotA ztz;pjS85(66g_zz)Q2u-zvI5b{t%%(0YJ^CQ(q9Y4MPjCv$2lLbKZLORg4ijHlkx= zVrzJJX`Z`tO+I|@eLPT4Vj^Rx-MxeHu=e2x+X5vf)QG%iF3+hK8#G)_Tok)b{qi-3PUyNoJVWY$7f6E%a9DGY z!SFR}ey+eVpf43L-P)2y~(PaJc-p!l58Tx4tAO`!8151Aa%= zn(K7%y)HSz*M99+5D{DmW?%dEw=}1})6q25UYF&?WzP4yTxs`0ZNG4*R_Cqx1qAqR z5FS1pBQs`)$~WfgLxqn3?>3vn-f*o-2?a}=}Cqb2}^^&W*6Dgkg%c!v*s zAMMtrI{wNu+d{hnmzhJ(gNb9Uy&o#x>4d61K_~n04{%&NTQs~?T`IG`m$;-#PMI1Ayx zOoaPJH;bG@=L6)x27`^iUlnxnN9Y9LBoA`ALuj4BfJ#hl^YMiW9|hwzlS%f`j$sxs zjzpkM^tU_JML`wzMj?VXhIgBD81I=Ya?YhGD_P39v`1zPAJrRd*+|QT$9z5>*o-1F z5x%pq1OktD+AQTtn36b09>RehNKQCin4lrjEo=My4~IknwAc{^=rZWJP@%#DC~f>Z zNrDq$G0(8TmG%~AvQ+8Bj71XIh-1Y2qlBvVg|0DuDl`YoXBqWif<-tAfy@u6u1>N5 z0FOiH8XL@<(S`xU@QJ6>pQayCsl+e;BVZ_mxE zV{=S`pp1uijlqlX=E5TH&dpPE1uw7PCvpXyLZbk6gwd5Z9Rob{jBqznuEy-}W10bX z(RH5@9+d6wPVfj-m?T_iquvWS5ZTl z?dz}i2-pfQq=!Flh0}&IeOQe4Ik;Z06FIFXfB_}gy(Hb<&&)q9PoUrplu_* zwz4wVa>l3;^fM`~<+}@u^g3-Wq^Y)43r#govK;7%;cgUTL%R4Ok)i9|5;pu&0OY85 zutJ3cp`41TG2E#oylR#JxYBNu_<~QgHV_Xt>UHiUwZ2DtTqrex+eyMV7nbnAW1IJ> z7bnxl?a&?%Th@|sCpE*SiHepaS47DgfHYeX$j02e}A6Yq=5X9~SeRxgsY59_w{!*@!!}+F0|@%j0fZ z%Yuto&QG3|>jdscmR1mEM?{$iU>V8-_z>s;_mBHxE6fg@2pwyAePIy~JipaqzMWx! z=UXlABsJ~^7UDcF85AeMxaCZI8IozBcbl-0v|A>0hIL}Cv99RoB#}y zjFjDrl-^oPS|>T_PVxjFv3Pud5ac6N1Gq~l2S@3_PV$&lm;!hp4}1aF8V&9yHLUl1 z-^P8G@{AX^TH2+k(dc(98VA;*h{QWiQsHYZ>Lck`%k{WM`)DRWnE|+ouJ>(Wz>*WN zi~0dlw0@%E2dr>pl*_GaEUB?X&e5?J>tQL&5TKUS=$P>o5P7t4sB6qgTK{B5NJU${ z_d?;*5zz^^l%bIrZV!GBcpVK9yo~k{uTWtmC_?=}ZY|$hT;_b*<1_0Tcv_DlBJa49 z)W#wN?ndztx8d|dfV(!~PMpvaGlhELtaM9JPS6N+M9sceL6~>A(CD;sc z`gz9Z6gVjhe~j2>_g}qwwg1MjYjFd38?_ZaNu>c)7z0Yq!Hp>9T5}G7`68#*b*#rR zxs1MWs2lhfQ!!Z4CMb4_I|vJ&wJ74lq^3zgM?Yi%yboO8`NpsS*hE!?Vdl^Z6-JIs zgssSOvsTB8@XS_=dXe(R{DLMEc|X#^p;UyfXkt*|JvHwbUyGBYLp-co%k`m3$|J%9 zAER|Y+hBHl$Wf&PSC|m`VZqRd)SxND=BNkW1CH^RB_DZA&}_;voae4Xj>kTbnvf5Veh}Z8JGy{1JO#<46 zoe9RW<5r=zW=G04b^}B&e-W1D-nW0jV(iNJCfP zjW{N8I{D9~DeF~(p`yPZYKu5%#aBHE(eh*aq zM$k_TaDWR*L3dDl;Ylh@U?MQEttI)id#gu@lFYMfEQM$Yuvz4^BHPbfJu19tN^nWA zF>MBJDu#|R+_#Z(C?1~pa~Lhu_HUy#KE-en5bWL_+yP$=|L_CHJus&M0-VV*BIo+^ zay^P@+mY-7Cjt(*Rj+GT-#q7Bug6-P&>2xous~R|HZ<56Np1be;DOicbKHoNemA2L z;T_;tQK$Z{q=R}~0s8INrw|&XANk1*=l1L>SE4=s z>0Pu_(3B}kvxUBg#(U28y3~UPV7w=5H2bZ?%bNN!cfJUTBC{l+y$J0P4}w zR^X^`Ks$uivMHI;n)IU!|3;i}GjwAfA#S7Ie+Yd5c4999@CGn<+yitPP%iGrx*g{8 z94}xzti>^RlLX_n6R-82BrJ$-XvR@8=}gCTJ{mM1KwF8eq$zVnKGJkuC&H$&DgZ`f zUytCNwC>*_TuW-)9({}TkAZJ6)DCXi zPq1w)k@v^eGtdAxqlEWsjlS?3LCt@OHgF5ox5XUSPK0u*R9hTgaPh;S1z6`%AAFbq*aZG%IJbG=vEv)A*@7;9$4Zv+^i~Te@_@rD_Kw(V zg2)?li>${nH){1hmy>u;BRCB&b-O&@YVmQSL23*=W4SfrVwy=pP@l)R&cACc8&N_% z?H)^6uoIzYl}c7p-t^PDXkZJQ*e zQw!j3l5j7n@$$xfma>c}iZqEPIF?R|2r!{<;5Z9W1YLj~F~?F2q~C9NqtWD66!)tl zM}$(IY@nt6M=}A*-@(9k^K{~)He)D%^!@D6<>%Z(KBhmE?-Ofy5pBXb#k5z`f=Ma? zp6$s_WBBGWHN>;eT&jl&fDGja$WbzZuK=F`>XR6(S%m;yYk6gPCFB4+Y7*$;FCLL2 z=z;f}O|19K6*-^U+~D20IX;Yuu`yoXt++ZcS9*To*q7H>mQ3-$}qa?;0HG09LoH$49 z9I^96&SBt0_yYO`Q6X7pTxq+72)!{Le<#XSct46*ixOIa>wgSlx#a!(7;rlae|E!u z8;-q#`UJiNER281DjWuBm{fIRG|c53%ef|i-H+p`PaTe&o}okN*k~*ofS{R_o6&fV zzZ-nWJNQmxj<;$}JY(rm;DO&jvv}|B_n-DF07_p#g%bup8d|BD!g1(A!)DkRzrS3k z`(CU26#(y{c>&kZ=~PFHg(^%TauGIS<(6AXdpLxR$iftx0m5K1IuSZiG?p$w06h`5 z$}r%VVSw9F%zO1Fx1xl$k#SUfw$SzYt#I2nr{{hJz&+FiSO*rzK57+?1Rv@IjQ2E( zVpQZ3V@DYd^`Z$-<65A7AHW1gMZ9OrSgs{?TGo;V`tuPZMFqfh)c)T$4q^gG_>%in zjYFpz!=WY_V@BO*Pug#b|BusOF`{N0k3?B~l!+O2uK!MS(REo4+rFcl`xO8sv*`ba zrUm~n@a(t-uENpaMMI4XdCpu>ke7J@Q*Ht@ioCA{w8v-ybj7e~7;6~N0Usv~yujP_ z2CoLT-!c6HuK@puLBig?y*`f=0A(m)b#>JN-$P3aFQAlRc0b3cFgcXPL4^q7=~oz@ z1jNo^y(cq8+z% zqNy=#nTT&R=V=>DKAy(M4lVkLf!BdwJIrt$)E`mSX&h4-MTLW7+L!+1Au#^gD_{Y5 z5r^*Z;Wjpu?w&*U@;K=3orN#_9`L^ce;9aqeAiduFepT5MG+TzUFP$wUo|+*5bv4K za$@h;GL}{pjg8&Nq3#f61~OPYHFtE0;Lx(}Z#Cw4uhwA0MyhR$XUJN>|B0^0ud%bt zV4v8x04URgLu&9kN;df84BCm0oYAnt;ZRlzmK7la{rdW8Roet*NQ#|W{&^^B8s`{k zF_yu5N9~BmD@52b7USV=6mvU{$z*KNi~_a)-#|Cz+i)=3zr9n zsPxULfD62L9c$?rOJ)pn!Na~4O`pqVnD{jE%3z%tGg4OI2O+eLrDc_Kan2n+CLqAN zjkvnFf_V5|tP)pv~9%QT8#o&&N5=} zXxr(N)pJEb!xeO`r4Tccet`Qy&saLf_XW>kR*?rjs5QA6C%m5|0Bnu_{C@>a`Ry@j z0kFdt@EtS*=>qV_!||qbn>mH(Si@RqHn9|{0*`F$jsXoDNR^MH{iStff7Ewcnu*KZDlfbdIv~ zml%~xI74lc2>2uecG3#Rj50X95yxa=Sk6-L`aG56`-uc40P!Nk-Vu36FLXAV6njxl zS+KLe&nuIYMZD*pjky*lf$U=8!X&#~G3NG}z0NkoK*o?+fG51iY3FP~QQxE;DF|-7e?G5wtQ37m6=hTC5Q zTBET0hcW83umY7>C4WHW3z#AdH=!t1|1w3`F_GO2(6(pR`+j1Q3w;kJEdabcdJ#JW z!P5&NLqi~08UI+7@%;>q_a8dj?_n6V0C)@dS#(cX4JZ9Pl`r7fQT8Kvuh9g7E1eGW zdCpUvwmP+vgqyW`UoedN2P+qu^_~}7t$u1Uz^x?VPEwng04mWohOYN?j69GCBtRzG zMqGejUR>r{Tw~MPN$vbMP_z0j@VC%>n~`JG0w8D5QvBJ-sna?u>xLvCSnr=I`%D;z=MNb41D7$td z6T`ZV_#iZ7U9&N5W5-Rc?ipy!ZxYo0a2rdAeJrCMaswU*J^}n4AVG7`s#M`Afk$`a zC%PSs_blW&%V~-e;jQ@v+Samp#KIv#S$;h5WT(xgZWj+M3bN5Ey8R`&PHsbAigMYSkMvJIIh;qy*WBm#6UjTm_6$T%2#EieaFwWAj zvS6X=DKLeQ9rvKx!L|;>BS5KjXfYBDH$#&hM4-np27cGq2j^ub(5-lv(-H>jXRK>y zoC4q$D$)K%c>a^X=f`<56%Gb3!p)i%2iz|lcM~m%z1Zy#dChh!O@gkmw5`PjrrR{s z>zA}$CZrk1!LDD-GwMabxn4IkE;ap3zi%xq)3&xxRB~KZikS!n&=W)3#$@RE^~CVy z#U<8k%vNZ(HX#$`4r=cU@T(}rx5jVBgs}*Kt5>hGy1Lp!i9=pNeF2{Weh2C&Xizx@ zj~yP3Zvzx!$c;g~=drG*76>}aAIaK5w4e|nHi8SgIzDVy-jjs(Uh{cQy(m}+_WouR zY-kbg#Yy1(Ki(-&Mm};8I>yowLng{ccrC8co~&=8hdTYf9-dzZ(s8K$!x%R^#1=|d zoS}5$8M^TQ5LJ`WsX#fsGZFHTBk--IWo+;Z0IXyg^F_}2UQ0M)!Ir=Vl1N>D27M7b!7q4+!usrW%Fh{H~A@EAYzqZ-KFAkRQ{9P7Au z{70dXK^Ns?5>O7vu3o)5G1)UoeyH!DQmqF30B{~SJHhX-Z~*u~E9OPGo5Zvt%UT>G zUYTxVx1C7Ch03@rETFEn}vn4|!(L${1UK|^I0OeywS)U$?T3`G{G^UpEpvNe{J-@PzN0g#6aUI+dY;CBIk zJ-oJzCO=fDa2k-KyZ=81{(E#Ce#nFuKTL?t_u92s$`c zD@~xnEW?Fc8x8mUCQ9(x4mUsUu-{G`%YqA0fd$}cR0H_$P>rC<52!H9XrsIQyTG48 z3w}PH^r9ceai{2(S(Xu1lhF#Z55r)tANSe=j(5>@fcH?7;D1MHj{iM0L8xjwUSXC{ zpsN4>gNFLnQICJ;xKHfZ)$L#oyok0I`&;KCs?}W!wp(<6Va0v8JZT8E+|Ata~eZ<~{h!e-L3xH5Kl%s>S z&LB!)n36%NP~ng$`)1~7#$N}>kJIV5+X+q!3RF5ewDr+N;B#ooFjQnB6;2My4eiU} z@mJ6||FPTrJ8|qjfSm|Ffy-!!@V^0mFuc_~?sKb9VV~%r+U%bL)==~I?P=QiOH7jn zFpPVsYP$B&HT5dW=yQW9v-x*o>IA?Jl*9-fG*WOG6#^dh2~3>{Q{hx1 zLv#DzMKyp;CPe6QR7|@7xEAg|1YQUJ6lz!HDC_XFpMQnfhex^mz6ShdbW^&H3W2G| z)bF6dDHx%NL0<%ZEWGv8z!|FcV-=1ETMTykzmIbG|KI4E+GGNJextzD3xE4@4j*4q-EJz)b@`V_y@`o%PMK8!X!}g^%V@} zU(5+LM^D;GcTtIJPtU0p5EK?nFIDv8fAC@;P+^teKW!(zA(=p8gaxHUl{8)xC-WEuPK*H9 z1rB&0_-oNhbei;Mda3Xj95+_ms3`trK_~0Nc zA)H{Ftin`57;sgV{xZjy8g(8AW@(YUj(TF7Xf@%>z?V?-;BhL_(F*%VfoAc&$-vJ4 zRW!bTA`*P|iKhjIokpv_4C5^A4)nyQ$n!v2w=as6LInX4@-5W2In^Ou+<4WLBX zS~&ymq5@z&yw@1|Ooa+N(PhxH;vSmbYnWk&@+=B~3{BGbf6>OI0Dl720{-;SHP7S^ zTH#PAo74OK9mMHick?{ox*J z)32fS{%@kHe+K*#>Pwm#hu?0PNdd4EK_J9vqEHU}ao}GEK1)SDdRpO8Ch89G3d%ik z57?OH1-}!gY4ZuVe~LVx0q8nCr*<9$k6g)5Bwjff8ckaG~~|!e*jpb z(g?kaH8u)$aj`1_VbHEj5I5X@7qDr>N*ZyHev zfF0OTYTR$?u)4Z>3v~{jK_}G;sv(qbHiOPOK0LpHQogm&xc&RU zO;iIY|F^;sahfOJ*bp=WgK7bS3WCp~osKV|4#Sr@-I<1^Gf&WP-Ayz_weBgEg!3g|UN z5_Rr`&wdY$ro0#4>rgrLjs=wfm|_HBVNoKJGYs+$E&&Uu@F;TLC``M^DT6t=cv7Y2i@rOVb?*+ql4Z`noe9ME{h23%d@-qgI)z#H1CO^ff1i05UK#Gc7PVEiy4wFgZFj zFgi0bD=;uRFfhNbIGF$d03~!qSaf7zbY(hiZ)9m^c>ppnGBYhOIW00VR4_R@G%z|d zGAl4JIxsNK@_;1(000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o00012 zdQ@0+Qek%>aB^>EX>4U6ba`-PAZc)PV*mhnoa6Eg2ys>@D9TUE%t_@^00ScnE@KN5 zBNI!L6ay0=M1VBIWCJ6!R3OXP)X2ol#2my2%YaCrN-hBE7ZG&wLN%2D0000DpeHi*XPgQAHTcKbI*Owc|G@@d(XZ1BwJe=Gtu+X0{{RfQxgN*ON#torK7oQ zSMtMDFA3N~*FqNnXv$zXM^Rt)1zb&REdYQgA^-p;4gmOb$-;aG077H|fGs2dpq>u^ zaG{GjY;Ii+(74<-HURwlUoQPvops5f4K}qfq}{y2apfjIpLJOX0Kn;LYM^WPcy6KC zJGF@PfDl6rmkIh>@Nv#*X)v^C%5+sk$go*eiep@_>@`N`?gUjiU2?RjAw3CJ3%kLR zXO$#FtpyRa6ECe{YUW^rS$Nv2NLj43hphA`vqwa=9jhzsb+rYZpclXLH-<@fYAAG$ zIrHx9j&7fIZ-##k-`!N}RqknWB>*6@%;rFLyf41^EAc7*^Y(i-YXCwA1hfXZW4-a= z;be*0QvI>%j)k7e}Nv8vIxSZS`B7D%+tX;E33Qym#S;8x3bV zk>005(?8~U4D$3*QfQ3>@+^k|_GqpFqFLJc@~`zOj8Vw|i68>@CYA^9L#>d|i%BIT zJ3x}j@L)%G{zPg*Wdn4}%q9#9V-<4!PJ_g$ zFB38U%B{5etGLHufm+~5HVH}uEYh@kJH<6rh*cvizc^qtU8t&Pu)XRf{s&XC=msK# z(m=RNT&>*<8aw*1(UHr;CwOUYf6OOPE;6VCrO)VT(`-mq!D!>f7t+zGDD~tI?^$s& zk8pzN1tu=HD)I(QVoYKV0Wa_Sisn5at*20e7KuS3&d8Y%l|Z5)d9MlfgT|-m3dLQA z;U@vJM0Kra&{y5XBXeIT1Ut_cGB^RY@-`P~OpNDnr^AYFIA)N7s4Y2-+t*GFCeE90 zD&jaNUIDm}uIBJOjw!u!et7slI@!4+kwJ8rAlZ6Kpi%0-objvc?S6{)3lhs--}!BD zBaB)pwDO8gmBfnqtq?53IRJN+ZzjLaPQ0FEX3qr@&!M07T)PhZl$>S~dcB#BE9zBN zJgbv5~cDUl#*{xXzL7X#AusExC|9pcj;2xuZ zFyIn6_s?exr}rj1eh-+cA_73?{VVeV%eFA>Xoi<-Io+{MvhIqsiP(K}(?yikwne01Q zNx~Q-ZN9k+vmukM&A0t7zYblL{ub-Ld8Mss1WM1Crdf0$3>cFm$bwSANCXa0Q%WBy|o^p}1l zuKNZ@j{;7@C-~ec)|#VCL@$;sAE~*FoaIZ*p3L@kO1JkA$!=mln#WiAnSGD~*{}V* ziFGa`W?4N$vV_LpP@7!fGr^hD$vZ6U9fLx!pv&zlGLb#fZDpZWoR8z;8;yX{&5U6< zzZ?q8tU>wuOKn+)y?PCxU+RomP#mG49*%v5JE7bxNb%$XGj{j$TSuQImSvUyJ1n*= zubC85PilGcoAHtCi&gXjk@fc8ZW1!2znpHff4Nq*Uq5&g+{dq5d@S=>F1M<6Ab-Jxd<D(EsOwKnUWzsXY!&gm()bO8$V0O%0n%4!r z7w_WO))eM>HZ<_jEjns0>E1e2_ViR`sC9V)S zR{o~j@*2ofusNa|F1GbKflbhNPemr>c1;=FgzDRU=ap93?O!d&FCG|3O$@Sitfx8C zY9%>diNbDjUsJ{P)9w|a_B@Bvo}}AH9@=ssVd({_<=vSQkQ>xS++C9!d@o7SO3p%v zdGQ0Rdh3a|n&s3Vga&S1NORz%vj>pOSw$~KqG(yYdbu%ffHz)>P9KH`-{$ZotLAH2 z-2;s#uhiDm>$#v=$T|?TVol3g3RQIM-8b|1XwK-0!3f3;}mt2FctO^;wt9Iz>d}dag|_Ei9^n1=+!F%JFS9lHLX74U#nN4lwE^UZH#WnNBe%^i9w$xF<#`K^ zs@!s^fY+>xy|Q}lEuB?yWwYBs$8j7ZOF09W53qLj4dSyak?dN$WpUSLqZnN-Vi8zM zLmOu&!>k2tsliTsB%q{iLf_G9$JoeUVI_)2{L=~9KQLHJ+d-8o zH+8dm_TP9PMC9h_oOWbx@Ne;S)#vVSOg`!*tn(|3ReIku8$G)yy+7~T zKB&O#O;qpq*~<=E^YX8Qu0}ua^wTykSF+L!i=|j;>9Xd3I*u0kT$E6kcg4uqW^xi5 zwRD#MF|@e4B$A56J)HcOZ;mIy+>jM(iy*GUgEiS$^(ylZyViY|!rzJ!|%F7p@X-_5CVYFgS(DL>@`3l{|@E z!ycpOpI!~T4{h4-J%mcBU`bwiCesC&?R~38be%c=+2XF4&XeKFJVWU(Z-KwZtCCrP5& z6zdPGQrjQ)cD{wKv+a(C$G(bwp7D2^D4R=UxAV5!bXPm=XOG++ao*UDXDC(rA%6B1 zsY!4tlw}>*PUW@Z&tQnB!mc9wBEB7HTU^*!y8Kq5`b`~j;FaRy=G1|Y&XV^FUV@X6 zkGtU;3|W))FLq3@$BJh=jHBGjMp=V}?`29>h6kR3{X1zlcOy=JYIYWUlDl1c$Gs#X z*Z9*f?jOmUUv27EPSx}X%ZM`1v1t(nh1k3Nc~5%Q?WGANM)((7Y@{HyhCgb0A>JMA z+rxAh(4Z0`Up%ahRJ-j3UTYD4Of~hQJ2%!-NTN;7JBD#^U_*?yiq`%LtE4n~``y6HiCKx?na9Nv@@!Zb|qxY#gYt#vHXUvWO2*23XBZdwWVh8$bf&oXJL< zD^3^M;}CBxVwwe7?LIkuj!oko1}UKTFb+W*)g(=mB+19*EdZV04~HPkFIT$>)ey^<~_sFJ2CY{D9VRBhwwWD&+YTNKM>}?Fs2eQ=sMdy^ZmF-NZKsqV{nSoLu>-6%EJCIV(A~1$WlvHgYE0WJ4r->*sTUK{_?KosLCC zmeO6-F1WY?YKo(^lZ>uF>g&`) zJdDf`!5zR^*%L6auNnIg(_>a`Q%kT0icGtp_Q-Rgt?DBwmj=)yc-hoK0 z;Iwd6IgX+uSlRx3#J{6gokR8INLa@bA3pP$uRRGb@@y&CQ@%$oLF17UZ~CN-90>6% z$`;s??DZfF@p(OPhZ~7wOyX#rCwMzp)adFx+n+N@PN-0|YYg#8bj6I6#608bb}Aa< z@VSp^3AoZuHv=jeP*#e%Bgncu{erDh$gO(T+c_Ko4tXz2|vQ1w#Z~gdoDHsSv+{Lg#JI8jE}UHjGeD^{R29KU(nun!VoL zEoh_pYI;*vca?UkW;z)Tqx_)xtpb*lYsyqj(6|WdkvOS%ARp-s>AxR2H4ook3D#zj z7+_lRfThnlDR3+&y#K2yPTwaiLy-88UJ%bP>-Y<*9Ub`rwtCmcmD1fR2$z8(odwAz zAul5BMQrJ5De$pyts^EDHzmb;kR30u@24!P!-m`9@4gA(xcbXgi)8`_4%OrHh{)q- zz|wch4s!cU@BVr?#Q#)XvHob}&_Ecel#k8%8o>u_ z60P0cFna@?R0G0vgi?eFD9Ih)e}SSY9>&Ap&>HeP>ian}D)z>K*X9u`THDc8WtVod zeKR^znKSfwf-UO-+A&hwSeWkd8^j{c(o^JcXZQE-`^kni?qzFEyCGH9YY)pRWV|ue zIFax2kZ)5vdp15#lglbTSk-T}k2K;c?QC!XF$B-yow~7(@~>)gX!XW&lPh-#m3*hv z`9Yc`(rK*0(r+0tF$8wasw5iRb?D9oXEYW=aUaV#KG?NU#>P3QF4ytNX0&$y z7|m0DB#R}-?IO`!6ZPmUn*DGex<6Ha%SRYJ!w=o=?g_IwVTmn|6Z|-fHe*w+cJgV&leMVcc=j?=>l=}p9fv`FmGE!q=p@{RURR{48Fa-sDNLhBF!D; z>^3u7xoE@@ua?w*)W@h1D>l^46GLgu8qHN%rt;48j{{#N*eYfZ53jy;`(^Hx?VpzY z17++0K4+il@qMPmGv51F29VJ-X7BrF~^RVwNI{I}-L{iD`9D0lY+vr0Bp(BNMG@2d;SvM@Wx zJiXciW_^15`5wu(Qm)7f9t$>Ra7a}jjX%V=eR08wwot)I6&i1TQ;wKz6kdL7@oj)N zyGN5|tCgbHSLTn3e#HY%2zxF`j?GVWv#uoDrrwmh6ENC<>)E|5vJZ`+awTfMja;`i z*<()s(6M{<8fp{oENCu>aN=k+Zkb*67z=iDpRt1_`l3#~Xu2u_1wHRsWC&e}R~#5= zBzUp$A%E{$NB9b0TfQfz%VJ=o@_TpjoaXN1ga zAW9_HFYg-*S0xEq%7t#v3``;fyJ@;pe1jueNRx_BU=Ii5SR!ouwR{K}zG1R2o5PP* z3muWT#a%&s9Yt;U^=3hlTv^K41{AM+GCQ$~Ze#5Ro=aSl&@7&bAKU5YHrE?x=o6`t zvC}I5OLC4A)?3p4hi=AdZePuX@16T)Dom|$EqIQMung9m*s{Q=ZJ(lE!6X`Z|Cl~` z>-m#C8YsbVHWT5;w-Q2bY?3P}**^E1ZPr{`x!DE2^>msc@rUan$rqEv;dW+NI@dU9 zceY~fW<5L~iO9*X$rOPR~^Lfq!OM&`EH- zWfc+W5d*%^z8f*_F`Uuab{tq<-tg6IlqXxoA)&y(RNnukyRa0g-gWZIGUi=Jw?5+N26@ z{b^LrVX^GggV~AdIl^GpHE=W|MSt5(RpU1w+;v%rOu@$>rP^7>`(Tmm4&pTO36Q4E z>2sD=>^47KA@ur%oSPDw=Vhh((}nb-nAsseXP?tCq{Gm1E=cH>kJT7xmLmW#?|2zZ zEyRl-z#e?!m&EFCk2(!G)uuUd~QdOR#shB_O+yK^Zz5@>;KTpJ^cSKFdeW(cPYU0KZHB} z?!jTGKsSKyLw^@H0aIU;hnuY%>S1`me{TN^jo*J_2M@MIg$bYo{oTEM+ysKd(QX1> z=wMd>;BnFF0V7?&JyFqNtC3ODbz1;PkU`p&fnAXOb`}K0E?|IB?0X0jd~YW(GCMWY kKiUuNryaqVl$uEcwzyb>5A>9BE+GJ>hL#2mddS%S1CSV7GXMYp diff --git a/archive_docs/v3/static/apple-touch-icon.png b/archive_docs/v3/static/apple-touch-icon.png deleted file mode 100644 index 0ee95e6549e0f670e080cc03409951c690c85ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13882 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 diff --git a/archive_docs/v3/static/browserconfig.xml b/archive_docs/v3/static/browserconfig.xml deleted file mode 100644 index b3930d0f..00000000 --- a/archive_docs/v3/static/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - #da532c - - - diff --git a/archive_docs/v3/static/favicon-16x16.png b/archive_docs/v3/static/favicon-16x16.png deleted file mode 100644 index 6e2a5f7bb30024589b0cebe6e29ebbd01b985f99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1210 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 BIxheK diff --git a/archive_docs/v3/static/favicon.ico b/archive_docs/v3/static/favicon.ico deleted file mode 100644 index e734eba0d25de4264768b9e0d33d0caea8c763b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 DZY)W0 diff --git a/archive_docs/v3/static/pygments.emacs-dull.css b/archive_docs/v3/static/pygments.emacs-dull.css deleted file mode 100644 index 79ed4731..00000000 --- a/archive_docs/v3/static/pygments.emacs-dull.css +++ /dev/null @@ -1,69 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #161f27; padding: 0.5rem 1rem; border-radius: 5px; } -.highlight .c { color: #008800; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #008800; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #008800 } /* Comment.Preproc */ -.highlight .cpf { color: #008800; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #AA22FF } /* Keyword.Pseudo */ -.highlight .kr { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #666666 } /* Literal.Number */ -.highlight .s { color: #BB4444 } /* Literal.String */ -.highlight .na { color: #BB4444 } /* Name.Attribute */ -.highlight .nb { color: #AA22FF } /* Name.Builtin */ -.highlight .nc { color: rgba(142, 142, 255, 0.8)} /* Name.Class */ -.highlight .no { color: #880000 } /* Name.Constant */ -.highlight .nd { color: #AA22FF } /* Name.Decorator */ -.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #00A000 } /* Name.Function */ -.highlight .nl { color: #A0A000 } /* Name.Label */ -.highlight .nn { color: rgba(142, 142, 255, 0.8); font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #B8860B } /* Name.Variable */ -.highlight .ow { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #666666 } /* Literal.Number.Bin */ -.highlight .mf { color: #666666 } /* Literal.Number.Float */ -.highlight .mh { color: #666666 } /* Literal.Number.Hex */ -.highlight .mi { color: #666666 } /* Literal.Number.Integer */ -.highlight .mo { color: #666666 } /* Literal.Number.Oct */ -.highlight .sa { color: #BB4444 } /* Literal.String.Affix */ -.highlight .sb { color: #BB4444 } /* Literal.String.Backtick */ -.highlight .sc { color: #BB4444 } /* Literal.String.Char */ -.highlight .dl { color: #BB4444 } /* Literal.String.Delimiter */ -.highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #BB4444 } /* Literal.String.Double */ -.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */ -.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.highlight .sx { color: #008000 } /* Literal.String.Other */ -.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ -.highlight .s1 { color: #BB4444 } /* Literal.String.Single */ -.highlight .ss { color: #B8860B } /* Literal.String.Symbol */ -.highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #00A000 } /* Name.Function.Magic */ -.highlight .vc { color: #B8860B } /* Name.Variable.Class */ -.highlight .vg { color: #B8860B } /* Name.Variable.Global */ -.highlight .vi { color: #B8860B } /* Name.Variable.Instance */ -.highlight .vm { color: #B8860B } /* Name.Variable.Magic */ -.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/archive_docs/v3/static/safari-pinned-tab.svg b/archive_docs/v3/static/safari-pinned-tab.svg deleted file mode 100644 index c39f3979..00000000 --- a/archive_docs/v3/static/safari-pinned-tab.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -Created by potrace 1.14, written by Peter Selinger 2001-2017 - - - - - diff --git a/archive_docs/v3/static/site.webmanifest b/archive_docs/v3/static/site.webmanifest deleted file mode 100644 index de65106f..00000000 --- a/archive_docs/v3/static/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-256x256.png", - "sizes": "256x256", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/archive_docs/v3/static/water.css b/archive_docs/v3/static/water.css deleted file mode 100644 index 945210c0..00000000 --- a/archive_docs/v3/static/water.css +++ /dev/null @@ -1,929 +0,0 @@ -/** - * Forced dark theme version - */ - -:root { - --background-body: #202b38; - --background: #161f27; - --background-alt: #1a242f; - --selection: #1c76c5; - --text-main: #dbdbdb; - --text-bright: #fff; - --text-muted: #a9b1ba; - --links: #41adff; - --focus: #0096bfab; - --border: #526980; - --code: #ffbe85; - --animation-duration: 0.1s; - --button-base: #0c151c; - --button-hover: #040a0f; - --scrollbar-thumb: var(--button-hover); - --scrollbar-thumb-hover: rgb(0, 0, 0); - --form-placeholder: #a9a9a9; - --form-text: #fff; - --variable: #d941e2; - --highlight: #efdb43; - --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E"); -} - -html { - scrollbar-color: #040a0f #202b38; - scrollbar-color: var(--scrollbar-thumb) var(--background-body); - scrollbar-width: thin; -} - -body { - font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif; - line-height: 1.4; - max-width: 1000px; - margin: 0 auto; - padding: 0 10px; - word-wrap: break-word; - color: #dbdbdb; - color: var(--text-main); - background: #202b38; - background: var(--background-body); - text-rendering: optimizeLegibility; - letter-spacing: 1px; - display: flex; - flex-direction: row; -} - -aside { - width: 250px; - border-right: 1px solid rgba(220, 220, 220, 0.5); - padding-right: 10px; - padding-bottom: 40px; - height: 100%; - overflow-y: auto; - position: fixed; -} - -aside ul { - list-style: none; - padding-left: 0; - padding-bottom: 10px; - margin: 0; -} - -aside ul > ul { - padding-top: 5px; - padding-left: 5px; -} - -section { - width: 750px; - padding-left: 290px; - padding-top: 30px; - padding-bottom: 30px; -} - -section > div:nth-child(2) { - margin-top: 20px; -} - -hr { - margin: 40px 0; -} - -.highlight { - margin-bottom: 1rem; - overflow-y: auto; -} - -button { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -input { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -textarea { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -h1 { - font-size: 2.2em; - margin-top: 0; - margin-bottom: 12px; -} - -h2, -h3, -h4, -h5, -h6 { - margin-bottom: 12px; - margin-top: 24px; -} - -h1 { - color: #fff; - color: var(--text-bright); -} - -h2 { - color: #fff; - color: var(--text-bright); -} - -h3 { - color: #fff; - color: var(--text-bright); -} - -h4 { - color: #fff; - color: var(--text-bright); -} - -h5 { - color: #fff; - color: var(--text-bright); -} - -h6 { - color: #fff; - color: var(--text-bright); -} - -strong { - color: #fff; - color: var(--text-bright); -} - -h1, -h2, -h3, -h4, -h5, -h6, -b, -strong, -th { - font-weight: 600; -} - -q::before { - content: none; -} - -q::after { - content: none; -} - -blockquote { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -q { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -blockquote > footer { - font-style: normal; - border: 0; -} - -blockquote cite { - font-style: normal; -} - -address { - font-style: normal; -} - -a[href^='mailto\:']::before { - content: '📧 '; -} - -a[href^='tel\:']::before { - content: '📞 '; -} - -a[href^='sms\:']::before { - content: '💬 '; -} - -mark { - background-color: #efdb43; - background-color: var(--highlight); - border-radius: 2px; - padding: 0 2px 0 2px; - color: #000; -} - -a > code, -a > strong { - color: inherit; -} - -button, -select, -input[type='submit'], -input[type='reset'], -input[type='button'], -input[type='checkbox'], -input[type='range'], -input[type='radio'] { - cursor: pointer; -} - -input, -select { - display: block; -} - -[type='checkbox'], -[type='radio'] { - display: initial; -} - -input { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -textarea { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -select { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='submit'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='reset'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='button'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -button:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='submit']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='reset']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='button']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='color'] { - min-height: 2rem; - padding: 8px; - cursor: pointer; -} - -input[type='checkbox'], -input[type='radio'] { - height: 1em; - width: 1em; -} - -input[type='radio'] { - border-radius: 100%; -} - -input { - vertical-align: top; -} - -label { - vertical-align: middle; - margin-bottom: 4px; - display: inline-block; -} - -input:not([type='checkbox']):not([type='radio']), -input[type='range'], -select, -button, -textarea { - -webkit-appearance: none; -} - -textarea { - display: block; - margin-right: 0; - box-sizing: border-box; - resize: vertical; -} - -textarea:not([cols]) { - width: 100%; -} - -textarea:not([rows]) { - min-height: 40px; - height: 140px; -} - -select { - background: #161f27 url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat; - background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat; - padding-right: 35px; -} - -select::-ms-expand { - display: none; -} - -select[multiple] { - padding-right: 10px; - background-image: none; - overflow-y: auto; -} - -input:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -select:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -button:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -textarea:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -input[type='checkbox']:active, -input[type='radio']:active, -input[type='submit']:active, -input[type='reset']:active, -input[type='button']:active, -input[type='range']:active, -button:active { - transform: translateY(2px); -} - -input:disabled, -select:disabled, -button:disabled, -textarea:disabled { - cursor: not-allowed; - opacity: 0.5; -} - -::-moz-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -:-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -fieldset { - border: 1px #0096bfab solid; - border: 1px var(--focus) solid; - border-radius: 6px; - margin: 0; - margin-bottom: 12px; - padding: 10px; -} - -legend { - font-size: 0.9em; - font-weight: 600; -} - -input[type='range'] { - margin: 10px 0; - padding: 10px 0; - background: transparent; -} - -input[type='range']:focus { - outline: none; -} - -input[type='range']::-webkit-slider-runnable-track { - width: 100%; - height: 9.5px; - -webkit-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-webkit-slider-thumb { - box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); - -webkit-appearance: none; - margin-top: -7px; -} - -input[type='range']:focus::-webkit-slider-runnable-track { - background: #161f27; - background: var(--background); -} - -input[type='range']::-moz-range-track { - width: 100%; - height: 9.5px; - -moz-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-moz-range-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']::-ms-track { - width: 100%; - height: 9.5px; - background: transparent; - border-color: transparent; - border-width: 16px 0; - color: transparent; -} - -input[type='range']::-ms-fill-lower { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-fill-upper { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - border: 1px solid #000; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']:focus::-ms-fill-lower { - background: #161f27; - background: var(--background); -} - -input[type='range']:focus::-ms-fill-upper { - background: #161f27; - background: var(--background); -} - -a { - text-decoration: none; - color: #41adff; - color: var(--links); -} - -a:hover { - text-decoration: underline; -} - -code { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -samp { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -time { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -pre { - overflow-x: auto; -} - -pre > code { - padding: 10px; - display: block; - overflow-x: auto; -} - -var { - color: #d941e2; - color: var(--variable); - font-style: normal; - font-family: monospace; -} - -kbd { - background: #161f27; - background: var(--background); - border: 1px solid #526980; - border: 1px solid var(--border); - border-radius: 2px; - color: #dbdbdb; - color: var(--text-main); - padding: 2px 4px 2px 4px; -} - -img, -video { - max-width: 100%; - height: auto; -} - -hr { - border: none; - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -table { - border-collapse: collapse; - margin-bottom: 10px; - width: 100%; - table-layout: fixed; -} - -table caption { - text-align: left; -} - -td, -th { - padding: 6px; - text-align: left; - vertical-align: top; - word-wrap: break-word; -} - -thead { - border-bottom: 1px solid #526980; - border-bottom: 1px solid var(--border); -} - -tfoot { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -tbody tr:nth-child(even) { - background-color: #161f27; - background-color: var(--background); -} - -tbody tr:nth-child(even) button { - background-color: #1a242f; - background-color: var(--background-alt); -} - -tbody tr:nth-child(even) button:hover { - background-color: #202b38; - background-color: var(--background-body); -} - -::-webkit-scrollbar { - height: 10px; - width: 10px; -} - -::-webkit-scrollbar-track { - background: #161f27; - background: var(--background); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb { - background: #040a0f; - background: var(--scrollbar-thumb); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgb(0, 0, 0); - background: var(--scrollbar-thumb-hover); -} - -::-moz-selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -::selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -details { - display: flex; - flex-direction: column; - align-items: flex-start; - background-color: #1a242f; - background-color: var(--background-alt); - padding: 10px 10px 0; - margin: 1em 0; - border-radius: 6px; - overflow: hidden; -} - -details[open] { - padding: 10px; -} - -details > :last-child { - margin-bottom: 0; -} - -details[open] summary { - margin-bottom: 10px; -} - -summary { - display: list-item; - background-color: #161f27; - background-color: var(--background); - padding: 10px; - margin: -10px -10px 0; - cursor: pointer; - outline: none; -} - -summary:hover, -summary:focus { - text-decoration: underline; -} - -details > :not(summary) { - margin-top: 0; -} - -summary::-webkit-details-marker { - color: #dbdbdb; - color: var(--text-main); -} - -dialog { - background-color: #1a242f; - background-color: var(--background-alt); - color: #dbdbdb; - color: var(--text-main); - border: none; - border-radius: 6px; - border-color: #526980; - border-color: var(--border); - padding: 10px 30px; -} - -dialog > header:first-child { - background-color: #161f27; - background-color: var(--background); - border-radius: 6px 6px 0 0; - margin: -10px -30px 10px; - padding: 10px; - text-align: center; -} - -dialog::-webkit-backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -dialog::backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -footer { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); - padding-top: 10px; - color: #a9b1ba; - color: var(--text-muted); -} - -body > footer { - margin-top: 40px; -} - -@media print { - body, - pre, - code, - summary, - details, - button, - input, - textarea { - background-color: #fff; - } - - button, - input, - textarea { - border: 1px solid #000; - } - - body, - h1, - h2, - h3, - h4, - h5, - h6, - pre, - code, - button, - input, - textarea, - footer, - summary, - strong { - color: #000; - } - - summary::marker { - color: #000; - } - - summary::-webkit-details-marker { - color: #000; - } - - tbody tr:nth-child(even) { - background-color: #f2f2f2; - } - - a { - color: #00f; - text-decoration: underline; - } -} \ No newline at end of file diff --git a/archive_docs/v4/blueprint-config-x.html b/archive_docs/v4/blueprint-config-x.html deleted file mode 100644 index 4d85687c..00000000 --- a/archive_docs/v4/blueprint-config-x.html +++ /dev/null @@ -1,370 +0,0 @@ - - - - - The Flask-Imp Blueprint Config File | Flask-Imp - - - - - - - - - - - - - - -
      -

      The Flask-Imp Blueprint Config File

      -
      -

      Recommendation: Try and favour the use of a py file for your -configuration settings, as this will trigger reloads under -debug mode.

      -

      Also, the bonus of being able to use Python to programmatically -set values is nice.

      -
      -

      The Flask-Imp Blueprint loads configuration settings from either a class -defined in a module or from a toml file.

      -

      This file needs to sit next to the __init__.py file.

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)  # will look for config.toml / config.py w/ Config class
      -# or
      -bp = Blueprint(__name__, config="config.Development")  # will look for Development class in config.py
      -# or
      -bp = Blueprint(__name__, config="development.toml")  # will look for development.toml file
      -
      -

      For more information about the config parameter see: Imp / config.x

      -

      Using environment variables

      -

      toml

      -

      In a toml config, you can set environment variables by using {{ }}

      -
      TEST_VALUE = "{{ test_value }}"
      -
      -

      You can also set the type of the variable by using :type after the variable name.

      -
      TEST_VALUE = "{{ test_value:int }}"
      -
      -

      Supported types are int, float, bool, str.

      -

      py

      -

      In a py config, you can set environment variables by using os.getenv.

      -
      TEST_VALUE = os.getenv("TEST_VALUE", "default_value_here")
      -
      -

      Example config.py configuration file:

      -
      from flask_imp import ImpBlueprintConfig, DatabaseConfig
      -
      -
      -class Config(ImpBlueprintConfig):
      -    ENABLED: bool = True
      -    URL_PREFIX: str = "/"
      -    # SUBDOMAIN: str = ""
      -    # URL_DEFAULTS: dict = {}
      -    STATIC_FOLDER: str = "static"
      -    TEMPLATE_FOLDER: str = "templates"
      -    STATIC_URL_PATH: str = "/static"
      -    # ROOT_PATH: str = ""
      -    # CLI_GROUP: str = ""
      -
      -    INIT_SESSION: dict = {
      -        "www_session": "yes"
      -    }
      -
      -    DATABASE_BINDS: set[DatabaseConfig] = {
      -        DatabaseConfig(
      -            ENABLED=True,
      -            DIALECT="sqlite",
      -            NAME="www",
      -            BIND_KEY="www",
      -            LOCATION="",
      -            PORT=0,
      -            USERNAME="",
      -            PASSWORD="",
      -        )
      -    }
      -
      -

      Example config.toml configuration file:

      -
      ENABLED = "yes"
      -
      -[SETTINGS]
      -URL_PREFIX = "/"
      -#SUBDOMAIN = ""
      -#URL_DEFAULTS = {}
      -STATIC_FOLDER = "static"
      -TEMPLATE_FOLDER = "templates"
      -STATIC_URL_PATH = "/static"
      -#ROOT_PATH = ""
      -#CLI_GROUP = ""
      -
      -[SESSION]
      -www_session = "yes"
      -
      -# Set ENABLED to true to allow the blueprint
      -# to create a database bind, change settings accordingly.
      -[DATABASE_BIND]
      -ENABLED = true
      -DIALECT = "sqlite"
      -DATABASE_NAME = "www"
      -BIND_KEY = "www"
      -LOCATION = ""
      -PORT = ""
      -USERNAME = ""
      -PASSWORD = ""
      -
      -

      These config files reflect the args that are passed to a regular Flask Blueprint class, -with the addition of the ability to enable/disable the Blueprint, set session variables and -include database binds.

      -

      For more information about the args of a regular Flask Blueprint see: -Flask docs (Blueprint)

      -

      Session Variables

      -

      You can set the default session variables for the blueprint by setting values in INIT_SESSION, these can be loaded -using the before_request function in the blueprint.

      -
      @blueprint.before_app_request
      -def load_session():
      -    blueprint.init_session()
      -
      -

      Database Binds

      -

      You can also allow the blueprint to create a database bind, by setting ENABLED to true in the DATABASE_BIND -section of the toml file, or by adding to the DATABASE_BINDS set of the Config class.

      -

      Using a py config file will allow you to set multiple database binds for the blueprint.

      -

      This will add to the Flask app's SQLALCHEMY_BINDS config variable, and allows blueprints to be more modular -with their database connections.

      -

      Including the attribute __bind_key__ in the blueprint's model(s) will match the model to the database bind.

      -
      class User(db.Model):
      -    __bind_key__ = "example"
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint-init.html b/archive_docs/v4/blueprint-init.html deleted file mode 100644 index 3e16914e..00000000 --- a/archive_docs/v4/blueprint-init.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - - Flask-Imp Blueprint __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint __init__

      -
      Blueprint(dunder_name: str, config_file: str = "config.toml") -> None
      -
      -
      -

      Initializes the Flask-Imp Blueprint.

      -

      dunder_name should always be set to __name__

      -

      config_file is the name of the config file to load. -It will be loaded from the same directory as the __init__.py file.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint-introduction.html b/archive_docs/v4/blueprint-introduction.html deleted file mode 100644 index fad28dfa..00000000 --- a/archive_docs/v4/blueprint-introduction.html +++ /dev/null @@ -1,316 +0,0 @@ - - - - - Flask-Imp Blueprint Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint Introduction

      -

      The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints.

      -

      The Flask-Imp Blueprint by default, reads configuration from a config.toml file or from a config class, -which is located in the same directory as the -__init__.py file.

      -

      Here's an example of a Flask-Imp Blueprint structure:

      -
      www/
      -├── nested_blueprints/
      -│   ├── blueprint_one/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.py
      -│   └── blueprint_two/
      -│       ├── ...
      -│       ├── __init__.py
      -│       └── config.py
      -├── standalone_nested_blueprint/
      -│   ├── ...
      -│   ├── __init__.py
      -│   └── config.py
      -├── models/
      -│   └── ...
      -├── routes/
      -│   └── index.py
      -├── static/
      -│   └── ...
      -├── templates/
      -│   └── www/
      -│       └── index.html
      -├── __init__.py
      -└── config.py
      -
      -

      File: __init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -bp.import_nested_blueprints("nested_blueprints")
      -bp.import_nested_blueprint("standalone_nested_blueprint")
      -
      -
      -@bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      -

      During the __init__ method of the Blueprint class, if the config argument is not set to None, the Blueprint will -attempt to load the configuration from either config.toml file or a Config class from a config.py file.

      -

      To see more about configuration see: Blueprint / config.x

      -

      import_resources method will walk one level deep into the routes folder, and import all .py files as modules. -For more information see: Blueprint.x / import_resources

      -

      import_models works the same as imp.import_models, it will look for instances of db.Model and import them. These -will also be available in the model lookup method imp.model. -For more information see: Imp.x / import_models

      -

      import_nested_blueprints will do the same as imp.import_blueprints, but will register the blueprints found as -nested to the current blueprint. For example www.blueprint_one.index

      -

      import_nested_blueprint behaves the same as import_nested_blueprints, but will only import a single blueprint.

      -

      bp.init_session will load the session variables from the config file into the session object. For more information -see: Blueprint.x / init_session and -Blueprint / config.x

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-import_models.html b/archive_docs/v4/blueprint_x-import_models.html deleted file mode 100644 index 1357b215..00000000 --- a/archive_docs/v4/blueprint_x-import_models.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - Blueprint.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_models

      -
      import_models(folder: str = "models") -> None
      -
      -
      -

      Will import all the models from the given folder relative to the Blueprint's root directory.

      -

      Works the same as Imp.x / import_models but relative to the Blueprint root.

      -

      Blueprint models will also be available in the Imp.x / model lookup.

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── animal_models.py
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      or

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── models/
      -│   └── animals.py
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("animal_models.py")
      -
      -

      or

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -
      -

      File: my_blueprint/animal_models.py or my_blueprint/models/animals.py

      -
      from app import db
      -
      -
      -class Animals(db.Model):
      -    animal_id = db.Column(db.Integer, primary_key=True)
      -    name = db.Column(db.String(64), index=True, unique=True)
      -    species = db.Column(db.String(64), index=True, unique=True)
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-import_nested_blueprint.html b/archive_docs/v4/blueprint_x-import_nested_blueprint.html deleted file mode 100644 index 494cc370..00000000 --- a/archive_docs/v4/blueprint_x-import_nested_blueprint.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - Blueprint.import_nested_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_nested_blueprint

      -
      import_nested_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root.

      -

      Works the same as Imp.x / import_blueprint but relative to the Blueprint root.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.my_nested_blueprint.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── my_nested_blueprint/
      -│   ├── routes/
      -│   │   └── index.py
      -│   ├── static/...
      -│   ├── templates/...
      -│   ├── __init__.py
      -│   └── config.toml
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprint("my_nested_blueprint")
      -
      -

      File: my_blueprint/my_nested_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -
      -

      File: my_blueprint/my_nested_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-import_nested_blueprints.html b/archive_docs/v4/blueprint_x-import_nested_blueprints.html deleted file mode 100644 index 7bb022ee..00000000 --- a/archive_docs/v4/blueprint_x-import_nested_blueprints.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - Blueprint.import_nested_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_nested_blueprints

      -
      import_nested_blueprints(self, folder: str) -> None
      -
      -
      -

      Will import all the Blueprints from the given folder relative to the Blueprint's root directory.

      -

      Uses Blueprint.x / import_nested_blueprint to import blueprints from -the specified folder.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.nested_bp_one.index')

      -

      url_for('my_blueprint.nested_bp_two.index')

      -

      url_for('my_blueprint.nested_bp_three.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── nested_blueprints/
      -│   │
      -│   ├── nested_bp_one/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.toml
      -│   ├── nested_bp_two/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   │   └── config.toml
      -│   └── nested_bp_three/
      -│       ├── ...
      -│       ├── __init__.py
      -│       └── config.toml
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprints("nested_blueprints")
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-import_resources.html b/archive_docs/v4/blueprint_x-import_resources.html deleted file mode 100644 index 6204718b..00000000 --- a/archive_docs/v4/blueprint_x-import_resources.html +++ /dev/null @@ -1,292 +0,0 @@ - - - - - Blueprint.import_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.import_resources

      -
      import_resources(folder: str = "routes") -> None
      -
      -
      -

      Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory.

      -
      my_blueprint
      -├── user_routes
      -│   ├── user_dashboard.py
      -│   └── user_settings.py
      -├── car_routes
      -│   ├── car_dashboard.py
      -│   └── car_settings.py
      -├── static/...
      -├── templates/
      -│   └── my_blueprint/
      -│       ├── user_dashboard.html
      -│       └── ...
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("user_routes")
      -bp.import_resources("car_routes")
      -
      -

      File: my_blueprint/user_routes/user_dashboard.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -@bp.route("/user-dashboard")
      -def user_dashboard():
      -    return render_template(bp.tmpl("user_dashboard.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-init_session.html b/archive_docs/v4/blueprint_x-init_session.html deleted file mode 100644 index 0d0780b1..00000000 --- a/archive_docs/v4/blueprint_x-init_session.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - Blueprint.init_session | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.init_session

      -
      init_session() -> None
      -
      -
      -

      Has the same functionality as Imp.x / init_session but loads session key values from the -Blueprint's config file.

      -
      @bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/blueprint_x-tmpl.html b/archive_docs/v4/blueprint_x-tmpl.html deleted file mode 100644 index 7e52bcc3..00000000 --- a/archive_docs/v4/blueprint_x-tmpl.html +++ /dev/null @@ -1,285 +0,0 @@ - - - - - Blueprint.tmpl | Flask-Imp - - - - - - - - - - - - - - -
      -

      Blueprint.tmpl

      -
      tmpl(template: str) -> str
      -
      -
      -

      Scopes the template lookup to the name of the blueprint (this takes from the __name__ attribute of the Blueprint).

      -

      Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder.

      -
      my_blueprint/
      -├── routes/
      -│   └── index.py
      -├── static/...
      -│
      -├── templates/
      -│   └── my_blueprint/
      -│       └── index.html
      -│
      -├── __init__.py
      -└── config.toml
      -
      -

      File: my_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      -

      bp.tmpl("index.html") will output "my_blueprint/index.html".

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/cli_commands-flask-imp_blueprint.html b/archive_docs/v4/cli_commands-flask-imp_blueprint.html deleted file mode 100644 index 3b1c3c58..00000000 --- a/archive_docs/v4/cli_commands-flask-imp_blueprint.html +++ /dev/null @@ -1,328 +0,0 @@ - - - - - Generate A Flask-Imp Blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Generate a Flask-Imp Blueprint

      -

      Flask-Imp has its own type of blueprint. It can read some configuration from a toml file and has some extra methods for -auto importing.

      -
      flask-imp blueprint --help
      -
      -

      To generate a Flask-Imp blueprint, run the following command:

      -
      flask-imp blueprint
      -
      -

      After running this command, you will be prompted to enter the location of where you want to create your blueprint:

      -
      ~ $ flask-imp blueprint
      -(Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]:
      -
      -

      As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder app/blueprints, you would enter app/blueprints in the prompt.

      -
      ~ $ flask-imp blueprint
      -(Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]: app/blueprints
      -
      -

      You will then be prompted to enter a name for your blueprint:

      -
      ~ $ flask-imp blueprint
      -...
      -Name of the blueprint to create [my_new_blueprint]:
      -
      -

      The default name is 'my_new_blueprint', we will change this to 'admin'

      -
      ~ $ flask-imp blueprint
      -...
      -Name of the blueprint to create [my_new_blueprint]: admin
      -
      -

      Finally, you will be asked what type of configuration file you would like to use:

      -
      ~ $ flask-imp blueprint
      -...
      -What type of config file would you like to use? (py, toml) [py]:
      -
      -

      py is recommended, as it is more flexible.

      -

      After creating your blueprint, the folder structure will look like this:

      -
      app/
      -├── blueprints
      -│   └── admin
      -│       ├── routes
      -│       │   └── index.py
      -│       │
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       │
      -│       ├── templates
      -│       │   └── www
      -│       │       ├── extends
      -│       │       │   └── main.html
      -│       │       ├── includes
      -│       │       │   ├── footer.html
      -│       │       │   └── header.html
      -│       │       └── index.html
      -│       │
      -│       ├── __init__.py
      -│       └─── config.py
      -│
      -...
      -
      -

      This is a self-contained blueprint, so it has its own static, templates and routes folders. You can now navigate ' -/admin'

      -

      You can streamline this process by specifying the name of the blueprint, the folder to -create it in and the configuration to use, like so:

      -
      flask-imp blueprint -n admin -f app/blueprints --pyconfig
      -
      -

      or

      -
      flask-imp blueprint -n admin -f app/blueprints --tomlconfig
      -
      -

      for a toml config.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/cli_commands-flask-imp_init.html b/archive_docs/v4/cli_commands-flask-imp_init.html deleted file mode 100644 index 7f5ae20e..00000000 --- a/archive_docs/v4/cli_commands-flask-imp_init.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - Initialising A Flask-Imp Project | Flask-Imp - - - - - - - - - - - - - - -
      -

      Initialising a Flask-Imp Project

      -

      Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp.

      -
      flask-imp init --help
      -
      -

      Create a new project

      -

      Make sure you are in the virtual environment, and at the root of your -project folder, then run the following command:

      -
      flask-imp init
      -
      -

      After running this command, you will be prompted to choose what type of -app you want to deploy:

      -
      ~ $ flask-imp init
      -What type of app would you like to create? (full, slim, minimal) [full]:
      -
      -

      See below for the differences between the app types.

      -

      After this, you will be prompted to enter a name for your app:

      -
      ~ $ flask-imp init
      -...
      -What would you like to call your app? [app]:
      -
      -

      'app' is the default name, so if you just press enter, your app will be -called 'app'. You will then see this output:

      -

      Next you will be asked what configuration file you would like to use:

      -
      ~ $ flask-imp init
      -...
      -What type of config file would you like to use? (py, toml) [py]:
      -
      -

      py is recommended, as it is more flexible.

      -
      ~ FILES CREATED WILL LOOP OUT HERE ~
      -
      -===================
      -Flask app deployed!
      -===================
      - 
      -Your app has the default name of 'app'
      -Flask will automatically look for this!
      -Run: flask run --debug
      -
      -

      If you called your app something other than 'app', like 'new' for example, you will see:

      -
      ~ FILES CREATED WILL LOOP OUT HERE ~
      -
      -===================
      -Flask app deployed!
      -===================
      -
      -Your app has the name of 'new'
      -Run: flask --app new run --debug
      -
      -

      As you can see from the output, it gives you instructions on how to start your app, -depending on the name you gave it.

      -

      You should see a new folder that has been given the name you specified in -the flask-imp init command.

      -

      Additional options

      -

      You can also specify a name for your app in the command itself, like so:

      -
      flask-imp init -n my_app
      -
      -

      This will create a new app called 'my_app'.

      -

      You can also deploy a slim app, that will have one blueprint and no models, like so:

      -
      flask-imp init -n my_app --slim
      -
      -

      You can also deploy a minimal app, that will have no blueprints, models, or extensions, like so:

      -
      flask-imp init -n my_app --minimal
      -
      -

      This also works for what configuration file you would like to use:

      -
      flask-imp init -n my_app --pyconfig
      -
      -

      or

      -
      flask-imp init -n my_app --tomlconfig
      -
      -

      This will create a new minimal app called 'my_app' with a python configuration file.

      -
      flask-imp init -n my_app --minimal --pyconfig
      -
      -

      init Folder structures

      -

      Full app

      -

      flask-imp init --full:

      -
      app/
      -├── blueprints
      -│   └── www
      -│       ├── config.py
      -│       ├── __init__.py
      -│       ├── routes
      -│       │   └── index.py
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       └── templates
      -│           └── www
      -│               ├── extends
      -│               │   └── main.html
      -│               ├── includes
      -│               │   ├── footer.html
      -│               │   └── header.html
      -│               └── index.html
      -│
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── context_processors
      -│   │   └── context_processors.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── filters
      -│   │   └── filters.py
      -│   ├── routes
      -│   │   └── routes.py
      -│   ├── static
      -│   │   └── favicon.ico
      -│   └── templates
      -│       ├── errors
      -│       │   ├── 400.html
      -│       │   ├── 401.html
      -│       │   ├── 403.html
      -│       │   ├── 404.html
      -│       │   ├── 405.html
      -│       │   └── 500.html
      -│       └── index.html
      -│
      -├── models
      -│   ├── example_user_table.py
      -│   └── __init__.py
      -│
      -├── __init__.py
      -└── config.py
      -
      -

      Slim app

      -

      flask-imp init --slim:

      -
      app/
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── static
      -│   │   └── favicon.ico
      -│   └── templates
      -│       └── errors
      -│           ├── 400.html
      -│           ├── 401.html
      -│           ├── 403.html
      -│           ├── 404.html
      -│           ├── 405.html
      -│           └── 500.html
      -│
      -├── www
      -│   ├── config.py
      -│   ├── __init__.py
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── js
      -│   │       └── main.js
      -│   └── templates
      -│       └── www
      -│           ├── extends
      -│           │   └── main.html
      -│           ├── includes
      -│           │   ├── footer.html
      -│           │   └── header.html
      -│           └── index.html
      -│
      -├── __init__.py
      -└── config.py
      -
      -

      Minimal app

      -

      flask-imp init --minimal:

      -
      app/
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── favicon.ico
      -│   ├── templates
      -│   │   └── index.html
      -│   └── routes.py
      -│
      -├── __init__.py
      -└── config.py
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-authenticate_password.html b/archive_docs/v4/flask_imp_auth-authenticate_password.html deleted file mode 100644 index 3387bd30..00000000 --- a/archive_docs/v4/flask_imp_auth-authenticate_password.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - Authenticate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      authenticate_password - flask_imp.auth

      -
      from flask_imp.auth import authenticate_password
      -
      -
      authenticate_password(
      -    input_password: str,
      -    database_password: str,
      -    database_salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end",
      -    use_multiprocessing: bool = False
      -) -> bool
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / encrypt_password function.

      -

      Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match.

      -

      Note:

      -

      use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.

      -

      If you are using socketio, you must set use_multiprocessing to False (default).

      -

      Note:

      -
        -
      • You must know the pepper length used to hash the password.
      • -
      • You must know the position of the pepper used to hash the password.
      • -
      • You must know the encryption level used to hash the password.
      • -
      -

      Authentication Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
      input_password = "password"
      -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database
      -database_salt = "^%$*" # pulled from database
      -
      -authenticate_password(
      -    input_password,
      -    database_password,
      -    database_salt
      -)  # >>> True
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-encrypt_password.html b/archive_docs/v4/flask_imp_auth-encrypt_password.html deleted file mode 100644 index e534f2ac..00000000 --- a/archive_docs/v4/flask_imp_auth-encrypt_password.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Encrypt_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      encrypt_password - flask_imp.auth

      -
      from flask_imp.auth import encrypt_password
      -
      -
      encrypt_password(
      -    password: str,
      -    salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end"
      -) -> str
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / authenticate_password function.

      -

      Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified.

      -

      Can set the encryption level to 256 or 512, defaults to 512.

      -

      Can set the pepper length, defaults to 1. Max is 3.

      -

      Can set the pepper position, "start" or "end", defaults to "end".

      -

      Note:

      -
        -
      • You must inform the authenticate_password function of the pepper length used to hash the password.
      • -
      • You must inform the authenticate_password function of the position of the pepper used to hash the password.
      • -
      • You must inform the authenticate_password function of the encryption level used to hash the password.
      • -
      -

      Encryption Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
        -
      1. Pepper is added to the end of the plain password: "passwordA"
      2. -
      3. Salt is added to the end of the peppered password: "passwordA^%$*"
      4. -
      5. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..."
      6. -
      7. Salt and hashed password are then stored in the database.
      8. -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_alphanumeric_validator.html b/archive_docs/v4/flask_imp_auth-generate_alphanumeric_validator.html deleted file mode 100644 index ad3cf7ba..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_alphanumeric_validator.html +++ /dev/null @@ -1,265 +0,0 @@ - - - - - Generate_alphanumeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_alphanumeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_alphanumeric_validator
      -
      -
      generate_alphanumeric_validator(length: int = 8) -> str
      -
      -
      -

      Generates a random alphanumeric string of the given length.

      -

      (letters are capitalized)

      -
      Example:
      -
      generate_alphanumeric_validator(8)  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_csrf_token.html b/archive_docs/v4/flask_imp_auth-generate_csrf_token.html deleted file mode 100644 index 3bc441fc..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_csrf_token.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - Generate_csrf_token - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_csrf_token - flask_imp.auth

      -
      from flask_imp.auth import generate_csrf_token
      -
      -
      generate_csrf_token() -> str
      -
      -
      -

      Generates a SHA1 using the current date and time.

      -

      For use in Cross-Site Request Forgery.

      -

      Also used by the flask_imp.security / csrf_protect decorator.

      -
      Example:
      -
      generate_csrf_token()  # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_email_validator.html b/archive_docs/v4/flask_imp_auth-generate_email_validator.html deleted file mode 100644 index 1c381996..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_email_validator.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - Generate_email_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_email_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_email_validator
      -
      -
      generate_email_validator() -> str
      -
      -
      -

      Uses generate_alphanumeric_validator with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email.

      -

      See flask_imp.auth / generate_alphanumeric_validator -for more information.

      -
      Example:
      -
      generate_email_validator()  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_numeric_validator.html b/archive_docs/v4/flask_imp_auth-generate_numeric_validator.html deleted file mode 100644 index f6f04489..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_numeric_validator.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - Generate_numeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_numeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_numeric_validator
      -
      -
      generate_numeric_validator(length: int) -> int
      -
      -
      -

      Generates random choice between 1 * (length) and 9 * (length).

      -

      If the length is 4, it will generate a number between 1111 and 9999.

      -

      For use in MFA email, or unique filename generation.

      -
      Example:
      -
      generate_numeric_validator(4)  # >>> 1234
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_password.html b/archive_docs/v4/flask_imp_auth-generate_password.html deleted file mode 100644 index 762e04c7..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_password.html +++ /dev/null @@ -1,266 +0,0 @@ - - - - - Generate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_password - flask_imp.auth

      -
      from flask_imp.auth import generate_password
      -
      -
      generate_password(style: str = "mixed", length: int = 3) -> str
      -
      -
      -

      Generates a password of (length) characters.

      -

      The Default length is 3.

      -

      Style options: "animals", "colors", "mixed" - defaults to "mixed"

      -
      Example:
      -
      generate_password(style="animals", length=3)  # >>> 'Cat-Goat-Pig12'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_private_key.html b/archive_docs/v4/flask_imp_auth-generate_private_key.html deleted file mode 100644 index f6c13b82..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_private_key.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - Generate_private_key - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_private_key - flask_imp.auth

      -
      from flask_imp.auth import generate_private_key
      -
      -
      generate_private_key(hook: t.Optional[str]) -> str
      -
      -
      -

      Generates a sha256 private key from a passed in hook value.

      -

      If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000.

      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt,
      -            private_key=generate_private_key(hook=username)
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-generate_salt.html b/archive_docs/v4/flask_imp_auth-generate_salt.html deleted file mode 100644 index 8b5ddd6b..00000000 --- a/archive_docs/v4/flask_imp_auth-generate_salt.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - - Generate_salt - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_salt - flask_imp.auth

      -
      from flask_imp.auth import generate_salt
      -
      -
      generate_salt(length: int = 4) -> str
      -
      -
      -

      Generates a string of (length) characters of punctuation.

      -

      The Default length is 4.

      -

      For use in password hashing and storage of passwords in the database.

      -
      Example:
      -
      generate_salt()  # >>> '*!$%'
      -
      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-is_email_address_valid.html b/archive_docs/v4/flask_imp_auth-is_email_address_valid.html deleted file mode 100644 index 3102bd5d..00000000 --- a/archive_docs/v4/flask_imp_auth-is_email_address_valid.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - - Is_email_address_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_email_address_valid - flask_imp.auth

      -
      from flask_imp.auth import is_email_address_valid
      -
      -
      is_email_address_valid(
      -    email_address: str
      -) -> bool
      -
      -
      -

      Checks if an email address is valid.

      -

      Is not completely RFC 5322 compliant, but it is good enough for most use cases.

      -

      Here are examples of mistakes that it will not catch:

      -
      Valid but fails:
      -
      email@[123.123.123.123]
      -“email”@example.com
      -very.unusual.“@”.unusual.com@example.com
      -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com
      -
      -
      Invalid but passes:
      -
      email@example.com (Joe Smith)
      -email@111.222.333.44444
      -
      -
      Example:
      -
      is_email_address_valid('hello@example.com')  # >>> True
      -
      -is_email_address_valid('hello@hello@example.com')  # >>> False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_auth-is_username_valid.html b/archive_docs/v4/flask_imp_auth-is_username_valid.html deleted file mode 100644 index 06d71cac..00000000 --- a/archive_docs/v4/flask_imp_auth-is_username_valid.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Is_username_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_username_valid - flask_imp.auth

      -
      from flask_imp.auth import is_username_valid
      -
      -
      is_username_valid(
      -    username: str,
      -    allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None
      -) -> bool
      -
      -
      -

      Checks if a username is valid.

      -

      Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned.

      -
      Example "all":
      -
      is_username_valid("username", allowed=["all"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user_name : WILL PASS : True
      -_user_name : WILL PASS : False
      -
      -
      Example "dot", "dash":
      -
      is_username_valid("username", allowed=["dot", "dash"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user-name.name : WILL PASS : True
      -user_name : WILL PASS : False
      -_user_name : WILL PASS : False
      -.user.name : WILL PASS : False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_security-api_login_check.html b/archive_docs/v4/flask_imp_security-api_login_check.html deleted file mode 100644 index 1144bc34..00000000 --- a/archive_docs/v4/flask_imp_security-api_login_check.html +++ /dev/null @@ -1,281 +0,0 @@ - - - - - Api_login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      api_login_check - flask_imp.security

      -
      from flask_imp.security import api_login_check
      -
      -
      api_login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_json: t.Optional[t.Dict[str, t.Any]] = None
      -)
      -
      -

      @api_login_check(...)

      -
      -

      A decorator that is used to secure API routes that return JSON responses.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_json JSON that is returned on failure. {"error": "You are not logged in."} by default.

      -
      Example:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True)
      -def api_page():
      -    ...
      -
      -
      Example of defined fail_json:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."})
      -def api_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_security-include_csrf.html b/archive_docs/v4/flask_imp_security-include_csrf.html deleted file mode 100644 index 36621f4c..00000000 --- a/archive_docs/v4/flask_imp_security-include_csrf.html +++ /dev/null @@ -1,285 +0,0 @@ - - - - - Include_csrf - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      include_csrf - flask_imp.security

      -
      from flask_imp.security import include_csrf
      -
      -
      include_csrf(
      -    session_key: str = "csrf",
      -    form_key: str = "csrf",
      -    abort_code: int = 401
      -)
      -
      -

      @include_csrf(...)

      -
      -

      A decorator that handles CSRF protection.

      -

      On a GET request, a CSRF token is generated and stored in the session key -specified by the session_key parameter.

      -

      On a POST request, the form_key specified is checked against the session_key -specified.

      -
        -
      • If they match, the request is allowed to continue.
      • -
      • If no match, the response will be abort(abort_code), default 401.
      • -
      -
      @bp.route("/admin", methods=["GET", "POST"])
      -@include_csrf(session_key="csrf", form_key="csrf")
      -def admin_page():
      -    ...
      -    # You must pass in the CSRF token from the session into the template.
      -    # Then add <input type="hidden" name="csrf" value="{{ csrf }}"> to the form.
      -    return render_template("admin.html", csrf=session.get("csrf"))
      -
      -

      Form key:

      -
      <input type="hidden" name="csrf" value="{{ csrf }}">
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_security-login_check.html b/archive_docs/v4/flask_imp_security-login_check.html deleted file mode 100644 index 1188931b..00000000 --- a/archive_docs/v4/flask_imp_security-login_check.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - Login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      login_check - flask_imp.security

      -
      from flask_imp.security import login_check
      -
      -
      login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    pass_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @login_check(...)

      -
      -

      A decorator that checks if the specified session key exists and contains the specified value.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example of a route that requires a user to be logged in:
      -
      @bp.route("/admin", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    fail_endpoint='blueprint.login_page',
      -    message="Login needed"
      -)
      -def admin_page():
      -    ...
      -
      -
      Example of a route that if the user is already logged in, redirects to the specified endpoint:
      -
      @bp.route("/login-page", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    pass_endpoint='blueprint.admin_page',
      -    message="Already logged in"
      -)
      -def login_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_security-pass_function_check.html b/archive_docs/v4/flask_imp_security-pass_function_check.html deleted file mode 100644 index 7a44ab6b..00000000 --- a/archive_docs/v4/flask_imp_security-pass_function_check.html +++ /dev/null @@ -1,346 +0,0 @@ - - - - - Pass_function_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      pass_function_check - flask_imp.security

      -
      from flask_imp.security import pass_function_check
      -
      -
      def pass_function_check(
      -    function: t.Callable,
      -    predefined_args: t.Optional[t.Dict] = None,
      -    fail_endpoint: t.Optional[str] = None,
      -    pass_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message",
      -    fail_on_missing_kwargs: bool = False,
      -    with_app_context: bool = False,
      -)
      -
      -

      NOTE: This was added mostly as an experimental feature, but ended up being useful in some cases.

      -

      A decorator that takes the result of a function and checks if it is True or False.

      -

      URL variables from @route will be read by this decorator. -To use URL variables in your passed in function, -make sure your functions argument(s) name(s) match the name(s) of the URL variable(s).

      -

      Example:

      -
      def check_if_number(value):
      -    if isinstance(value, int):
      -        return True
      -    return False
      -
      -@bp.route("/admin-page/<int:value>", methods=["GET"])
      -@login_check('logged_in', True, 'blueprint.login_page')  # can be mixed with login_check
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args=None,
      -    fail_endpoint='www.index',
      -    message="Failed message"
      -)
      -def admin_page():
      -    ...
      -
      -@bp.route("/admin-page/<int:value>", methods=["GET"])
      -@login_check('logged_in', True, 'blueprint.login_page')  # can be mixed with login_check
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args={'value': 10},
      -    fail_endpoint='www.index',
      -    message="Failed message"
      -)
      -def admin_page_overwrite():
      -    ...
      -
      -

      Advanced use case:

      -

      Here's an example of accessing flask.session from within the passed in function. including the -with_app_context parameter, the function will be called with app_context().

      -
      from flask import current_app
      -from flask import session
      -
      -...
      -
      -def check_if_number(number=1, session_=None):
      -    if session_:
      -        print(session_)
      -    try:
      -        int(number)
      -        return True
      -    except ValueError:
      -        return False
      -
      -@bp.route("/pass-func-check-with-url-var/<number>", methods=["GET"])
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args={'number': 10, 'session_': session},
      -    fail_endpoint="www.index",
      -    with_app_context=True
      -)
      -def admin_page_overwrite_with_session():
      -    ...
      -
      -

      If you pass in a predefined arg that has the same key name as a session variable that exists, the value -of that predefined arg will be replaced with the session variable value.

      -
      session['car'] = 'Toyota'
      -...
      -def check_function(car):
      -    if car == 'Toyota':
      -        return True
      -    return False
      -...
      -@bp.route("/pass-func-check-with-url-var/<number>", methods=["GET"])
      -@pass_function_check(
      -    check_function,
      -    predefined_args={'car': session},
      -    ...
      -
      -

      This will pass, as pass_function_check will replace the value of the predefined arg 'car' with the value -of the session variable 'car'.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/flask_imp_security-permission_check.html b/archive_docs/v4/flask_imp_security-permission_check.html deleted file mode 100644 index a62f68b3..00000000 --- a/archive_docs/v4/flask_imp_security-permission_check.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - Permission_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      permission_check - flask_imp.security

      -
      from flask_imp.security import permission_check
      -
      -
      permission_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @permission_check(...)

      -
      -

      A decorator that checks if the specified session key exists and its value(s) match the specified value(s).

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example:
      -
      @bp.route("/admin-page", methods=["GET"])
      -@login_check(
      -    'logged_in', 
      -    True, 
      -    'blueprint.login_page'
      -)  # can be mixed with login_check
      -@permission_check(
      -    'permissions', 
      -    ['admin'], 
      -    fail_endpoint='www.index', 
      -    message="Failed message"
      -)
      -def admin_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp-config-x.html b/archive_docs/v4/imp-config-x.html deleted file mode 100644 index b31d25c7..00000000 --- a/archive_docs/v4/imp-config-x.html +++ /dev/null @@ -1,488 +0,0 @@ - - - - - The Flask-Imp Config File | Flask-Imp - - - - - - - - - - - - - - -
      -

      The Flask-Imp Config File

      -
      -

      Recommendation: Try and favour the use of a py file for your -configuration settings, as this will trigger reloads under -debug mode.

      -

      Also, the bonus of being able to use Python to programmatically -set values is nice.

      -
      -

      Flask-Imp loads configuration settings from either a class -defined in a module or from a toml file.

      -

      This example:

      -
      def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app, config="dev.config.toml")
      -
      -

      Will load configuration from the dev.config.toml file.

      -

      This example:

      -
      def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app, config="config.Config")
      -
      -

      Will load the configuration from the Config class from the config.py file.

      -

      Both of these files need to be located in the root of the app.

      -

      The config class must be an instance of ImpConfig from flask_imp.

      -

      You can also set the config by using the IMP_CONFIG environment -variable, but you will need to omit or set the config parameter to None.

      -

      For example, given the following folder structure:

      -
      Project/
      -├── app/
      -│   ├── ...
      -│   ├── __init__.py
      -│   ├── config.py
      -│   └── dev.config.toml
      -├── venv/...
      -└── ...
      -
      -

      You'd set the IMP_CONFIG=dev.config.toml and this will load the dev.config.toml file.

      -

      Using environment variables

      -

      toml

      -

      In a toml config, you can set environment variables by using {{ }}

      -
      TEST_VALUE = "{{ test_value }}"
      -
      -

      You can also set the type of the variable by using :type after the variable name.

      -
      TEST_VALUE = "{{ test_value:int }}"
      -
      -

      Supported types are int, float, bool, str.

      -

      py

      -

      In a py config, you can set environment variables by using os.getenv.

      -
      TEST_VALUE = os.getenv("TEST_VALUE", "default_value_here")
      -
      -

      Example config.py configuration file:

      -
      Project/
      -├── app/
      -│   ├── ...
      -│   ├── __init__.py
      -│   └── config.py
      -├── venv/...
      -└── ...
      -
      -
      from flask_imp import (
      -    FlaskConfig,
      -    ImpConfig,
      -    DatabaseConfig
      -)
      -
      -
      -class Config(ImpConfig):
      -    FLASK = FlaskConfig(
      -        # DEBUG=False,
      -        # PROPAGATE_EXCEPTIONS = True,
      -        TRAP_HTTP_EXCEPTIONS=False,
      -        # TRAP_BAD_REQUEST_ERRORS = True,
      -        SECRET_KEY="flask-imp",  # CHANGE ME
      -        SESSION_COOKIE_NAME="session",
      -        # SESSION_COOKIE_DOMAIN = "domain-here.com",
      -        # SESSION_COOKIE_PATH = "/",
      -        SESSION_COOKIE_HTTPONLY=True,
      -        SESSION_COOKIE_SECURE=False,
      -        SESSION_COOKIE_SAMESITE="Lax",
      -        PERMANENT_SESSION_LIFETIME=3600,  # 1 hour,
      -        SESSION_REFRESH_EACH_REQUEST=True,
      -        USE_X_SENDFILE=False,
      -        # SEND_FILE_MAX_AGE_DEFAULT = 43200,
      -        ERROR_404_HELP=True,
      -        # SERVER_NAME = "localhost:5000",
      -        APPLICATION_ROOT="/",
      -        PREFERRED_URL_SCHEME="http",
      -        # MAX_CONTENT_LENGTH = 0,
      -        # TEMPLATES_AUTO_RELOAD = True,
      -        EXPLAIN_TEMPLATE_LOADING=False,
      -        MAX_COOKIE_SIZE=4093,
      -    )
      -
      -    # This will set the default session variables for the app.
      -    INIT_SESSION = {
      -        "logged_in": False,
      -    }
      -
      -    # Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy.
      -    # This sets the file extension for SQLite databases, and where to create the folder
      -    # that the database will be stored in.
      -    # True will create the folder on the same level as your
      -    # app, False will create the folder in the app root.
      -    SQLITE_DB_EXTENSION = ".sqlite"
      -    SQLITE_STORE_IN_PARENT = False
      -    #
      -
      -    # SQLAlchemy settings that will be passed to Flask
      -    # Any SQLAlchemy setting here will overwrite anything
      -    # set in the config above
      -    SQLALCHEMY_ECHO = False
      -    SQLALCHEMY_TRACK_MODIFICATIONS = False
      -    SQLALCHEMY_RECORD_QUERIES = False
      -    #
      -
      -    # Main database settings, this will be converted to SQLALCHEMY_DATABASE_URI
      -    DATABASE_MAIN = DatabaseConfig(
      -        ENABLED=True,
      -        DIALECT="sqlite",
      -        NAME="main",
      -        LOCATION="",
      -        PORT=0,
      -        USERNAME="",
      -        PASSWORD="",
      -    )
      -
      -    # Binds are additional databases that can be used in your app
      -    # These will be added to the SQLALCHEMY_BINDS dictionary
      -    # DATABASE_BINDS = {
      -    #     DatabaseConfig(
      -    #         ENABLED=True,
      -    #         DIALECT="sqlite",
      -    #         NAME="additional_database",
      -    #         BIND_KEY="additional_database",
      -    #         LOCATION="",
      -    #         PORT=0,
      -    #         USERNAME="",
      -    #         PASSWORD="",
      -    #     )
      -    # }
      -
      -

      Example config.toml configuration file:

      -
      Project/
      -├── app/
      -│   ├── ...
      -│   ├── __init__.py
      -│   └── config.toml
      -├── venv/...
      -└── ...
      -
      -
      # Flask-Imp Config File
      -# ------------------------
      -# Updates the Flask app config with the variables below.
      -# If any variable below does not exist in the standard Flask env
      -# vars it is created and will be accessible using
      -# app.config. All key names defined below will be
      -# capitalised when imported.
      -[FLASK]
      -#DEBUG = false
      -#PROPAGATE_EXCEPTIONS = true
      -TRAP_HTTP_EXCEPTIONS = false
      -#TRAP_BAD_REQUEST_ERRORS = true
      -SECRET_KEY = "super_secret_key"
      -SESSION_COOKIE_NAME = "session"
      -#SESSION_COOKIE_DOMAIN = "domain-here.com"
      -#SESSION_COOKIE_PATH = "/"
      -SESSION_COOKIE_HTTPONLY = true
      -SESSION_COOKIE_SECURE = false
      -SESSION_COOKIE_SAMESITE = "Lax"
      -PERMANENT_SESSION_LIFETIME = 3600  # 1 hour
      -SESSION_REFRESH_EACH_REQUEST = true
      -USE_X_SENDFILE = false
      -#SEND_FILE_MAX_AGE_DEFAULT = 43200
      -ERROR_404_HELP = true
      -#SERVER_NAME = "localhost:5000"
      -APPLICATION_ROOT = "/"
      -PREFERRED_URL_SCHEME = "http"
      -#MAX_CONTENT_LENGTH = 0
      -#TEMPLATES_AUTO_RELOAD = true
      -EXPLAIN_TEMPLATE_LOADING = false
      -MAX_COOKIE_SIZE = 4093
      -
      -
      -# This will set the default session variables for the app.
      -# Anything here will be accessible using session["your_var_name"]
      -# or session.get("your_var_name")
      -[SESSION]
      -logged_in = false
      -
      -# These settings are spcific to the Flask-SQLAlchemy extension.
      -# Anything here will be accessible using app.config
      -[SQLALCHEMY]
      -SQLALCHEMY_ECHO = false
      -SQLALCHEMY_TRACK_MODIFICATIONS = false
      -SQLALCHEMY_RECORD_QUERIES = false
      -# Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy.
      -# This sets the file extension for SQLite databases, and where to create the folder
      -# that the database will be stored in. true will create the folder on the same level as your
      -# app, false will create the folder in the app root.
      -SQLITE_DB_EXTENSION = ".sqlite"
      -SQLITE_STORE_IN_PARENT = true
      -
      -# [DATABASE.MAIN] is loaded as SQLALCHEMY_DATABASE_URI
      -# Dialets = mysql / postgresql / sqlite / oracle / mssql
      -
      -# Uncomment below to generate the SQLALCHEMY_DATABASE_URI.
      -[DATABASE.MAIN]
      -ENABLED = true
      -DIALECT = "sqlite"
      -NAME = "database"
      -LOCATION = "db"
      -PORT = ""
      -USERNAME = ""
      -PASSWORD = ""
      -
      -# Adding another database is as simple as adding a new section.
      -# [DATABASE.ANOTHER] will then be accessible using SQLALCHEMY_BINDS
      -# The bind key will be stored as a lowercase value, so "ANOTHER" will
      -# be accessible as "another"
      -# You can then use the bind key in the model as follows:
      -# class MyModel(db.Model):
      -#     __bind_key__ = "another"
      -#     ...
      -
      -# Uncomment below to generate and add to SQLALCHEMY_BINDS.
      -#[DATABASE.ANOTHER]
      -#ENABLED = true
      -#DIALECT = "sqlite"
      -#NAME = "database_another"
      -#LOCATION = "db"
      -#PORT = ""
      -#USERNAME = "user"
      -#PASSWORD = "password"
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp-introduction.html b/archive_docs/v4/imp-introduction.html deleted file mode 100644 index ebb11ac4..00000000 --- a/archive_docs/v4/imp-introduction.html +++ /dev/null @@ -1,312 +0,0 @@ - - - - - Flask-Imp Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Introduction

      -

      Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources from a Flask application. It uses the importlib module to achieve this.

      -

      Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using only -Blueprints. However, you can use Flask-Imp without using Blueprints.

      -

      Here's an example of a standard Flask-Imp project structure:

      -
      app/
      -├── blueprints/
      -│   ├── admin/...
      -│   ├── api/...
      -│   └── www/...
      -├── resources/
      -│   ├── filters/...
      -│   ├── context_processors/...
      -│   ├── static/...
      -│   └── templates/...
      -├── models/...
      -├── config.py
      -└── __init__.py
      -
      -

      Here's an example of the app/__init__.py file:

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -from flask_imp import Imp
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -    db.init_app(app)
      -
      -    imp.import_app_resources("resources")
      -    imp.import_models("models")
      -    imp.import_blueprints("blueprints")
      -
      -    return app
      -
      -

      The init_app method of the Imp class will automatically load configuration -if the config argument is not set to None.

      -

      An attempt to load the configuration from either config.toml file or a Config -class from a config.py file will be made.

      -

      For more information about the config parameter see: Imp / config.x

      -

      import_app_resources will walk one level deep into the resources folder, and import -all .py files as modules. -It will also check for the existence of a static and templates folder, and register them with the Flask app.

      -

      There is a couple of options for import_app_resources to control what -is imported, see: Imp.x / import_app_resources

      -

      import_models will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via imp.model

      -

      See more about how import_models and the lookup -here: Imp.x / import_models and Imp.x / model

      -

      import_blueprints expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's __init__.py file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app.

      -

      See more about how importing blueprints work here: Blueprint / Introduction

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-import_app_resources.html b/archive_docs/v4/imp_x-import_app_resources.html deleted file mode 100644 index 850649ed..00000000 --- a/archive_docs/v4/imp_x-import_app_resources.html +++ /dev/null @@ -1,324 +0,0 @@ - - - - - Imp.import_app_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_app_resources

      -
      import_app_resources(
      -    folder: str = "resources",
      -    factories: Optional[List] = None,
      -    static_folder: str = "static",
      -    templates_folder: str = "templates",
      -    files_to_import: Optional[List] = None,
      -    folders_to_import: Optional[List] = None,
      -    ) -> None
      -
      -
      -

      Import standard app resources from the specified folder.

      -

      This will import any resources that have been set to the Flask app.

      -

      Routes, context processors, cli, etc.

      -

      Can only be called once.

      -

      If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config.

      -

      Small example of usage:

      -
      imp.import_app_resources(folder="resources")
      -# or
      -imp.import_app_resources()
      -# as the default folder is "resources"
      -
      -

      Folder Structure: resources

      -
      app
      -├── resources
      -│   ├── routes.py
      -│   ├── app_fac.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   └── templates
      -│       └── index.html
      -└── ...
      -...
      -
      -

      File: routes.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      How factories work

      -

      Factories are functions that are called when importing the app resources. Here's an example:

      -
      imp.import_app_resources(
      -    folder="resources",
      -    factories=["development_cli"]
      -)
      -
      -

      ["development_cli"] => development_cli(app) function will be called, and the current app will be passed in.

      -

      File: app_fac.py

      -
      def development_cli(app):
      -    @app.cli.command("dev")
      -    def dev():
      -        print("dev cli command")
      -
      -

      Scoping imports

      -

      By default, all files and folders will be imported.

      -

      To disable this, set files_to_import and or -folders_to_import to [None].

      -
      imp.import_app_resources(files_to_import=[None], folders_to_import=[None])
      -
      -

      To scope the imports, set the files_to_import and or folders_to_import to a list of files and or folders.

      -

      files_to_import=["cli.py", "routes.py"] => will only import the files resources/cli.py -and resources/routes.py

      -

      folders_to_import=["template_filters", "context_processors"] => will import all files in the folders -resources/template_filters/*.py and resources/context_processors/*.py

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-import_blueprint.html b/archive_docs/v4/imp_x-import_blueprint.html deleted file mode 100644 index 95ed6b07..00000000 --- a/archive_docs/v4/imp_x-import_blueprint.html +++ /dev/null @@ -1,339 +0,0 @@ - - - - - Imp.import_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprint

      -
      import_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root.

      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprint("my_blueprint")
      -
      -    return app
      -
      -

      Flask-Imp Blueprints have the ability to import configuration from a toml file, import resources, and initialize session -variables.

      -

      For more information on how Flask-Imp Blueprints work, see the Blueprint / Introduction

      -
      Example of 'my_blueprint' as a Flask-Imp Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   ├── templates
      -│   │   └── my_blueprint
      -│   │       └── index.html
      -│   ├── __init__.py
      -│   └── config.toml
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask_imp import Blueprint
      -
      -bp = Blueprint(__name__)
      -
      -bp.import_resources("routes")
      -
      -
      -@bp.before_app_request
      -def before_app_request():
      -    bp.init_session()
      -
      -

      File: routes / index.py

      -
      from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -
      Example of 'my_blueprint' as a standard Flask Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask import Blueprint
      -
      -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint")
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -

      Both of the above examples will work with imp.import_blueprint("my_blueprint"), they will be registered -with the Flask app, and will be accessible via url_for("my_blueprint.index").

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-import_blueprints.html b/archive_docs/v4/imp_x-import_blueprints.html deleted file mode 100644 index ffa220c8..00000000 --- a/archive_docs/v4/imp_x-import_blueprints.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - Imp.import_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprints

      -
      import_blueprints(self, folder: str) -> None
      -
      -
      -

      Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root.

      -
      app/
      -├── blueprints/
      -│   ├── admin/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   ├── www/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   └── api/
      -│       ├── ...
      -│       └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprints("blueprints")
      -
      -    return app
      -
      -

      This will import all Blueprints from the blueprints folder using the Imp.import_blueprint method. -See Imp.x / import_blueprint for more information.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-import_models.html b/archive_docs/v4/imp_x-import_models.html deleted file mode 100644 index 04c72338..00000000 --- a/archive_docs/v4/imp_x-import_models.html +++ /dev/null @@ -1,314 +0,0 @@ - - - - - Imp.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_models

      -
      import_models(file_or_folder: str) -> None
      -
      -
      -

      Imports all the models from the given file or folder relative to the Flask app root.

      -

      Each Model that is imported will be available in the imp.model lookup method. -See Imp.x / model for more information.

      -
      Example of importing models from a file
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── users_model.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -
      -from flask_imp import Imp
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -    db.init_app(app)  # must be below imp.init_app
      -
      -    imp.import_blueprint("my_blueprint")
      -    imp.import_models("users_model.py")
      -
      -    return app
      -
      -

      File: app/users_model.py

      -
      from app import db
      -
      -
      -class User(db.Model):
      -    attribute = db.Column(db.String(255))
      -
      -
      Example of importing models from a folder
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── models/
      -│   ├── boats.py
      -│   ├── cars.py
      -│   └── users.py
      -├── ...
      -└── __init__.py
      -
      -
      def create_app():
      -    ...
      -    imp.import_models("models")
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-init_app-init.html b/archive_docs/v4/imp_x-init_app-init.html deleted file mode 100644 index 5d4af941..00000000 --- a/archive_docs/v4/imp_x-init_app-init.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Imp.init_app, __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_app, __init__

      -
      def init_app(
      -    app: Flask,
      -    config: t.Union[str, ImpConfig] = os.environ.get("IMP_CONFIG")
      -) -> None:
      -# -or- 
      -Imp(
      -    app: Flask,
      -    config: t.Union[str, ImpConfig] = os.environ.get("IMP_CONFIG")
      -) -> None
      -
      -
      -

      Initializes the flask app to work with flask-imp.

      -

      If no config specified, an attempt to read IMP_CONFIG from the environment will be made.

      -

      The config value can be a toml file my_config.toml, for example; or an import string. An example -of an import string would be config.Config where config is the module and Config is the class.

      -

      If IMP_CONFIG is not in the environment variables, an attempt to load config.toml will be made.

      -

      If config.toml is not found, an attempt to load a class called Config from config.py will be made. -The Config class must be an instance of ImpConfig from flask_imp import ImpConfig.

      -

      An exception will be raised if none of the above methods are successful.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-init_session.html b/archive_docs/v4/imp_x-init_session.html deleted file mode 100644 index 6caa7cb9..00000000 --- a/archive_docs/v4/imp_x-init_session.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - - Imp.init_session | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_session

      -
      init_session() -> None
      -
      -
      -

      Initialize the session variables found in the config. Commonly used in app.before_request.

      -
      @app.before_request
      -def before_request():
      -    imp.init_session()
      -
      -

      File: config.toml

      -
      ...
      -[SESSION]
      -logged_in = false
      -...
      -
      -

      logged_in is now available in the session.

      -
      @app.route('/get-session-value')
      -def login():
      -    print(session['logged_in'])
      -    return "Check Terminal"
      -
      -

      Output: False

      -

      Can also be used to reset the values in the session. Here's an example:

      -
      @app.route('/logout')
      -def logout():
      -    session.clear()
      -    imp.init_session()
      -    return redirect(url_for('index'))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/imp_x-model.html b/archive_docs/v4/imp_x-model.html deleted file mode 100644 index ca7ca685..00000000 --- a/archive_docs/v4/imp_x-model.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - Imp.model | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.model

      -
      model(class_: str) -> DefaultMeta
      -
      -
      -

      Returns the SQLAlchemy model class for the given class name that was imported using Imp.import_models or -Blueprint.import_models.

      -

      This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting.

      -

      For example:

      -
      from app.models.boats import Boats
      -from app.models.cars import Cars
      -
      -

      Can be replaced with:

      -
      from app import imp
      -
      -Boats = imp.model("Boats")
      -Cars = imp.model("Cars")
      -
      -

      Or used directly:

      -
      from app import imp
      -
      -all_boats = imp.model("Boats").select_all()
      -
      -

      file: models/boats.py

      -
      from app import db
      -
      -
      -class Boats(db.Model):
      -    name = db.Column(db.String())
      -
      -    @classmethod
      -    def select_all(cls):
      -        return db.session.execute(
      -            db.select(cls)
      -        ).scalars().all()
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v4/index.html b/archive_docs/v4/index.html deleted file mode 100644 index 68c01417..00000000 --- a/archive_docs/v4/index.html +++ /dev/null @@ -1,414 +0,0 @@ - - - - - Flask-Imp - - - - - - - - - - - - - - -
      -

      Welcome to the Flask-Imp Documentation

      -

      What is Flask-Imp?

      -

      Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication.

      -

      Install Flask-Imp

      -
      pip install flask-imp
      -
      -

      Getting Started

      -

      To get started right away, you can use the CLI commands to create a new Flask-Imp project.

      -
      flask-imp init
      -
      -

      Minimal Flask-Imp Setup

      -

      Run the following command to create a minimal Flask-Imp project.

      -
      flask-imp init -n app --minimal --pyconfig
      -
      -

      See CLI Commands / flask-imp init for more information.

      -

      The minimal structure

      -

      Folder Structure

      -
      app/
      -├── resources/
      -│   ├── static/...
      -│   ├── templates/
      -│   │   └── index.html
      -│   └── index.py
      -├── config.py
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_app_resources()
      -    # Takes argument 'folder' default folder is 'resources'
      -
      -    return app
      -
      -

      File: app/config.py

      -
      from flask_imp import (
      -    FlaskConfig,
      -    ImpConfig,
      -    DatabaseConfig
      -)
      -
      -
      -class Config(ImpConfig):
      -    FLASK = FlaskConfig(
      -        # DEBUG=False,
      -        # PROPAGATE_EXCEPTIONS = True,
      -        TRAP_HTTP_EXCEPTIONS=False,
      -        # TRAP_BAD_REQUEST_ERRORS = True,
      -        SECRET_KEY="flask-imp",
      -        SESSION_COOKIE_NAME="session",
      -        # SESSION_COOKIE_DOMAIN = "domain-here.com",
      -        # SESSION_COOKIE_PATH = "/",
      -        SESSION_COOKIE_HTTPONLY=True,
      -        SESSION_COOKIE_SECURE=False,
      -        SESSION_COOKIE_SAMESITE="Lax",
      -        PERMANENT_SESSION_LIFETIME=3600,  # 1 hour,
      -        SESSION_REFRESH_EACH_REQUEST=True,
      -        USE_X_SENDFILE=False,
      -        # SEND_FILE_MAX_AGE_DEFAULT = 43200,
      -        ERROR_404_HELP=True,
      -        # SERVER_NAME = "localhost:5000",
      -        APPLICATION_ROOT="/",
      -        PREFERRED_URL_SCHEME="http",
      -        # MAX_CONTENT_LENGTH = 0,
      -        # TEMPLATES_AUTO_RELOAD = True,
      -        EXPLAIN_TEMPLATE_LOADING=False,
      -        MAX_COOKIE_SIZE=4093,
      -    )
      -
      -    # INIT_SESSION = {
      -    #     "logged_in": False,
      -    # }
      -
      -    # Below are extra settings that Flask-Imp uses but relates to Flask-SQLAlchemy.
      -    # This sets the file extension for SQLite databases, and where to create the folder
      -    # that the database will be stored in.
      -    # True will create the folder on the same level as your
      -    # app, False will create the folder in the app root.
      -    SQLITE_DB_EXTENSION = ".sqlite"
      -    SQLITE_STORE_IN_PARENT = False
      -    #
      -
      -    # SQLAlchemy settings that will be passed to Flask
      -    # Any SQLAlchemy setting here will overwrite anything
      -    # set in the config above
      -    SQLALCHEMY_ECHO = False
      -    SQLALCHEMY_TRACK_MODIFICATIONS = False
      -    SQLALCHEMY_RECORD_QUERIES = False
      -    #
      -
      -    # Main database settings, this will be turned int the SQLALCHEMY_DATABASE_URI
      -    # DATABASE_MAIN = DatabaseConfig(
      -    #     ENABLED=True,
      -    #     DIALECT="sqlite",
      -    #     NAME="main",
      -    #     LOCATION="",
      -    #     PORT=0,
      -    #     USERNAME="",
      -    #     PASSWORD="",
      -    # )
      -
      -    # Binds are additional databases that can be used in your app
      -    # These will be added to the SQLALCHEMY_BINDS dictionary
      -    # DATABASE_BINDS = {
      -    #     DatabaseConfig(
      -    #         ENABLED=True,
      -    #         DIALECT="sqlite",
      -    #         NAME="additional_database",
      -    #         BIND_KEY="additional_database",
      -    #         LOCATION="",
      -    #         PORT=0,
      -    #         USERNAME="",
      -    #         PASSWORD="",
      -    #     )
      -    # }
      -
      -

      File: app/resources/index.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      File: app/resources/templates/index.html

      -
      <!DOCTYPE html>
      -<html lang="en">
      -<head>
      -    <meta charset="UTF-8">
      -    <title>Flask-Imp</title>
      -</head>
      -<body>
      -<h1>Flask-Imp</h1>
      -</body>
      -</html>
      -
      -
      -

      Setting up a virtual environment is recommended.

      -

      Linux / Darwin

      -
      python3 -m venv venv
      -
      -
      source venv/bin/activate
      -
      -

      Windows

      -
      python -m venv venv
      -
      -
      .\venv\Scripts\activate
      -
      - -
      - - - - \ No newline at end of file diff --git a/archive_docs/v4/static/Flask-Imp-Medium.png b/archive_docs/v4/static/Flask-Imp-Medium.png deleted file mode 100644 index 1140eb4cc5c4f9538ea0a3c788db40a8fe08a663..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7987 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 diff --git a/archive_docs/v4/static/android-chrome-192x192.png b/archive_docs/v4/static/android-chrome-192x192.png deleted file mode 100644 index 1207f940bfb8ce81bb79fded911cd9167265ce42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15163 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 diff --git a/archive_docs/v4/static/android-chrome-256x256.png b/archive_docs/v4/static/android-chrome-256x256.png deleted file mode 100644 index 34e3d27479cf54144da963f21a635d7487f171ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20999 zcmV*9Kybf_P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 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 diff --git a/archive_docs/v4/static/apple-touch-icon.png b/archive_docs/v4/static/apple-touch-icon.png deleted file mode 100644 index 0ee95e6549e0f670e080cc03409951c690c85ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13882 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 diff --git a/archive_docs/v4/static/browserconfig.xml b/archive_docs/v4/static/browserconfig.xml deleted file mode 100644 index b3930d0f..00000000 --- a/archive_docs/v4/static/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - #da532c - - - diff --git a/archive_docs/v4/static/favicon-16x16.png b/archive_docs/v4/static/favicon-16x16.png deleted file mode 100644 index 6e2a5f7bb30024589b0cebe6e29ebbd01b985f99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1210 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 BIxheK diff --git a/archive_docs/v4/static/favicon.ico b/archive_docs/v4/static/favicon.ico deleted file mode 100644 index e734eba0d25de4264768b9e0d33d0caea8c763b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 DZY)W0 diff --git a/archive_docs/v4/static/pygments.emacs-dull.css b/archive_docs/v4/static/pygments.emacs-dull.css deleted file mode 100644 index 79ed4731..00000000 --- a/archive_docs/v4/static/pygments.emacs-dull.css +++ /dev/null @@ -1,69 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #161f27; padding: 0.5rem 1rem; border-radius: 5px; } -.highlight .c { color: #008800; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #008800; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #008800 } /* Comment.Preproc */ -.highlight .cpf { color: #008800; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #AA22FF } /* Keyword.Pseudo */ -.highlight .kr { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #666666 } /* Literal.Number */ -.highlight .s { color: #BB4444 } /* Literal.String */ -.highlight .na { color: #BB4444 } /* Name.Attribute */ -.highlight .nb { color: #AA22FF } /* Name.Builtin */ -.highlight .nc { color: rgba(142, 142, 255, 0.8)} /* Name.Class */ -.highlight .no { color: #880000 } /* Name.Constant */ -.highlight .nd { color: #AA22FF } /* Name.Decorator */ -.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #00A000 } /* Name.Function */ -.highlight .nl { color: #A0A000 } /* Name.Label */ -.highlight .nn { color: rgba(142, 142, 255, 0.8); font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #B8860B } /* Name.Variable */ -.highlight .ow { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #666666 } /* Literal.Number.Bin */ -.highlight .mf { color: #666666 } /* Literal.Number.Float */ -.highlight .mh { color: #666666 } /* Literal.Number.Hex */ -.highlight .mi { color: #666666 } /* Literal.Number.Integer */ -.highlight .mo { color: #666666 } /* Literal.Number.Oct */ -.highlight .sa { color: #BB4444 } /* Literal.String.Affix */ -.highlight .sb { color: #BB4444 } /* Literal.String.Backtick */ -.highlight .sc { color: #BB4444 } /* Literal.String.Char */ -.highlight .dl { color: #BB4444 } /* Literal.String.Delimiter */ -.highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #BB4444 } /* Literal.String.Double */ -.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */ -.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.highlight .sx { color: #008000 } /* Literal.String.Other */ -.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ -.highlight .s1 { color: #BB4444 } /* Literal.String.Single */ -.highlight .ss { color: #B8860B } /* Literal.String.Symbol */ -.highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #00A000 } /* Name.Function.Magic */ -.highlight .vc { color: #B8860B } /* Name.Variable.Class */ -.highlight .vg { color: #B8860B } /* Name.Variable.Global */ -.highlight .vi { color: #B8860B } /* Name.Variable.Instance */ -.highlight .vm { color: #B8860B } /* Name.Variable.Magic */ -.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/archive_docs/v4/static/safari-pinned-tab.svg b/archive_docs/v4/static/safari-pinned-tab.svg deleted file mode 100644 index c39f3979..00000000 --- a/archive_docs/v4/static/safari-pinned-tab.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -Created by potrace 1.14, written by Peter Selinger 2001-2017 - - - - - diff --git a/archive_docs/v4/static/site.webmanifest b/archive_docs/v4/static/site.webmanifest deleted file mode 100644 index de65106f..00000000 --- a/archive_docs/v4/static/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-256x256.png", - "sizes": "256x256", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/archive_docs/v4/static/water.css b/archive_docs/v4/static/water.css deleted file mode 100644 index 945210c0..00000000 --- a/archive_docs/v4/static/water.css +++ /dev/null @@ -1,929 +0,0 @@ -/** - * Forced dark theme version - */ - -:root { - --background-body: #202b38; - --background: #161f27; - --background-alt: #1a242f; - --selection: #1c76c5; - --text-main: #dbdbdb; - --text-bright: #fff; - --text-muted: #a9b1ba; - --links: #41adff; - --focus: #0096bfab; - --border: #526980; - --code: #ffbe85; - --animation-duration: 0.1s; - --button-base: #0c151c; - --button-hover: #040a0f; - --scrollbar-thumb: var(--button-hover); - --scrollbar-thumb-hover: rgb(0, 0, 0); - --form-placeholder: #a9a9a9; - --form-text: #fff; - --variable: #d941e2; - --highlight: #efdb43; - --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E"); -} - -html { - scrollbar-color: #040a0f #202b38; - scrollbar-color: var(--scrollbar-thumb) var(--background-body); - scrollbar-width: thin; -} - -body { - font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif; - line-height: 1.4; - max-width: 1000px; - margin: 0 auto; - padding: 0 10px; - word-wrap: break-word; - color: #dbdbdb; - color: var(--text-main); - background: #202b38; - background: var(--background-body); - text-rendering: optimizeLegibility; - letter-spacing: 1px; - display: flex; - flex-direction: row; -} - -aside { - width: 250px; - border-right: 1px solid rgba(220, 220, 220, 0.5); - padding-right: 10px; - padding-bottom: 40px; - height: 100%; - overflow-y: auto; - position: fixed; -} - -aside ul { - list-style: none; - padding-left: 0; - padding-bottom: 10px; - margin: 0; -} - -aside ul > ul { - padding-top: 5px; - padding-left: 5px; -} - -section { - width: 750px; - padding-left: 290px; - padding-top: 30px; - padding-bottom: 30px; -} - -section > div:nth-child(2) { - margin-top: 20px; -} - -hr { - margin: 40px 0; -} - -.highlight { - margin-bottom: 1rem; - overflow-y: auto; -} - -button { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -input { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -textarea { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -h1 { - font-size: 2.2em; - margin-top: 0; - margin-bottom: 12px; -} - -h2, -h3, -h4, -h5, -h6 { - margin-bottom: 12px; - margin-top: 24px; -} - -h1 { - color: #fff; - color: var(--text-bright); -} - -h2 { - color: #fff; - color: var(--text-bright); -} - -h3 { - color: #fff; - color: var(--text-bright); -} - -h4 { - color: #fff; - color: var(--text-bright); -} - -h5 { - color: #fff; - color: var(--text-bright); -} - -h6 { - color: #fff; - color: var(--text-bright); -} - -strong { - color: #fff; - color: var(--text-bright); -} - -h1, -h2, -h3, -h4, -h5, -h6, -b, -strong, -th { - font-weight: 600; -} - -q::before { - content: none; -} - -q::after { - content: none; -} - -blockquote { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -q { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -blockquote > footer { - font-style: normal; - border: 0; -} - -blockquote cite { - font-style: normal; -} - -address { - font-style: normal; -} - -a[href^='mailto\:']::before { - content: '📧 '; -} - -a[href^='tel\:']::before { - content: '📞 '; -} - -a[href^='sms\:']::before { - content: '💬 '; -} - -mark { - background-color: #efdb43; - background-color: var(--highlight); - border-radius: 2px; - padding: 0 2px 0 2px; - color: #000; -} - -a > code, -a > strong { - color: inherit; -} - -button, -select, -input[type='submit'], -input[type='reset'], -input[type='button'], -input[type='checkbox'], -input[type='range'], -input[type='radio'] { - cursor: pointer; -} - -input, -select { - display: block; -} - -[type='checkbox'], -[type='radio'] { - display: initial; -} - -input { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -textarea { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -select { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='submit'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='reset'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='button'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -button:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='submit']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='reset']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='button']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='color'] { - min-height: 2rem; - padding: 8px; - cursor: pointer; -} - -input[type='checkbox'], -input[type='radio'] { - height: 1em; - width: 1em; -} - -input[type='radio'] { - border-radius: 100%; -} - -input { - vertical-align: top; -} - -label { - vertical-align: middle; - margin-bottom: 4px; - display: inline-block; -} - -input:not([type='checkbox']):not([type='radio']), -input[type='range'], -select, -button, -textarea { - -webkit-appearance: none; -} - -textarea { - display: block; - margin-right: 0; - box-sizing: border-box; - resize: vertical; -} - -textarea:not([cols]) { - width: 100%; -} - -textarea:not([rows]) { - min-height: 40px; - height: 140px; -} - -select { - background: #161f27 url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat; - background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat; - padding-right: 35px; -} - -select::-ms-expand { - display: none; -} - -select[multiple] { - padding-right: 10px; - background-image: none; - overflow-y: auto; -} - -input:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -select:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -button:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -textarea:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -input[type='checkbox']:active, -input[type='radio']:active, -input[type='submit']:active, -input[type='reset']:active, -input[type='button']:active, -input[type='range']:active, -button:active { - transform: translateY(2px); -} - -input:disabled, -select:disabled, -button:disabled, -textarea:disabled { - cursor: not-allowed; - opacity: 0.5; -} - -::-moz-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -:-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -fieldset { - border: 1px #0096bfab solid; - border: 1px var(--focus) solid; - border-radius: 6px; - margin: 0; - margin-bottom: 12px; - padding: 10px; -} - -legend { - font-size: 0.9em; - font-weight: 600; -} - -input[type='range'] { - margin: 10px 0; - padding: 10px 0; - background: transparent; -} - -input[type='range']:focus { - outline: none; -} - -input[type='range']::-webkit-slider-runnable-track { - width: 100%; - height: 9.5px; - -webkit-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-webkit-slider-thumb { - box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); - -webkit-appearance: none; - margin-top: -7px; -} - -input[type='range']:focus::-webkit-slider-runnable-track { - background: #161f27; - background: var(--background); -} - -input[type='range']::-moz-range-track { - width: 100%; - height: 9.5px; - -moz-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-moz-range-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']::-ms-track { - width: 100%; - height: 9.5px; - background: transparent; - border-color: transparent; - border-width: 16px 0; - color: transparent; -} - -input[type='range']::-ms-fill-lower { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-fill-upper { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - border: 1px solid #000; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']:focus::-ms-fill-lower { - background: #161f27; - background: var(--background); -} - -input[type='range']:focus::-ms-fill-upper { - background: #161f27; - background: var(--background); -} - -a { - text-decoration: none; - color: #41adff; - color: var(--links); -} - -a:hover { - text-decoration: underline; -} - -code { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -samp { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -time { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -pre { - overflow-x: auto; -} - -pre > code { - padding: 10px; - display: block; - overflow-x: auto; -} - -var { - color: #d941e2; - color: var(--variable); - font-style: normal; - font-family: monospace; -} - -kbd { - background: #161f27; - background: var(--background); - border: 1px solid #526980; - border: 1px solid var(--border); - border-radius: 2px; - color: #dbdbdb; - color: var(--text-main); - padding: 2px 4px 2px 4px; -} - -img, -video { - max-width: 100%; - height: auto; -} - -hr { - border: none; - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -table { - border-collapse: collapse; - margin-bottom: 10px; - width: 100%; - table-layout: fixed; -} - -table caption { - text-align: left; -} - -td, -th { - padding: 6px; - text-align: left; - vertical-align: top; - word-wrap: break-word; -} - -thead { - border-bottom: 1px solid #526980; - border-bottom: 1px solid var(--border); -} - -tfoot { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -tbody tr:nth-child(even) { - background-color: #161f27; - background-color: var(--background); -} - -tbody tr:nth-child(even) button { - background-color: #1a242f; - background-color: var(--background-alt); -} - -tbody tr:nth-child(even) button:hover { - background-color: #202b38; - background-color: var(--background-body); -} - -::-webkit-scrollbar { - height: 10px; - width: 10px; -} - -::-webkit-scrollbar-track { - background: #161f27; - background: var(--background); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb { - background: #040a0f; - background: var(--scrollbar-thumb); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgb(0, 0, 0); - background: var(--scrollbar-thumb-hover); -} - -::-moz-selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -::selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -details { - display: flex; - flex-direction: column; - align-items: flex-start; - background-color: #1a242f; - background-color: var(--background-alt); - padding: 10px 10px 0; - margin: 1em 0; - border-radius: 6px; - overflow: hidden; -} - -details[open] { - padding: 10px; -} - -details > :last-child { - margin-bottom: 0; -} - -details[open] summary { - margin-bottom: 10px; -} - -summary { - display: list-item; - background-color: #161f27; - background-color: var(--background); - padding: 10px; - margin: -10px -10px 0; - cursor: pointer; - outline: none; -} - -summary:hover, -summary:focus { - text-decoration: underline; -} - -details > :not(summary) { - margin-top: 0; -} - -summary::-webkit-details-marker { - color: #dbdbdb; - color: var(--text-main); -} - -dialog { - background-color: #1a242f; - background-color: var(--background-alt); - color: #dbdbdb; - color: var(--text-main); - border: none; - border-radius: 6px; - border-color: #526980; - border-color: var(--border); - padding: 10px 30px; -} - -dialog > header:first-child { - background-color: #161f27; - background-color: var(--background); - border-radius: 6px 6px 0 0; - margin: -10px -30px 10px; - padding: 10px; - text-align: center; -} - -dialog::-webkit-backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -dialog::backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -footer { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); - padding-top: 10px; - color: #a9b1ba; - color: var(--text-muted); -} - -body > footer { - margin-top: 40px; -} - -@media print { - body, - pre, - code, - summary, - details, - button, - input, - textarea { - background-color: #fff; - } - - button, - input, - textarea { - border: 1px solid #000; - } - - body, - h1, - h2, - h3, - h4, - h5, - h6, - pre, - code, - button, - input, - textarea, - footer, - summary, - strong { - color: #000; - } - - summary::marker { - color: #000; - } - - summary::-webkit-details-marker { - color: #000; - } - - tbody tr:nth-child(even) { - background-color: #f2f2f2; - } - - a { - color: #00f; - text-decoration: underline; - } -} \ No newline at end of file diff --git a/archive_docs/v5/cli_commands-flask-imp_blueprint.html b/archive_docs/v5/cli_commands-flask-imp_blueprint.html deleted file mode 100644 index cd325fe9..00000000 --- a/archive_docs/v5/cli_commands-flask-imp_blueprint.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - Generate A Flask-Imp Blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Generate a Flask-Imp Blueprint

      -

      Flask-Imp has its own type of blueprint. It comes with some methods to auto import routes, and models etc... see -ImpBlueprint / Introduction for more information.

      -

      You have the option to generate a regular template rendering blueprint, or a API blueprint that returns a JSON response.

      -
      flask-imp blueprint --help
      -
      -

      or

      -
      flask-imp api-blueprint --help
      -
      -

      To generate a Flask-Imp blueprint, run the following command:

      -
      flask-imp blueprint
      -
      -

      or

      -
      flask-imp api-blueprint
      -
      -

      After running this command, you will be prompted to enter the location of where you want to create your blueprint:

      -
      ~ $ flask-imp blueprint
      -(Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]:
      -
      -

      As detailed in the prompt, the creation of the blueprint is relative to the current working directory. So to create a -blueprint in the folder app/blueprints, you would enter app/blueprints in the prompt.

      -
      ~ $ flask-imp blueprint
      -(Creation is relative to the current working directory)
      -Folder to create blueprint in [Current Working Directory]: app/blueprints
      -
      -

      You will then be prompted to enter a name for your blueprint:

      -
      ~ $ flask-imp blueprint
      -...
      -Name of the blueprint to create [my_new_blueprint]:
      -
      -

      The default name is 'my_new_blueprint', we will change this to 'admin'

      -
      ~ $ flask-imp blueprint
      -...
      -Name of the blueprint to create [my_new_blueprint]: admin
      -
      -

      After creating your blueprint, the folder structure will look like this:

      -
      app/
      -├── blueprints
      -│   └── admin
      -│       ├── routes
      -│       │   └── index.py
      -│       │
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       │
      -│       ├── templates
      -│       │   └── www
      -│       │       ├── extends
      -│       │       │   └── main.html
      -│       │       ├── includes
      -│       │       │   ├── footer.html
      -│       │       │   └── header.html
      -│       │       └── index.html
      -│       │
      -│       └── __init__.py
      -│
      -...
      -
      -

      This is a self-contained blueprint, so it has its own static, templates and routes folders. -You can now navigate '/admin'

      -

      You can streamline this process by specifying the name of the blueprint, the folder to -create it in and the configuration to use, like so:

      -
      flask-imp blueprint -n admin -f app/blueprints
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/cli_commands-flask-imp_init.html b/archive_docs/v5/cli_commands-flask-imp_init.html deleted file mode 100644 index 3766d39a..00000000 --- a/archive_docs/v5/cli_commands-flask-imp_init.html +++ /dev/null @@ -1,427 +0,0 @@ - - - - - Initialising A Flask-Imp Project | Flask-Imp - - - - - - - - - - - - - - -
      -

      Initialising a Flask-Imp Project

      -

      Flask-Imp has a cli command that deploys a new ready-to-go project. -This project is structured in a way to give you the best idea of -how to use Flask-Imp.

      -
      flask-imp init --help
      -
      -

      Create a new project

      -

      Make sure you are in the virtual environment, and at the root of your -project folder, then run the following command:

      -
      flask-imp init
      -
      -

      After running this command, you will be prompted to choose what type of -app you want to deploy:

      -
      ~ $ flask-imp init
      -What type of app would you like to create? (minimal, slim, full) [minimal]:
      -
      -

      See below for the differences between the app types.

      -

      After this, you will be prompted to enter a name for your app:

      -
      ~ $ flask-imp init
      -...
      -What would you like to call your app? [app]:
      -
      -

      'app' is the default name, so if you just press enter, your app will be -called 'app'. You will then see this output:

      -
      ~ FILES CREATED WILL LOOP OUT HERE ~
      -
      -===================
      -Flask app deployed!
      -===================
      - 
      -Your app has the default name of 'app'
      -Flask will automatically look for this!
      -Run: flask run --debug
      -
      -

      If you called your app something other than 'app', like 'new' for example, you will see:

      -
      ~ FILES CREATED WILL LOOP OUT HERE ~
      -
      -===================
      -Flask app deployed!
      -===================
      -
      -Your app has the name of 'new'
      -Run: flask --app new run --debug
      -
      -

      As you can see from the output, it gives you instructions on how to start your app, -depending on the name you gave it.

      -

      You should see a new folder that has been given the name you specified in -the flask-imp init command.

      -

      Additional options

      -

      You can also specify a name for your app in the command itself, like so:

      -
      flask-imp init -n my_app
      -
      -

      This will create a new app called 'my_app'. -The default will be a minimal app, this has no blueprints or database models.

      -

      You can also deploy a slim app, that will have one blueprint and no database models, like so:

      -
      flask-imp init -n my_app --slim
      -
      -

      You can also deploy a full app that is setup for multiple blueprints and database models, like so:

      -
      flask-imp init -n my_app --full
      -
      -

      init Folder structures

      -

      Minimal app (default)

      -

      flask-imp init --minimal:

      -
      app/
      -├── resources
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── favicon.ico
      -│   ├── templates
      -│   │   └── index.html
      -│   └── routes.py
      -│
      -└── __init__.py
      -
      -

      Slim app

      -

      flask-imp init --slim:

      -
      app/
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── favicon.ico
      -│   └── templates
      -│       └── error.html
      -│
      -├── www
      -│   ├── __init__.py
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   ├── css
      -│   │   │   └── water.css
      -│   │   ├── img
      -│   │   │   └── flask-imp-logo.png
      -│   │   └── js
      -│   │       └── main.js
      -│   └── templates
      -│       └── www
      -│           ├── extends
      -│           │   └── main.html
      -│           ├── includes
      -│           │   ├── footer.html
      -│           │   └── header.html
      -│           └── index.html
      -│
      -└── __init__.py
      -
      -

      Full app

      -

      flask-imp init --full:

      -
      app/
      -├── blueprints
      -│   └── www
      -│       ├── __init__.py
      -│       ├── routes
      -│       │   └── index.py
      -│       ├── static
      -│       │   ├── css
      -│       │   │   └── water.css
      -│       │   ├── img
      -│       │   │   └── flask-imp-logo.png
      -│       │   └── js
      -│       │       └── main.js
      -│       └── templates
      -│           └── www
      -│               ├── extends
      -│               │   └── main.html
      -│               ├── includes
      -│               │   ├── footer.html
      -│               │   └── header.html
      -│               └── index.html
      -│
      -├── extensions
      -│   └── __init__.py
      -│
      -├── resources
      -│   ├── cli
      -│   │   └── cli.py
      -│   ├── context_processors
      -│   │   └── context_processors.py
      -│   ├── error_handlers
      -│   │   └── error_handlers.py
      -│   ├── filters
      -│   │   └── filters.py
      -│   ├── routes
      -│   │   └── routes.py
      -│   ├── static
      -│   │   └── favicon.ico
      -│   └── templates
      -│       └── error.html
      -│
      -├── models
      -│   └── example_user_table.py
      -│
      -└── __init__.py
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-authenticate_password.html b/archive_docs/v5/flask_imp_auth-authenticate_password.html deleted file mode 100644 index 57c63131..00000000 --- a/archive_docs/v5/flask_imp_auth-authenticate_password.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - Authenticate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      authenticate_password - flask_imp.auth

      -
      from flask_imp.auth import authenticate_password
      -
      -
      authenticate_password(
      -    input_password: str,
      -    database_password: str,
      -    database_salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end",
      -    use_multiprocessing: bool = False
      -) -> bool
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / encrypt_password function.

      -

      Takes the plain input password, the stored hashed password along with the stored salt -and will try every possible combination of pepper values to find a match.

      -

      Note:

      -

      use_multiprocessing is not compatible with coroutine workers, e.g. eventlet/gevent -commonly used with socketio.

      -

      If you are using socketio, you must set use_multiprocessing to False (default).

      -

      Note:

      -
        -
      • You must know the pepper length used to hash the password.
      • -
      • You must know the position of the pepper used to hash the password.
      • -
      • You must know the encryption level used to hash the password.
      • -
      -

      Authentication Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
      input_password = "password"
      -database_password = "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..." # pulled from database
      -database_salt = "^%$*" # pulled from database
      -
      -authenticate_password(
      -    input_password,
      -    database_password,
      -    database_salt
      -)  # >>> True
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-encrypt_password.html b/archive_docs/v5/flask_imp_auth-encrypt_password.html deleted file mode 100644 index 02389194..00000000 --- a/archive_docs/v5/flask_imp_auth-encrypt_password.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - Encrypt_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      encrypt_password - flask_imp.auth

      -
      from flask_imp.auth import encrypt_password
      -
      -
      encrypt_password(
      -    password: str,
      -    salt: str,
      -    encryption_level: int = 512,
      -    pepper_length: int = 1,
      -    pepper_position: t.Literal["start", "end"] = "end"
      -) -> str
      -
      -
      -

      For use in password hashing.

      -

      To be used alongside the flask_imp.auth / authenticate_password function.

      -

      Takes the plain password, applies a pepper, salts it, then produces a digested sha512 or sha256 if specified.

      -

      Can set the encryption level to 256 or 512, defaults to 512.

      -

      Can set the pepper length, defaults to 1. Max is 3.

      -

      Can set the pepper position, "start" or "end", defaults to "end".

      -

      Note:

      -
        -
      • You must inform the authenticate_password function of the pepper length used to hash the password.
      • -
      • You must inform the authenticate_password function of the position of the pepper used to hash the password.
      • -
      • You must inform the authenticate_password function of the encryption level used to hash the password.
      • -
      -

      Encryption Scenario:

      -
      Plain password: "password"
      -Generated salt: "^%$*" (randomly generated)
      -Generated pepper (length 1): "A" (randomly generated)
      -Pepper position: "end"
      -
        -
      1. Pepper is added to the end of the plain password: "passwordA"
      2. -
      3. Salt is added to the end of the peppered password: "passwordA^%$*"
      4. -
      5. Password is hashed: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0..."
      6. -
      7. Salt and hashed password are then stored in the database.
      8. -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_alphanumeric_validator.html b/archive_docs/v5/flask_imp_auth-generate_alphanumeric_validator.html deleted file mode 100644 index 11f5d94f..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_alphanumeric_validator.html +++ /dev/null @@ -1,271 +0,0 @@ - - - - - Generate_alphanumeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_alphanumeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_alphanumeric_validator
      -
      -
      generate_alphanumeric_validator(length: int = 8) -> str
      -
      -
      -

      Generates a random alphanumeric string of the given length.

      -

      (letters are capitalized)

      -
      Example:
      -
      generate_alphanumeric_validator(8)  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_csrf_token.html b/archive_docs/v5/flask_imp_auth-generate_csrf_token.html deleted file mode 100644 index 6f401f44..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_csrf_token.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - Generate_csrf_token - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_csrf_token - flask_imp.auth

      -
      from flask_imp.auth import generate_csrf_token
      -
      -
      generate_csrf_token() -> str
      -
      -
      -

      Generates a SHA1 using the current date and time.

      -

      For use in Cross-Site Request Forgery.

      -

      Also used by the flask_imp.security / csrf_protect decorator.

      -
      Example:
      -
      generate_csrf_token()  # >>> 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_email_validator.html b/archive_docs/v5/flask_imp_auth-generate_email_validator.html deleted file mode 100644 index a2078885..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_email_validator.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Generate_email_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_email_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_email_validator
      -
      -
      generate_email_validator() -> str
      -
      -
      -

      Uses generate_alphanumeric_validator with a length of 8 to -generate a random alphanumeric value for the specific use of -validating accounts via email.

      -

      See flask_imp.auth / generate_alphanumeric_validator -for more information.

      -
      Example:
      -
      generate_email_validator()  # >>> 'A1B2C3D4'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_numeric_validator.html b/archive_docs/v5/flask_imp_auth-generate_numeric_validator.html deleted file mode 100644 index 8b6e88e9..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_numeric_validator.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - Generate_numeric_validator - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_numeric_validator - flask_imp.auth

      -
      from flask_imp.auth import generate_numeric_validator
      -
      -
      generate_numeric_validator(length: int) -> int
      -
      -
      -

      Generates random choice between 1 * (length) and 9 * (length).

      -

      If the length is 4, it will generate a number between 1111 and 9999.

      -

      For use in MFA email, or unique filename generation.

      -
      Example:
      -
      generate_numeric_validator(4)  # >>> 1234
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_password.html b/archive_docs/v5/flask_imp_auth-generate_password.html deleted file mode 100644 index bb682bd8..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_password.html +++ /dev/null @@ -1,272 +0,0 @@ - - - - - Generate_password - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_password - flask_imp.auth

      -
      from flask_imp.auth import generate_password
      -
      -
      generate_password(style: str = "mixed", length: int = 3) -> str
      -
      -
      -

      Generates a password of (length) characters.

      -

      The Default length is 3.

      -

      Style options: "animals", "colors", "mixed" - defaults to "mixed"

      -
      Example:
      -
      generate_password(style="animals", length=3)  # >>> 'Cat-Goat-Pig12'
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_private_key.html b/archive_docs/v5/flask_imp_auth-generate_private_key.html deleted file mode 100644 index c6bc8bbb..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_private_key.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - Generate_private_key - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_private_key - flask_imp.auth

      -
      from flask_imp.auth import generate_private_key
      -
      -
      generate_private_key(hook: t.Optional[str]) -> str
      -
      -
      -

      Generates a sha256 private key from a passed in hook value.

      -

      If no hook is passed in, it will generate a hook using datetime.now() and a -random number between 1 and 1000.

      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt,
      -            private_key=generate_private_key(hook=username)
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-generate_salt.html b/archive_docs/v5/flask_imp_auth-generate_salt.html deleted file mode 100644 index f5b82db4..00000000 --- a/archive_docs/v5/flask_imp_auth-generate_salt.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Generate_salt - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      generate_salt - flask_imp.auth

      -
      from flask_imp.auth import generate_salt
      -
      -
      generate_salt(length: int = 4) -> str
      -
      -
      -

      Generates a string of (length) characters of punctuation.

      -

      The Default length is 4.

      -

      For use in password hashing and storage of passwords in the database.

      -
      Example:
      -
      generate_salt()  # >>> '*!$%'
      -
      -
      @app.route('/register', methods=['GET', 'POST'])
      -def register():
      -    if request.method == "POST":
      -        ...
      -        salt = generate_salt()
      -        password = request.form.get('password')
      -        encrypted_password = encrypt_password(password, salt)
      -        ...
      -
      -        user = User(
      -            username=username,
      -            email=email,
      -            password=encrypted_password,
      -            salt=salt
      -        )
      -        ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-is_email_address_valid.html b/archive_docs/v5/flask_imp_auth-is_email_address_valid.html deleted file mode 100644 index 65014904..00000000 --- a/archive_docs/v5/flask_imp_auth-is_email_address_valid.html +++ /dev/null @@ -1,286 +0,0 @@ - - - - - Is_email_address_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_email_address_valid - flask_imp.auth

      -
      from flask_imp.auth import is_email_address_valid
      -
      -
      is_email_address_valid(
      -    email_address: str
      -) -> bool
      -
      -
      -

      Checks if an email address is valid.

      -

      Is not completely RFC 5322 compliant, but it is good enough for most use cases.

      -

      Here are examples of mistakes that it will not catch:

      -
      Valid but fails:
      -
      email@[123.123.123.123]
      -“email”@example.com
      -very.unusual.“@”.unusual.com@example.com
      -very.“(),:;<>[]”.VERY.“very@\\ "very”.unusual@strange.example.com
      -
      -
      Invalid but passes:
      -
      email@example.com (Joe Smith)
      -email@111.222.333.44444
      -
      -
      Example:
      -
      is_email_address_valid('hello@example.com')  # >>> True
      -
      -is_email_address_valid('hello@hello@example.com')  # >>> False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_auth-is_username_valid.html b/archive_docs/v5/flask_imp_auth-is_username_valid.html deleted file mode 100644 index 9e458bdf..00000000 --- a/archive_docs/v5/flask_imp_auth-is_username_valid.html +++ /dev/null @@ -1,295 +0,0 @@ - - - - - Is_username_valid - Flask_imp.auth | Flask-Imp - - - - - - - - - - - - - - -
      -

      is_username_valid - flask_imp.auth

      -
      from flask_imp.auth import is_username_valid
      -
      -
      is_username_valid(
      -    username: str,
      -    allowed: t.Optional[t.List[t.Literal["all", "dot", "dash", "under"]]] = None
      -) -> bool
      -
      -
      -

      Checks if a username is valid.

      -

      Valid usernames can only include letters, -numbers, ., -, and _ but cannot begin or end with -the last three mentioned.

      -
      Example "all":
      -
      is_username_valid("username", allowed=["all"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user_name : WILL PASS : True
      -_user_name : WILL PASS : False
      -
      -
      Example "dot", "dash":
      -
      is_username_valid("username", allowed=["dot", "dash"])
      -
      -

      Output:

      -
      username : WILL PASS : True
      -user.name : WILL PASS : True
      -user-name : WILL PASS : True
      -user-name.name : WILL PASS : True
      -user_name : WILL PASS : False
      -_user_name : WILL PASS : False
      -.user.name : WILL PASS : False
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-databaseconfig.html b/archive_docs/v5/flask_imp_config-databaseconfig.html deleted file mode 100644 index 2c5bf9cd..00000000 --- a/archive_docs/v5/flask_imp_config-databaseconfig.html +++ /dev/null @@ -1,281 +0,0 @@ - - - - - Databaseconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      DatabaseConfig - flask_imp.config

      -
      from flask_imp.config import DatabaseConfig
      -
      -
      DatabaseConfig(
      -    enabled: bool = False,
      -    dialect: t.Literal[
      -        "mysql", "postgresql", "sqlite", "oracle", "mssql"
      -    ] = "sqlite",
      -    name: str = "database",
      -    bind_key: str = "",
      -    location: str = "",
      -    port: int = 0,
      -    username: str = "",
      -    password: str = "",
      -    sqlite_db_extension: str = ".sqlite"
      -)
      -
      -
      -

      A class that holds a database configuration.

      -

      This configuration is parsed into a database URI and -used in either the SQLALCHEMY_DATABASE_URI or SQLALCHEMY_BINDS configuration variables.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-flaskconfig.html b/archive_docs/v5/flask_imp_config-flaskconfig.html deleted file mode 100644 index 1f205bf7..00000000 --- a/archive_docs/v5/flask_imp_config-flaskconfig.html +++ /dev/null @@ -1,306 +0,0 @@ - - - - - Flaskconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      FlaskConfig - flask_imp.config

      -
      from flask_imp.config import FlaskConfig
      -
      -
      FlaskConfig(
      -    debug: t.Optional[bool] = None,
      -    propagate_exceptions: t.Optional[bool] = None,
      -    trap_http_exceptions: t.Optional[bool] = None,
      -    trap_bad_request_errors: t.Optional[bool] = None,
      -    secret_key: t.Optional[str] = None,
      -    session_cookie_name: t.Optional[str] = None,
      -    session_cookie_domain: t.Optional[str] = None,
      -    session_cookie_path: t.Optional[str] = None,
      -    session_cookie_httponly: t.Optional[bool] = None,
      -    session_cookie_secure: t.Optional[bool] = None,
      -    session_cookie_samesite: t.Optional[t.Literal["Lax", "Strict"]] = None,
      -    permanent_session_lifetime: t.Optional[int] = None,
      -    session_refresh_each_request: t.Optional[bool] = None,
      -    use_x_sendfile: t.Optional[bool] = None,
      -    send_file_max_age_default: t.Optional[int] = None,
      -    error_404_help: t.Optional[bool] = None,
      -    server_name: t.Optional[str] = None,
      -    application_root: t.Optional[str] = None,
      -    preferred_url_scheme: t.Optional[str] = None,
      -    max_content_length: t.Optional[int] = None,
      -    templates_auto_reload: t.Optional[bool] = None,
      -    explain_template_loading: t.Optional[bool] = None,
      -    max_cookie_size: t.Optional[int] = None,
      -    app_instance: t.Optional["Flask"] = None
      -)
      -
      -
      -

      A class that holds a Flask configuration values.

      -

      You can set the configuration values to the app instance by either passing the app instance to the app_instance -parameter or by calling the apply_config method on the FlaskConfig instance.

      -
      def create_app():
      -    app = Flask(__name__)
      -    FlaskConfig(debug=True, app_instance=app)
      -    return app
      -
      -

      or

      -
      def create_app():
      -    app = Flask(__name__)
      -    config = FlaskConfig(debug=True)
      -    config.apply_config(app)
      -    return app
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-impblueprintconfig.html b/archive_docs/v5/flask_imp_config-impblueprintconfig.html deleted file mode 100644 index a4ea264b..00000000 --- a/archive_docs/v5/flask_imp_config-impblueprintconfig.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - Impblueprintconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprintConfig - flask_imp.config

      -
      from flask_imp.config import ImpBlueprintConfig
      -
      -
      ImpBlueprintConfig(
      -    enabled: bool = False,
      -    url_prefix: str = None,
      -    subdomain: str = None,
      -    url_defaults: dict = None,
      -    static_folder: t.Optional[str] = None,
      -    template_folder: t.Optional[str] = None,
      -    static_url_path: t.Optional[str] = None,
      -    root_path: str = None,
      -    cli_group: str = None,
      -    init_session: dict = None,
      -    database_binds: t.Iterable[DatabaseConfig] = None
      -)
      -
      -
      -

      A class that holds a Flask-Imp blueprint configuration.

      -

      Most of these values are passed to the Blueprint class when the blueprint is registered.

      -

      The enabled argument is used to enable or disable the blueprint. This is useful for feature flags.

      -

      init_session is used to set the session values in the main before_request function.

      -

      database_binds is a list of DatabaseConfig instances that are used to create SQLALCHEMY_BINDS configuration -variables. Again this is useful for feature flags, or for creating multiple databases per blueprint.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-impconfig.html b/archive_docs/v5/flask_imp_config-impconfig.html deleted file mode 100644 index 91dca741..00000000 --- a/archive_docs/v5/flask_imp_config-impconfig.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - Impconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpConfig - flask_imp.config

      -
      from flask_imp.config import ImpConfig
      -
      -
      ImpConfig(
      -    init_session: t.Optional[t.Dict[str, t.Any]] = None,
      -    database_main: t.Optional[
      -        t.Union[DatabaseConfig, SQLiteDatabaseConfig, SQLDatabaseConfig]
      -    ] = None,
      -    database_binds: t.Optional[
      -        t.List[t.Union[DatabaseConfig, SQLiteDatabaseConfig, SQLDatabaseConfig]]
      -    ] = None,
      -)
      -
      -
      -

      The ImpConfig class is used to set the initial session, the main database, and any additional databases -that the application will use.

      -
      imp_config = ImpConfig(
      -    init_session={"key": "value"},
      -    database_main=SQLiteDatabaseConfig(
      -        name="test1",
      -    ),
      -    database_binds=[
      -        DatabaseConfig(
      -            enabled=True,
      -            dialect="sqlite",
      -            name="test2",
      -            bind_key="test2"
      -        )
      -    ]
      -)
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    FlaskConfig(debug=True, app_instance=app)
      -    imp.init_app(app, imp_config)
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-sqldatabaseconfig.html b/archive_docs/v5/flask_imp_config-sqldatabaseconfig.html deleted file mode 100644 index 6e8456f6..00000000 --- a/archive_docs/v5/flask_imp_config-sqldatabaseconfig.html +++ /dev/null @@ -1,278 +0,0 @@ - - - - - Sqldatabaseconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      SQLDatabaseConfig - flask_imp.config

      -
      from flask_imp.config import SQLDatabaseConfig
      -
      -
      SQLDatabaseConfig(
      -    dialect: t.Literal["mysql", "postgresql", "oracle", "mssql"],
      -    enabled: bool = True,
      -    name: str = "database",
      -    bind_key: str = "",
      -    location: str = "",
      -    port: int = 0,
      -    username: str = "",
      -    password: str = "",
      -)
      -
      -
      -

      A class that holds a SQL database configuration.

      -

      This configuration is parsed into a database URI and -used in either the SQLALCHEMY_DATABASE_URI or SQLALCHEMY_BINDS configuration variables.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_config-sqlitedatabaseconfig.html b/archive_docs/v5/flask_imp_config-sqlitedatabaseconfig.html deleted file mode 100644 index 18c40ca8..00000000 --- a/archive_docs/v5/flask_imp_config-sqlitedatabaseconfig.html +++ /dev/null @@ -1,275 +0,0 @@ - - - - - Sqlitedatabaseconfig - Flask_imp.config | Flask-Imp - - - - - - - - - - - - - - -
      -

      SQLiteDatabaseConfig - flask_imp.config

      -
      from flask_imp.config import SQLiteDatabaseConfig
      -
      -
      SQLiteDatabaseConfig(
      -    enabled: bool = True,
      -    name: str = "database",
      -    bind_key: str = "",
      -    sqlite_db_extension: str = ".sqlite",
      -    location: t.Optional[Path] = None,
      -)
      -
      -
      -

      A class that holds a SQLite database configuration.

      -

      This configuration is parsed into a database URI and -used in either the SQLALCHEMY_DATABASE_URI or SQLALCHEMY_BINDS configuration variables.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_security-api_login_check.html b/archive_docs/v5/flask_imp_security-api_login_check.html deleted file mode 100644 index 6a6fa4f0..00000000 --- a/archive_docs/v5/flask_imp_security-api_login_check.html +++ /dev/null @@ -1,287 +0,0 @@ - - - - - Api_login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      api_login_check - flask_imp.security

      -
      from flask_imp.security import api_login_check
      -
      -
      api_login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_json: t.Optional[t.Dict[str, t.Any]] = None
      -)
      -
      -

      @api_login_check(...)

      -
      -

      A decorator that is used to secure API routes that return JSON responses.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_json JSON that is returned on failure. {"error": "You are not logged in."} by default.

      -
      Example:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True)
      -def api_page():
      -    ...
      -
      -
      Example of defined fail_json:
      -
      @bp.route("/api/resource", methods=["GET"])
      -@api_login_check('logged_in', True, fail_json={"failed": "You need to be logged in."})
      -def api_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_security-include_csrf.html b/archive_docs/v5/flask_imp_security-include_csrf.html deleted file mode 100644 index b48164b0..00000000 --- a/archive_docs/v5/flask_imp_security-include_csrf.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - Include_csrf - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      include_csrf - flask_imp.security

      -
      from flask_imp.security import include_csrf
      -
      -
      include_csrf(
      -    session_key: str = "csrf",
      -    form_key: str = "csrf",
      -    abort_code: int = 401
      -)
      -
      -

      @include_csrf(...)

      -
      -

      A decorator that handles CSRF protection.

      -

      On a GET request, a CSRF token is generated and stored in the session key -specified by the session_key parameter.

      -

      On a POST request, the form_key specified is checked against the session_key -specified.

      -
        -
      • If they match, the request is allowed to continue.
      • -
      • If no match, the response will be abort(abort_code), default 401.
      • -
      -
      @bp.route("/admin", methods=["GET", "POST"])
      -@include_csrf(session_key="csrf", form_key="csrf")
      -def admin_page():
      -    ...
      -    # You must pass in the CSRF token from the session into the template.
      -    # Then add <input type="hidden" name="csrf" value="{{ csrf }}"> to the form.
      -    return render_template("admin.html", csrf=session.get("csrf"))
      -
      -

      Form key:

      -
      <input type="hidden" name="csrf" value="{{ csrf }}">
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_security-login_check.html b/archive_docs/v5/flask_imp_security-login_check.html deleted file mode 100644 index e0481780..00000000 --- a/archive_docs/v5/flask_imp_security-login_check.html +++ /dev/null @@ -1,304 +0,0 @@ - - - - - Login_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      login_check - flask_imp.security

      -
      from flask_imp.security import login_check
      -
      -
      login_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    pass_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @login_check(...)

      -
      -

      A decorator that checks if the specified session key exists and contains the specified value.

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example of a route that requires a user to be logged in:
      -
      @bp.route("/admin", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    fail_endpoint='blueprint.login_page',
      -    message="Login needed"
      -)
      -def admin_page():
      -    ...
      -
      -
      Example of a route that if the user is already logged in, redirects to the specified endpoint:
      -
      @bp.route("/login-page", methods=["GET"])
      -@login_check(
      -    'logged_in',
      -    True,
      -    pass_endpoint='blueprint.admin_page',
      -    message="Already logged in"
      -)
      -def login_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_security-pass_function_check.html b/archive_docs/v5/flask_imp_security-pass_function_check.html deleted file mode 100644 index 3a8496b3..00000000 --- a/archive_docs/v5/flask_imp_security-pass_function_check.html +++ /dev/null @@ -1,352 +0,0 @@ - - - - - Pass_function_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      pass_function_check - flask_imp.security

      -
      from flask_imp.security import pass_function_check
      -
      -
      def pass_function_check(
      -    function: t.Callable,
      -    predefined_args: t.Optional[t.Dict] = None,
      -    fail_endpoint: t.Optional[str] = None,
      -    pass_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message",
      -    fail_on_missing_kwargs: bool = False,
      -    with_app_context: bool = False,
      -)
      -
      -

      NOTE: This was added mostly as an experimental feature, but ended up being useful in some cases.

      -

      A decorator that takes the result of a function and checks if it is True or False.

      -

      URL variables from @route will be read by this decorator. -To use URL variables in your passed in function, -make sure your functions argument(s) name(s) match the name(s) of the URL variable(s).

      -

      Example:

      -
      def check_if_number(value):
      -    if isinstance(value, int):
      -        return True
      -    return False
      -
      -@bp.route("/admin-page/<int:value>", methods=["GET"])
      -@login_check('logged_in', True, 'blueprint.login_page')  # can be mixed with login_check
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args=None,
      -    fail_endpoint='www.index',
      -    message="Failed message"
      -)
      -def admin_page():
      -    ...
      -
      -@bp.route("/admin-page/<int:value>", methods=["GET"])
      -@login_check('logged_in', True, 'blueprint.login_page')  # can be mixed with login_check
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args={'value': 10},
      -    fail_endpoint='www.index',
      -    message="Failed message"
      -)
      -def admin_page_overwrite():
      -    ...
      -
      -

      Advanced use case:

      -

      Here's an example of accessing flask.session from within the passed in function. including the -with_app_context parameter, the function will be called with app_context().

      -
      from flask import current_app
      -from flask import session
      -
      -...
      -
      -def check_if_number(number=1, session_=None):
      -    if session_:
      -        print(session_)
      -    try:
      -        int(number)
      -        return True
      -    except ValueError:
      -        return False
      -
      -@bp.route("/pass-func-check-with-url-var/<number>", methods=["GET"])
      -@pass_function_check(
      -    check_if_number,
      -    predefined_args={'number': 10, 'session_': session},
      -    fail_endpoint="www.index",
      -    with_app_context=True
      -)
      -def admin_page_overwrite_with_session():
      -    ...
      -
      -

      If you pass in a predefined arg that has the same key name as a session variable that exists, the value -of that predefined arg will be replaced with the session variable value.

      -
      session['car'] = 'Toyota'
      -...
      -def check_function(car):
      -    if car == 'Toyota':
      -        return True
      -    return False
      -...
      -@bp.route("/pass-func-check-with-url-var/<number>", methods=["GET"])
      -@pass_function_check(
      -    check_function,
      -    predefined_args={'car': session},
      -    ...
      -
      -

      This will pass, as pass_function_check will replace the value of the predefined arg 'car' with the value -of the session variable 'car'.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/flask_imp_security-permission_check.html b/archive_docs/v5/flask_imp_security-permission_check.html deleted file mode 100644 index 3b3cc5dc..00000000 --- a/archive_docs/v5/flask_imp_security-permission_check.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - Permission_check - Flask_imp.security | Flask-Imp - - - - - - - - - - - - - - -
      -

      permission_check - flask_imp.security

      -
      from flask_imp.security import permission_check
      -
      -
      permission_check(
      -    session_key: str,
      -    values_allowed: t.Union[t.List[t.Union[str, int, bool]], str, int, bool],
      -    fail_endpoint: t.Optional[str] = None,
      -    endpoint_kwargs: t.Optional[t.Dict[str, t.Union[str, int]]] = None,
      -    message: t.Optional[str] = None,
      -    message_category: str = "message"
      -)
      -
      -

      @permission_check(...)

      -
      -

      A decorator that checks if the specified session key exists and its value(s) match the specified value(s).

      -

      session_key The session key to check for.

      -

      values_allowed A list of or singular value(s) that the session key must contain.

      -

      fail_endpoint The endpoint to redirect to if the session key does not exist or does not contain the specified values.

      -

      endpoint_kwargs A dictionary of keyword arguments to pass to the redirect endpoint.

      -

      message If a message is specified, a flash message is shown.

      -

      message_category The category of the flash message.

      -
      Example:
      -
      @bp.route("/admin-page", methods=["GET"])
      -@login_check(
      -    'logged_in', 
      -    True, 
      -    'blueprint.login_page'
      -)  # can be mixed with login_check
      -@permission_check(
      -    'permissions', 
      -    ['admin'], 
      -    fail_endpoint='www.index', 
      -    message="Failed message"
      -)
      -def admin_page():
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-import_app_resources.html b/archive_docs/v5/imp-import_app_resources.html deleted file mode 100644 index c96a381f..00000000 --- a/archive_docs/v5/imp-import_app_resources.html +++ /dev/null @@ -1,330 +0,0 @@ - - - - - Imp.import_app_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_app_resources

      -
      import_app_resources(
      -    folder: str = "resources",
      -    factories: Optional[List] = None,
      -    static_folder: str = "static",
      -    templates_folder: str = "templates",
      -    files_to_import: Optional[List] = None,
      -    folders_to_import: Optional[List] = None,
      -    ) -> None
      -
      -
      -

      Import standard app resources from the specified folder.

      -

      This will import any resources that have been set to the Flask app.

      -

      Routes, context processors, cli, etc.

      -

      Can only be called once.

      -

      If no static and or template folder is found, the static and or template folder will be set to None in the Flask app -config.

      -

      Small example of usage:

      -
      imp.import_app_resources(folder="resources")
      -# or
      -imp.import_app_resources()
      -# as the default folder is "resources"
      -
      -

      Folder Structure: resources

      -
      app
      -├── resources
      -│   ├── routes.py
      -│   ├── app_fac.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   └── templates
      -│       └── index.html
      -└── ...
      -...
      -
      -

      File: routes.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      How factories work

      -

      Factories are functions that are called when importing the app resources. Here's an example:

      -
      imp.import_app_resources(
      -    folder="resources",
      -    factories=["development_cli"]
      -)
      -
      -

      ["development_cli"] => development_cli(app) function will be called, and the current app will be passed in.

      -

      File: app_fac.py

      -
      def development_cli(app):
      -    @app.cli.command("dev")
      -    def dev():
      -        print("dev cli command")
      -
      -

      Scoping imports

      -

      By default, all files and folders will be imported.

      -

      To disable this, set files_to_import and or -folders_to_import to [None].

      -
      imp.import_app_resources(scope_import=[None], folders_to_import=[None])
      -
      -

      To scope the imports, set the files_to_import and or folders_to_import to a list of files and or folders.

      -

      files_to_import=["cli.py", "routes.py"] => will only import the files resources/cli.py -and resources/routes.py

      -

      folders_to_import=["template_filters", "context_processors"] => will import all files in the folders -resources/template_filters/*.py and resources/context_processors/*.py

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-import_blueprint.html b/archive_docs/v5/imp-import_blueprint.html deleted file mode 100644 index e3a3f38d..00000000 --- a/archive_docs/v5/imp-import_blueprint.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - - Imp.import_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprint

      -
      import_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Flask app root.

      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprint("my_blueprint")
      -
      -    return app
      -
      -

      Flask-Imp Blueprints have the ability to auto import resources, and initialize session variables.

      -

      For more information on how Flask-Imp Blueprints work, see the ImpBlueprint / Introduction

      -
      Example of 'my_blueprint' as a Flask-Imp Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── routes
      -│   │   └── index.py
      -│   ├── static
      -│   │   └── css
      -│   │       └── style.css
      -│   ├── templates
      -│   │   └── my_blueprint
      -│   │       └── index.html
      -│   ├── __init__.py
      -│   └── config.toml
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(
      -    __name__,
      -    ImpBlueprintConfig(
      -        enabled=True,
      -        url_prefix="/my-blueprint",
      -        static_folder="static",
      -        template_folder="templates",
      -        static_url_path="/static/my_blueprint",
      -        init_session={"my_blueprint": "session_value"},
      -    ),
      -)
      -
      -bp.import_resources("routes")
      -
      -

      File: routes / index.py

      -
      from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -
      Example of 'my_blueprint' as a standard Flask Blueprint:
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -└── ...
      -
      -

      File: __init__.py

      -
      from flask import Blueprint
      -
      -bp = Blueprint("my_blueprint", __name__, url_prefix="/my-blueprint")
      -
      -
      -@bp.route("/")
      -def index():
      -    return "regular_blueprint"
      -
      -

      Both of the above examples will work with imp.import_blueprint("my_blueprint"), they will be registered -with the Flask app, and will be accessible via url_for("my_blueprint.index").

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-import_blueprints.html b/archive_docs/v5/imp-import_blueprints.html deleted file mode 100644 index 826992c5..00000000 --- a/archive_docs/v5/imp-import_blueprints.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - Imp.import_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_blueprints

      -
      import_blueprints(self, folder: str) -> None
      -
      -
      -

      Import all Flask-Imp or standard Flask Blueprints from a specified folder relative to the Flask app root.

      -
      app/
      -├── blueprints/
      -│   ├── admin/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   ├── www/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   └── api/
      -│       ├── ...
      -│       └── __init__.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -
      -    imp.import_blueprints("blueprints")
      -
      -    return app
      -
      -

      This will import all Blueprints from the blueprints folder using the Imp.import_blueprint method. -See Imp / import_blueprint for more information.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-import_models.html b/archive_docs/v5/imp-import_models.html deleted file mode 100644 index 8e5eb916..00000000 --- a/archive_docs/v5/imp-import_models.html +++ /dev/null @@ -1,320 +0,0 @@ - - - - - Imp.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.import_models

      -
      import_models(file_or_folder: str) -> None
      -
      -
      -

      Imports all the models from the given file or folder relative to the Flask app root.

      -

      Each Model that is imported will be available in the imp.model lookup method. -See Imp / model for more information.

      -
      Example of importing models from a file
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── users_model.py
      -├── ...
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -
      -from flask_imp import Imp
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    imp.init_app(app)
      -    db.init_app(app)  # must be below imp.init_app
      -
      -    imp.import_blueprint("my_blueprint")
      -    imp.import_models("users_model.py")
      -
      -    return app
      -
      -

      File: app/users_model.py

      -
      from app import db
      -
      -
      -class User(db.Model):
      -    attribute = db.Column(db.String(255))
      -
      -
      Example of importing models from a folder
      -
      app
      -├── my_blueprint
      -│   ├── ...
      -│   └── __init__.py
      -├── models/
      -│   ├── boats.py
      -│   ├── cars.py
      -│   └── users.py
      -├── ...
      -└── __init__.py
      -
      -
      def create_app():
      -    ...
      -    imp.import_models("models")
      -    ...
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-init_app-init.html b/archive_docs/v5/imp-init_app-init.html deleted file mode 100644 index 4ec60be1..00000000 --- a/archive_docs/v5/imp-init_app-init.html +++ /dev/null @@ -1,274 +0,0 @@ - - - - - Imp.init_app, __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_app, __init__

      -
      def init_app(
      -    app: Flask,
      -    config: ImpConfig
      -) -> None:
      -# -or- 
      -Imp(
      -    app: Flask,
      -    config: ImpConfig
      -)
      -
      -
      -

      Initializes the flask app to work with flask-imp.

      -

      See flask_imp_config-impconfig.md for more information on the ImpConfig class.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-init_session.html b/archive_docs/v5/imp-init_session.html deleted file mode 100644 index a1fe55fe..00000000 --- a/archive_docs/v5/imp-init_session.html +++ /dev/null @@ -1,289 +0,0 @@ - - - - - Imp.init_session | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.init_session

      -
      init_session() -> None
      -
      -
      -

      Initialize the session variables found in the config. Commonly used in app.before_request.

      -
      @app.before_request
      -def before_request():
      -    imp._init_session()
      -
      -

      File: config.toml

      -
      ...
      -[SESSION]
      -logged_in = false
      -...
      -
      -

      logged_in is now available in the session.

      -
      @app.route('/get-session-value')
      -def login():
      -    print(session['logged_in'])
      -    return "Check Terminal"
      -
      -

      Output: False

      -

      Can also be used to reset the values in the session. Here's an example:

      -
      @app.route('/logout')
      -def logout():
      -    session.clear()
      -    imp._init_session()
      -    return redirect(url_for('index'))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-introduction.html b/archive_docs/v5/imp-introduction.html deleted file mode 100644 index e7ffbabc..00000000 --- a/archive_docs/v5/imp-introduction.html +++ /dev/null @@ -1,329 +0,0 @@ - - - - - Flask-Imp Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Introduction

      -

      Flask-Imp is a Flask extension that provides auto import methods for various Flask resources. It will import models, -blueprints, and other resources. It uses the importlib module to achieve this.

      -

      Flask-Imp favors the application factory pattern as a project structure, and is opinionated towards using -Blueprints. However, you can use Flask-Imp without using Blueprints.

      -

      Here's an example of a standard Flask-Imp project structure:

      -
      app/
      -├── blueprints/
      -│   ├── admin/...
      -│   ├── api/...
      -│   └── www/...
      -├── resources/
      -│   ├── filters/...
      -│   ├── context_processors/...
      -│   ├── static/...
      -│   └── templates/...
      -├── models/...
      -└── __init__.py
      -
      -

      Here's an example of the app/__init__.py file:

      -
      from flask import Flask
      -from flask_sqlalchemy import SQLAlchemy
      -from flask_imp import Imp
      -from flask_imp.config import FlaskConfig, ImpConfig
      -
      -db = SQLAlchemy()
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__)
      -    FlaskConfig(
      -        secret_key="super_secret_key",
      -        app_instance=app,
      -    )
      -    
      -    imp.init_app(app, config=ImpConfig(
      -        init_session={"logged_in": False},
      -    ))
      -    imp.import_app_resources("resources")
      -    imp.import_models("models")
      -    imp.import_blueprints("blueprints")
      -    
      -    db.init_app(app)
      -
      -    return app
      -
      -

      The Flask configuration can be loaded from any standard Flask configuration method, or from the FlaskConfig class -shown above.

      -

      This class contains the standard Flask configuration options found in the Flask documentation.

      -

      The ImpConfig class is used to configure the Imp instance.

      -

      The init_session option of the ImpConfig class is used to set the initial session variables for the Flask app. -This happens before the request is processed.

      -

      ImpConfig also has the ability to set SQLALCHEMY_DATABASE_URI and SQLALCHEMY_BINDS

      -

      For more information about the configuration setting see -flask_imp_config-impconfig.md.

      -

      import_app_resources will walk one level deep into the resources folder, and import -all .py files as modules. -It will also check for the existence of a static and templates folder, and register them with the Flask app.

      -

      There is a couple of options for import_app_resources to control what -is imported, see: Imp / import_app_resources

      -

      import_models will import all Model classes from the specified file or folder. It will also place each model found -into a lookup table that you can access via imp.model

      -

      See more about how import_models and the lookup -here: Imp / import_models and Imp / model

      -

      import_blueprints expects a folder that contains many Blueprint as Python packages. -It will check each blueprint folder's __init__.py file for an instance of a Flask Blueprint or a -Flask-Imp Blueprint. That instant will then be registered with the Flask app.

      -

      See more about how importing blueprints work here: ImpBlueprint / Introduction

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/imp-model.html b/archive_docs/v5/imp-model.html deleted file mode 100644 index efc09e24..00000000 --- a/archive_docs/v5/imp-model.html +++ /dev/null @@ -1,296 +0,0 @@ - - - - - Imp.model | Flask-Imp - - - - - - - - - - - - - - -
      -

      Imp.model

      -
      model(class_: str) -> DefaultMeta
      -
      -
      -

      Returns the SQLAlchemy model class for the given class name that was imported using Imp.import_models or -Blueprint.import_models.

      -

      This method has convenience for being able to omit the need to import the model class from the file it was defined in. -However, it is not compatible with IDE type hinting.

      -

      For example:

      -
      from app.models.boats import Boats
      -from app.models.cars import Cars
      -
      -

      Can be replaced with:

      -
      from app import imp
      -
      -Boats = imp.model("Boats")
      -Cars = imp.model("Cars")
      -
      -

      Or used directly:

      -
      from app import imp
      -
      -all_boats = imp.model("Boats").select_all()
      -
      -

      file: models/boats.py

      -
      from app import db
      -
      -
      -class Boats(db.Model):
      -    name = db.Column(db.String())
      -
      -    @classmethod
      -    def select_all(cls):
      -        return db.session.execute(
      -            db.select(cls)
      -        ).scalars().all()
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-import_models.html b/archive_docs/v5/impblueprint-import_models.html deleted file mode 100644 index afb66f7f..00000000 --- a/archive_docs/v5/impblueprint-import_models.html +++ /dev/null @@ -1,322 +0,0 @@ - - - - - Impblueprint.import_models | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprint.import_models

      -
      import_models(folder: str = "models") -> None
      -
      -
      -

      Will import all the models from the given folder relative to the Blueprint's root directory.

      -

      Works the same as Imp / import_models but relative to the Blueprint root.

      -

      Blueprint models will also be available in the Imp / model lookup.

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── animal_models.py
      -│
      -├── __init__.py
      -
      -

      or

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── models/
      -│   └── animals.py
      -│
      -├── __init__.py
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("routes")
      -bp.import_models("animal_models.py")
      -
      -

      or

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -
      -

      File: my_blueprint/animal_models.py or my_blueprint/models/animals.py

      -
      from app import db
      -
      -
      -class Animals(db.Model):
      -    animal_id = db.Column(db.Integer, primary_key=True)
      -    name = db.Column(db.String(64), index=True, unique=True)
      -    species = db.Column(db.String(64), index=True, unique=True)
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-import_nested_blueprint.html b/archive_docs/v5/impblueprint-import_nested_blueprint.html deleted file mode 100644 index 990e2542..00000000 --- a/archive_docs/v5/impblueprint-import_nested_blueprint.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - Impblueprint.import_nested_blueprint | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprint.import_nested_blueprint

      -
      import_nested_blueprint(self, blueprint: str) -> None
      -
      -
      -

      Import a specified Flask-Imp or standard Flask Blueprint relative to the Blueprint root.

      -

      Works the same as Imp / import_blueprint but relative to the Blueprint root.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.my_nested_blueprint.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── my_nested_blueprint/
      -│   ├── routes/
      -│   │   └── index.py
      -│   ├── static/...
      -│   ├── templates/...
      -│   ├── __init__.py
      -│
      -├── __init__.py
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprint("my_nested_blueprint")
      -
      -

      File: my_blueprint/my_nested_blueprint/__init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("routes")
      -
      -

      File: my_blueprint/my_nested_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-import_nested_blueprints.html b/archive_docs/v5/impblueprint-import_nested_blueprints.html deleted file mode 100644 index df49cd8a..00000000 --- a/archive_docs/v5/impblueprint-import_nested_blueprints.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - Impblueprint.import_nested_blueprints | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprint.import_nested_blueprints

      -
      import_nested_blueprints(self, folder: str) -> None
      -
      -
      -

      Will import all the Blueprints from the given folder relative to the Blueprint's root directory.

      -

      Uses Blueprint / import_nested_blueprint to import blueprints from -the specified folder.

      -

      Blueprints that are imported this way will be scoped to the parent Blueprint that imported them.

      -

      url_for('my_blueprint.nested_bp_one.index')

      -

      url_for('my_blueprint.nested_bp_two.index')

      -

      url_for('my_blueprint.nested_bp_three.index')

      -
      my_blueprint/
      -├── routes/...
      -├── static/...
      -├── templates/...
      -│
      -├── nested_blueprints/
      -│   │
      -│   ├── nested_bp_one/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   ├── nested_bp_two/
      -│   │   ├── ...
      -│   │   ├── __init__.py
      -│   └── nested_bp_three/
      -│       ├── ...
      -│       ├── __init__.py
      -│
      -├── __init__.py
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("routes")
      -bp.import_nested_blueprints("nested_blueprints")
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-import_resources.html b/archive_docs/v5/impblueprint-import_resources.html deleted file mode 100644 index 1cc49994..00000000 --- a/archive_docs/v5/impblueprint-import_resources.html +++ /dev/null @@ -1,302 +0,0 @@ - - - - - Impblueprint.import_resources | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprint.import_resources

      -
      import_resources(folder: str = "routes") -> None
      -
      -
      -

      Will import all the resources (cli, routes, filters, context_processors...) from the given folder relative to the -Blueprint's root directory.

      -
      my_blueprint
      -├── user_routes
      -│   ├── user_dashboard.py
      -│   └── user_settings.py
      -├── car_routes
      -│   ├── car_dashboard.py
      -│   └── car_settings.py
      -├── static/...
      -├── templates/
      -│   └── my_blueprint/
      -│       ├── user_dashboard.html
      -│       └── ...
      -├── __init__.py
      -
      -

      File: my_blueprint/__init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    static_folder="static",
      -    template_folder="templates",
      -))
      -
      -bp.import_resources("user_routes")
      -bp.import_resources("car_routes")
      -
      -

      File: my_blueprint/user_routes/user_dashboard.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -@bp.route("/user-dashboard")
      -def user_dashboard():
      -    return render_template(bp.tmpl("user_dashboard.html"))
      -
      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-init.html b/archive_docs/v5/impblueprint-init.html deleted file mode 100644 index 48d85069..00000000 --- a/archive_docs/v5/impblueprint-init.html +++ /dev/null @@ -1,268 +0,0 @@ - - - - - Flask-Imp Blueprint __init__ | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint __init__

      -
      ImpBlueprint(dunder_name: str, config: ImpBlueprintConfig) -> None
      -
      -
      -

      Initializes the Flask-Imp Blueprint.

      -

      dunder_name should always be set to __name__

      -

      config is an instance of ImpBlueprintConfig that will be used to load the Blueprint's configuration. -See flask_imp.config / ImpBlueprintConfig for more information.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-introduction.html b/archive_docs/v5/impblueprint-introduction.html deleted file mode 100644 index b24e290e..00000000 --- a/archive_docs/v5/impblueprint-introduction.html +++ /dev/null @@ -1,317 +0,0 @@ - - - - - Flask-Imp Blueprint Introduction | Flask-Imp - - - - - - - - - - - - - - -
      -

      Flask-Imp Blueprint Introduction

      -

      The Flask-Imp Blueprint inherits from the Flask Blueprint class, then adds some additional methods to allow for auto -importing of models, resources and other nested blueprints.

      -

      The Flask-Imp Blueprint requires you to provide the ImpBlueprintConfig class as the second argument to the Blueprint.

      -

      Here's an example of a Flask-Imp Blueprint structure:

      -
      www/
      -├── nested_blueprints/
      -│   ├── blueprint_one/
      -│   │   ├── ...
      -│   │   └── __init__.py
      -│   └── blueprint_two/
      -│       ├── ...
      -│       └── __init__.py
      -├── standalone_nested_blueprint/
      -│   ├── ...
      -│   └── __init__.py
      -├── models/
      -│   └── ...
      -├── routes/
      -│   └── index.py
      -├── static/
      -│   └── ...
      -├── templates/
      -│   └── www/
      -│       └── index.html
      -└── __init__.py
      -
      -

      File: __init__.py

      -
      from flask_imp import ImpBlueprint
      -from flask_imp.config import ImpBlueprintConfig
      -
      -bp = ImpBlueprint(__name__, ImpBlueprintConfig(
      -    enabled=True,
      -    url_prefix="/www",
      -    static_folder="static",
      -    template_folder="templates",
      -    init_session={"logged_in": False},
      -))
      -
      -bp.import_resources("routes")
      -bp.import_models("models")
      -bp.import_nested_blueprints("nested_blueprints")
      -bp.import_nested_blueprint("standalone_nested_blueprint")
      -
      -

      The ImpBlueprintConfig class is used to configure the Blueprint. It provides a little more flexibility than the -standard Flask Blueprint configuration, like the ability to enable or disable the Blueprint.

      -

      ImpBlueprintConfig's init_session works the same as ImpConfig's init_session, this will add the session data to -the Flask app's session object on initialization of the Flask app.

      -

      To see more about configuration see: flask_imp.config / ImpBlueprintConfig

      -

      import_resources method will walk one level deep into the routes folder, and import all .py files as modules. -For more information see: ImpBlueprint / import_resources

      -

      import_models works the same as imp.import_models, it will look for instances of db.Model and import them. These -will also be available in the model lookup method imp.model. -For more information see: Imp / import_models

      -

      import_nested_blueprints will do the same as imp.import_blueprints, but will register the blueprints found as -nested to the current blueprint. For example www.blueprint_one.index

      -

      import_nested_blueprint behaves the same as import_nested_blueprints, but will only import a single blueprint.

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/impblueprint-tmpl.html b/archive_docs/v5/impblueprint-tmpl.html deleted file mode 100644 index 8f34d9b9..00000000 --- a/archive_docs/v5/impblueprint-tmpl.html +++ /dev/null @@ -1,290 +0,0 @@ - - - - - Impblueprint.tmpl | Flask-Imp - - - - - - - - - - - - - - -
      -

      ImpBlueprint.tmpl

      -
      tmpl(template: str) -> str
      -
      -
      -

      Scopes the template lookup to the name of the blueprint (this takes from the __name__ attribute of the Blueprint).

      -

      Due to the way Flask templating works, and to avoid template name collisions. -It is standard practice to place the name of the Blueprint in the template path, -then to place any templates under that folder.

      -
      my_blueprint/
      -├── routes/
      -│   └── index.py
      -├── static/...
      -│
      -├── templates/
      -│   └── my_blueprint/
      -│       └── index.html
      -│
      -├── __init__.py
      -
      -

      File: my_blueprint/routes/index.py

      -
      from flask import render_template
      -
      -from .. import bp
      -
      -
      -@bp.route("/")
      -def index():
      -    return render_template(bp.tmpl("index.html"))
      -
      -

      bp.tmpl("index.html") will output "my_blueprint/index.html".

      - -
      - - - \ No newline at end of file diff --git a/archive_docs/v5/index.html b/archive_docs/v5/index.html deleted file mode 100644 index ac82493e..00000000 --- a/archive_docs/v5/index.html +++ /dev/null @@ -1,343 +0,0 @@ - - - - - Flask-Imp - - - - - - - - - - - - - - -
      -

      Welcome to the Flask-Imp Documentation

      -

      What is Flask-Imp?

      -

      Flask-Imp's main purpose is to help simplify the importing of blueprints, resources, and models. It has a few extra -features built in to help with securing pages and password authentication.

      -

      Install Flask-Imp

      -
      pip install flask-imp
      -
      -

      Getting Started

      -

      To get started right away, you can use the CLI commands to create a new Flask-Imp project.

      -
      flask-imp init
      -
      -

      Minimal Flask-Imp Setup

      -

      Run the following command to create a minimal Flask-Imp project.

      -
      flask-imp init -n app --minimal
      -
      -

      See CLI Commands / flask-imp init for more information.

      -

      The minimal structure

      -

      Folder Structure

      -
      app/
      -├── resources/
      -│   ├── static/...
      -│   ├── templates/
      -│   │   └── index.html
      -│   └── index.py
      -└── __init__.py
      -
      -

      File: app/__init__.py

      -
      from flask import Flask
      -
      -from flask_imp import Imp
      -from flask_imp.config import FlaskConfig, ImpConfig
      -
      -imp = Imp()
      -
      -
      -def create_app():
      -    app = Flask(__name__, static_url_path="/")
      -    FlaskConfig(
      -        secret_key="secret_key",
      -        app_instance=app
      -    )
      -    
      -    imp.init_app(app, ImpConfig())
      -
      -    imp.import_app_resources()
      -    # Takes argument 'folder' default folder is 'resources'
      -
      -    return app
      -
      -

      File: app/resources/routes.py

      -
      from flask import current_app as app
      -from flask import render_template
      -
      -
      -@app.route("/")
      -def index():
      -    return render_template("index.html")
      -
      -

      File: app/resources/templates/index.html

      -
      <!DOCTYPE html>
      -<html lang="en">
      -<head>
      -    <meta charset="UTF-8">
      -    <title>Flask-Imp</title>
      -</head>
      -<body>
      -<h1>Flask-Imp</h1>
      -</body>
      -</html>
      -
      -
      -

      Setting up a virtual environment is recommended.

      -

      Linux / Darwin

      -
      python3 -m venv venv
      -
      -
      source venv/bin/activate
      -
      -

      Windows

      -
      python -m venv venv
      -
      -
      .\venv\Scripts\activate
      -
      - -
      - - - - \ No newline at end of file diff --git a/archive_docs/v5/static/Flask-Imp-Medium.png b/archive_docs/v5/static/Flask-Imp-Medium.png deleted file mode 100644 index 1140eb4cc5c4f9538ea0a3c788db40a8fe08a663..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7987 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 diff --git a/archive_docs/v5/static/android-chrome-192x192.png b/archive_docs/v5/static/android-chrome-192x192.png deleted file mode 100644 index 1207f940bfb8ce81bb79fded911cd9167265ce42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15163 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 diff --git a/archive_docs/v5/static/android-chrome-256x256.png b/archive_docs/v5/static/android-chrome-256x256.png deleted file mode 100644 index 34e3d27479cf54144da963f21a635d7487f171ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20999 zcmV*9Kybf_P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw00006 zVoOIv0RI600RN!9r;`8x00(qQO+^Ri2^9$_AjF{Ys{jB{gGod|RCwC$y?Kmm*?r&l z`JHp`t)=(3&3p6a%|62+DGgKTrUNDm;j=V0;h+9$lO%x+s0P&%;g71?YCU`Ec7W{4V$9%?*7|5pMa=tvttGI43uB zEfuB|a`Zz~I0%Mz_XOR=m&04>%%~Rbi%pz!h4!`NiQO%(pJ_9N^ zTqP_fk4ghL9vF1NJ`TJPUi%%ug>VmW1r-LK$^1?>+=elKgyR*cz<2`{B5wg7pu*zo zzzqfhrqnDdOc<2_7z4sC4+9NL!p(%|7Tt-Xq1Q?^J7=Kw_ZZmkCrw)`O@cf;A2vx0 z1D`~x4Y9hqS_*+-)1xvY#)wJ)j1LCg#RYZVeLCFEq3Zif=)|w16TMX5YvKPR20QXe zTl_FEL0%5eKgmECbi?CP19%I#1N=6s4ZMqL4%fqHDvSvyabiskhIaaxf#)4y4ps4= zXCMeZi7xtc=)!oOYWz#Q2i!wV0|&ehyczB{!)u$U-=K|-TL$<_J2)CD4dCbybWvXh z{xx*6{!ZW-;8_M^EW7+)1;x|AQw;ncWfbCl)UkLE_$A;KR7()lhmarSODa5wN&t)o zS-6$na~OEt&0!CE${@QumZ4keA4$;9{$gT$+pVAQ* zq4DPO_$ulw{QIbo{cSWGvGflNYhyqaP1p^U39vUTx}*OH zI+6YWYNtMjPPiKC>4v?NYbuNf2KWIqs`4dt(SLv@A+>?tD z5$@;0rBJbxVBHC_zwRnEPW zi86Ws@HQGjcm@4!ucF$)dqDRzYXYa;2T)eveG2$#wB~-{NJp$NEr=M*@0ZcYz%${s z9vVWtcHAd<+&C2iU?{X#hV)9Jj0@p@nSyoe-9c$T4s>sQ(<-yqhVZte;4@Ez%QZ;|J%UNqJD$!p^kn+F_S)kAgsBn8S)Fvga8Qm9JjGz>Ef`N&>;tX9K0*M1Zf|`}L7@Do4cdSy zk1r1nq8HJ6+i+iq3XoEW478F5HIZZgLH38T6g(L^SU^5y>+y70e* zO6?k2pC5C~j=tFI5>CQyJy+;1Z}7|)1&MdmoG!z?=q{g%%F{wrV5MTnMUT-nLN11`7zAip zOD3u%0CbGL2e58!UvNx0N;3e|A8-x$yWzFh&@iGUP?McRv*09a00uaV*69~0QO7gK zeNrU^U8n$ah2u<-b0N!U26g?hEM>09Styj&uHg!d_uI9E;e!o5*lQa)$o6FX4!vZX z|6s3c8v2lba97X8&<$q8?YPF4vD}Q6Dq$^(Shp4rv`o-brr%r`rgZx}8a5nmpY|P8 z0F=>#6NeKc0Ctq^3IiM8483+NFsQ0)`p-S$QJWp8c}MIW7LW1z*?zCBpF6WwyUQcPbsHvhyD}59Wq3#_yLLR97N@rp*BoL-}HCYBU?u+61I#8^xuAVsO z;E53c0SW5uPk{dx?W$8U$xbAdcc&e1yysk=F<%rsk!E;-OKFd#B4;H}b-|-5yZFH# zu0rF{-ujb-$a`$iXf8X|oS*Hs0dPZ626ZA@ZpSqQ_&7?~u$FgfbzE>Hc8nR)Ql@5n z8o(byW&ZB~eg+L0{>Law@z!yl;6X9<0$|AAkI{177f`AD0!r91k?@}N9t+GDh0@WK zUU}eLmeO>N3%Ppm&*mv}MZsKA1g&6-_p=eB-_kfNUb~Blk$ClAxKab~o`u3C5Vnlz`z?<7^2+&E_HfM5Ow)IOuZ8)V0>w$t2BuyB1jMMl|A&A-k2+nR zoaFg8yr=0LpKfm{+z$uiJ&mHEQE1bjOKE9VYbc^+Bi5ss zcWMn<*3veHH|h=LUY{Pn!P#(gz<-UBlKw|}5!~X0Xagrj0C)!cZslzv>#Y2ee!p!| zUDhN09myemTerf&G3<_%ke{F-#&X{saWHP7pMo!1PUk0-+UI z)@;nZD8U2o*6Os4;l7=Ul8!Fg+wiNXdHT1);~Px5DKK>!z>v*vQ30@s#`k}mLC?Lh zqwXAwMZptU4~OtfugiRqZxcBuM$DfuMBWqof`%*l+o{imJ5j-$(+J8&WQo0{E8BAy z5Y1|wFzV=B{ZVvH{TABT^gfV=uE$d;2&PT|1YAOE`2Ta@GYn$>6ZvIh@A-lD7U%Pf zE4?mWgqnBwsnwTe4-aHdde50GWhGAmc%jpxYYf+u1_saT^(MFCm;&Kik{pL{j?gr8 z0sb=ZCxO3$h6t~t`~p*lX%zrvT}hJxN8iNq`30zXPZDkfuXQw(sH4JQIBmDWxM9@! z0zibvdm-^IWb5b~UIwXqvg3Xtr>JN!s63tOsWBCM+K}4+IO^;90`L=PA;uHoV-sWN zjlAdSUXM9f^ow)mik#Sc=7U;VbB&``k#{7n@&!y1xdDb z#}CDw=L$#7JFa9Y0<7dYE4dbhJ(+fCx`JA83Raj5BJVjHOoFp{5Am9ge6yDEUQ*+g z<~#;ZH`FXla3Uq)_NUN!{qtyZlGjkdFf}-K4Iu3PPXd>LzlN$$k24@}Joa-0O>8k} zTCYbqpQfD8dU#+d%cyzBLQ&v>1?Q+S&=z9vsrkxKm;^kK8cWw0HjPFI-mf=Vvk~8J zH1KFqQ$Cq|f|6P2Ch$J+KLTGv^H|=wdiCnDPl##J0Gg-+XjnUFPtw=wB}r&l*0pfhx48kLGb-- z|6!?SLut*_GnJe`?2I5J&N1h59?McZupULUjHPGHBukP#s@Z-5%@TZTb#*lbvg7m# z9H$0QN4xFjz<-FwP@7EI&c7GR)IYZ4B`3#vE_entZQbr(+EA5Z;6l!G_zPL#M|(Xjt$jnl^lF zm}nZ+>gp<2u3RY#DqaBo7}~b!i>R7ZviMFt1SpKsW}Q!an4xmuz5hx2`Jx%nL+Fao z79kTMBbX0?{pUms#0i4Pz?U=cauV;kkY~&}N6T6mf3Z=?GE~lU0p7cECmrgaMUOaU2(ZRLIb+WXV0q{|+Bx__b|Jyu18Qg`-1@ilk3O0vb}x z1DOd-#1zZJeS!*reh-34`UEDa0hA8$dEl?3MLicdA*{VSp^ILp%eCel%UQ}ZTde~h zqtqET0+-$zC9A0?3dA8xcoIBKKm4B+jsgKLr5cjIkac;k)8>`A1>UY}smYBf?#J-P z0E?!!{}dYT_GtR>2TXV~oTLCa7j8{d{lCl!T=+ZTMcA?tiF18Y&63amASi$Jz7Zip z5g3FLw)dwhjmT(**o2M)CCRFBj>u;`mZkK>C@F~uy-<-j29!V93c40txChM_n3#m0 zh!gP2l`8`C>u5MDE`<*_7Dq=8txZoq0Aboksc`{LqZQcyE>-rqJ@c$TU^EfpAKNU<4qryU- z^HOUAk8q*aWiAvEjS}UL6{GxwweSTsJT*LX-Upj*A0f#KyP{-xx*NybjuPHz%puoqT_vDzr?^xhbm3%Xb@gl5by|FZv zE(J;&L_s$&?al$tL%n1hK3S|(Qw0swdoHCt66e{nT2c5xtU25=q?_5D@Uk=-2QcO5GP=o!O@jV2y=tlME_0_7g1 z!PrLVh;TnhgapsB_sn}wGt?p+JE8Uog9jFioX>1+0-i-za63-;XN${yX5ul7=mp?E zLpA3NO%=AlM~uloFfya2O!K{RdoDI!SI>wH=daYF25_Iv$sK4wDpty473ZqUH z9<>HAoa_8YfgeOo)R}iumwo^xtc<9|371^)(C)nBI0w+JBNd^AXgf0CLMT3pDn;N> zIGd#`=NTq=SiaGm<8BmVz28P0b3_OO=BqEEAOAfLuj|&Q>S&V#R-K77t-!T zHGrKc8)^XD5JL=opTIJn`cTX93Xg{Mp2yP;;=y>w<5`9SetBV$wy~q$=`Nvuv<)8bjMg6bMlW$sNZoJUk)OAPmX?VLiNC z52Phk#Ng2olw3rB(k9yq&dM$p3!D!X3=KTc4V)~+!ka?w!<0FT-#9(4lFT)OW;;fF{)rqKr9t=xEm zrLZ#rVS9^rH}v|55rxC%jJWsUk#&|(=(7O)3AE7X`xt~Xrg8311O`~nGE%FGb;FGz zHSh>1f0#m`8`y}_z)lp)^a`$NL==1}T@!IW&*+JvXUwR^uly-`;r?YbWq4y0A;Cin zfFXJ>(CnqZ47`N;0Z#SeFEQr|GGmFnV z>t#<#M%vmcVz9x^F{0G^0}Ftmu%Ac!_I)4P!n=wh?Lcl!$PhFXqDiCEFA5X|Lc2U$ z(N+lY2|EAdfJaTIl{}+s3?IcYsWHj|J=#s+8MN#0ZvcLEb=7mou;5WOfFA??NVxWC z=`u7G@W56G1GcR;p@_XZ*2JLw!l4YtH$-LnlK0Gs=bSJ4QhxfcV)7`Pz`WSq;;FR5 zdr6(P(F($Jv_65K0zL)&97pUjbl62(R{A}MQhS~Hu;0UwieV#;S;{gZU!0i5Q%=~f zK#m|-44%ZpJie+h+yhEM?)gl+MIplbNsU*VbE9k{zl{3czKF`|cTg_D1LLp)UH&@v*dSJ^_&6G<~+$)%cwlz8&5hkpO6- zk+)BxPQXpZEdX}d{ucE@R*|B8VAlEqmsKhjskDH7z~HGlM;ZuYMuf7%mLoJADf@36 z#20W-4WMl1@gne-(3pRPN1$gc_mYH_EM;!G@_`P7K^n2Jg>c?G<|%iCN)QY~fTg^L z0MB;S{rmN~Ij+YEW;9iV^T3~F&{gOvhX~djL;wit^(Wk~pv4Lm9)UuHuC=%mt}mA} zt3VCUwg^73AVzm=fuGSFLm2I znWn5;%SRzicto?{`_ah2zXEQpuC5CEObptu2@r=bcp4=soLPq7aliwGs1WF<1 za_AS)sK6@f7+eE>Yd`KO0o7&8ig zz)L7O&wGqm19%qrJTuzf%LqgUo;%a!`!2MxQt-LQKO!w6?sOIq;FsSy$A{~6?zENc z^DxMap=&MiG4lhC3uSKvfcqY5A}so%(gt=Q_Kv4|9qvUD^Uh(sr+4%$K|#ZTPjG;B zx~l*vQwkYm7R~(cXT(!Dp;ri23|pxobB44~Y9|p-WIU14TyN(ESDCkaqFnT@|F}vU z9!9wZ81KiCJ0Y;Y)Zm9{05Mwim!dpmUt|Vz|GkIBq~N7e<5|iVTN?oU^Mxfgj$ShS0}Mj;%V;Fvq0xXx34qIJz403a=;Vfto}rVg zd#2ShIB!{QIJ}3amLpc`jw?%B2(Z=>u5ZK`fz8zJOB--9=pa1nC_Cw-;c-udH26Le zPJv3f57b=2**wJo4d>_@b5!DxI=V?O0FMK=ID!CJ1b!0z9j_esV2ukRu+g);a^t}^ z2Aiqn-TO6-<9m2!rNi%j`U7f_qi)Y5-h#kauFcWSA05oeLo$##CF!yr=!6Wo`(Ddp z4RFyP){8Pb@W4WmvryzXgiFm71Kfz?qa3!>(9Z$C5BN3U&cpuUQM>wZE3}z`^F!^O z!e`T-NjK<-pP+}Mh^vDM_;x6dI0@2}PA=E9FYsrdp| zmRdwlL+*rc-e}OxAI$^rg8F|NOn_l1Q?B&8S~M{v-qW0|edW*)JTG-REEfg0=i^a~ z$}(CU^da!|hkft?0WcH+XrSRggW41)8b)9~&Tt5q7q$f!l?*`JT0S9o%# zi~7Cwm_}6a&i!SKc-DIsYhq0l@~~Xbs6{P$g%Fwj{bZ$Gd>W^HfzpZ@G;P=mG-os) z;xM?7r#R85K)FF2VV*S5{sCtIR##UIA@Hy>BCwkVAiz`M0A+XI6V3SRf%&AzzxCql zSmU_YS>U^OALC!VH%D4nBIBrA&!^5`=c&c}81a1ST*l+`_jqh>9Ra?2^BHoVXfG&K z3&@>Nxcz(eJ+sFSbP$v=Jykmq<{-CEj*?=Ccl<^;S5 zJc&B=-(#1G!M#iXgE|x$5Mp>EPh)B5`I>z(8`%A2+mYVfEwRo2z_1LYT5+!Y%$uKAdPTH}w)?+d! zET%bGZfHm9gxzZ|JM|3{hmZrCAvI_jUyTb8dC$cx1t68$C|HBeqME#*{(yaH0A)(y zOU%%3k~_=Itz}~4cx!E$H`f-iW@sPsaHD+@11#23e(cH`bPJ+2_5OeV;(d~)Y6~LJ z*|gmIsEz~9c2X#y9X-4wy79h$JMBmj?u6OZK!}IB?4DL6UYUfA_pDjVtvEhvmf&Ty zh9^gxi1c=TU^f9^fKQ_WU?w0yw=jI;)(S>ot(#zt+b-SuW%`~hGkoV8E0~U>b4SgB zi_duGbI1Cf1RHtoei(E8b&D9dw9#f!Qs#;r@o=rtU?X~PXbnn~F>~pZheVkTu#O=W z&zYgdBc}}>NWA08w1f4Yx9fH4&SBsvoB@}C&jB3*bMQ{=`EqqAXX-8C5NnRhv{aedCeTeTWq1lb|I z#h3B$)4kKdc4w$=OEaTv9vaqrmWmwfJ$2{QfcKtM4n1QQPzJ9p_VDFJu#NVsbpF+t zLB?MR_PhAqCtDQM^8}ALzkJ$_ z{ZVJN9Qd$ki_inM5DY?sr{VXXVL3}M&SCI8mZiMd?U0MG-e?}S!}MclLEk!>9Mnd& zfj))>z&vU*lv3l=nPZKjU^z=Mo(Fd6zBcb4?&SxVD+;nKjXNOrj(SlLRZhSM z;DHtrdJHJd_{{7+2ObMyu_(BZrKDnz#-R^YYV{F=!oEEPzzUi;V3<+npNGMVFrR0f z@AWjMf5=7ZfrTt1a*pr$g>5=itte>bc@^^71rAsjO{y~9u`px~oJK6?8Hx9_jXBCr zTv}5Rs?ld?LQo&4ZkK;3WOP}2dmiVs&ggyMwA=pMAd|@&9o7KOp@agSQ>Xy|)ST;= zXYQPcr9!YDQ>^X^%meMSg@$u1oX`%zlR%D6zAc2?Vp#Ex+5xI9X9XUZFLLIJoGoKH zljm$&dz8c=i-z`7G#{XkVFAztE}+`jsSH(%*RacO+t9*Nja=MFWm<6TJx%AxL}(qpHbBq~ere|$yJ-M9r&I$d!%>bM zwvmU={rDOS%Q?UBw=a@s5C0h)LYdOyfy6oH@|;>xV7;pZz(XKF51}Wrt>I|x6gp1J zuFF@_9#I@~Cpt7KSE&Kq-TB6DI>qT5>7h&C%MP^>MA1HnMnJ2ErQZ{7aMV*gya&W- z+w~ugk&MOzlP@a!h@liO^7ad!`TnpduD#O$55_)ZB9>}uo@1P6sn;VjhFFBe7;MEOejs!aQf9On z#Xcc;mWqPr(OSs~S{b-B^c=uPsC`hHy~CUpr*5nAQu5f#0|Q{pJ{Ep}gg=oh@ZJ*{ z!BW)#927&jS3~^;P8WnwMLN2}S#+%z1Oe~_y6c|}Z#Fo642k9CIc;^>)ir3fOdrPhNTQzexJI;81nHbIZ zwSG>`93Z15wIR{x_K(M zW4KMT--jwx{s_an|K1-y?yEb|IF0uIZi8^dbchFdY0E01oL#bnP8)paXO|h_y}3D7 zvXm>GwmJlDgfoV_QG`c`5t6*nkYSc;oqv((aeT77il66*_joZ-X#o3%15yz>Uf2qG z6-|G73WdCA2>EQDWALn7OHbr5*I#Gg1E_-vfCWx*_TMl{u~;B%L=lO1<=fy||G$|?n|hlW=lz!50a%f5jn z<9DS2>;@;o^?IFNqd{}|4BmTQ`0Qs%78Y55_gxC_;rhpLU3=dybz2(aH(^)zz;2`; zE=Rmju>u|(f)d;1XnE{B?$ngBdW6I|&Se?mJyGq@dvzUc8d`FG^b>wglQ7*EJc9S& z!meGW^(uAMz$SIO{3r165v{iWL%}oX#aNF2sT#`CFLktw-qw1c>?2+<2m@9Cy!XT_ zXIOdud7O7VyZQy1i;H|<%95^WOEjOxAs@SsHld+>_+iWBfKaHx4EK+g*zS}uDUU_CSgNvP$} zJr#!qKs@|{qtXBX5D{z?@%Yov@R`rN%pd;ApQLaF=g*wM8pD@<=yPBU@4JF`H#ac? zty|a0JKc~1ESO#w$#YyS$W&v8;{Iw%2yD z>pjLR=b(fJ8&RR$1LbET=dk$xg0aq@=+xv53>p5^Oj_$5%_8ro1|Je-BG5Jg5VK1O z{Aq;`gIjMjSX^A>;)U}RML`nB;63M-ml0!VEiSS?um1ln8{ z@$X~|nwIk$2Q-=A?=L}ZZx{vwz`&qD;MDs7y!Xt_&oj5Mz}(zCKlKNGic1$R5Lru9 zs_!B!o;iaNq4n5BUc3Axv2!$=^F(PzqrC+pNRexOK;Zu?O@nT&L1rV`QOqk#EBb4M zaA6}&iM?YfJfF*RlF%AzG3${T%T^R4cy1>(+SYO>iSYU?Y-45cla#53)8uYBCYYd%m?t68VaR4G}dh}o2e!YI^e+AV_R3H`1 z=Q)d6Mx!XSotkq*LypNwz#(+Pa;W#S1ZEf8h3lcN)}ZTsn+Y(>W43QdaLhU9z&u!W z;k>7C4hjb@?9h3JIHz%aYbc@!M2O-T;yAPx3$cIiF-EkeTMWh+B5R3*2H?HN2bI5U zOkzO)FYK}*%5^9f0rNzRk_McX|8Q zf1R{&EWZ97&b;<*u!efQ&gRNx-um1Z@CZ-czQOXwecWr`(E^~Y4b0u!G?tc-m9wPA zaCT{#OHV$@b1%M#2hKkE6r1boB+WUz_Y}@k1P#E6&<$Dxz`aDH3vbLX0NT>5Q52lb zQs(oV73cWm#yT5u!e*?gG9NUWq{h%4;+EglJP-wdQz`%eyz>-U z&W#&4c;n6QVT_Q(G4)!FdR={^*Y2%x^VS`rkFP;qVDH{RI$L-f(R=z?{9_k6_vDj! z;KJEu&UD(y;v%?$?A~2^AALyt+zS*-E9BNtTUp`!V;8yn#1*`EY}~)k-8*;4vkdP& z&bw_Dg`R;*-cKWv0d<)dq2?U1(dMJZdyNVN=h#Y?l8K=m7ID{F@?Zk&dz{Mq;s4oj zjzs!A@}7Dvd^ipZ+61&6zW2caiuwY<0B6%4%b|ee6Rk~cz-c1{_@LQjJxwz9k=H~GtEC%hw0GB%*nnli;wAa6e!=MZYdY}u$Au=#OgV}*){>Kqf zIssuw08|Jw(1>7++UM3p#zZ*P%02JjqMi&t|;{0IdBpZ zboBdt@DGSFeSg4FE@ivzy?c19%mW-|hZu*QuEi^U+j;4IIiUwWgQHCESq%Y>86_HaAZ?zkoM}{HdpD zTzP^Ye)d^Bp7|)EW-UexB2cTn$eBx*uu+7uhOE=&)?07#t#{t#x4!*tM1(ireV46v z`$&twgh!oz>rvcS`R^tPiF3?{+=L6g4v%-+Y=#WQ^(f|Ek|2cC;}MN*DPXp&hCcDI z8O6lTF;~o~zaUF#76oT}-M*voAPZVh3UTeEqandr6A0yRs^;G4j#~);)Df8H8DuFQ zT>$UC^%n8M0*&=e@Sg8qTxOxsAX-|+q$$POb8zk)h+tP%Xe=#pacL14B>t4YQxwP4 z=I7{iIuvVo&J!Z(0U*aHkdjFcjb@YPe*otE6A+G>n zIZK(#b4XYe?p02NA<1MEHBtrp$(7Oh)10r*aPi-nalytMi|vBt25u!bSFhTs2* z7kK>4N`LXTIvuh+XK8*OBf^bq*Ld^QSNZa9{wD8VyGD|xoPFbUOq#OV>*5hUYBcB> z(+{iFoEG!sBD~X_>xc0Ud`abl;1s+b3Y2cu>R9i%*zJaF!;H_h@8U(cRjacVMSNIq z0PLAibm((I1w$Ft_@L3i(BR!>6OV8gu~9^w4A==S4M%8HxsY zv~i7^N~044l>pcSKE&=zl|0Wf4a?Q*U@hK3;XKw_>Pbv39t@?3Y^xt|K<+*5PKV7_ zi&~np&~B3yIrZQ-D4RdH;2S7+!I54Q0}sA7+bElu>#kdK4kr@o1h(f6jH6RbpMotA ztz;pjS85(66g_zz)Q2u-zvI5b{t%%(0YJ^CQ(q9Y4MPjCv$2lLbKZLORg4ijHlkx= zVrzJJX`Z`tO+I|@eLPT4Vj^Rx-MxeHu=e2x+X5vf)QG%iF3+hK8#G)_Tok)b{qi-3PUyNoJVWY$7f6E%a9DGY z!SFR}ey+eVpf43L-P)2y~(PaJc-p!l58Tx4tAO`!8151Aa%= zn(K7%y)HSz*M99+5D{DmW?%dEw=}1})6q25UYF&?WzP4yTxs`0ZNG4*R_Cqx1qAqR z5FS1pBQs`)$~WfgLxqn3?>3vn-f*o-2?a}=}Cqb2}^^&W*6Dgkg%c!v*s zAMMtrI{wNu+d{hnmzhJ(gNb9Uy&o#x>4d61K_~n04{%&NTQs~?T`IG`m$;-#PMI1Ayx zOoaPJH;bG@=L6)x27`^iUlnxnN9Y9LBoA`ALuj4BfJ#hl^YMiW9|hwzlS%f`j$sxs zjzpkM^tU_JML`wzMj?VXhIgBD81I=Ya?YhGD_P39v`1zPAJrRd*+|QT$9z5>*o-1F z5x%pq1OktD+AQTtn36b09>RehNKQCin4lrjEo=My4~IknwAc{^=rZWJP@%#DC~f>Z zNrDq$G0(8TmG%~AvQ+8Bj71XIh-1Y2qlBvVg|0DuDl`YoXBqWif<-tAfy@u6u1>N5 z0FOiH8XL@<(S`xU@QJ6>pQayCsl+e;BVZ_mxE zV{=S`pp1uijlqlX=E5TH&dpPE1uw7PCvpXyLZbk6gwd5Z9Rob{jBqznuEy-}W10bX z(RH5@9+d6wPVfj-m?T_iquvWS5ZTl z?dz}i2-pfQq=!Flh0}&IeOQe4Ik;Z06FIFXfB_}gy(Hb<&&)q9PoUrplu_* zwz4wVa>l3;^fM`~<+}@u^g3-Wq^Y)43r#govK;7%;cgUTL%R4Ok)i9|5;pu&0OY85 zutJ3cp`41TG2E#oylR#JxYBNu_<~QgHV_Xt>UHiUwZ2DtTqrex+eyMV7nbnAW1IJ> z7bnxl?a&?%Th@|sCpE*SiHepaS47DgfHYeX$j02e}A6Yq=5X9~SeRxgsY59_w{!*@!!}+F0|@%j0fZ z%Yuto&QG3|>jdscmR1mEM?{$iU>V8-_z>s;_mBHxE6fg@2pwyAePIy~JipaqzMWx! z=UXlABsJ~^7UDcF85AeMxaCZI8IozBcbl-0v|A>0hIL}Cv99RoB#}y zjFjDrl-^oPS|>T_PVxjFv3Pud5ac6N1Gq~l2S@3_PV$&lm;!hp4}1aF8V&9yHLUl1 z-^P8G@{AX^TH2+k(dc(98VA;*h{QWiQsHYZ>Lck`%k{WM`)DRWnE|+ouJ>(Wz>*WN zi~0dlw0@%E2dr>pl*_GaEUB?X&e5?J>tQL&5TKUS=$P>o5P7t4sB6qgTK{B5NJU${ z_d?;*5zz^^l%bIrZV!GBcpVK9yo~k{uTWtmC_?=}ZY|$hT;_b*<1_0Tcv_DlBJa49 z)W#wN?ndztx8d|dfV(!~PMpvaGlhELtaM9JPS6N+M9sceL6~>A(CD;sc z`gz9Z6gVjhe~j2>_g}qwwg1MjYjFd38?_ZaNu>c)7z0Yq!Hp>9T5}G7`68#*b*#rR zxs1MWs2lhfQ!!Z4CMb4_I|vJ&wJ74lq^3zgM?Yi%yboO8`NpsS*hE!?Vdl^Z6-JIs zgssSOvsTB8@XS_=dXe(R{DLMEc|X#^p;UyfXkt*|JvHwbUyGBYLp-co%k`m3$|J%9 zAER|Y+hBHl$Wf&PSC|m`VZqRd)SxND=BNkW1CH^RB_DZA&}_;voae4Xj>kTbnvf5Veh}Z8JGy{1JO#<46 zoe9RW<5r=zW=G04b^}B&e-W1D-nW0jV(iNJCfP zjW{N8I{D9~DeF~(p`yPZYKu5%#aBHE(eh*aq zM$k_TaDWR*L3dDl;Ylh@U?MQEttI)id#gu@lFYMfEQM$Yuvz4^BHPbfJu19tN^nWA zF>MBJDu#|R+_#Z(C?1~pa~Lhu_HUy#KE-en5bWL_+yP$=|L_CHJus&M0-VV*BIo+^ zay^P@+mY-7Cjt(*Rj+GT-#q7Bug6-P&>2xous~R|HZ<56Np1be;DOicbKHoNemA2L z;T_;tQK$Z{q=R}~0s8INrw|&XANk1*=l1L>SE4=s z>0Pu_(3B}kvxUBg#(U28y3~UPV7w=5H2bZ?%bNN!cfJUTBC{l+y$J0P4}w zR^X^`Ks$uivMHI;n)IU!|3;i}GjwAfA#S7Ie+Yd5c4999@CGn<+yitPP%iGrx*g{8 z94}xzti>^RlLX_n6R-82BrJ$-XvR@8=}gCTJ{mM1KwF8eq$zVnKGJkuC&H$&DgZ`f zUytCNwC>*_TuW-)9({}TkAZJ6)DCXi zPq1w)k@v^eGtdAxqlEWsjlS?3LCt@OHgF5ox5XUSPK0u*R9hTgaPh;S1z6`%AAFbq*aZG%IJbG=vEv)A*@7;9$4Zv+^i~Te@_@rD_Kw(V zg2)?li>${nH){1hmy>u;BRCB&b-O&@YVmQSL23*=W4SfrVwy=pP@l)R&cACc8&N_% z?H)^6uoIzYl}c7p-t^PDXkZJQ*e zQw!j3l5j7n@$$xfma>c}iZqEPIF?R|2r!{<;5Z9W1YLj~F~?F2q~C9NqtWD66!)tl zM}$(IY@nt6M=}A*-@(9k^K{~)He)D%^!@D6<>%Z(KBhmE?-Ofy5pBXb#k5z`f=Ma? zp6$s_WBBGWHN>;eT&jl&fDGja$WbzZuK=F`>XR6(S%m;yYk6gPCFB4+Y7*$;FCLL2 z=z;f}O|19K6*-^U+~D20IX;Yuu`yoXt++ZcS9*To*q7H>mQ3-$}qa?;0HG09LoH$49 z9I^96&SBt0_yYO`Q6X7pTxq+72)!{Le<#XSct46*ixOIa>wgSlx#a!(7;rlae|E!u z8;-q#`UJiNER281DjWuBm{fIRG|c53%ef|i-H+p`PaTe&o}okN*k~*ofS{R_o6&fV zzZ-nWJNQmxj<;$}JY(rm;DO&jvv}|B_n-DF07_p#g%bup8d|BD!g1(A!)DkRzrS3k z`(CU26#(y{c>&kZ=~PFHg(^%TauGIS<(6AXdpLxR$iftx0m5K1IuSZiG?p$w06h`5 z$}r%VVSw9F%zO1Fx1xl$k#SUfw$SzYt#I2nr{{hJz&+FiSO*rzK57+?1Rv@IjQ2E( zVpQZ3V@DYd^`Z$-<65A7AHW1gMZ9OrSgs{?TGo;V`tuPZMFqfh)c)T$4q^gG_>%in zjYFpz!=WY_V@BO*Pug#b|BusOF`{N0k3?B~l!+O2uK!MS(REo4+rFcl`xO8sv*`ba zrUm~n@a(t-uENpaMMI4XdCpu>ke7J@Q*Ht@ioCA{w8v-ybj7e~7;6~N0Usv~yujP_ z2CoLT-!c6HuK@puLBig?y*`f=0A(m)b#>JN-$P3aFQAlRc0b3cFgcXPL4^q7=~oz@ z1jNo^y(cq8+z% zqNy=#nTT&R=V=>DKAy(M4lVkLf!BdwJIrt$)E`mSX&h4-MTLW7+L!+1Au#^gD_{Y5 z5r^*Z;Wjpu?w&*U@;K=3orN#_9`L^ce;9aqeAiduFepT5MG+TzUFP$wUo|+*5bv4K za$@h;GL}{pjg8&Nq3#f61~OPYHFtE0;Lx(}Z#Cw4uhwA0MyhR$XUJN>|B0^0ud%bt zV4v8x04URgLu&9kN;df84BCm0oYAnt;ZRlzmK7la{rdW8Roet*NQ#|W{&^^B8s`{k zF_yu5N9~BmD@52b7USV=6mvU{$z*KNi~_a)-#|Cz+i)=3zr9n zsPxULfD62L9c$?rOJ)pn!Na~4O`pqVnD{jE%3z%tGg4OI2O+eLrDc_Kan2n+CLqAN zjkvnFf_V5|tP)pv~9%QT8#o&&N5=} zXxr(N)pJEb!xeO`r4Tccet`Qy&saLf_XW>kR*?rjs5QA6C%m5|0Bnu_{C@>a`Ry@j z0kFdt@EtS*=>qV_!||qbn>mH(Si@RqHn9|{0*`F$jsXoDNR^MH{iStff7Ewcnu*KZDlfbdIv~ zml%~xI74lc2>2uecG3#Rj50X95yxa=Sk6-L`aG56`-uc40P!Nk-Vu36FLXAV6njxl zS+KLe&nuIYMZD*pjky*lf$U=8!X&#~G3NG}z0NkoK*o?+fG51iY3FP~QQxE;DF|-7e?G5wtQ37m6=hTC5Q zTBET0hcW83umY7>C4WHW3z#AdH=!t1|1w3`F_GO2(6(pR`+j1Q3w;kJEdabcdJ#JW z!P5&NLqi~08UI+7@%;>q_a8dj?_n6V0C)@dS#(cX4JZ9Pl`r7fQT8Kvuh9g7E1eGW zdCpUvwmP+vgqyW`UoedN2P+qu^_~}7t$u1Uz^x?VPEwng04mWohOYN?j69GCBtRzG zMqGejUR>r{Tw~MPN$vbMP_z0j@VC%>n~`JG0w8D5QvBJ-sna?u>xLvCSnr=I`%D;z=MNb41D7$td z6T`ZV_#iZ7U9&N5W5-Rc?ipy!ZxYo0a2rdAeJrCMaswU*J^}n4AVG7`s#M`Afk$`a zC%PSs_blW&%V~-e;jQ@v+Samp#KIv#S$;h5WT(xgZWj+M3bN5Ey8R`&PHsbAigMYSkMvJIIh;qy*WBm#6UjTm_6$T%2#EieaFwWAj zvS6X=DKLeQ9rvKx!L|;>BS5KjXfYBDH$#&hM4-np27cGq2j^ub(5-lv(-H>jXRK>y zoC4q$D$)K%c>a^X=f`<56%Gb3!p)i%2iz|lcM~m%z1Zy#dChh!O@gkmw5`PjrrR{s z>zA}$CZrk1!LDD-GwMabxn4IkE;ap3zi%xq)3&xxRB~KZikS!n&=W)3#$@RE^~CVy z#U<8k%vNZ(HX#$`4r=cU@T(}rx5jVBgs}*Kt5>hGy1Lp!i9=pNeF2{Weh2C&Xizx@ zj~yP3Zvzx!$c;g~=drG*76>}aAIaK5w4e|nHi8SgIzDVy-jjs(Uh{cQy(m}+_WouR zY-kbg#Yy1(Ki(-&Mm};8I>yowLng{ccrC8co~&=8hdTYf9-dzZ(s8K$!x%R^#1=|d zoS}5$8M^TQ5LJ`WsX#fsGZFHTBk--IWo+;Z0IXyg^F_}2UQ0M)!Ir=Vl1N>D27M7b!7q4+!usrW%Fh{H~A@EAYzqZ-KFAkRQ{9P7Au z{70dXK^Ns?5>O7vu3o)5G1)UoeyH!DQmqF30B{~SJHhX-Z~*u~E9OPGo5Zvt%UT>G zUYTxVx1C7Ch03@rETFEn}vn4|!(L${1UK|^I0OeywS)U$?T3`G{G^UpEpvNe{J-@PzN0g#6aUI+dY;CBIk zJ-oJzCO=fDa2k-KyZ=81{(E#Ce#nFuKTL?t_u92s$`c zD@~xnEW?Fc8x8mUCQ9(x4mUsUu-{G`%YqA0fd$}cR0H_$P>rC<52!H9XrsIQyTG48 z3w}PH^r9ceai{2(S(Xu1lhF#Z55r)tANSe=j(5>@fcH?7;D1MHj{iM0L8xjwUSXC{ zpsN4>gNFLnQICJ;xKHfZ)$L#oyok0I`&;KCs?}W!wp(<6Va0v8JZT8E+|Ata~eZ<~{h!e-L3xH5Kl%s>S z&LB!)n36%NP~ng$`)1~7#$N}>kJIV5+X+q!3RF5ewDr+N;B#ooFjQnB6;2My4eiU} z@mJ6||FPTrJ8|qjfSm|Ffy-!!@V^0mFuc_~?sKb9VV~%r+U%bL)==~I?P=QiOH7jn zFpPVsYP$B&HT5dW=yQW9v-x*o>IA?Jl*9-fG*WOG6#^dh2~3>{Q{hx1 zLv#DzMKyp;CPe6QR7|@7xEAg|1YQUJ6lz!HDC_XFpMQnfhex^mz6ShdbW^&H3W2G| z)bF6dDHx%NL0<%ZEWGv8z!|FcV-=1ETMTykzmIbG|KI4E+GGNJextzD3xE4@4j*4q-EJz)b@`V_y@`o%PMK8!X!}g^%V@} zU(5+LM^D;GcTtIJPtU0p5EK?nFIDv8fAC@;P+^teKW!(zA(=p8gaxHUl{8)xC-WEuPK*H9 z1rB&0_-oNhbei;Mda3Xj95+_ms3`trK_~0Nc zA)H{Ftin`57;sgV{xZjy8g(8AW@(YUj(TF7Xf@%>z?V?-;BhL_(F*%VfoAc&$-vJ4 zRW!bTA`*P|iKhjIokpv_4C5^A4)nyQ$n!v2w=as6LInX4@-5W2In^Ou+<4WLBX zS~&ymq5@z&yw@1|Ooa+N(PhxH;vSmbYnWk&@+=B~3{BGbf6>OI0Dl720{-;SHP7S^ zTH#PAo74OK9mMHick?{ox*J z)32fS{%@kHe+K*#>Pwm#hu?0PNdd4EK_J9vqEHU}ao}GEK1)SDdRpO8Ch89G3d%ik z57?OH1-}!gY4ZuVe~LVx0q8nCr*<9$k6g)5Bwjff8ckaG~~|!e*jpb z(g?kaH8u)$aj`1_VbHEj5I5X@7qDr>N*ZyHev zfF0OTYTR$?u)4Z>3v~{jK_}G;sv(qbHiOPOK0LpHQogm&xc&RU zO;iIY|F^;sahfOJ*bp=WgK7bS3WCp~osKV|4#Sr@-I<1^Gf&WP-Ayz_weBgEg!3g|UN z5_Rr`&wdY$ro0#4>rgrLjs=wfm|_HBVNoKJGYs+$E&&Uu@F;TLC``M^DT6t=cv7Y2i@rOVb?*+ql4Z`noe9ME{h23%d@-qgI)z#H1CO^ff1i05UK#Gc7PVEiy4wFgZFj zFgi0bD=;uRFfhNbIGF$d03~!qSaf7zbY(hiZ)9m^c>ppnGBYhOIW00VR4_R@G%z|d zGAl4JIxsNK@_;1(000?uMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o00012 zdQ@0+Qek%>aB^>EX>4U6ba`-PAZc)PV*mhnoa6Eg2ys>@D9TUE%t_@^00ScnE@KN5 zBNI!L6ay0=M1VBIWCJ6!R3OXP)X2ol#2my2%YaCrN-hBE7ZG&wLN%2D0000DpeHi*XPgQAHTcKbI*Owc|G@@d(XZ1BwJe=Gtu+X0{{RfQxgN*ON#torK7oQ zSMtMDFA3N~*FqNnXv$zXM^Rt)1zb&REdYQgA^-p;4gmOb$-;aG077H|fGs2dpq>u^ zaG{GjY;Ii+(74<-HURwlUoQPvops5f4K}qfq}{y2apfjIpLJOX0Kn;LYM^WPcy6KC zJGF@PfDl6rmkIh>@Nv#*X)v^C%5+sk$go*eiep@_>@`N`?gUjiU2?RjAw3CJ3%kLR zXO$#FtpyRa6ECe{YUW^rS$Nv2NLj43hphA`vqwa=9jhzsb+rYZpclXLH-<@fYAAG$ zIrHx9j&7fIZ-##k-`!N}RqknWB>*6@%;rFLyf41^EAc7*^Y(i-YXCwA1hfXZW4-a= z;be*0QvI>%j)k7e}Nv8vIxSZS`B7D%+tX;E33Qym#S;8x3bV zk>005(?8~U4D$3*QfQ3>@+^k|_GqpFqFLJc@~`zOj8Vw|i68>@CYA^9L#>d|i%BIT zJ3x}j@L)%G{zPg*Wdn4}%q9#9V-<4!PJ_g$ zFB38U%B{5etGLHufm+~5HVH}uEYh@kJH<6rh*cvizc^qtU8t&Pu)XRf{s&XC=msK# z(m=RNT&>*<8aw*1(UHr;CwOUYf6OOPE;6VCrO)VT(`-mq!D!>f7t+zGDD~tI?^$s& zk8pzN1tu=HD)I(QVoYKV0Wa_Sisn5at*20e7KuS3&d8Y%l|Z5)d9MlfgT|-m3dLQA z;U@vJM0Kra&{y5XBXeIT1Ut_cGB^RY@-`P~OpNDnr^AYFIA)N7s4Y2-+t*GFCeE90 zD&jaNUIDm}uIBJOjw!u!et7slI@!4+kwJ8rAlZ6Kpi%0-objvc?S6{)3lhs--}!BD zBaB)pwDO8gmBfnqtq?53IRJN+ZzjLaPQ0FEX3qr@&!M07T)PhZl$>S~dcB#BE9zBN zJgbv5~cDUl#*{xXzL7X#AusExC|9pcj;2xuZ zFyIn6_s?exr}rj1eh-+cA_73?{VVeV%eFA>Xoi<-Io+{MvhIqsiP(K}(?yikwne01Q zNx~Q-ZN9k+vmukM&A0t7zYblL{ub-Ld8Mss1WM1Crdf0$3>cFm$bwSANCXa0Q%WBy|o^p}1l zuKNZ@j{;7@C-~ec)|#VCL@$;sAE~*FoaIZ*p3L@kO1JkA$!=mln#WiAnSGD~*{}V* ziFGa`W?4N$vV_LpP@7!fGr^hD$vZ6U9fLx!pv&zlGLb#fZDpZWoR8z;8;yX{&5U6< zzZ?q8tU>wuOKn+)y?PCxU+RomP#mG49*%v5JE7bxNb%$XGj{j$TSuQImSvUyJ1n*= zubC85PilGcoAHtCi&gXjk@fc8ZW1!2znpHff4Nq*Uq5&g+{dq5d@S=>F1M<6Ab-Jxd<D(EsOwKnUWzsXY!&gm()bO8$V0O%0n%4!r z7w_WO))eM>HZ<_jEjns0>E1e2_ViR`sC9V)S zR{o~j@*2ofusNa|F1GbKflbhNPemr>c1;=FgzDRU=ap93?O!d&FCG|3O$@Sitfx8C zY9%>diNbDjUsJ{P)9w|a_B@Bvo}}AH9@=ssVd({_<=vSQkQ>xS++C9!d@o7SO3p%v zdGQ0Rdh3a|n&s3Vga&S1NORz%vj>pOSw$~KqG(yYdbu%ffHz)>P9KH`-{$ZotLAH2 z-2;s#uhiDm>$#v=$T|?TVol3g3RQIM-8b|1XwK-0!3f3;}mt2FctO^;wt9Iz>d}dag|_Ei9^n1=+!F%JFS9lHLX74U#nN4lwE^UZH#WnNBe%^i9w$xF<#`K^ zs@!s^fY+>xy|Q}lEuB?yWwYBs$8j7ZOF09W53qLj4dSyak?dN$WpUSLqZnN-Vi8zM zLmOu&!>k2tsliTsB%q{iLf_G9$JoeUVI_)2{L=~9KQLHJ+d-8o zH+8dm_TP9PMC9h_oOWbx@Ne;S)#vVSOg`!*tn(|3ReIku8$G)yy+7~T zKB&O#O;qpq*~<=E^YX8Qu0}ua^wTykSF+L!i=|j;>9Xd3I*u0kT$E6kcg4uqW^xi5 zwRD#MF|@e4B$A56J)HcOZ;mIy+>jM(iy*GUgEiS$^(ylZyViY|!rzJ!|%F7p@X-_5CVYFgS(DL>@`3l{|@E z!ycpOpI!~T4{h4-J%mcBU`bwiCesC&?R~38be%c=+2XF4&XeKFJVWU(Z-KwZtCCrP5& z6zdPGQrjQ)cD{wKv+a(C$G(bwp7D2^D4R=UxAV5!bXPm=XOG++ao*UDXDC(rA%6B1 zsY!4tlw}>*PUW@Z&tQnB!mc9wBEB7HTU^*!y8Kq5`b`~j;FaRy=G1|Y&XV^FUV@X6 zkGtU;3|W))FLq3@$BJh=jHBGjMp=V}?`29>h6kR3{X1zlcOy=JYIYWUlDl1c$Gs#X z*Z9*f?jOmUUv27EPSx}X%ZM`1v1t(nh1k3Nc~5%Q?WGANM)((7Y@{HyhCgb0A>JMA z+rxAh(4Z0`Up%ahRJ-j3UTYD4Of~hQJ2%!-NTN;7JBD#^U_*?yiq`%LtE4n~``y6HiCKx?na9Nv@@!Zb|qxY#gYt#vHXUvWO2*23XBZdwWVh8$bf&oXJL< zD^3^M;}CBxVwwe7?LIkuj!oko1}UKTFb+W*)g(=mB+19*EdZV04~HPkFIT$>)ey^<~_sFJ2CY{D9VRBhwwWD&+YTNKM>}?Fs2eQ=sMdy^ZmF-NZKsqV{nSoLu>-6%EJCIV(A~1$WlvHgYE0WJ4r->*sTUK{_?KosLCC zmeO6-F1WY?YKo(^lZ>uF>g&`) zJdDf`!5zR^*%L6auNnIg(_>a`Q%kT0icGtp_Q-Rgt?DBwmj=)yc-hoK0 z;Iwd6IgX+uSlRx3#J{6gokR8INLa@bA3pP$uRRGb@@y&CQ@%$oLF17UZ~CN-90>6% z$`;s??DZfF@p(OPhZ~7wOyX#rCwMzp)adFx+n+N@PN-0|YYg#8bj6I6#608bb}Aa< z@VSp^3AoZuHv=jeP*#e%Bgncu{erDh$gO(T+c_Ko4tXz2|vQ1w#Z~gdoDHsSv+{Lg#JI8jE}UHjGeD^{R29KU(nun!VoL zEoh_pYI;*vca?UkW;z)Tqx_)xtpb*lYsyqj(6|WdkvOS%ARp-s>AxR2H4ook3D#zj z7+_lRfThnlDR3+&y#K2yPTwaiLy-88UJ%bP>-Y<*9Ub`rwtCmcmD1fR2$z8(odwAz zAul5BMQrJ5De$pyts^EDHzmb;kR30u@24!P!-m`9@4gA(xcbXgi)8`_4%OrHh{)q- zz|wch4s!cU@BVr?#Q#)XvHob}&_Ecel#k8%8o>u_ z60P0cFna@?R0G0vgi?eFD9Ih)e}SSY9>&Ap&>HeP>ian}D)z>K*X9u`THDc8WtVod zeKR^znKSfwf-UO-+A&hwSeWkd8^j{c(o^JcXZQE-`^kni?qzFEyCGH9YY)pRWV|ue zIFax2kZ)5vdp15#lglbTSk-T}k2K;c?QC!XF$B-yow~7(@~>)gX!XW&lPh-#m3*hv z`9Yc`(rK*0(r+0tF$8wasw5iRb?D9oXEYW=aUaV#KG?NU#>P3QF4ytNX0&$y z7|m0DB#R}-?IO`!6ZPmUn*DGex<6Ha%SRYJ!w=o=?g_IwVTmn|6Z|-fHe*w+cJgV&leMVcc=j?=>l=}p9fv`FmGE!q=p@{RURR{48Fa-sDNLhBF!D; z>^3u7xoE@@ua?w*)W@h1D>l^46GLgu8qHN%rt;48j{{#N*eYfZ53jy;`(^Hx?VpzY z17++0K4+il@qMPmGv51F29VJ-X7BrF~^RVwNI{I}-L{iD`9D0lY+vr0Bp(BNMG@2d;SvM@Wx zJiXciW_^15`5wu(Qm)7f9t$>Ra7a}jjX%V=eR08wwot)I6&i1TQ;wKz6kdL7@oj)N zyGN5|tCgbHSLTn3e#HY%2zxF`j?GVWv#uoDrrwmh6ENC<>)E|5vJZ`+awTfMja;`i z*<()s(6M{<8fp{oENCu>aN=k+Zkb*67z=iDpRt1_`l3#~Xu2u_1wHRsWC&e}R~#5= zBzUp$A%E{$NB9b0TfQfz%VJ=o@_TpjoaXN1ga zAW9_HFYg-*S0xEq%7t#v3``;fyJ@;pe1jueNRx_BU=Ii5SR!ouwR{K}zG1R2o5PP* z3muWT#a%&s9Yt;U^=3hlTv^K41{AM+GCQ$~Ze#5Ro=aSl&@7&bAKU5YHrE?x=o6`t zvC}I5OLC4A)?3p4hi=AdZePuX@16T)Dom|$EqIQMung9m*s{Q=ZJ(lE!6X`Z|Cl~` z>-m#C8YsbVHWT5;w-Q2bY?3P}**^E1ZPr{`x!DE2^>msc@rUan$rqEv;dW+NI@dU9 zceY~fW<5L~iO9*X$rOPR~^Lfq!OM&`EH- zWfc+W5d*%^z8f*_F`Uuab{tq<-tg6IlqXxoA)&y(RNnukyRa0g-gWZIGUi=Jw?5+N26@ z{b^LrVX^GggV~AdIl^GpHE=W|MSt5(RpU1w+;v%rOu@$>rP^7>`(Tmm4&pTO36Q4E z>2sD=>^47KA@ur%oSPDw=Vhh((}nb-nAsseXP?tCq{Gm1E=cH>kJT7xmLmW#?|2zZ zEyRl-z#e?!m&EFCk2(!G)uuUd~QdOR#shB_O+yK^Zz5@>;KTpJ^cSKFdeW(cPYU0KZHB} z?!jTGKsSKyLw^@H0aIU;hnuY%>S1`me{TN^jo*J_2M@MIg$bYo{oTEM+ysKd(QX1> z=wMd>;BnFF0V7?&JyFqNtC3ODbz1;PkU`p&fnAXOb`}K0E?|IB?0X0jd~YW(GCMWY kKiUuNryaqVl$uEcwzyb>5A>9BE+GJ>hL#2mddS%S1CSV7GXMYp diff --git a/archive_docs/v5/static/apple-touch-icon.png b/archive_docs/v5/static/apple-touch-icon.png deleted file mode 100644 index 0ee95e6549e0f670e080cc03409951c690c85ea7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13882 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 diff --git a/archive_docs/v5/static/browserconfig.xml b/archive_docs/v5/static/browserconfig.xml deleted file mode 100644 index b3930d0f..00000000 --- a/archive_docs/v5/static/browserconfig.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - #da532c - - - diff --git a/archive_docs/v5/static/favicon-16x16.png b/archive_docs/v5/static/favicon-16x16.png deleted file mode 100644 index 6e2a5f7bb30024589b0cebe6e29ebbd01b985f99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1210 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 BIxheK diff --git a/archive_docs/v5/static/favicon.ico b/archive_docs/v5/static/favicon.ico deleted file mode 100644 index e734eba0d25de4264768b9e0d33d0caea8c763b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 DZY)W0 diff --git a/archive_docs/v5/static/pygments.emacs-dull.css b/archive_docs/v5/static/pygments.emacs-dull.css deleted file mode 100644 index 79ed4731..00000000 --- a/archive_docs/v5/static/pygments.emacs-dull.css +++ /dev/null @@ -1,69 +0,0 @@ -.highlight .hll { background-color: #ffffcc } -.highlight { background: #161f27; padding: 0.5rem 1rem; border-radius: 5px; } -.highlight .c { color: #008800; font-style: italic } /* Comment */ -.highlight .err { border: 1px solid #FF0000 } /* Error */ -.highlight .k { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword */ -.highlight .o { color: #666666 } /* Operator */ -.highlight .ch { color: #008800; font-style: italic } /* Comment.Hashbang */ -.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #008800 } /* Comment.Preproc */ -.highlight .cpf { color: #008800; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */ -.highlight .gd { color: #A00000 } /* Generic.Deleted */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #FF0000 } /* Generic.Error */ -.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.highlight .gi { color: #00A000 } /* Generic.Inserted */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.highlight .gt { color: #0044DD } /* Generic.Traceback */ -.highlight .kc { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Constant */ -.highlight .kd { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { color: #AA22FF } /* Keyword.Pseudo */ -.highlight .kr { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #666666 } /* Literal.Number */ -.highlight .s { color: #BB4444 } /* Literal.String */ -.highlight .na { color: #BB4444 } /* Name.Attribute */ -.highlight .nb { color: #AA22FF } /* Name.Builtin */ -.highlight .nc { color: rgba(142, 142, 255, 0.8)} /* Name.Class */ -.highlight .no { color: #880000 } /* Name.Constant */ -.highlight .nd { color: #AA22FF } /* Name.Decorator */ -.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #00A000 } /* Name.Function */ -.highlight .nl { color: #A0A000 } /* Name.Label */ -.highlight .nn { color: rgba(142, 142, 255, 0.8); font-weight: bold } /* Name.Namespace */ -.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.highlight .nv { color: #B8860B } /* Name.Variable */ -.highlight .ow { color: rgba(170, 34, 255, 0.8); font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mb { color: #666666 } /* Literal.Number.Bin */ -.highlight .mf { color: #666666 } /* Literal.Number.Float */ -.highlight .mh { color: #666666 } /* Literal.Number.Hex */ -.highlight .mi { color: #666666 } /* Literal.Number.Integer */ -.highlight .mo { color: #666666 } /* Literal.Number.Oct */ -.highlight .sa { color: #BB4444 } /* Literal.String.Affix */ -.highlight .sb { color: #BB4444 } /* Literal.String.Backtick */ -.highlight .sc { color: #BB4444 } /* Literal.String.Char */ -.highlight .dl { color: #BB4444 } /* Literal.String.Delimiter */ -.highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ -.highlight .s2 { color: #BB4444 } /* Literal.String.Double */ -.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */ -.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.highlight .sx { color: #008000 } /* Literal.String.Other */ -.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ -.highlight .s1 { color: #BB4444 } /* Literal.String.Single */ -.highlight .ss { color: #B8860B } /* Literal.String.Symbol */ -.highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ -.highlight .fm { color: #00A000 } /* Name.Function.Magic */ -.highlight .vc { color: #B8860B } /* Name.Variable.Class */ -.highlight .vg { color: #B8860B } /* Name.Variable.Global */ -.highlight .vi { color: #B8860B } /* Name.Variable.Instance */ -.highlight .vm { color: #B8860B } /* Name.Variable.Magic */ -.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/archive_docs/v5/static/safari-pinned-tab.svg b/archive_docs/v5/static/safari-pinned-tab.svg deleted file mode 100644 index c39f3979..00000000 --- a/archive_docs/v5/static/safari-pinned-tab.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - -Created by potrace 1.14, written by Peter Selinger 2001-2017 - - - - - diff --git a/archive_docs/v5/static/site.webmanifest b/archive_docs/v5/static/site.webmanifest deleted file mode 100644 index de65106f..00000000 --- a/archive_docs/v5/static/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "", - "short_name": "", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-256x256.png", - "sizes": "256x256", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/archive_docs/v5/static/water.css b/archive_docs/v5/static/water.css deleted file mode 100644 index 945210c0..00000000 --- a/archive_docs/v5/static/water.css +++ /dev/null @@ -1,929 +0,0 @@ -/** - * Forced dark theme version - */ - -:root { - --background-body: #202b38; - --background: #161f27; - --background-alt: #1a242f; - --selection: #1c76c5; - --text-main: #dbdbdb; - --text-bright: #fff; - --text-muted: #a9b1ba; - --links: #41adff; - --focus: #0096bfab; - --border: #526980; - --code: #ffbe85; - --animation-duration: 0.1s; - --button-base: #0c151c; - --button-hover: #040a0f; - --scrollbar-thumb: var(--button-hover); - --scrollbar-thumb-hover: rgb(0, 0, 0); - --form-placeholder: #a9a9a9; - --form-text: #fff; - --variable: #d941e2; - --highlight: #efdb43; - --select-arrow: url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E"); -} - -html { - scrollbar-color: #040a0f #202b38; - scrollbar-color: var(--scrollbar-thumb) var(--background-body); - scrollbar-width: thin; -} - -body { - font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif; - line-height: 1.4; - max-width: 1000px; - margin: 0 auto; - padding: 0 10px; - word-wrap: break-word; - color: #dbdbdb; - color: var(--text-main); - background: #202b38; - background: var(--background-body); - text-rendering: optimizeLegibility; - letter-spacing: 1px; - display: flex; - flex-direction: row; -} - -aside { - width: 250px; - border-right: 1px solid rgba(220, 220, 220, 0.5); - padding-right: 10px; - padding-bottom: 40px; - height: 100%; - overflow-y: auto; - position: fixed; -} - -aside ul { - list-style: none; - padding-left: 0; - padding-bottom: 10px; - margin: 0; -} - -aside ul > ul { - padding-top: 5px; - padding-left: 5px; -} - -section { - width: 750px; - padding-left: 290px; - padding-top: 30px; - padding-bottom: 30px; -} - -section > div:nth-child(2) { - margin-top: 20px; -} - -hr { - margin: 40px 0; -} - -.highlight { - margin-bottom: 1rem; - overflow-y: auto; -} - -button { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -input { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -textarea { - transition: background-color 0.1s linear, - border-color 0.1s linear, - color 0.1s linear, - box-shadow 0.1s linear, - transform 0.1s ease; - transition: background-color var(--animation-duration) linear, - border-color var(--animation-duration) linear, - color var(--animation-duration) linear, - box-shadow var(--animation-duration) linear, - transform var(--animation-duration) ease; -} - -h1 { - font-size: 2.2em; - margin-top: 0; - margin-bottom: 12px; -} - -h2, -h3, -h4, -h5, -h6 { - margin-bottom: 12px; - margin-top: 24px; -} - -h1 { - color: #fff; - color: var(--text-bright); -} - -h2 { - color: #fff; - color: var(--text-bright); -} - -h3 { - color: #fff; - color: var(--text-bright); -} - -h4 { - color: #fff; - color: var(--text-bright); -} - -h5 { - color: #fff; - color: var(--text-bright); -} - -h6 { - color: #fff; - color: var(--text-bright); -} - -strong { - color: #fff; - color: var(--text-bright); -} - -h1, -h2, -h3, -h4, -h5, -h6, -b, -strong, -th { - font-weight: 600; -} - -q::before { - content: none; -} - -q::after { - content: none; -} - -blockquote { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -q { - border-left: 4px solid #0096bfab; - border-left: 4px solid var(--focus); - margin: 1.5em 0; - padding: 0.5em 1em; - font-style: italic; -} - -blockquote > footer { - font-style: normal; - border: 0; -} - -blockquote cite { - font-style: normal; -} - -address { - font-style: normal; -} - -a[href^='mailto\:']::before { - content: '📧 '; -} - -a[href^='tel\:']::before { - content: '📞 '; -} - -a[href^='sms\:']::before { - content: '💬 '; -} - -mark { - background-color: #efdb43; - background-color: var(--highlight); - border-radius: 2px; - padding: 0 2px 0 2px; - color: #000; -} - -a > code, -a > strong { - color: inherit; -} - -button, -select, -input[type='submit'], -input[type='reset'], -input[type='button'], -input[type='checkbox'], -input[type='range'], -input[type='radio'] { - cursor: pointer; -} - -input, -select { - display: block; -} - -[type='checkbox'], -[type='radio'] { - display: initial; -} - -input { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -textarea { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -select { - color: #fff; - color: var(--form-text); - background-color: #161f27; - background-color: var(--background); - font-family: inherit; - font-size: inherit; - margin-right: 6px; - margin-bottom: 6px; - padding: 10px; - border: none; - border-radius: 6px; - outline: none; -} - -button { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='submit'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='reset'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -input[type='button'] { - background-color: #0c151c; - background-color: var(--button-base); - padding-right: 30px; - padding-left: 30px; -} - -button:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='submit']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='reset']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='button']:hover { - background: #040a0f; - background: var(--button-hover); -} - -input[type='color'] { - min-height: 2rem; - padding: 8px; - cursor: pointer; -} - -input[type='checkbox'], -input[type='radio'] { - height: 1em; - width: 1em; -} - -input[type='radio'] { - border-radius: 100%; -} - -input { - vertical-align: top; -} - -label { - vertical-align: middle; - margin-bottom: 4px; - display: inline-block; -} - -input:not([type='checkbox']):not([type='radio']), -input[type='range'], -select, -button, -textarea { - -webkit-appearance: none; -} - -textarea { - display: block; - margin-right: 0; - box-sizing: border-box; - resize: vertical; -} - -textarea:not([cols]) { - width: 100%; -} - -textarea:not([rows]) { - min-height: 40px; - height: 140px; -} - -select { - background: #161f27 url("data:image/svg+xml;charset=utf-8,%3C?xml version='1.0' encoding='utf-8'?%3E %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' height='62.5' width='116.9' fill='%23efefef'%3E %3Cpath d='M115.3,1.6 C113.7,0 111.1,0 109.5,1.6 L58.5,52.7 L7.4,1.6 C5.8,0 3.2,0 1.6,1.6 C0,3.2 0,5.8 1.6,7.4 L55.5,61.3 C56.3,62.1 57.3,62.5 58.4,62.5 C59.4,62.5 60.5,62.1 61.3,61.3 L115.2,7.4 C116.9,5.8 116.9,3.2 115.3,1.6Z'/%3E %3C/svg%3E") calc(100% - 12px) 50% / 12px no-repeat; - background: var(--background) var(--select-arrow) calc(100% - 12px) 50% / 12px no-repeat; - padding-right: 35px; -} - -select::-ms-expand { - display: none; -} - -select[multiple] { - padding-right: 10px; - background-image: none; - overflow-y: auto; -} - -input:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -select:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -button:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -textarea:focus { - box-shadow: 0 0 0 2px #0096bfab; - box-shadow: 0 0 0 2px var(--focus); -} - -input[type='checkbox']:active, -input[type='radio']:active, -input[type='submit']:active, -input[type='reset']:active, -input[type='button']:active, -input[type='range']:active, -button:active { - transform: translateY(2px); -} - -input:disabled, -select:disabled, -button:disabled, -textarea:disabled { - cursor: not-allowed; - opacity: 0.5; -} - -::-moz-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -:-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::-ms-input-placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -::placeholder { - color: #a9a9a9; - color: var(--form-placeholder); -} - -fieldset { - border: 1px #0096bfab solid; - border: 1px var(--focus) solid; - border-radius: 6px; - margin: 0; - margin-bottom: 12px; - padding: 10px; -} - -legend { - font-size: 0.9em; - font-weight: 600; -} - -input[type='range'] { - margin: 10px 0; - padding: 10px 0; - background: transparent; -} - -input[type='range']:focus { - outline: none; -} - -input[type='range']::-webkit-slider-runnable-track { - width: 100%; - height: 9.5px; - -webkit-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-webkit-slider-thumb { - box-shadow: 0 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); - -webkit-appearance: none; - margin-top: -7px; -} - -input[type='range']:focus::-webkit-slider-runnable-track { - background: #161f27; - background: var(--background); -} - -input[type='range']::-moz-range-track { - width: 100%; - height: 9.5px; - -moz-transition: 0.2s; - transition: 0.2s; - background: #161f27; - background: var(--background); - border-radius: 3px; -} - -input[type='range']::-moz-range-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']::-ms-track { - width: 100%; - height: 9.5px; - background: transparent; - border-color: transparent; - border-width: 16px 0; - color: transparent; -} - -input[type='range']::-ms-fill-lower { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-fill-upper { - background: #161f27; - background: var(--background); - border: 0.2px solid #010101; - border-radius: 3px; - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; -} - -input[type='range']::-ms-thumb { - box-shadow: 1px 1px 1px #000, 0 0 1px #0d0d0d; - border: 1px solid #000; - height: 20px; - width: 20px; - border-radius: 50%; - background: #526980; - background: var(--border); -} - -input[type='range']:focus::-ms-fill-lower { - background: #161f27; - background: var(--background); -} - -input[type='range']:focus::-ms-fill-upper { - background: #161f27; - background: var(--background); -} - -a { - text-decoration: none; - color: #41adff; - color: var(--links); -} - -a:hover { - text-decoration: underline; -} - -code { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -samp { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -time { - background: #161f27; - background: var(--background); - color: #ffbe85; - color: var(--code); - padding: 2.5px 5px; - border-radius: 6px; - font-size: 1em; -} - -pre { - overflow-x: auto; -} - -pre > code { - padding: 10px; - display: block; - overflow-x: auto; -} - -var { - color: #d941e2; - color: var(--variable); - font-style: normal; - font-family: monospace; -} - -kbd { - background: #161f27; - background: var(--background); - border: 1px solid #526980; - border: 1px solid var(--border); - border-radius: 2px; - color: #dbdbdb; - color: var(--text-main); - padding: 2px 4px 2px 4px; -} - -img, -video { - max-width: 100%; - height: auto; -} - -hr { - border: none; - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -table { - border-collapse: collapse; - margin-bottom: 10px; - width: 100%; - table-layout: fixed; -} - -table caption { - text-align: left; -} - -td, -th { - padding: 6px; - text-align: left; - vertical-align: top; - word-wrap: break-word; -} - -thead { - border-bottom: 1px solid #526980; - border-bottom: 1px solid var(--border); -} - -tfoot { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); -} - -tbody tr:nth-child(even) { - background-color: #161f27; - background-color: var(--background); -} - -tbody tr:nth-child(even) button { - background-color: #1a242f; - background-color: var(--background-alt); -} - -tbody tr:nth-child(even) button:hover { - background-color: #202b38; - background-color: var(--background-body); -} - -::-webkit-scrollbar { - height: 10px; - width: 10px; -} - -::-webkit-scrollbar-track { - background: #161f27; - background: var(--background); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb { - background: #040a0f; - background: var(--scrollbar-thumb); - border-radius: 6px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgb(0, 0, 0); - background: var(--scrollbar-thumb-hover); -} - -::-moz-selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -::selection { - background-color: #1c76c5; - background-color: var(--selection); - color: #fff; - color: var(--text-bright); -} - -details { - display: flex; - flex-direction: column; - align-items: flex-start; - background-color: #1a242f; - background-color: var(--background-alt); - padding: 10px 10px 0; - margin: 1em 0; - border-radius: 6px; - overflow: hidden; -} - -details[open] { - padding: 10px; -} - -details > :last-child { - margin-bottom: 0; -} - -details[open] summary { - margin-bottom: 10px; -} - -summary { - display: list-item; - background-color: #161f27; - background-color: var(--background); - padding: 10px; - margin: -10px -10px 0; - cursor: pointer; - outline: none; -} - -summary:hover, -summary:focus { - text-decoration: underline; -} - -details > :not(summary) { - margin-top: 0; -} - -summary::-webkit-details-marker { - color: #dbdbdb; - color: var(--text-main); -} - -dialog { - background-color: #1a242f; - background-color: var(--background-alt); - color: #dbdbdb; - color: var(--text-main); - border: none; - border-radius: 6px; - border-color: #526980; - border-color: var(--border); - padding: 10px 30px; -} - -dialog > header:first-child { - background-color: #161f27; - background-color: var(--background); - border-radius: 6px 6px 0 0; - margin: -10px -30px 10px; - padding: 10px; - text-align: center; -} - -dialog::-webkit-backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -dialog::backdrop { - background: #0000009c; - -webkit-backdrop-filter: blur(4px); - backdrop-filter: blur(4px); -} - -footer { - border-top: 1px solid #526980; - border-top: 1px solid var(--border); - padding-top: 10px; - color: #a9b1ba; - color: var(--text-muted); -} - -body > footer { - margin-top: 40px; -} - -@media print { - body, - pre, - code, - summary, - details, - button, - input, - textarea { - background-color: #fff; - } - - button, - input, - textarea { - border: 1px solid #000; - } - - body, - h1, - h2, - h3, - h4, - h5, - h6, - pre, - code, - button, - input, - textarea, - footer, - summary, - strong { - color: #000; - } - - summary::marker { - color: #000; - } - - summary::-webkit-details-marker { - color: #000; - } - - tbody tr:nth-child(even) { - background-color: #f2f2f2; - } - - a { - color: #00f; - text-decoration: underline; - } -} \ No newline at end of file From b9d79ee407076ae7b5429c461b0f2e85d17afbee Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 15:53:36 +0000 Subject: [PATCH 03/10] fix static path error --- docs/{ => _static}/logo.svg | 0 docs/conf.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{ => _static}/logo.svg (100%) diff --git a/docs/logo.svg b/docs/_static/logo.svg similarity index 100% rename from docs/logo.svg rename to docs/_static/logo.svg diff --git a/docs/conf.py b/docs/conf.py index e1cc5518..787c2483 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -38,7 +38,7 @@ html_theme = "furo" html_static_path = ["_static"] html_css_files = ["theme.css"] -html_logo = 'logo.svg' +html_logo = '_static/logo.svg' html_copy_source = False html_theme_options = { "source_repository": "https://github.com/CheeseCake87/flask-imp", From 3d37582ccb27647fc4a786e1941c909c711e9601 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 15:55:22 +0000 Subject: [PATCH 04/10] fix static path error --- docs/conf.py | 3 +-- docs/{_static => }/logo.svg | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename docs/{_static => }/logo.svg (100%) diff --git a/docs/conf.py b/docs/conf.py index 787c2483..991425ba 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -36,9 +36,8 @@ # HTML ----------------------------------------------------------------- html_theme = "furo" -html_static_path = ["_static"] html_css_files = ["theme.css"] -html_logo = '_static/logo.svg' +html_logo = 'logo.svg' html_copy_source = False html_theme_options = { "source_repository": "https://github.com/CheeseCake87/flask-imp", diff --git a/docs/_static/logo.svg b/docs/logo.svg similarity index 100% rename from docs/_static/logo.svg rename to docs/logo.svg From 26500a79b01df92956e8fa6cb55040242f2397ee Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 16:05:01 +0000 Subject: [PATCH 05/10] refresh logo --- README.md | 2 +- _assets/Flask-Imp-Large.png | Bin 8944 -> 0 bytes _assets/Flask-Imp-Medium.png | Bin 7987 -> 0 bytes _assets/Flask-Imp-Small.png | Bin 6429 -> 9957 bytes 4 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 _assets/Flask-Imp-Large.png delete mode 100644 _assets/Flask-Imp-Medium.png diff --git a/README.md b/README.md index 8e2c336a..4b09a6e0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![](https://raw.githubusercontent.com/CheeseCake87/Flask-Imp/master/_assets/Flask-Imp-Small.png) +![](https://raw.githubusercontent.com/CheeseCake87/flask-imp/refs/heads/main/_assets/Flask-Imp-Small.png) # Flask-Imp ![tests](https://github.com/CheeseCake87/flask-imp/actions/workflows/tests.yml/badge.svg) diff --git a/_assets/Flask-Imp-Large.png b/_assets/Flask-Imp-Large.png deleted file mode 100644 index 0c733c5fa76b0123c8bb9f089883664b29681e7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8944 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 diff --git a/_assets/Flask-Imp-Medium.png b/_assets/Flask-Imp-Medium.png deleted file mode 100644 index 1140eb4cc5c4f9538ea0a3c788db40a8fe08a663..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7987 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 diff --git a/_assets/Flask-Imp-Small.png b/_assets/Flask-Imp-Small.png index 10b6a9db3668a610bb01e5d7074d47abc1e4f258..c5280bed3e52d8363e291f65032d45923925403d 100644 GIT binary patch literal 9957 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 E0ADQ(+yDRo delta 5862 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 From 09faa7383ba8fbb7422010ef63d1b26c1c41b5f8 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 16:14:59 +0000 Subject: [PATCH 06/10] fix build errors, update changes --- CHANGES.md | 4 +++- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 61f1078b..40d1e8ce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,4 +7,6 @@ Released 2024-11-21 - updated project structure. - docs now using sphinx + readthedocs. - the start of the changes.md file. - +- changes to the order of arguments in database configs +- argument 'name' changed to 'database_name' in configs +- addition of abort_status and fail_status args in security decorators diff --git a/pyproject.toml b/pyproject.toml index acac4a3e..e7e30731 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "5.4.0" description = 'A Flask auto importer that allows your Flask apps to grow big.' authors = [{ name = "David Carmichael", email = "david@uilix.com" }] readme = "README.md" -license = { file = "LICENSE" } +license = { file = "LICENSE.txt" } classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', From 3036c2d99f53a939eb62faff03a1818c912a0001 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 16:18:12 +0000 Subject: [PATCH 07/10] update version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e7e30731..6cac7695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "flask-imp" -version = "5.4.0" +version = "5.5.0" description = 'A Flask auto importer that allows your Flask apps to grow big.' authors = [{ name = "David Carmichael", email = "david@uilix.com" }] readme = "README.md" From dc4f397e3f1f99df14849f8a3137101a650963b4 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 16:14:59 +0000 Subject: [PATCH 08/10] fix build errors, update changes --- CHANGES.md | 4 +++- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 61f1078b..40d1e8ce 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,4 +7,6 @@ Released 2024-11-21 - updated project structure. - docs now using sphinx + readthedocs. - the start of the changes.md file. - +- changes to the order of arguments in database configs +- argument 'name' changed to 'database_name' in configs +- addition of abort_status and fail_status args in security decorators diff --git a/pyproject.toml b/pyproject.toml index acac4a3e..e7e30731 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ version = "5.4.0" description = 'A Flask auto importer that allows your Flask apps to grow big.' authors = [{ name = "David Carmichael", email = "david@uilix.com" }] readme = "README.md" -license = { file = "LICENSE" } +license = { file = "LICENSE.txt" } classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', From bd891134224f5b7c65d8c38e561c8c820a2a345c Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 16:18:12 +0000 Subject: [PATCH 09/10] update version --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e7e30731..6cac7695 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "flask-imp" -version = "5.4.0" +version = "5.5.0" description = 'A Flask auto importer that allows your Flask apps to grow big.' authors = [{ name = "David Carmichael", email = "david@uilix.com" }] readme = "README.md" From 47e060e199757c0b852a208b8ed826dc258740a3 Mon Sep 17 00:00:00 2001 From: David Carmichael Date: Fri, 22 Nov 2024 19:44:27 +0000 Subject: [PATCH 10/10] add DS_Store to git ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 35ac867f..6edd8c6a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ docs/_build/ tests/instance/ example/instance/ _tool.py +.DS_Store +*/.DS_Store