From 0228fde529258a2b366450d75ae2db78f133ef58 Mon Sep 17 00:00:00 2001 From: Alex Raistrick Date: Thu, 17 Aug 2023 17:44:34 -0400 Subject: [PATCH] Unit tests * Set up pytest * asset tests * material tests * hello_world tests * Iterate github workflows * Update tests * fix gh actions * Remove installation checks for now * Ignore dependencies folder * Test improvements * Fix unit test commit pyproject toml --- .github/dependabot.yml | 11 ++ .github/workflows/checks.yml | 40 +++++++ .gitignore | 3 + .pre-commit-config.yaml | 16 +++ examples/__init__.py | 0 examples/generate_individual_assets.py | 8 +- examples/scripts/hello_world_stepbystep.sh | 2 + infinigen/__init__.py | 4 +- infinigen/assets/creatures/__init__.py | 1 + infinigen/assets/creatures/beetle.py | 3 +- infinigen/assets/creatures/bird.py | 17 +-- infinigen/assets/creatures/carnivore.py | 6 +- infinigen/assets/creatures/fish.py | 4 +- infinigen/assets/creatures/herbivore.py | 8 +- infinigen/assets/creatures/reptile.py | 10 +- infinigen/assets/grassland/__init__.py | 3 +- infinigen/assets/leaves/__init__.py | 7 ++ infinigen/assets/leaves/leaf.py | 2 +- infinigen/assets/monocot/__init__.py | 3 +- infinigen/assets/scatters/__init__.py | 2 + infinigen/assets/underwater/__init__.py | 3 +- infinigen/assets/weather/__init__.py | 14 ++- infinigen/core/placement/detail.py | 2 +- infinigen/core/util/blender.py | 3 +- pyproject.toml | 36 ++++-- setup.py | 13 ++- tests/{ => integration}/conftest.py | 0 .../manual_integration_check.py} | 0 tests/{ => integration}/run_tests.sh | 0 tests/test_nature_materials_basic.py | 25 ++++ tests/test_nature_materials_basic.txt | 58 ++++++++++ tests/test_nature_meshes_basic.py | 22 ++++ tests/test_nature_meshes_basic.txt | 109 ++++++++++++++++++ tests/utils.py | 44 +++++++ tox.ini | 40 +++++++ 35 files changed, 470 insertions(+), 49 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/checks.yml create mode 100644 .pre-commit-config.yaml create mode 100644 examples/__init__.py rename tests/{ => integration}/conftest.py (100%) rename tests/{test_infinigen.py => integration/manual_integration_check.py} (100%) rename tests/{ => integration}/run_tests.sh (100%) create mode 100644 tests/test_nature_materials_basic.py create mode 100644 tests/test_nature_materials_basic.txt create mode 100644 tests/test_nature_meshes_basic.py create mode 100644 tests/test_nature_meshes_basic.txt create mode 100644 tests/utils.py create mode 100644 tox.ini diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..9acbc7f21 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: +- package-ecosystem: pip + directory: "/" + schedule: + interval: weekly + time: "13:00" + groups: + python-packages: + patterns: + - "*" \ No newline at end of file diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml new file mode 100644 index 000000000..778ff0a48 --- /dev/null +++ b/.github/workflows/checks.yml @@ -0,0 +1,40 @@ + +name: Lint & Test + +on: + pull_request: + branches: + - main + - develop + push: + branches: + - main + - develop + +jobs: + + checks: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python 3.10 + uses: actions/setup-python@v4 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + pip install .[dev] + + - name: Lint with ruff + run: | + # stop the build if there are Python syntax errors or undefined names + ruff --format=github --select=E9,F63,F7,F82 . + # default set of ruff rules with GitHub Annotations + #ruff --format=github . # to be enabled in a future PR + - name: Test with pytest + run: | + pytest tests --doctest-modules --junitxml=junit/test-results.xml --cov=com --cov-report=xml --cov-report=html \ No newline at end of file diff --git a/.gitignore b/.gitignore index 42006c990..bc84a6572 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ blender blender.tar.xz Blender.app +.coverage +coverage.xml + */rclone.zip */miniconda.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..1c4ac1ccf --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ + +repos: + +# config from https://black.readthedocs.io/en/stable/integrations/source_version_control.html +#- repo: https://github.com/psf/black +# rev: 23.7.0 +# hooks: +# - id: black +# language_version: python3.10 + +# config from https://github.com/astral-sh/ruff-pre-commit +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.285 + hooks: + - id: ruff + diff --git a/examples/__init__.py b/examples/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/generate_individual_assets.py b/examples/generate_individual_assets.py index 8e1f7040a..d8cd39a7c 100644 --- a/examples/generate_individual_assets.py +++ b/examples/generate_individual_assets.py @@ -36,13 +36,13 @@ from infinigen.core.util.logging import Suppress from infinigen.core.util import blender as butil -from datagen.tools.results import strip_alpha_background as strip_alpha_background +from infinigen.datagen.tools.results import strip_alpha_background as strip_alpha_background import generate_nature # to load most/all factory.AssetFactory subclasses def build_scene_asset(factory_name, idx): factory = None - for subdir in os.listdir('assets'): + for subdir in os.listdir('infinigen/assets'): with gin.unlock_config(): module = importlib.import_module(f'assets.{subdir.split(".")[0]}') if hasattr(module, factory_name): @@ -91,7 +91,7 @@ def build_scene_asset(factory_name, idx): def build_scene_surface(factory_name, idx): try: with gin.unlock_config(): - scatter = importlib.import_module(f'surfaces.scatters.{factory_name}') + scatter = importlib.import_module(f'infinigen.assets.scatters.{factory_name}') if not hasattr(scatter, 'apply'): raise ValueError(f'{scatter} has no apply()') @@ -109,7 +109,7 @@ def build_scene_surface(factory_name, idx): except ModuleNotFoundError: try: with gin.unlock_config(): - template = importlib.import_module(f'assets.materials.{factory_name}') + template = importlib.import_module(f'infinigen.assets.materials.{factory_name}') bpy.ops.mesh.primitive_ico_sphere_add(radius=.8, subdivisions=9) asset = bpy.context.active_object template.apply(asset) diff --git a/examples/scripts/hello_world_stepbystep.sh b/examples/scripts/hello_world_stepbystep.sh index feeac0b76..415f239a1 100644 --- a/examples/scripts/hello_world_stepbystep.sh +++ b/examples/scripts/hello_world_stepbystep.sh @@ -1,3 +1,5 @@ +# DO NOT MODIFY STRUCTURE OR COMMENTS: commands are read by test_hello_world.py + # Generate a scene layout python examples/generate_nature.py -- --seed 0 --task coarse -g desert.gin simple.gin --output_folder outputs/helloworld/coarse diff --git a/infinigen/__init__.py b/infinigen/__init__.py index 6df8ed024..8cac5793a 100644 --- a/infinigen/__init__.py +++ b/infinigen/__init__.py @@ -1 +1,3 @@ -__version__ = '1.1.0' \ No newline at end of file +import pkg_resources +from pathlib import Path +__version__ = pkg_resources.get_distribution(Path(__file__).parent.name).version \ No newline at end of file diff --git a/infinigen/assets/creatures/__init__.py b/infinigen/assets/creatures/__init__.py index edcb80a95..0c02caf13 100644 --- a/infinigen/assets/creatures/__init__.py +++ b/infinigen/assets/creatures/__init__.py @@ -6,3 +6,4 @@ from .crustacean import CrustaceanFactory, CrabFactory, LobsterFactory, SpinyLobsterFactory from .reptile import FrogFactory, LizardFactory, SnakeFactory from .insects.dragonfly import DragonflyFactory +from .jellyfish import JellyfishFactory diff --git a/infinigen/assets/creatures/beetle.py b/infinigen/assets/creatures/beetle.py index 617e3fe81..2180c3499 100644 --- a/infinigen/assets/creatures/beetle.py +++ b/infinigen/assets/creatures/beetle.py @@ -22,6 +22,7 @@ from infinigen.core.placement.factory import AssetFactory, make_asset_collection from infinigen.core.util.math import lerp, clip_gaussian, FixedSeed +from infinigen.core import surface import infinigen.assets.materials.chitin from infinigen.assets.utils.tag import tag_object, tag_nodegroup @@ -103,7 +104,7 @@ def beetle_genome(): parts=body, postprocess_params=dict( surface_registry=[ - (assets.materials.chitin, 1) + (infinigen.assets.materials.chitin, 1) ], hair=insect_hair_params() ) diff --git a/infinigen/assets/creatures/bird.py b/infinigen/assets/creatures/bird.py index 8c29de77d..94d3e7c0d 100644 --- a/infinigen/assets/creatures/bird.py +++ b/infinigen/assets/creatures/bird.py @@ -30,6 +30,7 @@ from infinigen.core.util.math import clip_gaussian, FixedSeed from infinigen.core.util.random import random_general as rg from infinigen.core.util import blender as butil +from infinigen.core import surface from infinigen.core.placement.factory import AssetFactory from infinigen.assets.creatures.util.creature_util import offset_center @@ -150,10 +151,10 @@ def duck_genome(mode): animation=dict(), hair=bird_hair_params(flying=False), surface_registry=[ - (assets.materials.spot_sparse_attr, 4), - (assets.materials.reptile_brown_circle_attr, 0.5), - (assets.materials.reptile_two_color_attr, 0.5), - (assets.materials.bird, 5) + (infinigen.assets.materials.spot_sparse_attr, 4), + (infinigen.assets.materials.reptile_brown_circle_attr, 0.5), + (infinigen.assets.materials.reptile_two_color_attr, 0.5), + (infinigen.assets.materials.bird, 5) ] ) ) @@ -227,10 +228,10 @@ def flying_bird_genome(mode): animation=dict(), hair=bird_hair_params(flying=True), surface_registry=[ - #(assets.materials.spot_sparse_attr, 4), - #(assets.materials.reptile_brown_circle_attr, 0.5), - #(assets.materials.reptile_two_color_attr, 0.5), - (assets.materials.bird, 5) + #(infinigen.assets.materials.spot_sparse_attr, 4), + #(infinigen.assets.materials.reptile_brown_circle_attr, 0.5), + #(infinigen.assets.materials.reptile_two_color_attr, 0.5), + (infinigen.assets.materials.bird, 5) ] ) ) diff --git a/infinigen/assets/creatures/carnivore.py b/infinigen/assets/creatures/carnivore.py index abd185beb..f9cd91018 100644 --- a/infinigen/assets/creatures/carnivore.py +++ b/infinigen/assets/creatures/carnivore.py @@ -169,9 +169,9 @@ def tiger_genome(): hair=tiger_hair_params(), skin=tiger_skin_sim_params(), surface_registry=[ - (assets.materials.tiger_attr, 3), - (assets.materials.giraffe_attr, 0.2), - (assets.materials.spot_sparse_attr, 2) + (infinigen.assets.materials.tiger_attr, 3), + (infinigen.assets.materials.giraffe_attr, 0.2), + (infinigen.assets.materials.spot_sparse_attr, 2) ] ) ) diff --git a/infinigen/assets/creatures/fish.py b/infinigen/assets/creatures/fish.py index 51b35ab20..118f84193 100644 --- a/infinigen/assets/creatures/fish.py +++ b/infinigen/assets/creatures/fish.py @@ -169,8 +169,8 @@ def fish_genome(): cloth=fish_fin_cloth_sim_params(), anim=fish_swim_params(), surface_registry=[ - (assets.materials.fishbody, 3), - #(assets.materials.scale, 1), + (infinigen.assets.materials.fishbody, 3), + #(infinigen.assets.materials.scale, 1), ] ) ) diff --git a/infinigen/assets/creatures/herbivore.py b/infinigen/assets/creatures/herbivore.py index 116ea91c7..84b8d3885 100644 --- a/infinigen/assets/creatures/herbivore.py +++ b/infinigen/assets/creatures/herbivore.py @@ -166,14 +166,14 @@ def herbivore_genome(): if U() < 1: hair = herbivore_hair() registry = [ - (assets.materials.giraffe_attr, 1), - (assets.materials.spot_sparse_attr, 3) + (infinigen.assets.materials.giraffe_attr, 1), + (infinigen.assets.materials.spot_sparse_attr, 3) ] else: hair = None registry = [ - (assets.materials.reptile_brown_circle_attr, 1), - (assets.materials.reptile_gray_attr, 1) + (infinigen.assets.materials.reptile_brown_circle_attr, 1), + (infinigen.assets.materials.reptile_gray_attr, 1) ] return genome.CreatureGenome( diff --git a/infinigen/assets/creatures/reptile.py b/infinigen/assets/creatures/reptile.py index fa54a0aeb..f939c58da 100644 --- a/infinigen/assets/creatures/reptile.py +++ b/infinigen/assets/creatures/reptile.py @@ -115,7 +115,7 @@ def dinosaur(): postprocess_params=dict( animation=dict(), surface_registry=[ - (assets.materials.snake_scale, 1), + (infinigen.assets.materials.snake_scale, 1), ] ) ) @@ -178,7 +178,7 @@ def lizard_genome(): postprocess_params=dict( anim=lizard_run_params(), surface_registry=[ - (assets.materials.snake_scale, 1), + (infinigen.assets.materials.snake_scale, 1), ] ) ) @@ -227,7 +227,7 @@ def snake_genome(): postprocess_params=dict( anim=snake_swim_params(), surface_registry=[ - (assets.materials.snake_scale, 1), + (infinigen.assets.materials.snake_scale, 1), ] ) ) @@ -243,7 +243,7 @@ def chameleon_genome(): postprocess_params=dict( anim=snake_swim_params(), surface_registry=[ - (assets.materials.snake_scale, 1), + (infinigen.assets.materials.snake_scale, 1), ] ) ) @@ -304,7 +304,7 @@ def frog_genome(): speed_m_s=0.5 ), surface_registry=[ - (assets.materials.snake_scale, 1), + (infinigen.assets.materials.snake_scale, 1), ] ) ) diff --git a/infinigen/assets/grassland/__init__.py b/infinigen/assets/grassland/__init__.py index bc20be0da..93a301451 100644 --- a/infinigen/assets/grassland/__init__.py +++ b/infinigen/assets/grassland/__init__.py @@ -6,4 +6,5 @@ from .dandelion import DandelionFactory, DandelionSeedFactory from .flowerplant import FlowerPlantFactory -from .grass_tuft import GrassTuftFactory \ No newline at end of file +from .grass_tuft import GrassTuftFactory +from .flower import FlowerFactory \ No newline at end of file diff --git a/infinigen/assets/leaves/__init__.py b/infinigen/assets/leaves/__init__.py index e69de29bb..a70f5173f 100644 --- a/infinigen/assets/leaves/__init__.py +++ b/infinigen/assets/leaves/__init__.py @@ -0,0 +1,7 @@ +from .leaf import BerryFactory, LeafFactory +from .leaf_broadleaf import LeafFactoryBroadleaf +from .leaf_ginko import LeafFactoryGinko +from .leaf_maple import LeafFactoryMaple +from .leaf_pine import LeafFactoryPine +from .leaf_v2 import LeafFactoryV2 +from .leaf_wrapped import LeafFactoryWrapped \ No newline at end of file diff --git a/infinigen/assets/leaves/leaf.py b/infinigen/assets/leaves/leaf.py index 6335ca57b..84235d2fa 100644 --- a/infinigen/assets/leaves/leaf.py +++ b/infinigen/assets/leaves/leaf.py @@ -87,7 +87,7 @@ def create_asset(self, **params) -> bpy.types.Object: butil.apply_transform(obj) return obj - + class BerryFactory(AssetFactory): def __init__(self, factory_seed, genome, coarse=False): diff --git a/infinigen/assets/monocot/__init__.py b/infinigen/assets/monocot/__init__.py index 14f4a47d4..833443f62 100644 --- a/infinigen/assets/monocot/__init__.py +++ b/infinigen/assets/monocot/__init__.py @@ -1,6 +1,5 @@ from .agave import AgaveMonocotFactory -from .grasses import GrassesMonocotFactory, WheatMonocotFactory, WheatEarMonocotFactory, MaizeMonocotFactory, \ - ReedMonocotFactory +from .grasses import GrassesMonocotFactory, WheatMonocotFactory, WheatEarMonocotFactory, MaizeMonocotFactory from .tussock import TussockMonocotFactory from .pinecone import PineconeFactory from .generate import MonocotFactory diff --git a/infinigen/assets/scatters/__init__.py b/infinigen/assets/scatters/__init__.py index e69de29bb..5d6ed9ce3 100644 --- a/infinigen/assets/scatters/__init__.py +++ b/infinigen/assets/scatters/__init__.py @@ -0,0 +1,2 @@ +from .moss import MossFactory +from .lichen import LichenFactory \ No newline at end of file diff --git a/infinigen/assets/underwater/__init__.py b/infinigen/assets/underwater/__init__.py index 0063ca67d..ba27ddac7 100644 --- a/infinigen/assets/underwater/__init__.py +++ b/infinigen/assets/underwater/__init__.py @@ -1 +1,2 @@ -from . import seaweed, urchin \ No newline at end of file +from .seaweed import SeaweedFactory +from .urchin import UrchinFactory \ No newline at end of file diff --git a/infinigen/assets/weather/__init__.py b/infinigen/assets/weather/__init__.py index 41585af20..0d5bf77f5 100644 --- a/infinigen/assets/weather/__init__.py +++ b/infinigen/assets/weather/__init__.py @@ -1,3 +1,15 @@ from . import particles, cloud -from .cloud import CloudFactory +from .cloud import ( + CloudFactory, + CumulonimbusFactory, + CumulusFactory, + AltocumulusFactory, + StratocumulusFactory +) +from .particles import ( + DustMoteFactory, + RaindropFactory, + SnowflakeFactory +) + from .kole_clouds import add_kole_clouds \ No newline at end of file diff --git a/infinigen/core/placement/detail.py b/infinigen/core/placement/detail.py index d00318f00..a4df66fdc 100644 --- a/infinigen/core/placement/detail.py +++ b/infinigen/core/placement/detail.py @@ -24,7 +24,7 @@ IS_COARSE = False # Global VARIABLE, set by examples/generate_nature.py and used only for whether to emit warnings @gin.configurable -def scatter_res_distance(dist): +def scatter_res_distance(dist=4): return dist @gin.configurable diff --git a/infinigen/core/util/blender.py b/infinigen/core/util/blender.py index 8bfd30594..b3ef65745 100644 --- a/infinigen/core/util/blender.py +++ b/infinigen/core/util/blender.py @@ -777,7 +777,8 @@ def approve_all_drivers(): def count_objects(): count = 0 for obj in bpy.context.scene.objects: - if element.type != "MESH": continue + if obj.type != "MESH": + continue count +=1 return count diff --git a/pyproject.toml b/pyproject.toml index 084bf267d..0aad919be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,10 +4,20 @@ build-backend = "setuptools.build_meta" [project] name = "infinigen" +version = "1.1.0" +requires-python = "==3.10.*" description = "Infinite Photorealistic Worlds using Procedural Generation" -keywords = ["computer vision", "data generation", "procedural"] +keywords = [ + "computer vision", + "data generation", + "procedural" +] +classifiers = [ + "Framework :: Blender", + "Programming Language :: Python :: 3" +] dependencies = [ - "bpy == 3.6.0", + "bpy", "einops", "flow_vis", "frozendict", @@ -27,11 +37,23 @@ dependencies = [ "wandb", "zarr", "pandas", + "landlab == 2.4.1", + "pycparser", + "pyrender" ] [project.optional-dependencies] -terrain = ["landlab == 2.4.1", "pycparser", "pyrender"] -dev = ["pytest", "pytest-ordering", "pytest-cov", "black", "ruff", "tabulate"] +dev = [ + "pytest", + "pytest-ordering", + "pytest-cov", + "black", + "ruff", + "tabulate" # for integration test results +] + +[tool.setuptools] +packages = ["infinigen"] [tool.pytest.ini_options] addopts = "--cov-report xml:coverage.xml --cov infinigen --cov-fail-under 0" @@ -68,9 +90,9 @@ ignore = [ [tool.ruff.per-file-ignores] "__init__.py" = [] "infinigen/assets/*" = [ - "F841", -] #transpiler currently creates lots of unused variablesclassifiers = ["Framework :: Blender", "Programming Language :: Python :: 3"] + "F841", #transpiler currently creates lots of unused variables +] [tool.ruff.mccabe] -max-complexity = 10 +max-complexity = 10 \ No newline at end of file diff --git a/setup.py b/setup.py index a8a939292..2468bf357 100644 --- a/setup.py +++ b/setup.py @@ -41,8 +41,7 @@ def ensure_submodules(): folders = get_submodule_folders() - isempty = lambda p: not any(p.iterdir()) - if any(not p.exists() or isempty(p) for p in folders): + if any(not p.exists() or not any(p.iterdir()) for p in folders): subprocess.run( ["git", "submodule", "update", "--init", "--recursive"], cwd=cwd ) @@ -85,10 +84,12 @@ def build_deps(deps): ext_modules=[ *cythonize(cython_extensions) ], - package_data=[ - "infinigen/terrain/lib", - "infinigen/datagen/customgt/build" - ] + package_data={ + "infinigen": [ + "infinigen/terrain/lib", + "infinigen/datagen/customgt/build" + ] + } # other opts come from pyproject.toml and setup.cfg ) diff --git a/tests/conftest.py b/tests/integration/conftest.py similarity index 100% rename from tests/conftest.py rename to tests/integration/conftest.py diff --git a/tests/test_infinigen.py b/tests/integration/manual_integration_check.py similarity index 100% rename from tests/test_infinigen.py rename to tests/integration/manual_integration_check.py diff --git a/tests/run_tests.sh b/tests/integration/run_tests.sh similarity index 100% rename from tests/run_tests.sh rename to tests/integration/run_tests.sh diff --git a/tests/test_nature_materials_basic.py b/tests/test_nature_materials_basic.py new file mode 100644 index 000000000..6d23b6965 --- /dev/null +++ b/tests/test_nature_materials_basic.py @@ -0,0 +1,25 @@ +from pathlib import Path +import importlib + +import pytest +import bpy +import gin + +from infinigen.assets import * # so gin can find them +from infinigen.core.util import blender as butil + +from utils import ( + setup_gin, + load_txt_list, +) + +setup_gin() + +@pytest.mark.parametrize('factory_name', load_txt_list('test_nature_materials_basic.txt')) +def test_material_runs(factory_name, **kwargs): + butil.clear_scene + with gin.unlock_config(): + mat = importlib.import_module(f'infinigen.assets.materials.{factory_name}') + bpy.ops.mesh.primitive_ico_sphere_add(radius=.8, subdivisions=5) + asset = bpy.context.active_object + mat.apply(asset) \ No newline at end of file diff --git a/tests/test_nature_materials_basic.txt b/tests/test_nature_materials_basic.txt new file mode 100644 index 000000000..476309fad --- /dev/null +++ b/tests/test_nature_materials_basic.txt @@ -0,0 +1,58 @@ +aluminumdisp2tut +atmosphere_light_haze +bark_birch +bark +bark_random +basic_bsdf +beak +bird +blackbody_shader +bone +chitin +chunkyrock +cobble_stone +cracked_ground +dirt +eyeball +face_size_visualizer +fishbody +fish_eye_shader +fishfin +giraffe_attr +grass_blade_texture +horn +ice +lava +mountain +mud +new_whitewater +nose +reptile_brown_circle_attr +reptile_gray_attr +reptile_two_color_attr +river_water +sand +sandstone +scale +simple_brownish +simple_greenery +simple_whitish +slimy +smoke_material +snake_plant +snake_scale +snake_shaders +snow +soil +spider_plant +spot_sparse_attr +stone +succulent +three_color_spots +tiger_attr +tongue +two_color_spots +twocolorz +waterfall_material +water +wood diff --git a/tests/test_nature_meshes_basic.py b/tests/test_nature_meshes_basic.py new file mode 100644 index 000000000..034440299 --- /dev/null +++ b/tests/test_nature_meshes_basic.py @@ -0,0 +1,22 @@ +from pathlib import Path + +import pytest +import bpy +import gin + +from infinigen.assets import * # so gin can find them +from infinigen.core.util import blender as butil + +from utils import ( + setup_gin, + get_def_from_folder, + load_txt_list, + check_factory_runs +) + +setup_gin() + +@pytest.mark.parametrize('factory_name', load_txt_list('test_nature_meshes_basic.txt')) +def test_factory_runs(factory_name, **kwargs): + fac_class = get_def_from_folder(factory_name, 'infinigen/assets') + check_factory_runs(fac_class, **kwargs) \ No newline at end of file diff --git a/tests/test_nature_meshes_basic.txt b/tests/test_nature_meshes_basic.txt new file mode 100644 index 000000000..2cc788b4f --- /dev/null +++ b/tests/test_nature_meshes_basic.txt @@ -0,0 +1,109 @@ +#AntSwarmFactory +#BoidSwarmFactory +#ChameleonFactory +#FanCoralFactory +#FrogFactory +#FruitFactoryGeneralFruit +#GenericTreeFactory +#HerbivoreFactory +#LeafFactoryIvy +#LizardFactory +#OctopusFactory +#ReedMonocotFactory +AgaveMonocotFactory +AltocumulusFactory +AugerFactory +BananaMonocotFactory +BeetleFactory +BirdFactory +BlenderRockFactory +BoulderFactory +BrainCoralFactory +BushCoralFactory +BushFactory +CactusFactory +CarnivoreFactory +CauliflowerCoralFactory +CausticsLampFactory +ClamFactory +CloudFactory +CoconutTreeFactory +ColumnarCactusFactory +ConchFactory +CoralFactory +CrabFactory +CrustaceanFactory +CumulonimbusFactory +CumulusFactory +DragonflyFactory +DustMoteFactory +ElkhornCoralFactory +FernFactory +FishFactory +FlowerFactory +FlowerPlantFactory +FlyingBirdFactory +FruitFactoryApple +FruitFactoryBlackberry +FruitFactoryCoconutgreen +FruitFactoryCoconuthairy +FruitFactoryCompositional +FruitFactoryDurian +FruitFactoryPineapple +FruitFactoryStarfruit +FruitFactoryStrawberry +GlobularCactusFactory +GlowingRocksFactory +GrassesMonocotFactory +GrassTuftFactory +HoneycombCoralFactory +JellyfishFactory +KalidiumCactusFactory +KelpMonocotFactory +LeafBananaTreeFactory +LeafFactory +LeafFactoryBroadleaf +LeafFactoryGinko +LeafFactoryMaple +LeafFactoryPine +LeafFactoryV2 +LeafPalmPlantFactory +LeafPalmTreeFactory +LeatherCoralFactory +LichenFactory +LobsterFactory +MaizeMonocotFactory +MolluskFactory +MonocotFactory +MossFactory +MushroomFactory +MusselFactory +NautilusFactory +PalmTreeFactory +PineconeFactory +PineNeedleFactory +PlantBananaTreeFactory +PrickyPearCactusFactory +RaindropFactory +ScallopFactory +SeaweedFactory +SnakeFactory +SnakePlantFactory +SnowflakeFactory +SpiderPlantFactory +SpinyLobsterFactory +StarCoralFactory +StratocumulusFactory +SucculentFactory +TableCoralFactory +TaroMonocotFactory +TreeFactory +TreeFlowerFactory +TubeCoralFactory +TussockMonocotFactory +TwigCoralFactory +UrchinFactory +VeratrumMonocotFactory +VoluteFactory +WheatEarMonocotFactory +WheatMonocotFactory \ No newline at end of file diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 000000000..ff298fb1c --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,44 @@ + +from pathlib import Path +import importlib + +import gin +import bpy + +from infinigen.core import surface +from infinigen.core.util import blender as butil + +def setup_gin(): + + gin.clear_config() + + gin.parse_config_files_and_bindings( + config_files=['examples/configs/base.gin'], + bindings=None, + skip_unknown=True + ) + + surface.registry.initialize_from_gin() + + +def get_def_from_folder(name, folder): + root = Path(__file__).parent.parent + for file in (root/folder).iterdir(): + with gin.unlock_config(): + module_parent = str(file.parent.relative_to(root)).replace('/', '.') + module = importlib.import_module(f'{module_parent}.{file.stem}') + if hasattr(module, name): + return getattr(module, name) + + raise ModuleNotFoundError(f'Could not find any factory with {name=}, make sure it is imported by a direct descendent of infinigen.assets') + +def load_txt_list(path): + res = (Path(__file__).parent/path).read_text().splitlines() + res = [f for f in res if not f.startswith('#')] + return res + +def check_factory_runs(fac_class, seed1=0, seed2=0, distance_m=50): + butil.clear_scene() + fac = fac_class(seed1) + asset = fac.spawn_asset(seed2, distance=distance_m) + assert isinstance(asset, bpy.types.Object) \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..02e2c2426 --- /dev/null +++ b/tox.ini @@ -0,0 +1,40 @@ +[tox] +min_version = 4.0 +env_list = + py310 + py39 + type + +[testenv] +description = run unit tests +deps = + pytest + coverage[toml] +commands = + coverage run -m pytest {posargs} + coverage xml + coverage report + +[testenv:ruff] +description = Lightening-fast linting for Python +skip_install = true +deps = ruff +commands = ruff {posargs:.} + +[testenv:package] +description = Build package and check metadata (or upload package) +skip_install = true +deps = + build +# twine +commands = + python -m build +# twine {posargs:check --strict} dist/* +#passenv = +# TWINE_USERNAME +# TWINE_PASSWORD +# TWINE_REPOSITORY_URL + +[testenv:type] +deps = mypy +commands = mypy src \ No newline at end of file