diff --git a/.github/workflows/conda_test.yaml b/.github/workflows/conda_test.yaml new file mode 100644 index 0000000..5dfb7ff --- /dev/null +++ b/.github/workflows/conda_test.yaml @@ -0,0 +1,97 @@ +# Testing if we can install Conda successfully. Sanity checking the CI flow. +name: conda-test + +on: [push] + +env: + CONDA_ENV_NAME: conda_test + +jobs: + conda-cache: + runs-on: ubuntu-20.04 + defaults: + run: + shell: bash -el {0} + continue-on-error: true + outputs: + pytestOutput: ${{ steps.unit-tests.outputs.test }} + strategy: + matrix: + python-version: ["3.7"] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + - name: Setup conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + activate-environment: ${{ env.CONDA_ENV_NAME }} + python-version: ${{ matrix.python-version }} + auto-activate-base: false + - name: Save Conda Env + # Workaround, this isn't working otherwise. + run: | + echo "CONDA=$CONDA" + echo "CONDA=$CONDA" >> "$GITHUB_ENV" + - name: Cache Conda env + uses: actions/cache@v3 + with: + path: ${{ env.CONDA }}/envs/${{ env.CONDA_ENV_NAME }} + key: + conda-test-conda-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + hashFiles('conda_test.yml') }}-${{ + env.CACHE_NUMBER }} + env: + CACHE_NUMBER: 0 + id: cache + - name: Update environment + run: | + echo "CONDA=$CONDA" + conda env update -n ${{ env.CONDA_ENV_NAME }} -f conda_test.yml + ls $CONDA/envs/ + if: steps.cache.outputs.cache-hit != 'true' + conda-cache-load: + needs: conda-cache + runs-on: ubuntu-20.04 + defaults: + run: + shell: bash -el {0} + continue-on-error: true + outputs: + pytestOutput: ${{ steps.unit-tests.outputs.test }} + strategy: + matrix: + python-version: ["3.7"] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + - name: Setup conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + activate-environment: ${{ env.CONDA_ENV_NAME }} + python-version: ${{ matrix.python-version }} + auto-activate-base: false + - name: Save Conda Env + # Workaround, this isn't working otherwise. + run: | + echo "CONDA=$CONDA" + echo "CONDA=$CONDA" >> "$GITHUB_ENV" + - name: Cache Conda env + uses: actions/cache@v3 + with: + path: ${{ env.CONDA }}/envs/${{ env.CONDA_ENV_NAME }} + key: + conda-test-conda-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + hashFiles('conda_test.yml') }}-${{ + env.CACHE_NUMBER }} + env: + CACHE_NUMBER: 0 + id: cache + - name: Fail + run: exit 1 + if: steps.cache.outputs.cache-hit != 'true' diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml new file mode 100644 index 0000000..f8f8581 --- /dev/null +++ b/.github/workflows/pr.yaml @@ -0,0 +1,157 @@ +# CI flow +name: pybag-pr-ci + +on: + push: + schedule: + - cron: '0 9 * * *' # 9AM UTC = 2AM PST + +env: + CONDA_ENV_NAME: bag_py3d7_c + +jobs: + build: + runs-on: ubuntu-20.04 + defaults: + run: + shell: bash -el {0} + continue-on-error: true + outputs: + pytestOutput: ${{ steps.unit-tests.outputs.test }} + strategy: + matrix: + python-version: ["3.7"] + steps: + - name: Install packages + run: | + sudo apt update + sudo apt -y install \ + autoconf \ + curl \ + gcc-8 \ + g++-8 \ + git \ + libtool \ + libltdl-dev \ + pkg-config \ + make \ + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Setup conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + activate-environment: ${{ env.CONDA_ENV_NAME }} + python-version: ${{ matrix.python-version }} + auto-activate-base: false + - name: Save Conda Env + # Workaround, this isn't working otherwise. + run: | + echo "CONDA=$CONDA" + echo "CONDA=$CONDA" >> "$GITHUB_ENV" + - name: Cache Conda env + uses: actions/cache@v3 + with: + path: ${{ env.CONDA }}/envs/${{ env.CONDA_ENV_NAME }} + key: + conda-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + hashFiles('environment.yml') }}-${{ + env.CACHE_NUMBER }} + env: + # Increase this value to reset cache if etc/example-environment.yml has not changed + CACHE_NUMBER: 0 + id: cache-conda + - name: Update conda environment + run: | + echo "CONDA=$CONDA" + conda env update -n ${{ env.CONDA_ENV_NAME }} -f environment.yml + if: steps.cache-conda.outputs.cache-hit != 'true' + - name: Install additional dependencies + if: steps.cache-conda.outputs.cache-hit != 'true' + run: | + cd setup + mkdir install + cp setup_script.sh install/ + cp render_template.py install/ + cp project-config.template install/ + cd install + ./setup_script.sh + cd ../../ + - name: Build cbag and pybag + id: cpp-build + run: | + export PYBAG_PYTHON=python + echo "PYBAG_PYTHON=$PYBAG_PYTHON" + ./run_test.sh + - name: Cache pybag build + uses: actions/cache@v3 + with: + path: _build + key: + build-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + env.CACHE_NUMBER }} + env: + # Increase this value to reset cache if etc/example-environment.yml has not changed + CACHE_NUMBER: 0 + id: cache-pybag + test: + needs: build + runs-on: ubuntu-20.04 + defaults: + run: + shell: bash -el {0} + continue-on-error: true + outputs: + pytestOutput: ${{ steps.unit-tests.outputs.test }} + strategy: + matrix: + python-version: ["3.7"] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: recursive + - name: Setup conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + activate-environment: bag_py3d7_c + python-version: ${{ matrix.python-version }} + auto-activate-base: false + - name: Save Conda Env + # Workaround, this isn't working otherwise. + run: | + echo "CONDA=$CONDA" + echo "CONDA=$CONDA" >> "$GITHUB_ENV" + - name: Cache Conda env + uses: actions/cache@v3 + with: + path: ${{ env.CONDA }}/envs/${{ env.CONDA_ENV_NAME }} + key: + conda-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + hashFiles('environment.yml') }}-${{ + env.CACHE_NUMBER }} + env: + # Increase this value to reset cache if etc/example-environment.yml has not changed + CACHE_NUMBER: 0 + id: cache-conda + - name: Cache pybag build + uses: actions/cache@v3 + with: + path: _build + key: + build-${{ runner.os }}--${{ runner.arch }}--${{ + steps.get-date.outputs.today }}-${{ + env.CACHE_NUMBER }} + env: + # Increase this value to reset cache if etc/example-environment.yml has not changed + CACHE_NUMBER: 0 + id: cache-pybag + - name: Run test + id: run-pytest + run: | + which pytest + pytest tests -v diff --git a/README.md b/README.md index 1bdcb80..78005d6 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,16 @@ # PYBAG -Python wrapper for [CBAG](https://github.com/bluecheetah/cbag) library. +Python wrapper for [CBAG](https://github.com/ucb-art/cbag) library for BAG3++. -This is a fork of [PYBAG] (https://github.com/ucb-art/pybag), which as of May 13th, 2019, -has been taken offline temporarily. +## Setup + +This library should be used with [BAG3++](https://github.com/ucb-art/bag). To setup BAG, follow the instructions outlined on the [RTD page](https://bag3-readthedocs.readthedocs.io/en/latest/dependencies/). + +Alternative, if you are using Ubuntu, you can use the `setup_script.sh` under the `setup` directory. This runs the steps described in the RTD page above. See the `setup/README.md` for discussion. + +To build the `pybag` library, run `./run_test.sh`. This will compile `cbag` as well as create the `pybag` Python wrappers for `BAG`. + +Running `./run_test.sh`requires the `PYBAG_PYTHON` environment variable be set to the Python from your Miniconda install from the setup process. ## Licensing diff --git a/conda_test.yml b/conda_test.yml new file mode 100644 index 0000000..f9570d7 --- /dev/null +++ b/conda_test.yml @@ -0,0 +1,8 @@ +name: conda_test +channels: + - anaconda + - conda-forge + - defaults +dependencies: + - numpy-base>=1.21.5 + \ No newline at end of file diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..ba53e68 --- /dev/null +++ b/environment.yml @@ -0,0 +1,137 @@ +name: bag_py3d7_c +channels: + - anaconda + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=main + - _openmp_mutex=4.5=1_gnu + - astroid=2.11.7=py37h06a4308_0 + - blas=1.0=mkl + - brotli=1.0.9=he6710b0_2 + - ca-certificates=2022.12.7=ha878542_0 + - certifi=2022.12.7=pyhd8ed1ab_0 + - dbus=1.13.18=hb2f20db_0 + - dill=0.3.6=py37h06a4308_0 + - expat=2.4.4=h295c915_0 + - flit-core=3.6.0=pyhd3eb1b0_0 + - fmt=8.0.1=h4bd325d_0 + - fontconfig=2.13.1=h6c09931_0 + - fonttools=4.25.0=pyhd3eb1b0_0 + - freetype=2.11.0=h70c0345_0 + - giflib=5.2.1=h7b6447c_0 + - glib=2.56.2=hd408876_0 + - gst-plugins-base=1.14.0=hbbd80ab_1 + - gstreamer=1.14.0=hb453b48_1 + - icu=58.2=he6710b0_3 + - intel-openmp=2021.4.0=h06a4308_3561 + - isort=5.9.3=pyhd3eb1b0_0 + - jpeg=9e=h7f8727e_0 + - lazy-object-proxy=1.6.0=py37h27cfd23_0 + - lcms2=2.12=h3be6417_0 + - ld_impl_linux-64=2.35.1=h7274673_9 + - libffi=3.3=he6710b0_2 + - libgcc-ng=9.3.0=h5101ec6_17 + - libgomp=9.3.0=h5101ec6_17 + - libpng=1.6.37=hbc83047_0 + - libstdcxx-ng=9.3.0=hd4cf53a_17 + - libtiff=4.2.0=h85742a9_0 + - libuuid=1.0.3=h7f8727e_2 + - libwebp=1.2.2=h55f646e_0 + - libwebp-base=1.2.2=h7f8727e_0 + - libxcb=1.15=h7f8727e_0 + - libxml2=2.9.12=h03d6c58_0 + - lz4-c=1.9.3=h295c915_1 + - matplotlib-base=3.5.1=py37ha18d171_1 + - mccabe=0.7.0=pyhd3eb1b0_0 + - mkl=2021.4.0=h06a4308_640 + - mkl-service=2.4.0=py37h7f8727e_0 + - mkl_fft=1.3.1=py37hd3c417c_0 + - mkl_random=1.2.2=py37h51133e4_0 + - munkres=1.1.4=py_0 + - ncurses=6.3=h7f8727e_2 + - numpy-base=1.21.5=py37hf524024_2 + - openssl=1.1.1k=h7f98852_0 + - pcre=8.45=h295c915_0 + - pillow=9.0.1=py37h22f2fdc_0 + - pip=21.2.2=py37h06a4308_0 + - platformdirs=2.5.2=py37h06a4308_0 + - pylint=2.14.5=py37h06a4308_0 + - pyqt=5.9.2=py37h05f1152_2 + - python=3.7.7=hcff3b4d_5 + - qt=5.9.7=h5867ecd_1 + - readline=8.1.2=h7f8727e_1 + - setuptools=58.0.4=py37h06a4308_0 + - spdlog=1.9.1=h4bd325d_0 + - sqlite=3.37.2=hc218d9a_0 + - tk=8.6.11=h1ccaba5_0 + - tomli=2.0.1=py37h06a4308_0 + - tomlkit=0.11.1=py37h06a4308_0 + - tornado=6.1=py37h27cfd23_0 + - typed-ast=1.4.3=py37h7f8727e_1 + - typing_extensions=4.4.0=py37h06a4308_0 + - wheel=0.37.1=pyhd3eb1b0_0 + - wrapt=1.13.3=py37h7f8727e_2 + - xz=5.2.5=h7b6447c_0 + - zlib=1.2.11=h7f8727e_4 + - zstd=1.4.9=haebb681_0 + - pip: + - apipkg==1.5 + - appdirs==1.4.3 + - argparse==1.4.0 + - arrow==1.2.2 + - attrs==19.3.0 + - backcall==0.1.0 + - cycler==0.10.0 + - decorator==4.4.2 + - distlib==0.3.0 + - docopt==0.6.2 + - execnet==1.7.1 + - filelock==3.0.12 + - h5py==2.10.0 + - importlib-metadata==1.6.0 + - inform==1.26.0 + - ipython==7.13.0 + - ipython-genutils==0.2.0 + - jedi==0.16.0 + - jinja2==2.11.1 + - kiwisolver==1.2.0 + - libpsf==0.1.3 + - markupsafe==1.1.1 + - matplotlib==3.2.1 + - more-itertools==8.2.0 + - networkx==2.4 + - numpy==1.18.2 + - packaging==20.3 + - pandocfilters==1.4.2 + - parso==0.6.2 + - pexpect==4.8.0 + - pickleshare==0.7.5 + - pluggy==0.13.1 + - ply==3.4 + - prompt-toolkit==3.0.5 + - psf-utils==1.5.0 + - ptyprocess==0.6.0 + - py==1.8.1 + - pygments==2.6.1 + - pyparsing==2.4.6 + - pyqt5==5.9 + - pyqt5-sip==12.7.1 + - pytest==5.4.1 + - pytest-forked==1.1.3 + - pytest-xdist==1.31.0 + - python-dateutil==2.8.1 + - pyzmq==19.0.0 + - quantiphy==2.17.0 + - ruamel-yaml==0.16.10 + - ruamel-yaml-clib==0.2.0 + - scipy==1.4.1 + - sip==4.19.8 + - six==1.14.0 + - sortedcontainers==2.1.0 + - traitlets==4.3.3 + - typing-extensions==4.1.1 + - virtualenv==20.0.15 + - wcwidth==0.1.9 + - zipp==3.1.0 + - zmq==0.0.0 \ No newline at end of file diff --git a/setup/.gitignore b/setup/.gitignore new file mode 100644 index 0000000..e9c0271 --- /dev/null +++ b/setup/.gitignore @@ -0,0 +1 @@ +install* \ No newline at end of file diff --git a/setup/README.md b/setup/README.md new file mode 100644 index 0000000..683ee14 --- /dev/null +++ b/setup/README.md @@ -0,0 +1,20 @@ +# Setup script for Pybag + +These scripts follow the instructions outlined on the [RTD page](https://bag3-readthedocs.readthedocs.io/en/latest/dependencies/). + +NOTE: this setup has only been tested on Ubuntu 20.04. Support for 22.04 has not been formally verified. + +## Files +- `README.md`: this file +- `setup_script.sh`: run script. Installs the dependencies as decribed in the RTD. +- `project-config.template`: a Jinja render template for creating the `project-config.jam` file for the Boost library. +- `render_template.py`: script to render `project-config.template` + +## Usage +1) Install the following dependencies using `apt`: +`autoconf curl gcc-8 g++-8 git libtool libltdl-dev pkg-config make` +2) Install [Miniconda](https://docs.anaconda.com/miniconda/miniconda-install/) and create the environment using the [environment.yml](https://github.com/ucb-art/pybag/environment.yml) file. +3) Make an `install` directory to install the dependencies and copy all the files from here to `install`. +4) Run `./setup_script.sh` + +Now you are ready to build `pybag`. diff --git a/setup/project-config.template b/setup/project-config.template new file mode 100644 index 0000000..83868df --- /dev/null +++ b/setup/project-config.template @@ -0,0 +1,38 @@ +# Boost.Build Configuration +# Based on autogenerated file from bootstrap.sh + +import option ; +import feature ; + +# Compiler configuration. This definition will be used unless +# you already have defined some toolsets in your user-config.jam +# file. +if ! gcc in [ feature.values ] +{ + using gcc : 8 : gcc-8 : ; +} + +project : default-build gcc ; + +# Python configuration +import python ; +if ! [ python.configured ] +{ + using python : 3.7 : {{ conda_env_path }} : {{ conda_env_path }}/include/python3.7m ; +} + +# List of --with- and --without- +# options. If left empty, all libraries will be built. +# Options specified on the command line completely +# override this variable. +libraries = ; + +# These settings are equivalent to corresponding command-line +# options. +option.set prefix : {{ conda_env_path }} ; +option.set exec-prefix : {{ conda_env_path }} ; +option.set libdir : {{ conda_env_path }}/lib ; +option.set includedir : {{ conda_env_path }}/include ; + +# Stop on first error +option.set keep-going : false ; \ No newline at end of file diff --git a/setup/render_template.py b/setup/render_template.py new file mode 100644 index 0000000..c74c03d --- /dev/null +++ b/setup/render_template.py @@ -0,0 +1,22 @@ +""" +Render a project-config.jam file with the correct Python (conda) pointers +""" +import os +from jinja2 import Template + +# Set by setup_script.sh +conda_env_path = os.environ['CONDA_ENV_PATH'] + +template_fname = "project-config.template" +output_fname = "project-config.jam" + +fin = open(template_fname, 'r') +raw_contents = fin.read() +fin.close() + +pop_contents = Template(raw_contents).render(conda_env_path=conda_env_path) + +fout = open(output_fname, 'w') +fout.write(pop_contents) +fout.write("\n") +fout.close() \ No newline at end of file diff --git a/setup/setup_script.sh b/setup/setup_script.sh new file mode 100755 index 0000000..ff0cbc7 --- /dev/null +++ b/setup/setup_script.sh @@ -0,0 +1,65 @@ +# Setup script + +# CHANGE THIS +export CONDA_ENV_PATH=${CONDA}/envs/bag_py3d7_c + +export CC=gcc-8 +export CXX=g++-8 + +# cmake +wget https://github.com/Kitware/CMake/releases/download/v3.17.0/cmake-3.17.0.tar.gz +tar -xvf cmake-3.17.0.tar.gz +cd cmake-3.17.0 +./bootstrap --prefix=$CONDA_ENV_PATH --parallel=4 +make -j4 +make install +cd ../ + +# magic enum +git clone https://github.com/Neargye/magic_enum.git +cd magic_enum +cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DMAGIC_ENUM_OPT_BUILD_EXAMPLES=FALSE -DMAGIC_ENUM_OPT_BUILD_TESTS=FALSE -DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH +cmake --build build +cd build +make install +cd ../../ + +# yaml cpp +git clone https://github.com/jbeder/yaml-cpp.git +cd yaml-cpp +cmake -B_build -H. -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH +cmake --build _build --target install -- -j 4 +cd ../ + +# libfyaml +git clone https://github.com/pantoniou/libfyaml.git +cd libfyaml +./bootstrap.sh +./configure --prefix=$CONDA_ENV_PATH +make -j12 +make install +cd ../ + +# HDF5 1.10 +wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-1.10/hdf5-1.10.6/src/hdf5-1.10.6.tar.gz +tar -xvf hdf5-1.10.6.tar.gz +cd hdf5-1.10.6 +./configure --prefix=$CONDA_ENV_PATH +make -j24 +make install +cd ../ + +# Boost +wget https://boostorg.jfrog.io/artifactory/main/release/1.72.0/source/boost_1_72_0.tar.gz +tar -xvf boost_1_72_0.tar.gz +cd boost_1_72_0 +./bootstrap.sh --prefix=$CONDA_ENV_PATH --without-icu + +# edit project-config.jam +# Create by rendering python +cd ../ +python render_template.py + +# TODO: run ./b2 +cd boost_1_72_0 +./b2 --build-dir=_build cxxflags=-fPIC -j8 -target=shared,static --with-filesystem --with-serialization --with-program_options --project-config=../project-config.jam install | tee install.log \ No newline at end of file diff --git a/tests/test_imports.py b/tests/test_imports.py new file mode 100644 index 0000000..add9664 --- /dev/null +++ b/tests/test_imports.py @@ -0,0 +1,11 @@ +# Tests if we can import pybag correctly. + +# TODO: in pytest 7, this can be moved to pytest.ini +import sys +sys.path.append('_build/lib') + +from pybag.enum import * +from pybag.core import * + +def test_import(): + assert True diff --git a/tests/test_pytest.py b/tests/test_pytest.py new file mode 100644 index 0000000..bf210df --- /dev/null +++ b/tests/test_pytest.py @@ -0,0 +1,9 @@ +# Sanity checks that we can run pytest. + +def test_always_passes(): + # Should always pass + assert True + +# def test_always_fails(): +# # if enabled, should always fail +# assert False