Skip to content
Snippets Groups Projects
Commit db664100 authored by Nathan Hertz's avatar Nathan Hertz
Browse files

Merge pull request #21 in SSA/data from SSA-6315-skeletal-build-system to main

* commit '4a6d284c':
  Updated type hinting to only hint function parameters and return values by @dlyons request
  Added type hinting and PEP8-ified
parents 7bd1910a 4a6d284c
No related branches found
No related tags found
No related merge requests found
import subprocess
import logging
import subprocess
from typing import List, Dict, Any, Callable, Optional
from zc.buildout.buildout import Buildout, Options
logger = logging.getLogger("buildout/build_pkgs")
def get_dirs():
def get_dirs() -> List[str]:
"""
Finds all subdirectories containing setup.py files.
:return: List of directories as strings.
......@@ -21,7 +25,8 @@ def get_dirs():
logger.debug("Done getting directories.")
return dirs
def get_names(dirs):
def get_names(dirs: List[str]) -> List[str]:
"""
Generate list of subproject names based on the rule that the name of the
subproject directory will be the name of the subproject.
......@@ -41,8 +46,9 @@ def get_names(dirs):
logger.debug("Done generating.")
return names
class Recipe:
def __init__(self, buildout, name, options):
def __init__(self, buildout: Optional[Buildout], name: str, options: Options):
"""
Initializes fields needed for recipe.
:param buildout: (Boilerplate) Dictionary of options from buildout section
......@@ -54,7 +60,7 @@ class Recipe:
self.options = options
self.pkg_list = get_names(get_dirs())
def install(self):
def install(self) -> Any:
"""
Install method that runs when recipe has components it needs to install.
:return: Paths to files, as strings, created by the recipe.
......@@ -79,4 +85,4 @@ class Recipe:
return self.options.created()
update = install
\ No newline at end of file
update = install
......@@ -3,6 +3,6 @@ from setuptools import setup
setup(
name='build_pkgs',
version='0.1',
py_modules = ['build_pkgs'],
entry_points = {"zc.buildout": ["default=build_pkgs:Recipe"]},
)
\ No newline at end of file
py_modules=['build_pkgs'],
entry_points={"zc.buildout": ["default=build_pkgs:Recipe"]},
)
import pytest
import zc.buildout.testing
from .. import build_pkgs
@pytest.fixture(scope='module')
def recipe():
def recipe() -> build_pkgs.Recipe:
"""
pytest fixture that initializes zc.buildout objects for use in testing.
Initializes Buildout, Options, and Recipe objects.
......@@ -13,4 +15,4 @@ def recipe():
buildout = zc.buildout.testing.Buildout()
options = buildout.Options(buildout, 'build_pkgs', {'recipe': 'build_pkgs', 'name': 'null'})
recipe = build_pkgs.Recipe(buildout=buildout, name=None, options=options)
return recipe
\ No newline at end of file
return recipe
import os
from typing import List
from .. import build_pkgs
class TestBuildPkgs:
def test_get_names(self):
"""
......@@ -17,14 +20,13 @@ class TestBuildPkgs:
"""
assert './apps/cli/executables/null' in build_pkgs.get_dirs()
def test_output(self, recipe):
def test_output(self, recipe: build_pkgs.Recipe):
"""
Test that the package specified in the recipe has been built correctly.
"""
created = recipe.install()
for path in created:
print(path)
if len(path) > 0:
assert path is not None, "conda build failed to build package"
assert os.path.exists(path)
......@@ -3,6 +3,6 @@ from setuptools import setup
setup(
name='setup_to_meta',
version='0.1',
py_modules = ['setup_to_meta'],
entry_points = {"zc.buildout": ["default=setup_to_meta:Recipe"]},
)
\ No newline at end of file
py_modules=['setup_to_meta'],
entry_points={"zc.buildout": ["default=setup_to_meta:Recipe"]},
)
import subprocess
import logging
import json
import os
import json
import logging
import subprocess
from typing import List, Any, Dict, Callable, Optional
from zc.buildout.buildout import Buildout, Options
PYTHON_VERSION = '3.8'
logger = logging.getLogger("buildout/setup_to_meta")
def write_metafile(metadata, filepath):
def write_metafile(metadata: str, filepath: str):
"""
Writes given metadata to file with given path.
:param metadata: String containing conda recipe metadata to be written
:param filepath: String containing the path to conda recipe file (meta.yaml)
"""
logger.debug(f"Writing meta.yaml file at {filepath}...")
try:
......@@ -26,12 +31,11 @@ class MetadataGenerator:
"""
Uses given info extracted from setup.py file to fill out metadata template.
"""
def __init__(self, setup, path):
def __init__(self, setup: Dict[str, str], path: str):
self.setup = setup
self.path = path
def fmt_ep(self):
def fmt_ep(self) -> str:
"""
Format entry points section of metadata.
:return: Formatted string if entry points exists; else empty string.
......@@ -44,7 +48,7 @@ class MetadataGenerator:
ep_string += ' '
return ep_string
def fmt_reqs(self):
def fmt_reqs(self) -> str:
"""
Format requirements section of metadata.
:return: Formatted string if requirements exists; else empty string.
......@@ -67,7 +71,7 @@ class MetadataGenerator:
'\n'
return reqs_string
def fmt_test(self):
def fmt_test(self) -> str:
"""
Format test section of metadata.
NOTE: May need further tweaking to be smarter based on individual project
......@@ -93,7 +97,7 @@ class MetadataGenerator:
)
return test_string
def generate(self):
def generate(self) -> str:
logger.debug(f"Generating meta.yaml file from {self.path}...")
# Filter numpy etc. out of the requirements
try:
......@@ -126,7 +130,7 @@ class MetadataGenerator:
)
def parse_setup(d):
def parse_setup(d: str) -> Dict[str, str]:
"""
Function for running parse_setup.py on each directory with a setup.py file.
NOTE: Contains a hack for getting parse_setup.py to run in each directory.
......@@ -143,7 +147,8 @@ def parse_setup(d):
logger.debug("Done parsing.")
return json.loads(proc.stdout)
def get_outputs(names):
def get_outputs(names: List[str]) -> List[str]:
"""
Generate list of metadata files that will be created.
:param dirs: List of dirs of all subprojects with a setup.py file.
......@@ -155,7 +160,7 @@ def get_outputs(names):
return outputs
def get_dirs():
def get_dirs() -> List[str]:
"""
Finds all subdirectories containing setup.py files.
:return: List of directories as strings.
......@@ -173,7 +178,8 @@ def get_dirs():
logger.debug("Done finding directories.")
return dirs
def get_names(dirs):
def get_names(dirs: List[str]) -> List[str]:
"""
Generate list of subproject names based on the rule that the name of the
subproject directory will be the name of the subproject.
......@@ -193,7 +199,8 @@ def get_names(dirs):
logger.debug("Done getting list of names.")
return names
def del_substrings(s, substrings):
def del_substrings(s: str, substrings: List[str]):
"""
Function for deleting multiple substrings from a string.
:param s: String to be modified.
......@@ -205,15 +212,17 @@ def del_substrings(s, substrings):
return s
root = os.getcwd()
class Recipe:
"""
Buildout Recipe class.
For more detailed information, see the link.
http://www.buildout.org/en/latest/topics/writing-recipes.html
"""
def __init__(self, buildout, name, options):
def __init__(self, buildout: Optional[Buildout], name: Optional[str], options: Options):
"""
Initializes fields needed for recipe.
:param buildout: (Boilerplate) Dictionary of options from buildout section
......@@ -226,7 +235,7 @@ class Recipe:
self.outputs = get_outputs(self.names)
self.options = options
def install(self):
def install(self) -> Any:
"""
Install method that runs when recipe has components it needs to install.
:return: Paths to files, as strings, created by the recipe.
......@@ -236,10 +245,10 @@ class Recipe:
setup_data = parse_setup(d)
metadata = MetadataGenerator(setup_data, d).generate()
write_metafile(metadata, self.outputs[i])
# Pass created file into options.created()
# Buildout-specific operation: pass created file into options.created()
self.options.created(self.outputs[i])
return self.options.created()
# No special procedure for updating vs. installing
update = install
\ No newline at end of file
update = install
import pytest
import zc.buildout.testing
from .. import setup_to_meta
@pytest.fixture(scope='module')
def recipe():
def recipe() -> setup_to_meta.Recipe:
"""
pytest fixture that initializes zc.buildout objects for use in testing.
Initializes Buildout, Options, and Recipe objects.
......@@ -11,6 +14,14 @@ def recipe():
"""
from .. import setup_to_meta
buildout = zc.buildout.testing.Buildout()
options = buildout.Options(buildout, 'gen_metadata', {'recipe': 'setup_to_meta'})
recipe = setup_to_meta.Recipe(buildout=buildout, name=None, options=options)
return recipe
\ No newline at end of file
options = buildout.Options(
buildout,
'gen_metadata',
{'recipe': 'setup_to_meta'}
)
recipe = setup_to_meta.Recipe(
buildout=buildout,
name=None,
options=options
)
return recipe
from typing import Dict, List
from .. import setup_to_meta
class TestSetupToMeta:
def test_del_substrings(self):
"""
......@@ -38,7 +41,7 @@ class TestSetupToMeta:
for key in keys:
assert key in setup_data
def test_output(self, recipe):
def test_output(self, recipe: setup_to_meta.Recipe):
"""
Test that metadata was successfully created and contains data.
......
from .. import test_recipes
class TestRecipes:
def test_get_recipes(self):
"""
......
import subprocess
import logging
from typing import Dict, Optional
from zc.buildout.buildout import Buildout, Options
logger = logging.getLogger("buildout/test_recipes")
def get_recipes():
def get_recipes() -> Dict[str, str]:
"""
Get all currently installed buildout recipes (including this one!)
:return: Dictionary with format {recipe_name: recipe_path_from_root,}
......@@ -26,6 +30,7 @@ def get_recipes():
return recipes
class Recipe:
"""
Buildout Recipe class.
......@@ -33,7 +38,7 @@ class Recipe:
http://www.buildout.org/en/latest/topics/writing-recipes.html
"""
def run_test(self, recipe):
def run_test(self, recipe: str):
"""
Run test for given recipe.
:param recipe: Name of recipe to be run.
......@@ -42,7 +47,7 @@ class Recipe:
subprocess.run(['pytest', '-vv', '--log-level=DEBUG', '--showlocals',
self.recipes[recipe]])
def __init__(self, buildout, name, options):
def __init__(self, buildout: Optional[Buildout], name: str, options: Options):
"""
Initializes fields needed for recipe.
:param buildout: (Boilerplate) Dictionary of options from buildout section
......@@ -68,4 +73,4 @@ class Recipe:
self.run_test(recipe)
else:
if self.choice in self.recipes:
self.run_test(self.choice)
\ No newline at end of file
self.run_test(self.choice)
......@@ -3,6 +3,8 @@ import setuptools
import json
data = {}
def my_setup(*args, **kwargs):
"""
A replacement for setuptools.setup().
......@@ -20,6 +22,7 @@ def my_setup(*args, **kwargs):
for field in fields:
data[field] = kwargs.get(field)
def main():
# Author of these shenanigans: Daniel Lyons (but you already knew that)
......@@ -36,5 +39,6 @@ def main():
# Instead of exiting, we now have populated our global variable, without doing any parsing
json.dump(data, sys.stdout)
if __name__ == "__main__":
main()
\ No newline at end of file
main()
import subprocess
import paramiko
import logging
import os
import sys
import fnmatch
import getpass
import sys
import os
import logging
from typing import List
import paramiko
import subprocess
from scp import SCPClient
......@@ -12,7 +14,8 @@ logger = logging.getLogger("buildtools/transfer_to_builder")
logger.setLevel(logging.INFO)
hander = logging.StreamHandler(stream=sys.stdout)
def get_build_pkg_names():
def get_build_pkg_names() -> List[str]:
"""
Search through pkgs directory for built .tar.bz2 packages
:return: List of package archive file names
......@@ -28,7 +31,8 @@ def get_build_pkg_names():
return pkg_names
def create_ssh_client(server):
def create_ssh_client(server: str) -> paramiko.SSHClient:
"""
Use paramiko to load SSH keys if they exist and set up an SSH connection to a server.
:param server: The server to connect to
......@@ -52,7 +56,8 @@ def create_ssh_client(server):
return client
def transfer_packages(pkg_names):
def transfer_packages(pkg_names: List[str]):
"""
Use shell commands to transfer build archives to builder and update its conda package index.
:param pkg_names: Names of the .tar.bz2 files for the built packages.
......@@ -74,7 +79,8 @@ def transfer_packages(pkg_names):
cmd_chmod])
else:
logger.error("No packages found in build/pkgs/noarch. "
"Did conda build successfully build the package(s)?")
"Did conda build successfully build the package(s)?")
if __name__ == "__main__":
transfer_packages(get_build_pkg_names())
\ No newline at end of file
transfer_packages(get_build_pkg_names())
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment