dataflow-core 2.1.18rc2__tar.gz → 2.1.18rc3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of dataflow-core might be problematic. Click here for more details.

Files changed (71) hide show
  1. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/PKG-INFO +1 -1
  2. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/authenticator/dataflowairflowauthenticator.py +10 -2
  3. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/authenticator/dataflowhubauthenticator.py +124 -3
  4. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/authenticator/dataflowsupersetauthenticator.py +11 -6
  5. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/configuration.py +7 -0
  6. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/database_manager.py +23 -0
  7. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/db.py +4 -3
  8. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/environment.py +20 -18
  9. dataflow_core-2.1.18rc3/dataflow/models/app_types.py +31 -0
  10. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/blacklist_library.py +3 -3
  11. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/connection.py +19 -2
  12. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/dataflow_zone.py +15 -0
  13. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/environment.py +125 -4
  14. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/environment_status.py +6 -0
  15. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/git_ssh.py +16 -0
  16. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/org_associations.py +35 -2
  17. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/organization.py +55 -10
  18. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/pinned_projects.py +13 -0
  19. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/pod_activity.py +14 -1
  20. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/pod_session_history.py +14 -1
  21. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/project_details.py +26 -0
  22. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/recent_project_studio.py +16 -0
  23. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/recent_projects.py +7 -0
  24. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/role.py +19 -0
  25. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/role_server.py +8 -1
  26. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/role_zone.py +17 -2
  27. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/server_config.py +36 -0
  28. dataflow_core-2.1.18rc3/dataflow/models/session.py +22 -0
  29. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/team.py +11 -2
  30. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/user.py +40 -7
  31. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/user_team.py +11 -0
  32. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/variables.py +26 -2
  33. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/schemas/connection.py +47 -5
  34. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/schemas/git_ssh.py +39 -5
  35. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/schemas/secret.py +32 -4
  36. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/factory.py +6 -2
  37. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/interface.py +3 -0
  38. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/aws_manager.py +55 -0
  39. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/azure_manager.py +55 -0
  40. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/utils/get_current_user.py +16 -2
  41. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/PKG-INFO +1 -1
  42. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dfmigration/env.py +10 -0
  43. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/setup.py +1 -1
  44. dataflow_core-2.1.18rc2/dataflow/models/app_types.py +0 -15
  45. dataflow_core-2.1.18rc2/dataflow/models/session.py +0 -17
  46. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/README.md +0 -0
  47. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/authenticator/__init__.py +0 -0
  48. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/__init__.py +0 -0
  49. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/dataflow.py +0 -0
  50. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/models/__init__.py +0 -0
  51. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/schemas/__init__.py +0 -0
  52. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/scripts/clone_environment.sh +0 -0
  53. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/scripts/create_environment.sh +0 -0
  54. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/scripts/update_environment.sh +0 -0
  55. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/__init__.py +0 -0
  56. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/__init__.py +0 -0
  57. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/providers/gcp_manager.py +0 -0
  58. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/service.py +0 -0
  59. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/secrets_manager/utils.py +0 -0
  60. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/utils/__init__.py +0 -0
  61. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/utils/exceptions.py +0 -0
  62. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow/utils/logger.py +0 -0
  63. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/SOURCES.txt +0 -0
  64. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/dependency_links.txt +0 -0
  65. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/entry_points.txt +0 -0
  66. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/requires.txt +0 -0
  67. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dataflow_core.egg-info/top_level.txt +0 -0
  68. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dfmigration/__init__.py +0 -0
  69. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dfmigration/versions/001_initial_baseline_migration.py +0 -0
  70. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/dfmigration/versions/__init__.py +0 -0
  71. {dataflow_core-2.1.18rc2 → dataflow_core-2.1.18rc3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dataflow-core
3
- Version: 2.1.18rc2
3
+ Version: 2.1.18rc3
4
4
  Summary: Dataflow core package
5
5
  Author: Dataflow
6
6
  Author-email:
@@ -18,9 +18,14 @@ dataflow = Dataflow()
18
18
  class DataflowAuthDBView(AuthDBView):
19
19
  @expose('/login/', methods=['GET', 'POST'])
20
20
  def login(self):
21
+
22
+ """This method checks for a 'dataflow_session' cookie, retrieves user details from Dataflow,
23
+ and logs in or creates the user in Airflow accordingly.
24
+ If the cookie is not present, it falls back to the standard login process.
25
+
26
+ Overrides the default login method to integrate with Dataflow authentication.
21
27
  """
22
- Override the default login method to handle custom authentication
23
- """
28
+
24
29
  try:
25
30
  session_id = request.cookies.get('dataflow_session')
26
31
  if not session_id:
@@ -52,6 +57,9 @@ class DataflowAuthDBView(AuthDBView):
52
57
  return super().login()
53
58
 
54
59
  class DataflowAirflowAuthenticator(FabAirflowSecurityManagerOverride):
60
+
61
+ """Custom Security Manager to integrate Airflow authentication with Dataflow."""
62
+
55
63
  authdbview = DataflowAuthDBView
56
64
 
57
65
  def __init__(self, appbuilder):
@@ -10,6 +10,13 @@ from dataflow.models import user as m_user, session as m_session
10
10
  from sqlalchemy import or_
11
11
 
12
12
  class DataflowBaseAuthenticator(Authenticator):
13
+
14
+ """Base Authenticator to handle Dataflow authentication and session management.
15
+ Provides methods to authenticate users via Dataflow credentials, manage sessions.
16
+
17
+ Overrides JupyterHub's Authenticator class.
18
+ """
19
+
13
20
  enable_dataflow_auth = Bool(True, config=True, help="Enable username/password authentication")
14
21
 
15
22
  def __init__(self, **kwargs):
@@ -24,9 +31,19 @@ class DataflowBaseAuthenticator(Authenticator):
24
31
  raise
25
32
 
26
33
  def generate_session_id(self):
34
+
35
+ """Generate and return a unique session ID using UUID4."""
36
+
27
37
  return str(uuid.uuid4())
28
38
 
29
39
  def set_session_cookie(self, handler, session_id):
40
+
41
+ """Set the dataflow_session cookie in the user's browser.
42
+
43
+ Args:
44
+ handler: The request handler to set the cookie on.
45
+ session_id: The session ID to set in the cookie."""
46
+
30
47
  expires = datetime.now(ZoneInfo("UTC")) + timedelta(days=60)
31
48
  host = handler.request.host
32
49
  domain = '.'.join(host.split('.')[-2:]) if len(host.split('.')) >= 2 else host
@@ -43,6 +60,16 @@ class DataflowBaseAuthenticator(Authenticator):
43
60
  self.log.info(f"Set session cookie: dataflow_session={session_id} for host={host}")
44
61
 
45
62
  def get_or_create_session(self, user_id):
63
+
64
+ """Retrieve existing session ID for user or create a new one.
65
+
66
+ Args:
67
+ user_id: The ID of the user to get or create a session for.
68
+
69
+ Returns:
70
+ session_id (str): The existing or newly created session ID.
71
+ """
72
+
46
73
  session_id = self.generate_session_id()
47
74
  while self.db.query(m_session.Session).filter(
48
75
  m_session.Session.session_id == session_id
@@ -57,6 +84,16 @@ class DataflowBaseAuthenticator(Authenticator):
57
84
  return session_id
58
85
 
59
86
  def check_blocked_users(self, username, authenticated):
87
+
88
+ """Check if the authenticated user is blocked based on allowed_users list.
89
+
90
+ Args:
91
+ username (str): The username of the authenticated user.
92
+ authenticated (dict|None): The authentication data returned from authenticate method.
93
+
94
+ Returns:
95
+ username (str|None): The username if not blocked, else None."""
96
+
60
97
  self.log.info(f"Checking blocked users for {username}: authenticated={authenticated}, allowed_users={self.allowed_users}")
61
98
 
62
99
  if not authenticated:
@@ -70,20 +107,46 @@ class DataflowBaseAuthenticator(Authenticator):
70
107
  return super().check_blocked_users(username, authenticated)
71
108
 
72
109
  def extract_username_from_email(self, email):
73
- """Extract username from email by removing domain"""
110
+
111
+ """Extract username from email by removing domain
112
+
113
+ Args:
114
+ email (str): User's email address
115
+
116
+ Returns:
117
+ username (str): Extracted username after removing domain
118
+ """
119
+
74
120
  if '@' in email:
75
121
  return email.split('@')[0]
76
122
  return email
77
123
 
78
124
  def generate_secure_password(self):
79
- """Generate a secure random password hash"""
125
+
126
+ """Generate secure random password hash
127
+
128
+ Returns:
129
+ password_hash (str): Securely hashed password
130
+ """
131
+
80
132
  salt = secrets.token_hex(16)
81
133
  random_uuid = str(uuid.uuid4())
82
134
  hash_obj = hashlib.sha256((random_uuid + salt).encode())
83
135
  return hash_obj.hexdigest()
84
136
 
85
137
  def create_new_user(self, email, first_name=None, last_name=None):
86
- """Create a new user with Applicant role"""
138
+
139
+ """Create a new user with Applicant role
140
+
141
+ Args:
142
+ email (str): User's email address
143
+ first_name (str): User's first name
144
+ last_name (str): User's last name
145
+
146
+ Returns:
147
+ new_user (m_user.User|None): Created user object or None if creation failed
148
+ """
149
+
87
150
  try:
88
151
  username = self.extract_username_from_email(email)
89
152
  username = re.sub(r'[^a-z0-9]', '', username.lower())
@@ -130,6 +193,17 @@ class DataflowBaseAuthenticator(Authenticator):
130
193
  return None
131
194
 
132
195
  async def authenticate_dataflow(self, handler, data):
196
+
197
+ """Authenticate user using Dataflow username/password.
198
+
199
+ Args:
200
+ handler: The request handler.
201
+ data: The authentication data containing username and password.
202
+
203
+ Returns:
204
+ dict|None: Authentication result with username and session_id if successful, else None.
205
+ """
206
+
133
207
  if not (self.enable_dataflow_auth and isinstance(data, dict) and data.get("username") and data.get("password")):
134
208
  return None
135
209
  user_name_or_email = data["username"]
@@ -162,6 +236,18 @@ class DataflowBaseAuthenticator(Authenticator):
162
236
  self.db.close()
163
237
 
164
238
  class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticator):
239
+
240
+ """Authenticator to handle Google OAuth authentication with Dataflow integration.
241
+
242
+ Overrides
243
+ - DataflowBaseAuthenticator
244
+ - GoogleOAuthenticator
245
+
246
+ Requires Google OAuth credentials.
247
+ - google_client_id
248
+ - google_client_secret
249
+ """
250
+
165
251
  dataflow_oauth_type = Unicode(
166
252
  default_value="google",
167
253
  config=True,
@@ -180,6 +266,17 @@ class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticato
180
266
  f"enable_dataflow_auth={self.enable_dataflow_auth}")
181
267
 
182
268
  async def authenticate(self, handler, data):
269
+
270
+ """Authenticate user using Google OAuth with Dataflow integration.
271
+
272
+ Args:
273
+ handler: The request handler.
274
+ data: The authentication data.
275
+
276
+ Returns:
277
+ dict|None: Authentication result with username and session_id if successful, else None.
278
+ """
279
+
183
280
  self.log.info(f"Authenticate called with data: {data}, request_uri: {handler.request.uri}")
184
281
  result = await self.authenticate_dataflow(handler, data)
185
282
  if result:
@@ -228,6 +325,19 @@ class DataflowGoogleAuthenticator(DataflowBaseAuthenticator, GoogleOAuthenticato
228
325
  self.db.close()
229
326
 
230
327
  class DataflowAzureAuthenticator(DataflowBaseAuthenticator, AzureAdOAuthenticator):
328
+
329
+ """Authenticator to handle Azure AD OAuth authentication with Dataflow integration.
330
+
331
+ Overrides
332
+ - DataflowBaseAuthenticator
333
+ - AzureAdOAuthenticator
334
+
335
+ Requires Azure AD OAuth credentials.
336
+ - azure_client_id
337
+ - azure_client_secret
338
+ - azure_tenant_id
339
+ """
340
+
231
341
  azure_client_id = Unicode(config=True, help="Azure AD OAuth client ID")
232
342
  azure_client_secret = Unicode(config=True, help="Azure AD OAuth client secret")
233
343
  azure_tenant_id = Unicode(config=True, help="Azure AD tenant ID")
@@ -249,6 +359,17 @@ class DataflowAzureAuthenticator(DataflowBaseAuthenticator, AzureAdOAuthenticato
249
359
  f"enable_dataflow_auth={self.enable_dataflow_auth}")
250
360
 
251
361
  async def authenticate(self, handler, data):
362
+
363
+ """Authenticate user using Azure AD OAuth with Dataflow integration.
364
+
365
+ Args:
366
+ handler: The request handler.
367
+ data: The authentication data.
368
+
369
+ Returns:
370
+ dict|None: Authentication result with username and session_id if successful, else None.
371
+ """
372
+
252
373
  result = await self.authenticate_dataflow(handler, data)
253
374
  if result:
254
375
  return result
@@ -12,6 +12,7 @@ from superset.security import SupersetSecurityManager
12
12
  from dataflow.dataflow import Dataflow
13
13
 
14
14
  class DataflowAuthDBView(AuthDBView):
15
+
15
16
  def __init__(self):
16
17
  self.dataflow = Dataflow()
17
18
 
@@ -33,14 +34,15 @@ class DataflowAuthDBView(AuthDBView):
33
34
  @expose('/login/', methods=['GET', "POST"])
34
35
  def login(self):
35
36
  """
36
- Handles both GET and POST login requests.
37
+ This method handles authentication for superset in Dataflow.
37
38
 
38
- - GET: Used for browser-based login. Authenticates using session cookie and redirects to home.
39
- - POST: Used for API-based login. Returns JWT access token for programmatic access.
39
+ Methods:
40
+ - GET:
41
+ Used for browser-based login. Authenticates using session cookie and redirects to home.
40
42
 
41
- Returns:
42
- - Redirect to home page (GET)
43
- - JSON response with access token (POST)
43
+ - POST:
44
+ Used for API-based login. Returns JWT access token for programmatic access.
45
+ Returns JSON response with access token
44
46
  """
45
47
  if request.method == "GET":
46
48
  session_id = request.cookies.get('dataflow_session')
@@ -71,6 +73,9 @@ class DataflowAuthDBView(AuthDBView):
71
73
  return jsonify(resp)
72
74
 
73
75
  class DataflowSecurityManager(SupersetSecurityManager):
76
+
77
+ """Custom Security Manager integrating Dataflow authentication with superset."""
78
+
74
79
  authdbview = DataflowAuthDBView
75
80
  def __init__(self, appbuilder):
76
81
  super(DataflowSecurityManager, self).__init__(appbuilder)
@@ -20,6 +20,13 @@ class ConfigurationManager:
20
20
  def get_config_value(self, section, option):
21
21
  """
22
22
  Get configuration value
23
+
24
+ Args:
25
+ section (str): The section in the config file.
26
+ option (str): The option within the section.
27
+
28
+ Returns:
29
+ str | None: The configuration value or None if not found.
23
30
  """
24
31
  try:
25
32
  return self.config.get(section, option)
@@ -5,11 +5,22 @@ from sqlalchemy import create_engine
5
5
  from sqlalchemy.orm import sessionmaker
6
6
 
7
7
  class DatabaseManager:
8
+
9
+ """Manages database connections and sessions."""
10
+
8
11
  def __init__(self, db_url):
9
12
  self.db_url = db_url
10
13
  self.engine = self.get_engine()
11
14
 
12
15
  def get_engine(self):
16
+
17
+ """
18
+ Create a new SQLAlchemy engine instance.
19
+
20
+ Returns:
21
+ Engine: The SQLAlchemy engine instance.
22
+ """
23
+
13
24
  try:
14
25
  engine = create_engine(self.db_url)
15
26
  return engine
@@ -17,6 +28,12 @@ class DatabaseManager:
17
28
  raise e
18
29
 
19
30
  def get_session(self):
31
+ """
32
+ Create a new SQLAlchemy session.
33
+
34
+ Returns:
35
+ Session: The SQLAlchemy session instance.
36
+ """
20
37
  try:
21
38
  engine = self.engine
22
39
  session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
@@ -30,4 +47,10 @@ class DatabaseManager:
30
47
  raise e
31
48
 
32
49
  def get_base(self):
50
+ """
51
+ Get the declarative base class for the ORM models.
52
+
53
+ Returns:
54
+ Base: The declarative base class.
55
+ """
33
56
  return declarative_base()
@@ -23,9 +23,10 @@ Base = declarative_base()
23
23
  Local_Base = declarative_base()
24
24
 
25
25
  def create_tables(local_db=False):
26
- """
27
- Create all tables in the database.
28
- This is called at the start of the application.
26
+ """Create all tables in the database.
27
+
28
+ Args:
29
+ local_db (bool): Flag indicating whether to create tables in the local database.
29
30
  """
30
31
  try:
31
32
  if local_db:
@@ -19,8 +19,7 @@ class EnvironmentManager:
19
19
  self.logger = CustomLogger().get_logger(__name__)
20
20
 
21
21
  async def create_env(self, env_name, py_version, pip_libraries, conda_libraries, status, env_version='1', user_name=None, db:Session=None):
22
- """
23
- Creates a conda environment with specified Python version and packages.
22
+ """Creates a conda environment with specified Python version and packages.
24
23
 
25
24
  Args:
26
25
  env_name (str): Name of the environment
@@ -84,8 +83,7 @@ class EnvironmentManager:
84
83
  raise ValueError("Invalid status. Use 'draft' or 'published'.")
85
84
 
86
85
  async def clone_env(self, source_path, env_name, pip_libraries, conda_libraries, user_name, db=None, local_clone=False):
87
- """
88
- Clones an existing conda environment.
86
+ """Clones an existing conda environment.
89
87
 
90
88
  Args:
91
89
  source_path (str): Path to source environment
@@ -141,8 +139,7 @@ class EnvironmentManager:
141
139
  return clone_status
142
140
 
143
141
  async def revert_env(self, env_name, curr_version, revert_version, new_version, user_name, db: Session):
144
- """
145
- Reverts an environment to a previous version.
142
+ """Reverts an environment to a previous version.
146
143
 
147
144
  Args:
148
145
  env_name (str): Name of the environment
@@ -195,8 +192,7 @@ class EnvironmentManager:
195
192
  log_file_location=None,
196
193
  py_version=None
197
194
  ):
198
- """
199
- Executes environment operations (create or clone).
195
+ """Executes environment operations (create or clone).
200
196
 
201
197
  Args:
202
198
  env_name (str): Name of the environment
@@ -325,8 +321,7 @@ class EnvironmentManager:
325
321
  return "failed"
326
322
 
327
323
  def _setup_logging(self, env_name: str, env_version: str, user_name: str, db: Session):
328
- """
329
- Sets up logging for environment operations.
324
+ """Sets up logging for environment operations.
330
325
 
331
326
  Args:
332
327
  env_name (str): Name of the environment
@@ -352,8 +347,7 @@ class EnvironmentManager:
352
347
  return log_file_location
353
348
 
354
349
  async def _update_job_status(self, log_file_name: str, build_status: str, log_file_location: str, db: Session):
355
- """
356
- Updates job status with retry logic.
350
+ """Updates job status with retry logic.
357
351
 
358
352
  Args:
359
353
  db (Session): Database session
@@ -386,8 +380,7 @@ class EnvironmentManager:
386
380
  self.logger.error(f"Failed to update job log after multiple attempts: {e}")
387
381
 
388
382
  def create_job_entry(self, user_name: str, db: Session, log_file_name: str, log_file_location: str):
389
- """
390
- Creates or updates a job entry for environment tracking.
383
+ """Creates or updates a job entry for environment tracking.
391
384
 
392
385
  Args:
393
386
  user_name (str): The user who initiated the job
@@ -428,8 +421,7 @@ class EnvironmentManager:
428
421
  return job
429
422
 
430
423
  def update_job_log(self, db, log_file_name, final_build_status):
431
- """
432
- Updates the JobLogs table with completion time and status.
424
+ """Updates the JobLogs table with completion time and status.
433
425
 
434
426
  Args:
435
427
  db (Session): Database session
@@ -460,8 +452,15 @@ class EnvironmentManager:
460
452
  return datetime.datetime.now().strftime("%b %d %I:%M:%S %p")
461
453
 
462
454
  def update_environment_db(self, env_short_name, version, pip_libraries, conda_libraries, status, db: Session):
463
- """
464
- Updates the environment table with the new version and libraries.
455
+ """Updates the environment table with the new version and libraries.
456
+
457
+ Args:
458
+ env_short_name (str): Short name of the environment
459
+ version (str): Version of the environment
460
+ pip_libraries (list): List of pip libraries
461
+ conda_libraries (list): List of conda libraries
462
+ status (str): Build status ('success' or 'failed')
463
+ db (Session): Database session
465
464
  """
466
465
  try:
467
466
  if isinstance(pip_libraries, list):
@@ -561,6 +560,9 @@ class EnvironmentManager:
561
560
  conda_channels (list): List of conda channels
562
561
  conda_packages (list): List of conda packages to install
563
562
  pip_packages (list): List of pip packages to install
563
+
564
+ Returns:
565
+ str: Path to the created YAML file
564
566
  """
565
567
  try:
566
568
  # Create the environment specification
@@ -0,0 +1,31 @@
1
+ from sqlalchemy import Column, Integer, String, Boolean
2
+ from sqlalchemy.orm import relationship
3
+ from dataflow.db import Base
4
+
5
+ class AppType(Base):
6
+
7
+ """TABLE 'APP_TYPE'.
8
+
9
+ Attributes:
10
+ id (int): Primary key for the app type.
11
+ name (str): Unique name identifier for the app type.
12
+ display_name (str): Human-readable name for the app type.
13
+ code_based (bool): Indicates if the app type is code-based.
14
+ studio (bool): Indicates if the app type is associated with Dataflow Studio.
15
+ runtime (bool): Indicates if the app type is a runtime application.
16
+ organizations (list): Relationship to organizations using this app type.
17
+
18
+ Relationships:
19
+ organizations: Many-to-many relationship with Organization model via ORGANIZATION_APP_TYPE association table.
20
+ """
21
+
22
+ __tablename__ = "APP_TYPE"
23
+
24
+ id = Column(Integer, primary_key=True, autoincrement=True, unique=True)
25
+ name = Column(String, unique=True, nullable=False)
26
+ display_name = Column(String, nullable=False)
27
+ code_based = Column(Boolean, nullable=False)
28
+ studio = Column(Boolean, nullable=False, default=False, server_default='false')
29
+ runtime = Column(Boolean, nullable=False, default=False, server_default='false')
30
+
31
+ organizations = relationship("Organization", secondary="ORGANIZATION_APP_TYPE", back_populates="apps")
@@ -3,15 +3,15 @@ from sqlalchemy import Column, Integer, String, UniqueConstraint
3
3
  from dataflow.db import Base
4
4
 
5
5
  class BlacklistedLibrary(Base):
6
- """
7
- BlacklistedLibrary model represents a table for storing blacklisted libraries with their versions.
6
+ """TABLE 'BLACKLISTED_LIBRARY'
8
7
 
9
8
  Attributes:
10
9
  id (int): Primary key of the table, auto-incremented.
11
10
  library_name (str): The name of the blacklisted library.
12
11
  version (str): The version of the blacklisted library.
13
12
 
14
- Unique constraint to ensure the combination of library_name and version is unique.
13
+ Constraints:
14
+ Unique constraint to ensure unique combination of library_name and version.
15
15
  """
16
16
 
17
17
  __tablename__ = "BLACKLISTED_LIBRARY"
@@ -3,9 +3,26 @@ from sqlalchemy.sql import func
3
3
  from dataflow.db import Base
4
4
 
5
5
  class Connection(Base):
6
+ """TABLE 'CONNECTION'
7
+
8
+ Attributes:
9
+ id (int): Primary key for the connection.
10
+ conn_id (str): Identifier for the connection.
11
+ org_id (int): Foreign key referencing the organization.
12
+ description (str): Description of the connection.
13
+ conn_type (str): Type of the connection.
14
+ runtime (str): Runtime environment for the connection.
15
+ slug (str): Slug identifier for the connection.
16
+ status (bool): Status of the connection (active/inactive).
17
+ created_by (str): User who created the connection.
18
+ created_at (datetime): Timestamp of when the connection was created.
19
+ updated_at (datetime): Timestamp of the last update to the connection.
20
+ is_active (bool): Indicates if the connection is active.
21
+
22
+ Constraints:
23
+ UniqueConstraint: Ensures unique active connections based on conn_id, org_id, runtime, slug, is_active, and created_by.
6
24
  """
7
- Database model for storing non-sensitive connection metadata
8
- """
25
+
9
26
  __tablename__ = "CONNECTION"
10
27
 
11
28
  id = Column(Integer, primary_key=True, index=True)
@@ -3,6 +3,21 @@ from sqlalchemy.orm import relationship
3
3
  from dataflow.db import Base
4
4
 
5
5
  class DataflowZone(Base):
6
+
7
+ """TABLE 'DATAFLOW_ZONE'.
8
+
9
+ Attributes:
10
+ id (int): Primary key for the dataflow zone.
11
+ slug (str): Unique slug identifier for the zone.
12
+ display_name (str): Human-readable name for the zone.
13
+ is_runtime (bool): Indicates if the zone is a runtime zone.
14
+ subdomain (str): Subdomain associated with the zone.
15
+ display_order (int): Order for displaying the zone in lists.
16
+
17
+ Relationships:
18
+ role_zone_assocs: One-to-many relationship with RoleZone model.
19
+ """
20
+
6
21
  __tablename__ = "DATAFLOW_ZONE"
7
22
 
8
23
  id = Column(Integer, primary_key=True, autoincrement=True)