Compare commits

...

28 Commits

Author SHA1 Message Date
d940735453 Mark version 1.25 as released today 2022-02-25 15:45:55 +01:00
7d71067b3d Use BAT version 1.11 for UDIM support 2022-02-25 15:45:55 +01:00
b0b804410d Bumped version to 1.25 2022-02-25 15:45:55 +01:00
d55f2dcee1 Compatibility with Blender 3.1 / Python 3.10
Blender 3.1 will be shipped with Python 3.10, which made some backward-
incompatible changes in its asyncio module (the removal of the `loop`
parameter from various functions).

Depending on which Python version is used in Blender, the add-on now
passes (or not) the `loop` parameter, retaining backward compatibility.
2022-02-25 15:45:52 +01:00
2fbb5ac788 Bumped version to 1.24 2022-02-04 11:01:55 +01:00
b47b407589 Update CHANGELOG.md 2022-02-04 10:58:55 +01:00
a136366804 Upgrade to BAT 1.10
Upgrade to BAT to fix doubly-compressed blend files.

This also changes the way the wheel files are loaded, as the old
alphabetical ordering won't pick up on BAT 1.10. It now uses the
modification time of the wheel files to find the latest one.
2022-02-04 10:57:45 +01:00
6718e1646f Attract: prevent rare error in ATTRACT_OT_open_meta_blendfile 2021-11-19 15:46:19 +01:00
9d7f9a979e Bumped version to 1.23 2021-11-09 11:25:58 +01:00
326a793de0 Bump BAT 1.7 → 1.8
Bump BAT version to allow sending read-only files to Flamenco.
2021-11-09 11:25:44 +01:00
88ccb0f376 Bumped version to 1.22 2021-11-05 16:33:07 +01:00
5b8895278a Mark version 1.22 as released today 2021-11-05 16:33:00 +01:00
eb37d20039 Bump blender-asset-tracer 1.6 → 1.7
BAT v1.7 adds support for zstandard-compressed files, which are written
by Blender 3.0
2021-11-05 16:32:32 +01:00
4f49e8ca0b Cleanup: remove some unused imports 2021-11-05 16:25:27 +01:00
c931700fec Cleanup: formatting with Black
No functional changes.
2021-07-29 19:34:11 +02:00
6285826bfc Fix Windows incompatibility when using Shaman URLs as job storage path
The Shaman URL check was done on the wrong string, which went unnoticed
on Linux because an URL is a valid file path. However, on Windows this is
not the case, and thus caused problems. This is now fixed.
2021-07-29 19:33:36 +02:00
25150397c0 Bumped version to 1.21 2021-07-27 17:12:18 +02:00
c67b161e3d Bump blender-asset-tracer version 1.5.1 → 1.6
BAT 1.6 has better compatibility with Geometry Nodes.
2021-07-27 17:12:18 +02:00
f76dcb964e Bumped version to 1.20 2021-07-22 17:16:00 +02:00
2d868ec724 Disable Strict Pointer Mode in Blender Asset Tracer
Disable BAT's Strict Pointer Mode to work around issues with dangling
pointers in the Blender Animation Studio files. These seem to be caused
by not-perfectly-resynced library overrides. Ignoring those pointers
seems to cause less problems than crashing on them.
2021-07-22 16:44:53 +02:00
666ae0fa90 Bump blender-asset-tracer version 1.3.1 → 1.5.1
Bump BAT version to have it tested on the currently used Python version
(3.9) and to have the ability to disable Strict Pointer Mode.
2021-07-22 16:44:47 +02:00
49844e17b2 Bumped version to 1.19 2021-02-23 11:58:09 +01:00
06432a3534 Mark 1.19 as released in CHANGELOG.md 2021-02-23 11:58:03 +01:00
3a2e9bc672 Simplify @pyside_cache decorator
This fixes a compatibility issue with Python 3.9+, and at the same time
avoids a not-yet-quite-stable area of Blender's Python API.
2021-02-23 11:57:29 +01:00
ce331c7b22 Mark 1.18 as released 2021-02-16 11:58:05 +01:00
8b5dc65d84 Bumped version to 1.18 2021-02-16 11:58:05 +01:00
3bc7dcfa9e Update update_script.sh for new formatting with Black 2021-02-16 11:58:05 +01:00
d9fe24ece7 Cleanup: reformat setup.py with Black
No functional changes.
2021-02-16 11:58:02 +01:00
12 changed files with 192 additions and 121 deletions

View File

@ -1,6 +1,43 @@
# Blender Cloud changelog
## Version 1.18 (in development)
## Version 1.25 (2022-02-25)
- Compatibility with Blender 3.1 (Python 3.10).
- Bump blender-asset-tracer to version 1.11, for UDIM support.
## Version 1.24 (2022-02-04)
- Bump blender-asset-tracer version 1.8 → 1.10, for fixing a bug where files were doubly-compressed.
## Version 1.23 (2021-11-09)
- Bump blender-asset-tracer version 1.7 → 1.8, for compatibility with sending read-only blend files to Flamenco.
## Version 1.22 (2021-11-05)
- Fix Windows incompatibility when using Shaman URLs as job storage path.
- Bump blender-asset-tracer version 1.6 → 1.7, for compatibility with files compressed by Blender 3.0.
## Version 1.21 (2021-07-27)
- Bump blender-asset-tracer version 1.5.1 → 1.6, for better compatibility with Geometry Nodes.
## Version 1.20 (2021-07-22)
- Bump blender-asset-tracer version 1.3.1 -> 1.5.1.
- Blender-asset-tracer "Strict Pointer Mode" disabled, to avoid issues with
not-entirely-synced library overrides.
## Version 1.19 (2021-02-23)
- Another Python 3.9+ compatibility fix.
## Version 1.18 (2021-02-16)
- Add compatibility with Python 3.9 (as used in Blender 2.93).
- Drop compatibility with Blender 2.79 and older. The last version of the

View File

@ -21,7 +21,7 @@
bl_info = {
"name": "Blender Cloud",
"author": "Sybren A. Stüvel, Francesco Siddi, Inês Almeida, Antony Riakiotakis",
"version": (1, 17),
"version": (1, 25),
"blender": (2, 80, 0),
"location": "Addon Preferences panel, and Ctrl+Shift+Alt+A anywhere for texture browser",
"description": "Texture library browser and Blender Sync. Requires the Blender ID addon "

View File

@ -56,8 +56,11 @@ def setup_asyncio_executor():
from . import pillar
# Python 3.8 deprecated the 'loop' parameter, 3.10 removed it.
kwargs = {"loop": loop} if sys.version_info < (3, 8) else {}
# No more than this many Pillar calls should be made simultaneously
pillar.pillar_semaphore = asyncio.Semaphore(3, loop=loop)
pillar.pillar_semaphore = asyncio.Semaphore(3, **kwargs)
def kick_async_loop(*args) -> bool:

View File

@ -668,6 +668,8 @@ class ATTRACT_OT_open_meta_blendfile(AttractOperatorMixin, Operator):
@classmethod
def poll(cls, context):
if context.selected_sequences is None:
return False
return bool(
any(cls.filename_from_metadata(s) for s in context.selected_sequences)
)

View File

@ -47,7 +47,7 @@ log = logging.getLogger(__name__)
icons = None
@pyside_cache("version")
@pyside_cache
def blender_syncable_versions(self, context):
"""Returns the list of items used by SyncStatusProperties.version EnumProperty."""
@ -117,7 +117,7 @@ class SyncStatusProperties(PropertyGroup):
self["available_blender_versions"] = new_versions
@pyside_cache("project")
@pyside_cache
def bcloud_available_projects(self, context):
"""Returns the list of items used by BlenderCloudProjectGroup.project EnumProperty."""

View File

@ -42,11 +42,10 @@ else:
from .. import blender
import bpy
from bpy.types import AddonPreferences, Operator, WindowManager, Scene, PropertyGroup
from bpy.types import Operator, PropertyGroup
from bpy.props import (
StringProperty,
EnumProperty,
PointerProperty,
BoolProperty,
IntProperty,
)
@ -54,6 +53,8 @@ from bpy.props import (
from .. import async_loop, pillar, project_specific, utils
from ..utils import pyside_cache, redraw
import blender_asset_tracer.blendfile
log = logging.getLogger(__name__)
# Global flag used to determine whether panels etc. can be drawn.
@ -91,7 +92,7 @@ def scene_sample_count(scene) -> int:
return samples
@pyside_cache("manager")
@pyside_cache
def available_managers(self, context):
"""Returns the list of items used by a manager-selector EnumProperty."""
@ -269,7 +270,7 @@ def is_file_inside_job_storage(prefs, current_file: typing.Union[str, Path]) ->
if isinstance(current_file, str):
# Shaman URLs are always remote, so the current file cannot be in there.
if is_shaman_url(current_file):
if is_shaman_url(prefs.flamenco_job_file_path):
return False
current_file = Path(current_file)
@ -649,6 +650,12 @@ class FLAMENCO_OT_render(
self.log.debug("projdir: %s", projdir)
# Due to issues with library overrides and unsynced pointers, it's quite
# common for the Blender Animation Studio to get crashes of BAT. To avoid
# these, Strict Pointer Mode is disabled.
blender_asset_tracer.blendfile.set_strict_pointer_mode(False)
if is_shaman_url(prefs.flamenco_job_file_path):
endpoint, _ = bat_interface.parse_shaman_endpoint(
prefs.flamenco_job_file_path
@ -947,7 +954,7 @@ async def create_job(
*,
priority: int = 50,
job_description: str = None,
start_paused=False
start_paused=False,
) -> dict:
"""Creates a render job at Flamenco Server, returning the job object as dictionary."""
@ -1000,7 +1007,7 @@ def _render_output_path(
render_image_format: str,
flamenco_render_frame_range: str,
*,
include_rel_path: bool = True
include_rel_path: bool = True,
) -> typing.Optional[PurePath]:
"""Cached version of render_output_path()

View File

@ -25,6 +25,7 @@ import logging
from contextlib import closing, contextmanager
import urllib.parse
import pathlib
import sys
import requests.adapters
import requests.packages.urllib3.util.retry
@ -261,14 +262,17 @@ async def pillar_call(pillar_func, *args, caching=True, **kwargs):
)
loop = asyncio.get_event_loop()
# Python 3.8 deprecated the 'loop' parameter, 3.10 removed it.
kwargs = {"loop": loop} if sys.version_info < (3, 8) else {}
# Use explicit calls to acquire() and release() so that we have more control over
# how long we wait and how we handle timeouts.
try:
await asyncio.wait_for(pillar_semaphore.acquire(), timeout=10, loop=loop)
await asyncio.wait_for(pillar_semaphore.acquire(), timeout=10, **kwargs)
except asyncio.TimeoutError:
log.info("Waiting for semaphore to call %s", pillar_func.__name__)
try:
await asyncio.wait_for(pillar_semaphore.acquire(), timeout=50, loop=loop)
await asyncio.wait_for(pillar_semaphore.acquire(), timeout=50, **kwargs)
except asyncio.TimeoutError:
raise RuntimeError("Timeout waiting for Pillar Semaphore!")
@ -648,9 +652,11 @@ async def fetch_texture_thumbs(
for texture_node in texture_nodes
)
# Python 3.8 deprecated the 'loop' parameter, 3.10 removed it.
kwargs = {"loop": asyncio.get_event_loop()} if sys.version_info < (3, 8) else {}
# raises any exception from failed handle_texture_node() calls.
loop = asyncio.get_event_loop()
await asyncio.gather(*coros, loop=loop)
await asyncio.gather(*coros, **kwargs)
log.info("fetch_texture_thumbs: Done downloading texture thumbnails")
@ -929,8 +935,10 @@ async def download_texture(
)
downloaders.append(dlr)
loop = asyncio.get_event_loop()
return await asyncio.gather(*downloaders, return_exceptions=True, loop=loop)
# Python 3.8 deprecated the 'loop' parameter, 3.10 removed it.
kwargs = {"loop": asyncio.get_event_loop()} if sys.version_info < (3, 8) else {}
return await asyncio.gather(*downloaders, return_exceptions=True, **kwargs)
async def upload_file(

View File

@ -19,6 +19,7 @@
import json
import pathlib
import typing
from typing import Any, Dict, Optional, Tuple
def sizeof_fmt(num: int, suffix="B") -> str:
@ -35,7 +36,7 @@ def sizeof_fmt(num: int, suffix="B") -> str:
return "%.1f Yi%s" % (num, suffix)
def find_in_path(path: pathlib.Path, filename: str) -> typing.Optional[pathlib.Path]:
def find_in_path(path: pathlib.Path, filename: str) -> Optional[pathlib.Path]:
"""Performs a breadth-first search for the filename.
Returns the path that contains the file, or None if not found.
@ -66,41 +67,29 @@ def find_in_path(path: pathlib.Path, filename: str) -> typing.Optional[pathlib.P
return None
def pyside_cache(propname):
# Mapping from (module name, function name) to the last value returned by that function.
_pyside_cache: Dict[Tuple[str, str], Any] = {}
def pyside_cache(wrapped):
"""Decorator, stores the result of the decorated callable in Python-managed memory.
This is to work around the warning at
https://www.blender.org/api/blender_python_api_master/bpy.props.html#bpy.props.EnumProperty
"""
if callable(propname):
raise TypeError('Usage: pyside_cache("property_name")')
def decorator(wrapped):
"""Stores the result of the callable in Python-managed memory.
This is to work around the warning at
https://www.blender.org/api/blender_python_api_master/bpy.props.html#bpy.props.EnumProperty
"""
import functools
@functools.wraps(wrapped)
# We can't use (*args, **kwargs), because EnumProperty explicitly checks
# for the number of fixed positional arguments.
def wrapper(self, context):
def decorator(self, context):
result = None
try:
result = wrapped(self, context)
return result
finally:
try:
rna_type, rna_info = self.bl_rna.__annotations__[propname]
except AttributeError:
rna_type, rna_info = getattr(self.bl_rna, propname)
rna_info["_cached_result"] = result
return wrapper
_pyside_cache[wrapped.__module__, wrapped.__name__] = result
return decorator

View File

@ -58,8 +58,12 @@ def wheel_filename(fname_prefix: str) -> str:
if not wheels:
raise RuntimeError("Unable to find wheel at %r" % path_pattern)
# If there are multiple wheels that match, load the latest one.
wheels.sort()
# If there are multiple wheels that match, load the last-modified one.
# Alphabetical sorting isn't going to cut it since BAT 1.10 was released.
def modtime(filename: str) -> int:
return os.stat(filename).st_mtime
wheels.sort(key=modtime)
return wheels[-1]
@ -68,3 +72,8 @@ def load_wheels():
load_wheel("lockfile", "lockfile")
load_wheel("cachecontrol", "CacheControl")
load_wheel("pillarsdk", "pillarsdk")
if __name__ == "__main__":
wheel = wheel_filename("blender_asset_tracer")
print(f"Wheel: {wheel}")

View File

@ -3,7 +3,7 @@
lockfile==0.12.2
pillarsdk==1.8.0
wheel==0.29.0
blender-asset-tracer==1.3.1
blender-asset-tracer==1.11
# Secondary requirements:
asn1crypto==0.24.0

156
setup.py
View File

@ -32,12 +32,14 @@ from distutils.command.install import install, INSTALL_SCHEMES
from distutils.command.install_egg_info import install_egg_info
from setuptools import setup, find_packages
requirement_re = re.compile('[><=]+')
requirement_re = re.compile("[><=]+")
sys.dont_write_bytecode = True
# Download wheels from pypi. The specific versions are taken from requirements.txt
wheels = [
'lockfile', 'pillarsdk', 'blender-asset-tracer',
"lockfile",
"pillarsdk",
"blender-asset-tracer",
]
@ -55,9 +57,9 @@ class BuildWheels(Command):
description = "builds/downloads the dependencies as wheel files"
user_options = [
('wheels-path=', None, "wheel file installation path"),
('deps-path=', None, "path in which dependencies are built"),
('cachecontrol-path=', None, "subdir of deps-path containing CacheControl"),
("wheels-path=", None, "wheel file installation path"),
("deps-path=", None, "path in which dependencies are built"),
("cachecontrol-path=", None, "subdir of deps-path containing CacheControl"),
]
def initialize_options(self):
@ -70,22 +72,23 @@ class BuildWheels(Command):
self.my_path = pathlib.Path(__file__).resolve().parent
package_path = self.my_path / self.distribution.get_name()
self.wheels_path = set_default_path(self.wheels_path, package_path / 'wheels')
self.deps_path = set_default_path(self.deps_path, self.my_path / 'build/deps')
self.cachecontrol_path = set_default_path(self.cachecontrol_path,
self.deps_path / 'cachecontrol')
self.bat_path = self.deps_path / 'bat'
self.wheels_path = set_default_path(self.wheels_path, package_path / "wheels")
self.deps_path = set_default_path(self.deps_path, self.my_path / "build/deps")
self.cachecontrol_path = set_default_path(
self.cachecontrol_path, self.deps_path / "cachecontrol"
)
self.bat_path = self.deps_path / "bat"
def run(self):
log.info('Storing wheels in %s', self.wheels_path)
log.info("Storing wheels in %s", self.wheels_path)
# Parse the requirements.txt file
requirements = {}
with open(str(self.my_path / 'requirements.txt')) as reqfile:
with open(str(self.my_path / "requirements.txt")) as reqfile:
for line in reqfile.readlines():
line = line.strip()
if not line or line.startswith('#'):
if not line or line.startswith("#"):
# comments are lines that start with # only
continue
@ -97,37 +100,45 @@ class BuildWheels(Command):
self.wheels_path.mkdir(parents=True, exist_ok=True)
for package in wheels:
pattern = package.replace('-', '_') + '*.whl'
pattern = package.replace("-", "_") + "*.whl"
if list(self.wheels_path.glob(pattern)):
continue
self.download_wheel(requirements[package])
# Build CacheControl.
if not list(self.wheels_path.glob('CacheControl*.whl')):
log.info('Building CacheControl in %s', self.cachecontrol_path)
if not list(self.wheels_path.glob("CacheControl*.whl")):
log.info("Building CacheControl in %s", self.cachecontrol_path)
# self.git_clone(self.cachecontrol_path,
# 'https://github.com/ionrock/cachecontrol.git',
# 'v%s' % requirements['CacheControl'][1])
# FIXME: we need my clone until pull request #125 has been merged & released
self.git_clone(self.cachecontrol_path,
'https://github.com/sybrenstuvel/cachecontrol.git',
'sybren-filecache-delete-crash-fix')
self.git_clone(
self.cachecontrol_path,
"https://github.com/sybrenstuvel/cachecontrol.git",
"sybren-filecache-delete-crash-fix",
)
self.build_copy_wheel(self.cachecontrol_path)
# Ensure that the wheels are added to the data files.
self.distribution.data_files.append(
('blender_cloud/wheels', (str(p) for p in self.wheels_path.glob('*.whl')))
("blender_cloud/wheels", (str(p) for p in self.wheels_path.glob("*.whl")))
)
def download_wheel(self, requirement):
"""Downloads a wheel from PyPI and saves it in self.wheels_path."""
subprocess.check_call([
sys.executable, '-m', 'pip',
'download', '--no-deps',
'--dest', str(self.wheels_path),
requirement[0]
])
subprocess.check_call(
[
sys.executable,
"-m",
"pip",
"download",
"--no-deps",
"--dest",
str(self.wheels_path),
requirement[0],
]
)
def git_clone(self, workdir: pathlib.Path, git_url: str, checkout: str = None):
if workdir.exists():
@ -136,24 +147,25 @@ class BuildWheels(Command):
workdir.mkdir(parents=True)
subprocess.check_call(['git', 'clone', git_url, str(workdir)],
cwd=str(workdir.parent))
subprocess.check_call(
["git", "clone", git_url, str(workdir)], cwd=str(workdir.parent)
)
if checkout:
subprocess.check_call(['git', 'checkout', checkout],
cwd=str(workdir))
subprocess.check_call(["git", "checkout", checkout], cwd=str(workdir))
def build_copy_wheel(self, package_path: pathlib.Path):
# Make sure no wheels exist yet, so that we know which one to copy later.
to_remove = list((package_path / 'dist').glob('*.whl'))
to_remove = list((package_path / "dist").glob("*.whl"))
for fname in to_remove:
fname.unlink()
subprocess.check_call([sys.executable, 'setup.py', 'bdist_wheel'],
cwd=str(package_path))
subprocess.check_call(
[sys.executable, "setup.py", "bdist_wheel"], cwd=str(package_path)
)
wheel = next((package_path / 'dist').glob('*.whl'))
log.info('copying %s to %s', wheel, self.wheels_path)
wheel = next((package_path / "dist").glob("*.whl"))
log.info("copying %s to %s", wheel, self.wheels_path)
shutil.copy(str(wheel), str(self.wheels_path))
@ -163,19 +175,19 @@ class BlenderAddonBdist(bdist):
def initialize_options(self):
super().initialize_options()
self.formats = ['zip']
self.plat_name = 'addon' # use this instead of 'linux-x86_64' or similar.
self.formats = ["zip"]
self.plat_name = "addon" # use this instead of 'linux-x86_64' or similar.
self.fix_local_prefix()
def fix_local_prefix(self):
"""Place data files in blender_cloud instead of local/blender_cloud."""
for key in INSTALL_SCHEMES:
if 'data' not in INSTALL_SCHEMES[key]:
if "data" not in INSTALL_SCHEMES[key]:
continue
INSTALL_SCHEMES[key]['data'] = '$base'
INSTALL_SCHEMES[key]["data"] = "$base"
def run(self):
self.run_command('wheels')
self.run_command("wheels")
super().run()
@ -184,7 +196,7 @@ class BlenderAddonFdist(BlenderAddonBdist):
"""Ensures that 'python setup.py fdist' creates a plain folder structure."""
user_options = [
('dest-path=', None, 'addon installation path'),
("dest-path=", None, "addon installation path"),
]
def initialize_options(self):
@ -198,12 +210,12 @@ class BlenderAddonFdist(BlenderAddonBdist):
filepath = self.distribution.dist_files[0][2]
# if dest_path is not specified use the filename as the dest_path (minus the .zip)
assert filepath.endswith('.zip')
assert filepath.endswith(".zip")
target_folder = self.dest_path or filepath[:-4]
print('Unzipping the package on {}.'.format(target_folder))
print("Unzipping the package on {}.".format(target_folder))
with zipfile.ZipFile(filepath, 'r') as zip_ref:
with zipfile.ZipFile(filepath, "r") as zip_ref:
zip_ref.extractall(target_folder)
@ -213,8 +225,8 @@ class BlenderAddonInstall(install):
def initialize_options(self):
super().initialize_options()
self.prefix = ''
self.install_lib = ''
self.prefix = ""
self.install_lib = ""
class AvoidEggInfo(install_egg_info):
@ -229,34 +241,38 @@ class AvoidEggInfo(install_egg_info):
setup(
cmdclass={'bdist': BlenderAddonBdist,
'fdist': BlenderAddonFdist,
'install': BlenderAddonInstall,
'install_egg_info': AvoidEggInfo,
'wheels': BuildWheels},
name='blender_cloud',
description='The Blender Cloud addon allows browsing the Blender Cloud from Blender.',
version='1.17',
author='Sybren A. Stüvel',
author_email='sybren@stuvel.eu',
packages=find_packages('.'),
cmdclass={
"bdist": BlenderAddonBdist,
"fdist": BlenderAddonFdist,
"install": BlenderAddonInstall,
"install_egg_info": AvoidEggInfo,
"wheels": BuildWheels,
},
name="blender_cloud",
description="The Blender Cloud addon allows browsing the Blender Cloud from Blender.",
version="1.25",
author="Sybren A. Stüvel",
author_email="sybren@stuvel.eu",
packages=find_packages("."),
data_files=[
('blender_cloud', ['README.md', 'README-flamenco.md', 'CHANGELOG.md']),
('blender_cloud/icons', glob.glob('blender_cloud/icons/*')),
('blender_cloud/texture_browser/icons',
glob.glob('blender_cloud/texture_browser/icons/*'))
("blender_cloud", ["README.md", "README-flamenco.md", "CHANGELOG.md"]),
("blender_cloud/icons", glob.glob("blender_cloud/icons/*")),
(
"blender_cloud/texture_browser/icons",
glob.glob("blender_cloud/texture_browser/icons/*"),
),
],
scripts=[],
url='https://developer.blender.org/diffusion/BCA/',
license='GNU General Public License v2 or later (GPLv2+)',
platforms='',
url="https://developer.blender.org/diffusion/BCA/",
license="GNU General Public License v2 or later (GPLv2+)",
platforms="",
classifiers=[
'Intended Audience :: End Users/Desktop',
'Operating System :: OS Independent',
'Environment :: Plugins',
'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
'Programming Language :: Python',
'Programming Language :: Python :: 3.5',
"Intended Audience :: End Users/Desktop",
"Operating System :: OS Independent",
"Environment :: Plugins",
"License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)",
"Programming Language :: Python",
"Programming Language :: Python :: 3.5",
],
zip_safe=False,
)

View File

@ -9,8 +9,8 @@ fi
BL_INFO_VER=$(echo "$VERSION" | sed 's/\./, /g')
sed "s/version='[^']*'/version='$VERSION'/" -i setup.py
sed "s/'version': ([^)]*)/'version': ($BL_INFO_VER)/" -i blender_cloud/__init__.py
sed "s/version=\"[^\"]*\"/version=\"$VERSION\"/" -i setup.py
sed "s/\"version\": ([^)]*)/\"version\": ($BL_INFO_VER)/" -i blender_cloud/__init__.py
git diff
echo