bazi 1.0.0__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.
- bazi-1.0.0/.github/workflows/release.yml +256 -0
- bazi-1.0.0/LICENSE +21 -0
- bazi-1.0.0/MANIFEST.in +16 -0
- bazi-1.0.0/PKG-INFO +138 -0
- bazi-1.0.0/README.md +125 -0
- bazi-1.0.0/RELEASE_NOTES.md +16 -0
- bazi-1.0.0/RELEASING.md +65 -0
- bazi-1.0.0/Requirements.txt +17 -0
- bazi-1.0.0/THIRD_PARTY_NOTICES.md +20 -0
- bazi-1.0.0/bazi/__init__.py +31 -0
- bazi-1.0.0/bazi/analyzer/__init__.py +5 -0
- bazi-1.0.0/bazi/analyzer/relationship.py +641 -0
- bazi-1.0.0/bazi/bazi.py +461 -0
- bazi-1.0.0/bazi/bazi_chart.py +667 -0
- bazi-1.0.0/bazi/calendar/__init__.py +23 -0
- bazi-1.0.0/bazi/calendar/backend.py +95 -0
- bazi-1.0.0/bazi/calendar/celestial_data/SCHEMA.md +136 -0
- bazi-1.0.0/bazi/calendar/celestial_data/__init__.py +5 -0
- bazi-1.0.0/bazi/calendar/celestial_data/data/jieqi_moments.txt +7223 -0
- bazi-1.0.0/bazi/calendar/celestial_data/data/lunar_years_algo1.txt +224 -0
- bazi-1.0.0/bazi/calendar/celestial_data/data/lunar_years_algo2.txt +224 -0
- bazi-1.0.0/bazi/calendar/celestial_data/generator.py +304 -0
- bazi-1.0.0/bazi/calendar/celestial_data/loader.py +200 -0
- bazi-1.0.0/bazi/calendar/celestial_utils.py +546 -0
- bazi-1.0.0/bazi/calendar/dates.py +99 -0
- bazi-1.0.0/bazi/calendar/hko_data/__init__.py +20 -0
- bazi-1.0.0/bazi/calendar/hko_data/common.py +78 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1901.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1902.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1903.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1904.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1905.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1906.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1907.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1908.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1909.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1910.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1911.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1912.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1913.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1914.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1915.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1916.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1917.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1918.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1919.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1920.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1921.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1922.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1923.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1924.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1925.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1926.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1927.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1928.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1929.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1930.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1931.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1932.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1933.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1934.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1935.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1936.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1937.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1938.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1939.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1940.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1941.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1942.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1943.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1944.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1945.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1946.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1947.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1948.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1949.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1950.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1951.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1952.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1953.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1954.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1955.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1956.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1957.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1958.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1959.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1960.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1961.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1962.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1963.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1964.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1965.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1966.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1967.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1968.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1969.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1970.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1971.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1972.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1973.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1974.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1975.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1976.txt +371 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1977.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1978.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1979.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1980.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1981.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1982.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1983.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1984.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1985.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1986.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1987.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1988.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1989.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1990.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1991.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1992.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1993.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1994.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1995.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1996.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1997.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1998.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/1999.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2000.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2001.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2002.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2003.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2004.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2005.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2006.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2007.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2008.txt +370 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2009.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2010.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2011.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2012.txt +379 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2013.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2014.txt +400 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2015.txt +376 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2016.txt +395 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2017.txt +383 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2018.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2019.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2020.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2021.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2022.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2023.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2024.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2025.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2026.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2027.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2028.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2029.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2030.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2031.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2032.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2033.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2034.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2035.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2036.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2037.txt +372 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2038.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2039.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2040.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2041.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2042.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2043.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2044.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2045.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2046.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2047.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2048.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2049.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2050.txt +380 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2051.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2052.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2053.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2054.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2055.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2056.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2057.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2058.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2059.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2060.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2061.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2062.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2063.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2064.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2065.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2066.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2067.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2068.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2069.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2070.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2071.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2072.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2073.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2074.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2075.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2076.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2077.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2078.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2079.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2080.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2081.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2082.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2083.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2084.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2085.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2086.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2087.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2088.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2089.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2090.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2091.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2092.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2093.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2094.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2095.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2096.txt +369 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2097.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2098.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2099.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/2100.txt +368 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/jieqi_encoded.bin +425 -0
- bazi-1.0.0/bazi/calendar/hko_data/data/lunardate_encoded.bin +0 -0
- bazi-1.0.0/bazi/calendar/hko_data/decoder.py +219 -0
- bazi-1.0.0/bazi/calendar/hko_data/encoder.py +231 -0
- bazi-1.0.0/bazi/calendar/hko_data_utils.py +582 -0
- bazi-1.0.0/bazi/calendar/utils_protocol.py +56 -0
- bazi-1.0.0/bazi/common.py +86 -0
- bazi-1.0.0/bazi/data_types.py +99 -0
- bazi-1.0.0/bazi/defines/__init__.py +17 -0
- bazi-1.0.0/bazi/defines/dizhi.py +35 -0
- bazi-1.0.0/bazi/defines/enum_base.py +70 -0
- bazi-1.0.0/bazi/defines/ganzhi.py +67 -0
- bazi-1.0.0/bazi/defines/jieqi.py +77 -0
- bazi-1.0.0/bazi/defines/relations.py +57 -0
- bazi-1.0.0/bazi/defines/shier_zhangsheng.py +35 -0
- bazi-1.0.0/bazi/defines/shishen.py +77 -0
- bazi-1.0.0/bazi/defines/tiangan.py +31 -0
- bazi-1.0.0/bazi/defines/wuxing.py +74 -0
- bazi-1.0.0/bazi/defines/yinyang.py +23 -0
- bazi-1.0.0/bazi/descriptions.py +476 -0
- bazi-1.0.0/bazi/interpreter.py +53 -0
- bazi-1.0.0/bazi/py.typed +0 -0
- bazi-1.0.0/bazi/rules.py +1414 -0
- bazi-1.0.0/bazi/school.py +496 -0
- bazi-1.0.0/bazi/transit_chart.py +174 -0
- bazi-1.0.0/bazi/transits.py +222 -0
- bazi-1.0.0/bazi/utils/__init__.py +11 -0
- bazi-1.0.0/bazi/utils/bazi_utils.py +383 -0
- bazi-1.0.0/bazi/utils/dizhi_utils.py +1018 -0
- bazi-1.0.0/bazi/utils/relation_discovery.py +60 -0
- bazi-1.0.0/bazi/utils/shensha_utils.py +660 -0
- bazi-1.0.0/bazi/utils/tiangan_utils.py +274 -0
- bazi-1.0.0/bazi.egg-info/PKG-INFO +138 -0
- bazi-1.0.0/bazi.egg-info/SOURCES.txt +315 -0
- bazi-1.0.0/bazi.egg-info/dependency_links.txt +1 -0
- bazi-1.0.0/bazi.egg-info/top_level.txt +1 -0
- bazi-1.0.0/pyproject.toml +30 -0
- bazi-1.0.0/ruff.toml +31 -0
- bazi-1.0.0/run_demo.py +136 -0
- bazi-1.0.0/run_interpreter.py +137 -0
- bazi-1.0.0/run_package_checks.py +200 -0
- bazi-1.0.0/run_relationship_analyzer.py +95 -0
- bazi-1.0.0/run_tests.py +506 -0
- bazi-1.0.0/setup.cfg +4 -0
- bazi-1.0.0/tests/analyzer/test_relationship_analyzer.py +2011 -0
- bazi-1.0.0/tests/calendar/celestial_fixtures/jieqi_moments.txt +142 -0
- bazi-1.0.0/tests/calendar/celestial_fixtures/lunar_years_algo1.txt +32 -0
- bazi-1.0.0/tests/calendar/celestial_fixtures/lunar_years_algo2.txt +32 -0
- bazi-1.0.0/tests/calendar/celestial_parity_data.py +121 -0
- bazi-1.0.0/tests/calendar/test_backend.py +181 -0
- bazi-1.0.0/tests/calendar/test_celestial_loader.py +294 -0
- bazi-1.0.0/tests/calendar/test_celestial_parity_derived.py +273 -0
- bazi-1.0.0/tests/calendar/test_celestial_tables.py +344 -0
- bazi-1.0.0/tests/calendar/test_celestial_utils.py +409 -0
- bazi-1.0.0/tests/calendar/test_dates.py +300 -0
- bazi-1.0.0/tests/calendar/test_hko_data.py +429 -0
- bazi-1.0.0/tests/calendar/test_hko_data_utils.py +718 -0
- bazi-1.0.0/tests/defines/test_dizhi.py +119 -0
- bazi-1.0.0/tests/defines/test_ganzhi.py +178 -0
- bazi-1.0.0/tests/defines/test_jieqi.py +118 -0
- bazi-1.0.0/tests/defines/test_relations.py +52 -0
- bazi-1.0.0/tests/defines/test_shier_zhangsheng.py +37 -0
- bazi-1.0.0/tests/defines/test_shishen.py +69 -0
- bazi-1.0.0/tests/defines/test_tiangan.py +116 -0
- bazi-1.0.0/tests/defines/test_wuxing.py +85 -0
- bazi-1.0.0/tests/defines/test_yinyang.py +48 -0
- bazi-1.0.0/tests/integration/test_ganzhi_relations.py +262 -0
- bazi-1.0.0/tests/integration/test_hko_data_regeneration.py +64 -0
- bazi-1.0.0/tests/integration/test_import_from_any_cwd.py +41 -0
- bazi-1.0.0/tests/integration/test_relationship_analysis.py +1088 -0
- bazi-1.0.0/tests/o_smoke.py +305 -0
- bazi-1.0.0/tests/package_smoke.py +138 -0
- bazi-1.0.0/tests/pytest.ini +9 -0
- bazi-1.0.0/tests/test_bazi.py +769 -0
- bazi-1.0.0/tests/test_bazi_chart.py +1124 -0
- bazi-1.0.0/tests/test_common.py +156 -0
- bazi-1.0.0/tests/test_interpreter.py +75 -0
- bazi-1.0.0/tests/test_package_checks.py +65 -0
- bazi-1.0.0/tests/test_release_policy.py +324 -0
- bazi-1.0.0/tests/test_rules.py +414 -0
- bazi-1.0.0/tests/test_run_relationship_analyzer.py +138 -0
- bazi-1.0.0/tests/test_run_tests.py +104 -0
- bazi-1.0.0/tests/test_school.py +594 -0
- bazi-1.0.0/tests/test_transit_chart.py +495 -0
- bazi-1.0.0/tests/test_transits.py +255 -0
- bazi-1.0.0/tests/utils/test_bazi_utils.py +389 -0
- bazi-1.0.0/tests/utils/test_dizhi_utils.py +1711 -0
- bazi-1.0.0/tests/utils/test_relation_discovery.py +33 -0
- bazi-1.0.0/tests/utils/test_shensha_utils.py +650 -0
- bazi-1.0.0/tests/utils/test_tiangan_utils.py +529 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
name: Prepare or Publish Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
mode:
|
|
7
|
+
description: Rehearse only, or explicitly publish the tested release
|
|
8
|
+
type: choice
|
|
9
|
+
options: [rehearsal, release]
|
|
10
|
+
default: rehearsal
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
permissions: {}
|
|
14
|
+
concurrency:
|
|
15
|
+
group: bazi-release
|
|
16
|
+
cancel-in-progress: false
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
preflight:
|
|
20
|
+
if: inputs.mode == 'release'
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
permissions: {}
|
|
23
|
+
steps:
|
|
24
|
+
- name: Require an existing protected release environment
|
|
25
|
+
env:
|
|
26
|
+
MODE: ${{ inputs.mode }}
|
|
27
|
+
REPOSITORY: ${{ github.repository }}
|
|
28
|
+
REF: ${{ github.ref }}
|
|
29
|
+
SHA: ${{ github.sha }}
|
|
30
|
+
shell: python
|
|
31
|
+
run: |
|
|
32
|
+
import json, os, re, urllib.request
|
|
33
|
+
if (os.environ['MODE'] != 'release' or os.environ['REPOSITORY'] != '0xf3cd/bazi'
|
|
34
|
+
or os.environ['REF'] != 'refs/heads/main' or not re.fullmatch(r'[0-9a-f]{40}', os.environ['SHA'])):
|
|
35
|
+
raise SystemExit('Real release requires the main dispatch SHA of 0xf3cd/bazi')
|
|
36
|
+
def get(path):
|
|
37
|
+
request = urllib.request.Request('https://api.github.com/repos/0xf3cd/bazi/' + path,
|
|
38
|
+
headers={'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28'})
|
|
39
|
+
with urllib.request.urlopen(request, timeout=30) as response:
|
|
40
|
+
return json.load(response)
|
|
41
|
+
environment = get('environments/release')
|
|
42
|
+
policies = get('environments/release/deployment-branch-policies?per_page=100')
|
|
43
|
+
reviewers = [rule for rule in environment.get('protection_rules', [])
|
|
44
|
+
if rule.get('type') == 'required_reviewers' and any(
|
|
45
|
+
reviewer.get('type') in ('User', 'Team') and isinstance(reviewer.get('reviewer', {}).get('id'), int)
|
|
46
|
+
and reviewer['reviewer']['id'] > 0 for reviewer in rule.get('reviewers', []))]
|
|
47
|
+
if (environment.get('name') != 'release' or not reviewers
|
|
48
|
+
or environment.get('deployment_branch_policy') != {'protected_branches': False, 'custom_branch_policies': True}
|
|
49
|
+
or policies.get('total_count') != 1
|
|
50
|
+
or [(p.get('name'), p.get('type')) for p in policies.get('branch_policies', [])] != [('main', 'branch')]):
|
|
51
|
+
raise SystemExit('release must have required reviewers and exactly the main branch policy')
|
|
52
|
+
|
|
53
|
+
build:
|
|
54
|
+
needs: [preflight]
|
|
55
|
+
if: ${{ !cancelled() && (inputs.mode == 'rehearsal' || (inputs.mode == 'release' && needs.preflight.result == 'success')) }}
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
permissions:
|
|
58
|
+
contents: read
|
|
59
|
+
outputs:
|
|
60
|
+
artifact-id: ${{ steps.upload.outputs.artifact-id }}
|
|
61
|
+
manifest-sha: ${{ steps.bundle.outputs.manifest-sha }}
|
|
62
|
+
version: ${{ steps.bundle.outputs.version }}
|
|
63
|
+
steps:
|
|
64
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
65
|
+
with:
|
|
66
|
+
ref: ${{ github.sha }}
|
|
67
|
+
persist-credentials: false
|
|
68
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
69
|
+
with:
|
|
70
|
+
python-version: '3.12'
|
|
71
|
+
- name: Verify source identity
|
|
72
|
+
env:
|
|
73
|
+
SHA: ${{ github.sha }}
|
|
74
|
+
MODE: ${{ inputs.mode }}
|
|
75
|
+
REPOSITORY: ${{ github.repository }}
|
|
76
|
+
REF: ${{ github.ref }}
|
|
77
|
+
shell: python
|
|
78
|
+
run: |
|
|
79
|
+
import os, re, subprocess
|
|
80
|
+
mode, sha = os.environ['MODE'], os.environ['SHA']
|
|
81
|
+
if mode not in ('rehearsal', 'release') or not re.fullmatch(r'[0-9a-f]{40}', sha):
|
|
82
|
+
raise SystemExit('Invalid release mode or SHA')
|
|
83
|
+
if mode == 'release' and (os.environ['REPOSITORY'], os.environ['REF']) != ('0xf3cd/bazi', 'refs/heads/main'):
|
|
84
|
+
raise SystemExit('Real release is main-only')
|
|
85
|
+
if subprocess.check_output(['git', 'rev-parse', 'HEAD'], text=True).strip() != sha:
|
|
86
|
+
raise SystemExit('Checkout SHA differs from dispatch SHA')
|
|
87
|
+
- name: Install development requirements
|
|
88
|
+
run: |
|
|
89
|
+
python -m pip install -r Requirements.txt
|
|
90
|
+
python -m pip install celestial-calendar==0.6.1
|
|
91
|
+
- name: Run full gate and retain its tested pair
|
|
92
|
+
run: python run_tests.py -a -v --package-output-dir "$RUNNER_TEMP/bundle/dist"
|
|
93
|
+
- name: Seal release bundle
|
|
94
|
+
id: bundle
|
|
95
|
+
env:
|
|
96
|
+
SHA: ${{ github.sha }}
|
|
97
|
+
REPOSITORY: ${{ github.repository }}
|
|
98
|
+
RUN_ID: ${{ github.run_id }}
|
|
99
|
+
MODE: ${{ inputs.mode }}
|
|
100
|
+
shell: python
|
|
101
|
+
run: |
|
|
102
|
+
import hashlib, json, os, re, shutil, tomllib
|
|
103
|
+
from pathlib import Path
|
|
104
|
+
version = tomllib.loads(Path('pyproject.toml').read_text())['project']['version']
|
|
105
|
+
if not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', version):
|
|
106
|
+
raise SystemExit('Use a stable three-part release version')
|
|
107
|
+
bundle = Path(os.environ['RUNNER_TEMP']) / 'bundle'
|
|
108
|
+
names = {f'bazi-{version}.tar.gz', f'bazi-{version}-py3-none-any.whl'}
|
|
109
|
+
if {p.name for p in (bundle / 'dist').iterdir()} != names:
|
|
110
|
+
raise SystemExit('Expected exactly the tested sdist and rebuilt wheel')
|
|
111
|
+
shutil.copyfile('RELEASE_NOTES.md', bundle / 'RELEASE_NOTES.md')
|
|
112
|
+
metadata = {'name': 'bazi', 'version': version, 'sha': os.environ['SHA'],
|
|
113
|
+
'repository': os.environ['REPOSITORY'], 'run_id': os.environ['RUN_ID'], 'mode': os.environ['MODE']}
|
|
114
|
+
(bundle / 'release.json').write_text(json.dumps(metadata, sort_keys=True) + '\n')
|
|
115
|
+
files = sorted([*(bundle / 'dist').iterdir(), bundle / 'RELEASE_NOTES.md', bundle / 'release.json'], key=lambda p: p.relative_to(bundle).as_posix())
|
|
116
|
+
checksums = ''.join(f'{hashlib.sha256(p.read_bytes()).hexdigest()} {p.relative_to(bundle).as_posix()}\n' for p in files)
|
|
117
|
+
(bundle / 'SHA256SUMS').write_bytes(checksums.encode('utf-8'))
|
|
118
|
+
with open(os.environ['GITHUB_OUTPUT'], 'a') as output:
|
|
119
|
+
output.write(f'version={version}\nmanifest-sha={hashlib.sha256(checksums.encode()).hexdigest()}\n')
|
|
120
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
121
|
+
id: upload
|
|
122
|
+
with:
|
|
123
|
+
name: tested-release
|
|
124
|
+
path: ${{ runner.temp }}/bundle/
|
|
125
|
+
if-no-files-found: error
|
|
126
|
+
overwrite: false
|
|
127
|
+
retention-days: 30
|
|
128
|
+
|
|
129
|
+
pypi:
|
|
130
|
+
needs: [preflight, build]
|
|
131
|
+
if: inputs.mode == 'release' && needs.preflight.result == 'success' && needs.build.result == 'success' && github.repository == '0xf3cd/bazi' && github.ref == 'refs/heads/main'
|
|
132
|
+
runs-on: ubuntu-latest
|
|
133
|
+
environment: release
|
|
134
|
+
permissions:
|
|
135
|
+
id-token: write
|
|
136
|
+
steps:
|
|
137
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
138
|
+
with: &download
|
|
139
|
+
artifact-ids: ${{ needs.build.outputs.artifact-id }}
|
|
140
|
+
path: artifact
|
|
141
|
+
merge-multiple: true
|
|
142
|
+
digest-mismatch: error
|
|
143
|
+
- &verify
|
|
144
|
+
name: Verify exact same-run bundle
|
|
145
|
+
env:
|
|
146
|
+
ARTIFACT_ID: ${{ needs.build.outputs.artifact-id }}
|
|
147
|
+
MANIFEST_SHA: ${{ needs.build.outputs.manifest-sha }}
|
|
148
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
149
|
+
SHA: ${{ github.sha }}
|
|
150
|
+
RUN_ID: ${{ github.run_id }}
|
|
151
|
+
MODE: ${{ inputs.mode }}
|
|
152
|
+
REPOSITORY: ${{ github.repository }}
|
|
153
|
+
REF: ${{ github.ref }}
|
|
154
|
+
shell: python
|
|
155
|
+
run: |
|
|
156
|
+
import hashlib, json, os, re
|
|
157
|
+
from pathlib import Path
|
|
158
|
+
version = os.environ['VERSION']
|
|
159
|
+
if (os.environ['MODE'] != 'release' or os.environ['REPOSITORY'] != '0xf3cd/bazi'
|
|
160
|
+
or os.environ['REF'] != 'refs/heads/main' or not re.fullmatch(r'[0-9a-f]{40}', os.environ['SHA'])
|
|
161
|
+
or not re.fullmatch(r'[1-9][0-9]*', os.environ['ARTIFACT_ID'])
|
|
162
|
+
or not re.fullmatch(r'[0-9]+\.[0-9]+\.[0-9]+', version)):
|
|
163
|
+
raise SystemExit('Invalid publication identity')
|
|
164
|
+
root = Path('artifact')
|
|
165
|
+
expected = {f'dist/bazi-{version}.tar.gz', f'dist/bazi-{version}-py3-none-any.whl', 'release.json', 'RELEASE_NOTES.md'}
|
|
166
|
+
if ({p.relative_to(root).as_posix() for p in root.rglob('*') if p.is_file()} != expected | {'SHA256SUMS'}
|
|
167
|
+
or any(p.is_symlink() for p in root.rglob('*'))):
|
|
168
|
+
raise SystemExit('Unexpected release bundle files')
|
|
169
|
+
checksums = (root / 'SHA256SUMS').read_bytes()
|
|
170
|
+
if hashlib.sha256(checksums).hexdigest() != os.environ['MANIFEST_SHA']:
|
|
171
|
+
raise SystemExit('Manifest differs from tested build')
|
|
172
|
+
wanted = ''.join(f'{hashlib.sha256((root / name).read_bytes()).hexdigest()} {name}\n' for name in sorted(expected))
|
|
173
|
+
if checksums.decode() != wanted:
|
|
174
|
+
raise SystemExit('Release bundle checksum mismatch')
|
|
175
|
+
metadata = json.loads((root / 'release.json').read_text())
|
|
176
|
+
if metadata != {'name': 'bazi', 'version': version, 'sha': os.environ['SHA'], 'repository': '0xf3cd/bazi', 'run_id': os.environ['RUN_ID'], 'mode': 'release'}:
|
|
177
|
+
raise SystemExit('Release metadata identity mismatch')
|
|
178
|
+
- name: Reject existing version, tag or release
|
|
179
|
+
env:
|
|
180
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
181
|
+
shell: python
|
|
182
|
+
run: |
|
|
183
|
+
import os, urllib.error, urllib.request
|
|
184
|
+
version = os.environ['VERSION']
|
|
185
|
+
urls = [f'https://pypi.org/pypi/bazi/{version}/json',
|
|
186
|
+
f'https://api.github.com/repos/0xf3cd/bazi/git/ref/tags/v{version}',
|
|
187
|
+
f'https://api.github.com/repos/0xf3cd/bazi/releases/tags/v{version}']
|
|
188
|
+
for url in urls:
|
|
189
|
+
try:
|
|
190
|
+
with urllib.request.urlopen(url, timeout=30):
|
|
191
|
+
pass
|
|
192
|
+
except urllib.error.HTTPError as error:
|
|
193
|
+
if error.code == 404:
|
|
194
|
+
continue
|
|
195
|
+
raise
|
|
196
|
+
raise SystemExit('Version, tag or release already exists; deliberate recovery required')
|
|
197
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
198
|
+
with:
|
|
199
|
+
packages-dir: artifact/dist/
|
|
200
|
+
skip-existing: false
|
|
201
|
+
|
|
202
|
+
github-release:
|
|
203
|
+
needs: [preflight, build, pypi]
|
|
204
|
+
if: inputs.mode == 'release' && needs.preflight.result == 'success' && needs.pypi.result == 'success' && github.repository == '0xf3cd/bazi' && github.ref == 'refs/heads/main'
|
|
205
|
+
runs-on: ubuntu-latest
|
|
206
|
+
environment: release
|
|
207
|
+
permissions:
|
|
208
|
+
contents: write
|
|
209
|
+
steps:
|
|
210
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
211
|
+
with: *download
|
|
212
|
+
- *verify
|
|
213
|
+
- name: Verify PyPI bytes and create the tag and release without overwriting
|
|
214
|
+
env:
|
|
215
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
216
|
+
SHA: ${{ github.sha }}
|
|
217
|
+
GH_TOKEN: ${{ github.token }}
|
|
218
|
+
shell: python
|
|
219
|
+
run: |
|
|
220
|
+
import hashlib, json, os, urllib.error, urllib.request
|
|
221
|
+
from pathlib import Path
|
|
222
|
+
version, sha = os.environ['VERSION'], os.environ['SHA']
|
|
223
|
+
with urllib.request.urlopen(f'https://pypi.org/pypi/bazi/{version}/json', timeout=30) as response:
|
|
224
|
+
published = json.load(response)
|
|
225
|
+
actual = {entry['filename']: entry['digests']['sha256'] for entry in published['urls']}
|
|
226
|
+
expected = {p.name: hashlib.sha256(p.read_bytes()).hexdigest() for p in Path('artifact/dist').iterdir()}
|
|
227
|
+
if actual != expected:
|
|
228
|
+
raise SystemExit('PyPI bytes differ from tested pair')
|
|
229
|
+
base = 'https://api.github.com/repos/0xf3cd/bazi'
|
|
230
|
+
headers = {'Authorization': 'Bearer ' + os.environ['GH_TOKEN'], 'Accept': 'application/vnd.github+json', 'X-GitHub-Api-Version': '2022-11-28'}
|
|
231
|
+
for path in (f'/git/ref/tags/v{version}', f'/releases/tags/v{version}'):
|
|
232
|
+
try:
|
|
233
|
+
with urllib.request.urlopen(urllib.request.Request(base + path, headers=headers), timeout=30):
|
|
234
|
+
pass
|
|
235
|
+
except urllib.error.HTTPError as error:
|
|
236
|
+
if error.code == 404:
|
|
237
|
+
continue
|
|
238
|
+
raise
|
|
239
|
+
raise SystemExit('Existing tag/release; deliberate recovery required')
|
|
240
|
+
def post(path, data):
|
|
241
|
+
request = urllib.request.Request(base + path, data=json.dumps(data).encode(), headers={**headers, 'Content-Type': 'application/json'}, method='POST')
|
|
242
|
+
with urllib.request.urlopen(request, timeout=30) as response:
|
|
243
|
+
return json.load(response)
|
|
244
|
+
post('/git/refs', {'ref': f'refs/tags/v{version}', 'sha': sha})
|
|
245
|
+
release = post('/releases', {'tag_name': f'v{version}', 'target_commitish': sha,
|
|
246
|
+
'name': f'bazi {version}', 'body': Path('artifact/RELEASE_NOTES.md').read_text(), 'draft': True})
|
|
247
|
+
for path in sorted(p for p in Path('artifact').rglob('*') if p.is_file()):
|
|
248
|
+
url = f'https://uploads.github.com/repos/0xf3cd/bazi/releases/{release["id"]}/assets?name={path.name}'
|
|
249
|
+
request = urllib.request.Request(url, data=path.read_bytes(), headers={**headers, 'Content-Type': 'application/octet-stream'}, method='POST')
|
|
250
|
+
with urllib.request.urlopen(request, timeout=60) as response:
|
|
251
|
+
asset = json.load(response)
|
|
252
|
+
if asset.get('digest') != 'sha256:' + hashlib.sha256(path.read_bytes()).hexdigest():
|
|
253
|
+
raise SystemExit('Uploaded GitHub asset digest mismatch; release remains draft')
|
|
254
|
+
request = urllib.request.Request(base + f'/releases/{release["id"]}', data=b'{"draft":false}', headers={**headers, 'Content-Type': 'application/json'}, method='PATCH')
|
|
255
|
+
with urllib.request.urlopen(request, timeout=30):
|
|
256
|
+
pass
|
bazi-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Ningqi Wang (0xf3cd)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
bazi-1.0.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
include pyproject.toml MANIFEST.in LICENSE THIRD_PARTY_NOTICES.md
|
|
2
|
+
include README.md RELEASE_NOTES.md RELEASING.md Requirements.txt ruff.toml
|
|
3
|
+
include run_tests.py run_package_checks.py run_demo.py run_interpreter.py run_relationship_analyzer.py
|
|
4
|
+
recursive-include bazi *.py py.typed
|
|
5
|
+
include bazi/calendar/hko_data/data/jieqi_encoded.bin
|
|
6
|
+
include bazi/calendar/hko_data/data/lunardate_encoded.bin
|
|
7
|
+
include bazi/calendar/hko_data/data/19[0-9][0-9].txt
|
|
8
|
+
include bazi/calendar/hko_data/data/20[0-9][0-9].txt
|
|
9
|
+
include bazi/calendar/hko_data/data/2100.txt
|
|
10
|
+
include bazi/calendar/celestial_data/data/jieqi_moments.txt
|
|
11
|
+
include bazi/calendar/celestial_data/data/lunar_years_algo1.txt
|
|
12
|
+
include bazi/calendar/celestial_data/data/lunar_years_algo2.txt
|
|
13
|
+
include bazi/calendar/celestial_data/SCHEMA.md
|
|
14
|
+
recursive-include tests *.py *.ini *.txt *.json
|
|
15
|
+
include .github/workflows/release.yml
|
|
16
|
+
global-exclude *.py[cod]
|
bazi-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bazi
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Four Pillars charts, calendar backends and Bazi relations
|
|
5
|
+
Author: Ningqi Wang (0xf3cd)
|
|
6
|
+
Project-URL: Repository, https://github.com/0xf3cd/bazi
|
|
7
|
+
Project-URL: Issues, https://github.com/0xf3cd/bazi/issues
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
License-File: THIRD_PARTY_NOTICES.md
|
|
12
|
+
Dynamic: license-file
|
|
13
|
+
|
|
14
|
+
# Bazi
|
|
15
|
+
> 排盘、五行、十神、纳音、刑冲破害、合会
|
|
16
|
+
|
|
17
|
+
A Python 3.11+ library for Four Pillars charts and their relations. Runtime uses
|
|
18
|
+
only the standard library and five bundled calendar tables; no network access or
|
|
19
|
+
data generation is needed.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
To build and validate the current checkout and retain an installable pair:
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
python -m pip install -r Requirements.txt
|
|
27
|
+
python run_package_checks.py --output-dir ../bazi-tested
|
|
28
|
+
python -m pip install ../bazi-tested/bazi-1.0.0-py3-none-any.whl
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The output directory must be empty and outside the checkout. For a published
|
|
32
|
+
version, install from the registry with `python -m pip install bazi==1.0.0`.
|
|
33
|
+
There is no installed CLI, `src` compatibility package or root-class facade.
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from datetime import datetime
|
|
37
|
+
|
|
38
|
+
from bazi.bazi import Bazi
|
|
39
|
+
from bazi.bazi_chart import BaziChart
|
|
40
|
+
from bazi.school import BaziConfig
|
|
41
|
+
from bazi.transit_chart import TransitChart
|
|
42
|
+
from bazi.analyzer.relationship import RelationshipAnalyzer
|
|
43
|
+
|
|
44
|
+
config = BaziConfig.from_values(backend='celestial', precision='day')
|
|
45
|
+
chart = BaziChart(Bazi.create(datetime(2000, 1, 1, 12), 'male', config))
|
|
46
|
+
restored = BaziChart.from_json(chart.json)
|
|
47
|
+
assert restored.json == chart.json
|
|
48
|
+
print(chart.json['pillars'])
|
|
49
|
+
print(TransitChart(chart).at_year(2024))
|
|
50
|
+
print(RelationshipAnalyzer(chart).at_birth.shensha)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Birth times are naive local civil times; timezone-aware inputs are rejected.
|
|
54
|
+
Defaults remain `CELESTIAL` with day precision. `hko` provides date-level calendar
|
|
55
|
+
data; `celestial` and `celestial-algo2` use the bundled astronomical tables.
|
|
56
|
+
Backend differences and supported date ranges are documented in the calendar
|
|
57
|
+
modules; selecting a backend does not install its offline generator.
|
|
58
|
+
|
|
59
|
+
## Interfaces
|
|
60
|
+
|
|
61
|
+
Use the defining modules rather than expecting classes at the package root:
|
|
62
|
+
|
|
63
|
+
| Module | Principal interfaces |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `bazi.bazi` | `Bazi`, `BaziGender` |
|
|
66
|
+
| `bazi.bazi_chart` | `BaziChart`, `BaziJson`, JSON restoration with `from_json` |
|
|
67
|
+
| `bazi.school` | `BaziConfig`, `BaziSchool`, precision and school options |
|
|
68
|
+
| `bazi.calendar` | `CalendarBackend`, `CalendarDate`, `CalendarType`, `calendar_utils_of` |
|
|
69
|
+
| `bazi.transit_chart`, `bazi.transits` | `TransitChart`, `TransitSet`, `TransitKind` |
|
|
70
|
+
| `bazi.analyzer.relationship` | `RelationshipAnalyzer` |
|
|
71
|
+
| `bazi.interpreter` | `Interpreter.interpret_tiangan`, `Interpreter.interpret_shishen` |
|
|
72
|
+
| `bazi.defines`, `bazi.utils` | Domain enums and relation utilities, documented in their modules |
|
|
73
|
+
|
|
74
|
+
Domain names use Pinyin; enums also provide Chinese aliases. JSON retains Chinese
|
|
75
|
+
domain values and records configuration. `py.typed` exposes the inline type hints.
|
|
76
|
+
Private names, offline generation tools and undocumented internals are not a
|
|
77
|
+
promise of a stable public interface.
|
|
78
|
+
|
|
79
|
+
## Instructions
|
|
80
|
+
|
|
81
|
+
`Requirements.txt` is the development setup, not the installed library's dependency
|
|
82
|
+
list. It includes test, lint, typing and distribution-verification tools.
|
|
83
|
+
Source-tree mypy also needs `celestial-calendar==0.6.1`, as installed by CPython CI.
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
python -m pip install -r Requirements.txt
|
|
87
|
+
python -m pip install celestial-calendar==0.6.1
|
|
88
|
+
python run_tests.py -a -v
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The full gate runs every test (including slow and HKO-data tests), requires 100%
|
|
92
|
+
coverage, runs ruff and strict source mypy, demos, Interpreter, optimized input
|
|
93
|
+
checks, and isolated wheel/sdist-derived-wheel checks. The artifact checks use two
|
|
94
|
+
fresh dependency-free consumers and a separate installed mypy environment.
|
|
95
|
+
The artifact checks (`run_package_checks.py`, `-pkg` and `-a`) may download tools
|
|
96
|
+
and their dependencies from the package index to seed isolated build and typing
|
|
97
|
+
environments, even after the development requirements are installed.
|
|
98
|
+
Builds and consumers live in external temporary directories. Root demo scripts may
|
|
99
|
+
write to `output_data/`; the installed library's read-only behavior is checked separately.
|
|
100
|
+
|
|
101
|
+
| Flag | Effect |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `-a`, `--all` | Full gate; overrides `-nt` and `-k` |
|
|
104
|
+
| `-nt`, `--no-test` | Skip tests and coverage |
|
|
105
|
+
| `-s`, `-hko` | Include slow tests or HKO-data tests |
|
|
106
|
+
| `-k <expression>` | Select pytest tests; ignores `-s` and `-hko` |
|
|
107
|
+
| `-v` | Verbose output |
|
|
108
|
+
| `-c` | Coverage report, also written to `covhtml/` |
|
|
109
|
+
| `-cr <rate>`, `--coverage-rate <rate>` | Minimum coverage (default 100) |
|
|
110
|
+
| `-r`, `--ruff` | Run `ruff check` |
|
|
111
|
+
| `-m`, `-mypy`, `--mypy` | Run source mypy with the runner's strict flags |
|
|
112
|
+
| `-d` | Run both demo scripts |
|
|
113
|
+
| `-i` | Run Interpreter examples |
|
|
114
|
+
| `-osmoke`, `--o-smoke` | Run source public-contract smoke with `python -O` |
|
|
115
|
+
| `-pkg`, `--package` | Run isolated distribution checks |
|
|
116
|
+
| `--package-output-dir <path>` | With `-pkg` or `-a`, retain only the verified sdist and its rebuilt wheel |
|
|
117
|
+
|
|
118
|
+
A bare `python run_tests.py` omits slow/HKO tests and all optional tasks. It is not
|
|
119
|
+
the full verification gate. Do not run autoformatters; use `ruff check .`.
|
|
120
|
+
|
|
121
|
+
## Offline Generation
|
|
122
|
+
|
|
123
|
+
The committed data is read, not regenerated, during packaging or installed use.
|
|
124
|
+
The source tree and sdist contain the raw HKO inputs; the wheel does not.
|
|
125
|
+
Maintainers can regenerate from those sources with `python -m bazi.calendar.hko_data.encoder`
|
|
126
|
+
(`requests` is needed only if inputs must be downloaded), or `python -m bazi.calendar.celestial_data.generator`
|
|
127
|
+
with `celestial-calendar==0.6.1`. These optional tools are not runtime dependencies.
|
|
128
|
+
If an installed table is missing, reinstall the distribution instead.
|
|
129
|
+
|
|
130
|
+
## License
|
|
131
|
+
|
|
132
|
+
Author-owned material is available under the standard [MIT License](LICENSE).
|
|
133
|
+
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) describes the separate scope of
|
|
134
|
+
calendar data, quotations and other third-party material. Those materials are not
|
|
135
|
+
relicensed by the author's MIT grant. Both notices are included in built artifacts.
|
|
136
|
+
|
|
137
|
+
See [RELEASE_NOTES.md](RELEASE_NOTES.md) for version changes and
|
|
138
|
+
[RELEASING.md](RELEASING.md) for the manual release procedure.
|
bazi-1.0.0/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Bazi
|
|
2
|
+
> 排盘、五行、十神、纳音、刑冲破害、合会
|
|
3
|
+
|
|
4
|
+
A Python 3.11+ library for Four Pillars charts and their relations. Runtime uses
|
|
5
|
+
only the standard library and five bundled calendar tables; no network access or
|
|
6
|
+
data generation is needed.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
To build and validate the current checkout and retain an installable pair:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
python -m pip install -r Requirements.txt
|
|
14
|
+
python run_package_checks.py --output-dir ../bazi-tested
|
|
15
|
+
python -m pip install ../bazi-tested/bazi-1.0.0-py3-none-any.whl
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The output directory must be empty and outside the checkout. For a published
|
|
19
|
+
version, install from the registry with `python -m pip install bazi==1.0.0`.
|
|
20
|
+
There is no installed CLI, `src` compatibility package or root-class facade.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from datetime import datetime
|
|
24
|
+
|
|
25
|
+
from bazi.bazi import Bazi
|
|
26
|
+
from bazi.bazi_chart import BaziChart
|
|
27
|
+
from bazi.school import BaziConfig
|
|
28
|
+
from bazi.transit_chart import TransitChart
|
|
29
|
+
from bazi.analyzer.relationship import RelationshipAnalyzer
|
|
30
|
+
|
|
31
|
+
config = BaziConfig.from_values(backend='celestial', precision='day')
|
|
32
|
+
chart = BaziChart(Bazi.create(datetime(2000, 1, 1, 12), 'male', config))
|
|
33
|
+
restored = BaziChart.from_json(chart.json)
|
|
34
|
+
assert restored.json == chart.json
|
|
35
|
+
print(chart.json['pillars'])
|
|
36
|
+
print(TransitChart(chart).at_year(2024))
|
|
37
|
+
print(RelationshipAnalyzer(chart).at_birth.shensha)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Birth times are naive local civil times; timezone-aware inputs are rejected.
|
|
41
|
+
Defaults remain `CELESTIAL` with day precision. `hko` provides date-level calendar
|
|
42
|
+
data; `celestial` and `celestial-algo2` use the bundled astronomical tables.
|
|
43
|
+
Backend differences and supported date ranges are documented in the calendar
|
|
44
|
+
modules; selecting a backend does not install its offline generator.
|
|
45
|
+
|
|
46
|
+
## Interfaces
|
|
47
|
+
|
|
48
|
+
Use the defining modules rather than expecting classes at the package root:
|
|
49
|
+
|
|
50
|
+
| Module | Principal interfaces |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `bazi.bazi` | `Bazi`, `BaziGender` |
|
|
53
|
+
| `bazi.bazi_chart` | `BaziChart`, `BaziJson`, JSON restoration with `from_json` |
|
|
54
|
+
| `bazi.school` | `BaziConfig`, `BaziSchool`, precision and school options |
|
|
55
|
+
| `bazi.calendar` | `CalendarBackend`, `CalendarDate`, `CalendarType`, `calendar_utils_of` |
|
|
56
|
+
| `bazi.transit_chart`, `bazi.transits` | `TransitChart`, `TransitSet`, `TransitKind` |
|
|
57
|
+
| `bazi.analyzer.relationship` | `RelationshipAnalyzer` |
|
|
58
|
+
| `bazi.interpreter` | `Interpreter.interpret_tiangan`, `Interpreter.interpret_shishen` |
|
|
59
|
+
| `bazi.defines`, `bazi.utils` | Domain enums and relation utilities, documented in their modules |
|
|
60
|
+
|
|
61
|
+
Domain names use Pinyin; enums also provide Chinese aliases. JSON retains Chinese
|
|
62
|
+
domain values and records configuration. `py.typed` exposes the inline type hints.
|
|
63
|
+
Private names, offline generation tools and undocumented internals are not a
|
|
64
|
+
promise of a stable public interface.
|
|
65
|
+
|
|
66
|
+
## Instructions
|
|
67
|
+
|
|
68
|
+
`Requirements.txt` is the development setup, not the installed library's dependency
|
|
69
|
+
list. It includes test, lint, typing and distribution-verification tools.
|
|
70
|
+
Source-tree mypy also needs `celestial-calendar==0.6.1`, as installed by CPython CI.
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
python -m pip install -r Requirements.txt
|
|
74
|
+
python -m pip install celestial-calendar==0.6.1
|
|
75
|
+
python run_tests.py -a -v
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The full gate runs every test (including slow and HKO-data tests), requires 100%
|
|
79
|
+
coverage, runs ruff and strict source mypy, demos, Interpreter, optimized input
|
|
80
|
+
checks, and isolated wheel/sdist-derived-wheel checks. The artifact checks use two
|
|
81
|
+
fresh dependency-free consumers and a separate installed mypy environment.
|
|
82
|
+
The artifact checks (`run_package_checks.py`, `-pkg` and `-a`) may download tools
|
|
83
|
+
and their dependencies from the package index to seed isolated build and typing
|
|
84
|
+
environments, even after the development requirements are installed.
|
|
85
|
+
Builds and consumers live in external temporary directories. Root demo scripts may
|
|
86
|
+
write to `output_data/`; the installed library's read-only behavior is checked separately.
|
|
87
|
+
|
|
88
|
+
| Flag | Effect |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `-a`, `--all` | Full gate; overrides `-nt` and `-k` |
|
|
91
|
+
| `-nt`, `--no-test` | Skip tests and coverage |
|
|
92
|
+
| `-s`, `-hko` | Include slow tests or HKO-data tests |
|
|
93
|
+
| `-k <expression>` | Select pytest tests; ignores `-s` and `-hko` |
|
|
94
|
+
| `-v` | Verbose output |
|
|
95
|
+
| `-c` | Coverage report, also written to `covhtml/` |
|
|
96
|
+
| `-cr <rate>`, `--coverage-rate <rate>` | Minimum coverage (default 100) |
|
|
97
|
+
| `-r`, `--ruff` | Run `ruff check` |
|
|
98
|
+
| `-m`, `-mypy`, `--mypy` | Run source mypy with the runner's strict flags |
|
|
99
|
+
| `-d` | Run both demo scripts |
|
|
100
|
+
| `-i` | Run Interpreter examples |
|
|
101
|
+
| `-osmoke`, `--o-smoke` | Run source public-contract smoke with `python -O` |
|
|
102
|
+
| `-pkg`, `--package` | Run isolated distribution checks |
|
|
103
|
+
| `--package-output-dir <path>` | With `-pkg` or `-a`, retain only the verified sdist and its rebuilt wheel |
|
|
104
|
+
|
|
105
|
+
A bare `python run_tests.py` omits slow/HKO tests and all optional tasks. It is not
|
|
106
|
+
the full verification gate. Do not run autoformatters; use `ruff check .`.
|
|
107
|
+
|
|
108
|
+
## Offline Generation
|
|
109
|
+
|
|
110
|
+
The committed data is read, not regenerated, during packaging or installed use.
|
|
111
|
+
The source tree and sdist contain the raw HKO inputs; the wheel does not.
|
|
112
|
+
Maintainers can regenerate from those sources with `python -m bazi.calendar.hko_data.encoder`
|
|
113
|
+
(`requests` is needed only if inputs must be downloaded), or `python -m bazi.calendar.celestial_data.generator`
|
|
114
|
+
with `celestial-calendar==0.6.1`. These optional tools are not runtime dependencies.
|
|
115
|
+
If an installed table is missing, reinstall the distribution instead.
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
Author-owned material is available under the standard [MIT License](LICENSE).
|
|
120
|
+
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md) describes the separate scope of
|
|
121
|
+
calendar data, quotations and other third-party material. Those materials are not
|
|
122
|
+
relicensed by the author's MIT grant. Both notices are included in built artifacts.
|
|
123
|
+
|
|
124
|
+
See [RELEASE_NOTES.md](RELEASE_NOTES.md) for version changes and
|
|
125
|
+
[RELEASING.md](RELEASING.md) for the manual release procedure.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# bazi 1.0.0
|
|
2
|
+
|
|
3
|
+
- Installable `bazi` package with modular imports, Python 3.11+, inline typing and
|
|
4
|
+
no runtime dependencies. Source imports now use `bazi.*`, not `src.*`.
|
|
5
|
+
- The wheel bundles the two encoded HKO tables and three celestial tables. The
|
|
6
|
+
source archive also includes raw HKO inputs and source-verification tests.
|
|
7
|
+
- Existing calendar backends, rules, school defaults, JSON restoration, transits,
|
|
8
|
+
relationship analysis and Interpreter remain available without data regeneration.
|
|
9
|
+
- Standard MIT permission covers author-owned material; third-party notices state
|
|
10
|
+
the separate scope of embedded data and quotations.
|
|
11
|
+
- The manual release workflow defaults to rehearsal. Publication requires protected
|
|
12
|
+
environment approval and publishes only the tested sdist and its rebuilt wheel.
|
|
13
|
+
|
|
14
|
+
No `src` shim, root-class facade or installed command-line entrypoint is provided.
|
|
15
|
+
See `README.md` for principal module interfaces and `RELEASING.md` for release
|
|
16
|
+
prerequisites.
|
bazi-1.0.0/RELEASING.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Releasing bazi
|
|
2
|
+
|
|
3
|
+
The manual `release.yml` workflow prepares one verified sdist and its rebuilt
|
|
4
|
+
wheel. The direct wheel is only a validation control. There are no push/tag
|
|
5
|
+
publication triggers and no arbitrary ref, registry or artifact inputs.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
The owner must separately confirm PyPI account/project eligibility for `bazi` and
|
|
10
|
+
configure a Trusted Publisher (or pending publisher) for owner `0xf3cd`, repository
|
|
11
|
+
`bazi`, workflow `release.yml`, environment `release`. A public name lookup does not
|
|
12
|
+
reserve the name or establish account readiness. No API token belongs in this repository.
|
|
13
|
+
|
|
14
|
+
Create the GitHub environment `release` explicitly, with at least one required
|
|
15
|
+
reviewer and a custom deployment policy containing exactly branch `main` (not a
|
|
16
|
+
tag or wildcard). Personal owner approval is valid; allow self-review if that is
|
|
17
|
+
the intended approval path. This workflow does not require two people. Only the
|
|
18
|
+
publishing jobs bind the environment; an earlier read-only REST preflight fails
|
|
19
|
+
closed if the environment, reviewer rule or exact branch policy is missing.
|
|
20
|
+
|
|
21
|
+
The workflow must exist on the default branch before it can be dispatched.
|
|
22
|
+
|
|
23
|
+
## Rehearsal
|
|
24
|
+
|
|
25
|
+
1. Review `pyproject.toml`'s static version and `RELEASE_NOTES.md`. Merge the intended
|
|
26
|
+
release changes to main before dispatch; do not create a tag yet.
|
|
27
|
+
2. Dispatch `Prepare or Publish Release` on main with `mode=rehearsal` (the default).
|
|
28
|
+
This runs the full source and artifact gates at the dispatch SHA, with no
|
|
29
|
+
environment binding, write permission or OIDC permission.
|
|
30
|
+
3. Inspect the run's `tested-release` artifact: exactly one wheel and sdist under
|
|
31
|
+
`dist/`, release notes, `release.json`, and `SHA256SUMS`. Confirm the source SHA,
|
|
32
|
+
run ID, version, licenses, file contents and checksums. Artifacts expire after
|
|
33
|
+
30 days; retain the approved bytes before expiry when recovery may be needed.
|
|
34
|
+
|
|
35
|
+
Run a rehearsal before authorizing real publication. Local artifact and offline
|
|
36
|
+
policy tests do not substitute for it or prove GitHub/PyPI configuration is ready.
|
|
37
|
+
|
|
38
|
+
## Real Release
|
|
39
|
+
|
|
40
|
+
1. Obtain separate authorization and dispatch main with `mode=release`. Confirm
|
|
41
|
+
that the dispatch SHA is the intended release commit. The real run performs its
|
|
42
|
+
own full verification; it never accepts an artifact ID from a previous run.
|
|
43
|
+
2. Approve the protected environment for PyPI after checking the run's verified
|
|
44
|
+
bundle. The OIDC-only job downloads the exact immutable artifact ID produced by
|
|
45
|
+
this run, verifies checksums and identity, and rejects existing versions/tags/releases.
|
|
46
|
+
3. After PyPI succeeds, approve the GitHub Release job. This contents-write-only job
|
|
47
|
+
checks PyPI hashes, creates `v<version>` at the tested SHA, creates a draft release,
|
|
48
|
+
uploads the same bytes and notices, checks asset digests, then publishes the draft.
|
|
49
|
+
Neither privileged job checks out, builds, installs or imports repository code.
|
|
50
|
+
4. Independently download both published artifacts from PyPI and GitHub and compare
|
|
51
|
+
them to the retained checksums. Confirm the tag SHA and release metadata. Install
|
|
52
|
+
the published wheel in a fresh environment and repeat the consumer smoke.
|
|
53
|
+
Verify the actual PyPI Trusted Publisher identity/attestations too.
|
|
54
|
+
|
|
55
|
+
## Partial Failure
|
|
56
|
+
|
|
57
|
+
Publication is not transactional. An existing version, tag or release is an error;
|
|
58
|
+
there is no overwrite, tag move or `skip-existing` recovery. Do not rerun the whole
|
|
59
|
+
workflow to bypass a partial failure and do not rebuild the accepted bytes.
|
|
60
|
+
|
|
61
|
+
If PyPI has the pair but GitHub failed, stop and inspect the retained same-run
|
|
62
|
+
bundle, PyPI digests, tag SHA and any draft release/assets. The owner must approve
|
|
63
|
+
a targeted recovery of only the missing operations using those exact bytes. If a
|
|
64
|
+
tag or draft already exists, verify it rather than moving or replacing it. A digest
|
|
65
|
+
mismatch requires investigation, not automatic deletion, a version bump or a new upload.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
colorama==0.4.6
|
|
2
|
+
psutil==7.2.2
|
|
3
|
+
tzdata==2026.3
|
|
4
|
+
pytest==9.1.1
|
|
5
|
+
ruff==0.16.1
|
|
6
|
+
coverage==7.16.0
|
|
7
|
+
mypy==2.3.1
|
|
8
|
+
emoji==2.15.0
|
|
9
|
+
types-colorama==0.4.15.20260508
|
|
10
|
+
types-psutil==7.2.2.20260906
|
|
11
|
+
|
|
12
|
+
# Distribution builds and artifact verification (not runtime dependencies).
|
|
13
|
+
build==1.6.1
|
|
14
|
+
setuptools==84.0.0
|
|
15
|
+
twine==7.0.0
|
|
16
|
+
PyYAML==6.0.3
|
|
17
|
+
types-PyYAML==6.0.12.20250915
|