wexample-filestate-python 0.0.8__tar.gz → 0.0.11__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.
Files changed (22) hide show
  1. wexample_filestate_python-0.0.11/PKG-INFO +19 -0
  2. wexample_filestate_python-0.0.11/pyproject.toml +39 -0
  3. wexample_filestate_python-0.0.11/wexample_filestate_python/helpers/package.py +127 -0
  4. wexample_filestate_python-0.0.11/wexample_filestate_python/workdir/__init__.py +0 -0
  5. wexample_filestate_python-0.0.11/wexample_filestate_python/workdir/python_package_workdir.py +90 -0
  6. wexample_filestate_python-0.0.11/wexample_filestate_python/workdir/python_packages_suite_workdir.py +5 -0
  7. wexample_filestate_python-0.0.11/wexample_filestate_python/workdir/python_workdir.py +78 -0
  8. wexample_filestate_python-0.0.11/wexample_filestate_python.egg-info/PKG-INFO +19 -0
  9. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python.egg-info/SOURCES.txt +5 -1
  10. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python.egg-info/requires.txt +5 -2
  11. wexample-filestate-python-0.0.8/PKG-INFO +0 -12
  12. wexample-filestate-python-0.0.8/setup.py +0 -25
  13. wexample-filestate-python-0.0.8/wexample_filestate_python/workdir/python_workdir.py +0 -87
  14. wexample-filestate-python-0.0.8/wexample_filestate_python.egg-info/PKG-INFO +0 -12
  15. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/README.md +0 -0
  16. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/setup.cfg +0 -0
  17. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python/__init__.py +0 -0
  18. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python/const/__init__.py +0 -0
  19. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python/const/name_pattern.py +0 -0
  20. {wexample-filestate-python-0.0.8/wexample_filestate_python/workdir → wexample_filestate_python-0.0.11/wexample_filestate_python/helpers}/__init__.py +0 -0
  21. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python.egg-info/dependency_links.txt +0 -0
  22. {wexample-filestate-python-0.0.8 → wexample_filestate_python-0.0.11}/wexample_filestate_python.egg-info/top_level.txt +0 -0
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.2
2
+ Name: wexample-filestate-python
3
+ Version: 0.0.11
4
+ Summary: Helpers for Python.
5
+ Author-email: weeger <contact@wexample.com>
6
+ License: MIT
7
+ Project-URL: homepage, https://github.com/wexample/python-filestate-python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: pip-tools
14
+ Requires-Dist: python-dotenv
15
+ Requires-Dist: pydantic
16
+ Requires-Dist: pytest
17
+ Requires-Dist: wexample-filestate
18
+ Requires-Dist: wexample-filestate-git
19
+ Requires-Dist: wexample-app
@@ -0,0 +1,39 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools",
4
+ "wheel",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
7
+
8
+ [project]
9
+ name = "wexample-filestate-python"
10
+ version = "0.0.11"
11
+ description = "Helpers for Python."
12
+ authors = [
13
+ { name = "weeger", email = "contact@wexample.com" },
14
+ ]
15
+ requires-python = ">=3.6"
16
+ classifiers = [
17
+ "Programming Language :: Python :: 3",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: OS Independent",
20
+ ]
21
+ dependencies = [
22
+ "pip-tools",
23
+ "python-dotenv",
24
+ "pydantic",
25
+ "pytest",
26
+ "wexample-filestate",
27
+ "wexample-filestate-git",
28
+ "wexample-app",
29
+ ]
30
+
31
+ [project.readme]
32
+ file = "README.md"
33
+ content-type = "text/markdown"
34
+
35
+ [project.license]
36
+ text = "MIT"
37
+
38
+ [project.urls]
39
+ homepage = "https://github.com/wexample/python-filestate-python"
@@ -0,0 +1,127 @@
1
+ import ast
2
+ from pathlib import Path
3
+ from typing import Dict, List, Set, Optional, Tuple
4
+
5
+ import tomli
6
+
7
+
8
+ def package_parse_setup(path: Path) -> Dict:
9
+ """
10
+ Parse a setup.py file to extract metadata.
11
+ """
12
+ with open(path) as f:
13
+ content = f.read()
14
+
15
+ tree = ast.parse(content)
16
+ for node in ast.walk(tree):
17
+ if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == 'setup':
18
+ result = {}
19
+ for kw in node.keywords:
20
+ if isinstance(kw.value, ast.Str):
21
+ result[kw.arg] = kw.value.s
22
+ elif isinstance(kw.value, ast.List):
23
+ result[kw.arg] = [
24
+ elt.s for elt in kw.value.elts
25
+ if isinstance(elt, ast.Str)
26
+ ]
27
+ return result
28
+ return {}
29
+
30
+
31
+ def package_parse_toml(path: Path) -> Dict:
32
+ """
33
+ Parse a pyproject.toml file to extract metadata.
34
+ """
35
+ try:
36
+ with open(path, "rb") as f:
37
+ data = tomli.load(f)
38
+ if "project" in data:
39
+ project_data = data["project"]
40
+ return {
41
+ "name": project_data.get("name"),
42
+ "install_requires": project_data.get("dependencies", [])
43
+ }
44
+ except Exception as e:
45
+ print(f"Error parsing {path}: {e}")
46
+ return {}
47
+
48
+
49
+ def package_get_info(package_dir: Path) -> Optional[Tuple[str, Set[str]]]:
50
+ """
51
+ Get package name and its dependencies from setup.py or pyproject.toml.
52
+ """
53
+ # Try pyproject.toml first
54
+ toml_path = package_dir / "pyproject.toml"
55
+ if toml_path.exists():
56
+ metadata = package_parse_toml(toml_path)
57
+ else:
58
+ # Fallback to setup.py
59
+ setup_py_path = package_dir / "setup.py"
60
+ if setup_py_path.exists():
61
+ metadata = package_parse_setup(setup_py_path)
62
+ else:
63
+ return None
64
+
65
+ name = metadata.get("name")
66
+ if not name:
67
+ return None
68
+
69
+ deps = metadata.get("install_requires", [])
70
+ return name, set(deps)
71
+
72
+
73
+ def package_get_dependencies(root_dir: str | Path) -> Dict[str, Set[str]]:
74
+ """
75
+ Get dependencies between packages in a directory.
76
+ """
77
+ packages_root = Path(root_dir)
78
+ if not packages_root.exists() or not packages_root.is_dir():
79
+ raise ValueError(f"Error: {packages_root} does not exist or is not a directory")
80
+
81
+ dependencies = {}
82
+
83
+ # First pass: collect all local packages
84
+ for package_dir in packages_root.iterdir():
85
+ if not package_dir.is_dir():
86
+ continue
87
+
88
+ package_info = package_get_info(package_dir)
89
+ if package_info:
90
+ name, _ = package_info
91
+ dependencies[name] = set()
92
+
93
+ # Second pass: analyze dependencies
94
+ for package_dir in packages_root.iterdir():
95
+ if not package_dir.is_dir():
96
+ continue
97
+
98
+ package_info = package_get_info(package_dir)
99
+ if package_info:
100
+ name, deps = package_info
101
+ if name in dependencies:
102
+ # Only keep dependencies that are local packages
103
+ dependencies[name] = {
104
+ dep for dep in deps
105
+ if dep in dependencies
106
+ }
107
+
108
+ return dependencies
109
+
110
+
111
+ def package_list_sorted(root_dir: str | Path) -> List[str]:
112
+ """
113
+ Get a list of package names sorted by dependency order.
114
+ """
115
+ from wexample_filestate_dev.helpers.dependencies import dependencies_sort
116
+
117
+ dependencies = package_get_dependencies(root_dir)
118
+ if not dependencies:
119
+ return []
120
+
121
+ # Convert dependencies dict to list for sorting
122
+ packages = list(dependencies.keys())
123
+
124
+ def get_deps(pkg: str) -> Set[str]:
125
+ return dependencies[pkg]
126
+
127
+ return dependencies_sort(packages, get_deps)
@@ -0,0 +1,90 @@
1
+ from typing import Optional
2
+
3
+ from wexample_config.const.types import DictConfig
4
+ from wexample_filestate_python.workdir.python_workdir import PythonWorkdir
5
+ from wexample_helpers.helpers.array import array_dict_get_by
6
+
7
+
8
+ class PythonPackageWorkdir(PythonWorkdir):
9
+ def prepare_value(self, config: Optional[DictConfig] = None) -> DictConfig:
10
+ from wexample_filestate.const.disk import DiskItemType
11
+ from wexample_filestate_python.const.name_pattern import NAME_PATTERN_PYTHON_NOT_PYCACHE
12
+ from wexample_filestate.config_option.children_file_factory_config_option import ChildrenFileFactoryConfigOption
13
+ from wexample_filestate.const.globals import NAME_PATTERN_NO_LEADING_DOT
14
+ from wexample_config.config_value.callback_render_config_value import CallbackRenderConfigValue
15
+
16
+ config = super().prepare_value(config)
17
+
18
+ # Retrieve the '.gitignore' configuration or create it if it doesn't exist
19
+ config_gitignore = array_dict_get_by('name', '.gitignore', config["children"])
20
+ if config_gitignore is not None:
21
+ generic_gitignore_rules = {
22
+ "Python artifacts": [
23
+ "*.egg-info",
24
+ "__pycache__/",
25
+ "*.py[cod]",
26
+ "*.pyo",
27
+ ],
28
+ "Build directories": [
29
+ "/build/",
30
+ "/dist/",
31
+ "/pip-wheel-metadata/",
32
+ ],
33
+ "Virtual environments": [
34
+ ".env",
35
+ ".venv",
36
+ "venv/",
37
+ ],
38
+ "Test and coverage artifacts": [
39
+ ".tox/",
40
+ ".mypy_cache/",
41
+ "pytest_cache/",
42
+ ".coverage",
43
+ "htmlcov/",
44
+ ],
45
+ "Editor and IDE settings": [
46
+ ".vscode/",
47
+ ".idea/",
48
+ "*.swp",
49
+ "*~",
50
+ ],
51
+ }
52
+
53
+ should_contain_lines = config_gitignore.setdefault("should_contain_lines", [])
54
+ if not isinstance(should_contain_lines, list):
55
+ raise ValueError("'should_contain_lines' must be a list")
56
+
57
+ for category, rules in generic_gitignore_rules.items():
58
+ category_header = f"# {category}"
59
+ if category_header not in should_contain_lines:
60
+ should_contain_lines.append(category_header)
61
+
62
+ for rule in rules:
63
+ if rule not in should_contain_lines:
64
+ should_contain_lines.append(rule)
65
+
66
+ config["children"].append(
67
+ {
68
+ 'name': 'pyproject.toml',
69
+ 'type': DiskItemType.FILE,
70
+ 'should_exist': True,
71
+ }
72
+ )
73
+
74
+ config["children"].append(
75
+ {
76
+ 'name': CallbackRenderConfigValue(raw=self._create_package_name_snake),
77
+ 'type': DiskItemType.DIRECTORY,
78
+ 'should_exist': True,
79
+ "children": [
80
+ ChildrenFileFactoryConfigOption(pattern={
81
+ "name": "__init__.py",
82
+ "type": DiskItemType.FILE,
83
+ "recursive": True,
84
+ "name_pattern": [NAME_PATTERN_PYTHON_NOT_PYCACHE, NAME_PATTERN_NO_LEADING_DOT],
85
+ })
86
+ ]
87
+ }
88
+ )
89
+
90
+ return config
@@ -0,0 +1,5 @@
1
+ from wexample_filestate_dev.workdir.framework_packages_suite_workdir import FrameworkPackageSuiteWorkdir
2
+
3
+
4
+ class PythonPackagesSuiteWorkdir(FrameworkPackageSuiteWorkdir):
5
+ pass
@@ -0,0 +1,78 @@
1
+ from typing import Optional, List, Type, TYPE_CHECKING
2
+
3
+ from wexample_config.const.types import DictConfig
4
+ from wexample_config.options_provider.abstract_options_provider import AbstractOptionsProvider
5
+ from wexample_filestate_dev.workdir.framework_package_workdir import FrameworkPackageWorkdir
6
+ from wexample_helpers.helpers.string import string_to_snake_case
7
+
8
+ if TYPE_CHECKING:
9
+ from wexample_filestate.operations_provider.abstract_operations_provider import AbstractOperationsProvider
10
+ from wexample_filestate.config_option.mixin.item_config_option_mixin import ItemTreeConfigOptionMixin
11
+
12
+
13
+ class PythonWorkdir(FrameworkPackageWorkdir):
14
+ def get_options_providers(self) -> List[Type["AbstractOptionsProvider"]]:
15
+ from wexample_filestate.options_provider.default_options_provider import DefaultOptionsProvider
16
+ from wexample_filestate_git.options_provider.git_options_provider import GitOptionsProvider
17
+
18
+ return [
19
+ DefaultOptionsProvider,
20
+ GitOptionsProvider
21
+ ]
22
+
23
+ def get_operations_providers(self) -> List[Type["AbstractOperationsProvider"]]:
24
+ from wexample_filestate.operations_provider.default_operations_provider import DefaultOperationsProvider
25
+ from wexample_filestate_git.operations_provider.git_operations_provider import GitOperationsProvider
26
+
27
+ return [
28
+ DefaultOperationsProvider,
29
+ GitOperationsProvider
30
+ ]
31
+
32
+ @staticmethod
33
+ def _create_package_name_snake(option: "ItemTreeConfigOptionMixin") -> str:
34
+ import os
35
+ return "wexample_" + string_to_snake_case(
36
+ os.path.basename(os.path.realpath(option.get_parent_item().get_path())))
37
+
38
+ def prepare_value(self, config: Optional[DictConfig] = None) -> DictConfig:
39
+ from wexample_filestate.const.disk import DiskItemType
40
+
41
+ config = super().prepare_value(config)
42
+
43
+ config['children'] += [
44
+ {
45
+ 'name': '.gitignore',
46
+ 'type': DiskItemType.FILE,
47
+ 'should_exist': True,
48
+ },
49
+ {
50
+ 'name': 'requirements.in',
51
+ 'type': DiskItemType.FILE,
52
+ 'should_exist': True,
53
+ },
54
+ {
55
+ 'name': 'requirements.txt',
56
+ 'type': DiskItemType.FILE,
57
+ 'should_exist': True,
58
+ },
59
+ {
60
+ 'name': 'tests',
61
+ 'type': DiskItemType.DIRECTORY,
62
+ 'should_exist': True,
63
+ },
64
+ # Remove unwanted files
65
+ # Should only be created during deployment
66
+ {
67
+ 'name': 'build',
68
+ 'type': DiskItemType.DIRECTORY,
69
+ 'should_exist': False,
70
+ },
71
+ {
72
+ 'name': 'dist',
73
+ 'type': DiskItemType.DIRECTORY,
74
+ 'should_exist': False,
75
+ }
76
+ ]
77
+
78
+ return config
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.2
2
+ Name: wexample-filestate-python
3
+ Version: 0.0.11
4
+ Summary: Helpers for Python.
5
+ Author-email: weeger <contact@wexample.com>
6
+ License: MIT
7
+ Project-URL: homepage, https://github.com/wexample/python-filestate-python
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: pip-tools
14
+ Requires-Dist: python-dotenv
15
+ Requires-Dist: pydantic
16
+ Requires-Dist: pytest
17
+ Requires-Dist: wexample-filestate
18
+ Requires-Dist: wexample-filestate-git
19
+ Requires-Dist: wexample-app
@@ -1,5 +1,5 @@
1
1
  README.md
2
- setup.py
2
+ pyproject.toml
3
3
  wexample_filestate_python/__init__.py
4
4
  wexample_filestate_python.egg-info/PKG-INFO
5
5
  wexample_filestate_python.egg-info/SOURCES.txt
@@ -8,5 +8,9 @@ wexample_filestate_python.egg-info/requires.txt
8
8
  wexample_filestate_python.egg-info/top_level.txt
9
9
  wexample_filestate_python/const/__init__.py
10
10
  wexample_filestate_python/const/name_pattern.py
11
+ wexample_filestate_python/helpers/__init__.py
12
+ wexample_filestate_python/helpers/package.py
11
13
  wexample_filestate_python/workdir/__init__.py
14
+ wexample_filestate_python/workdir/python_package_workdir.py
15
+ wexample_filestate_python/workdir/python_packages_suite_workdir.py
12
16
  wexample_filestate_python/workdir/python_workdir.py
@@ -1,4 +1,7 @@
1
- pydantic
1
+ pip-tools
2
2
  python-dotenv
3
- wexample-app
3
+ pydantic
4
+ pytest
4
5
  wexample-filestate
6
+ wexample-filestate-git
7
+ wexample-app
@@ -1,12 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: wexample-filestate-python
3
- Version: 0.0.8
4
- Summary: Helpers for Python.
5
- Home-page: https://github.com/wexample/python-filestate-python
6
- Author: weeger
7
- Author-email: contact@wexample.com
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.6
12
- Description-Content-Type: text/markdown
@@ -1,25 +0,0 @@
1
- from setuptools import setup, find_packages
2
-
3
- setup(
4
- name='wexample-filestate-python',
5
- version=open('version.txt').read(),
6
- author='weeger',
7
- author_email='contact@wexample.com',
8
- description='Helpers for Python.',
9
- long_description=open('README.md').read(),
10
- long_description_content_type='text/markdown',
11
- url='https://github.com/wexample/python-filestate-python',
12
- packages=find_packages(),
13
- classifiers=[
14
- 'Programming Language :: Python :: 3',
15
- 'License :: OSI Approved :: MIT License',
16
- 'Operating System :: OS Independent',
17
- ],
18
- install_requires=[
19
- 'python-dotenv',
20
- 'pydantic',
21
- 'wexample-filestate',
22
- 'wexample-app',
23
- ],
24
- python_requires='>=3.6',
25
- )
@@ -1,87 +0,0 @@
1
- from typing import Optional, List, Type, TYPE_CHECKING
2
-
3
- from wexample_filestate.config_option.children_file_factory_config_option import ChildrenFileFactoryConfigOption
4
- from wexample_filestate.const.globals import NAME_PATTERN_NO_LEADING_DOT
5
- from wexample_wex_addon_app.workdir.app_workdir import AppWorkdir
6
- from wexample_config.config_value.callback_render_config_value import CallbackRenderConfigValue
7
- from wexample_config.const.types import DictConfig
8
- from wexample_config.options_provider.abstract_options_provider import AbstractOptionsProvider
9
- from wexample_helpers.helpers.string_helper import string_to_snake_case
10
-
11
- if TYPE_CHECKING:
12
- from wexample_filestate.operations_provider.abstract_operations_provider import AbstractOperationsProvider
13
- from wexample_filestate.config_option.mixin.item_config_option_mixin import ItemTreeConfigOptionMixin
14
-
15
-
16
- class PythonWorkdir(AppWorkdir):
17
- def get_options_providers(self) -> List[Type["AbstractOptionsProvider"]]:
18
- from wexample_filestate.options_provider.default_options_provider import DefaultOptionsProvider
19
- from wexample_filestate_git.options_provider.git_options_provider import GitOptionsProvider
20
-
21
- return [
22
- DefaultOptionsProvider,
23
- GitOptionsProvider
24
- ]
25
-
26
- def get_operations_providers(self) -> List[Type["AbstractOperationsProvider"]]:
27
- from wexample_filestate.operations_provider.default_operations_provider import DefaultOperationsProvider
28
- from wexample_filestate_git.operations_provider.git_operations_provider import GitOperationsProvider
29
-
30
- return [
31
- DefaultOperationsProvider,
32
- GitOperationsProvider
33
- ]
34
-
35
- @staticmethod
36
- def _create_package_name_snake(option: "ItemTreeConfigOptionMixin") -> str:
37
- import os
38
- return "wexample_" + string_to_snake_case(
39
- os.path.basename(os.path.realpath(option.get_parent_item().get_path())))
40
-
41
- def prepare_value(self, config: Optional[DictConfig] = None) -> DictConfig:
42
- from wexample_filestate.const.disk import DiskItemType
43
- from wexample_filestate_python.const.name_pattern import NAME_PATTERN_PYTHON_NOT_PYCACHE
44
-
45
- config = super().prepare_value(config)
46
-
47
- config.update({
48
- "children": [
49
- {
50
- 'name': 'setup.py',
51
- 'type': DiskItemType.FILE,
52
- 'should_exist': True,
53
- },
54
- {
55
- 'name': 'tests',
56
- 'type': DiskItemType.DIRECTORY,
57
- 'should_exist': True,
58
- },
59
- # Remove unwanted files
60
- # Should only be created during deployment
61
- {
62
- 'name': 'build',
63
- 'type': DiskItemType.DIRECTORY,
64
- 'should_exist': False,
65
- },
66
- {
67
- 'name': 'dist',
68
- 'type': DiskItemType.DIRECTORY,
69
- 'should_exist': False,
70
- },
71
- {
72
- 'name': CallbackRenderConfigValue(raw=self._create_package_name_snake),
73
- 'type': DiskItemType.DIRECTORY,
74
- 'should_exist': True,
75
- "children": [
76
- ChildrenFileFactoryConfigOption(pattern={
77
- "name": "__init__.py",
78
- "type": DiskItemType.FILE,
79
- "recursive": True,
80
- "name_pattern": [NAME_PATTERN_PYTHON_NOT_PYCACHE, NAME_PATTERN_NO_LEADING_DOT],
81
- })
82
- ]
83
- }
84
- ]
85
- })
86
-
87
- return config
@@ -1,12 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: wexample-filestate-python
3
- Version: 0.0.8
4
- Summary: Helpers for Python.
5
- Home-page: https://github.com/wexample/python-filestate-python
6
- Author: weeger
7
- Author-email: contact@wexample.com
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: License :: OSI Approved :: MIT License
10
- Classifier: Operating System :: OS Independent
11
- Requires-Python: >=3.6
12
- Description-Content-Type: text/markdown